sql >> Database >  >> RDS >> MariaDB

ProxySQL-native clustering met Kubernetes

ProxySQL ondersteunt native clustering sinds v1.4.2. Dit betekent dat meerdere ProxySQL-instanties clusterbewust zijn; ze zijn op de hoogte van elkaars status en kunnen de configuratiewijzigingen automatisch verwerken door te synchroniseren met de meest up-to-date configuratie op basis van configuratieversie, tijdstempel en controlesomwaarde. Bekijk deze blogpost die laat zien hoe je clusterondersteuning voor ProxySQL kunt configureren en hoe je kunt verwachten dat het zich gedraagt.

ProxySQL is een gedecentraliseerde proxy, aanbevolen om dichter bij de applicatie te worden ingezet. Deze aanpak kan redelijk goed worden geschaald, zelfs tot honderden knooppunten, omdat het is ontworpen om tijdens runtime gemakkelijk opnieuw te kunnen worden geconfigureerd. Om meerdere ProxySQL-knooppunten efficiënt te beheren, moet men ervoor zorgen dat alle wijzigingen die op een van de knooppunten worden uitgevoerd, worden toegepast op alle knooppunten in de farm. Zonder native clustering moet je de configuraties handmatig exporteren en importeren naar de andere nodes (hoewel je dit zelf zou kunnen automatiseren).

In de vorige blogpost hebben we het gehad over ProxySQL-clustering via Kubernetes ConfigMap. Deze benadering is min of meer behoorlijk efficiënt met de gecentraliseerde configuratiebenadering in ConfigMap. Alles wat in ConfigMap is geladen, wordt in pods gemount. Het bijwerken van de configuratie kan worden gedaan via versiebeheer (wijzig de proxysql.cnf-inhoud en laad deze in ConfigMap met een andere naam) en druk vervolgens naar de pods, afhankelijk van de plannings- en updatestrategie van de implementatiemethode.

In een snel veranderende omgeving is deze ConfigMap-aanpak echter waarschijnlijk niet de beste methode, omdat om de nieuwe configuratie te laden, de pod opnieuw moet worden gepland om het ConfigMap-volume opnieuw te koppelen en dit kan de ProxySQL-service als geheel in gevaar brengen. Laten we bijvoorbeeld zeggen dat in onze omgeving ons strikte wachtwoordbeleid vereist dat het MySQL-gebruikerswachtwoord elke 7 dagen verloopt, wat we zouden moeten blijven doen om de ProxySQL ConfigMap wekelijks bij te werken voor het nieuwe wachtwoord. Een kanttekening is dat de MySQL-gebruiker in ProxySQL de gebruiker en het wachtwoord nodig heeft om overeen te komen met die op de backend MySQL-servers. Dat is waar we moeten beginnen met het gebruik van ProxySQL native clustering-ondersteuning in Kubernetes, om de configuratiewijzigingen automatisch toe te passen zonder het gedoe van ConfigMap-versiebeheer en pod-herplanning.

In deze blogpost laten we u zien hoe u ProxySQL-native clustering met headless-service op Kubernetes uitvoert. Onze architectuur op hoog niveau kan als volgt worden geïllustreerd:

We hebben 3 Galera-knooppunten die draaien op een bare-metal infrastructuur die wordt geïmplementeerd en beheerd door ClusterControl:

  • 192.168.0.21
  • 192.168.0.22
  • 192.168.0.23

Onze applicaties draaien allemaal als pods binnen Kubernetes. Het idee is om twee ProxySQL-instanties te introduceren tussen de applicatie en ons databasecluster om als reverse proxy te dienen. Applicaties maken vervolgens verbinding met ProxySQL-pods via Kubernetes-service, die load-balanced en failover zal zijn over een aantal ProxySQL-replica's.

Het volgende is een samenvatting van onze Kubernetes-configuratie:

[email protected]:~# kubectl get nodes -o wide
NAME    STATUS   ROLES    AGE     VERSION   INTERNAL-IP       EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
kube1   Ready    master   5m      v1.15.1   192.168.100.201   <none>        Ubuntu 18.04.1 LTS   4.15.0-39-generic   docker://18.9.7
kube2   Ready    <none>   4m1s    v1.15.1   192.168.100.202   <none>        Ubuntu 18.04.1 LTS   4.15.0-39-generic   docker://18.9.7
kube3   Ready    <none>   3m42s   v1.15.1   192.168.100.203   <none>        Ubuntu 18.04.1 LTS   4.15.0-39-generic   docker://18.9.7

ProxySQL-configuratie via ConfigMap

Laten we eerst onze basisconfiguratie voorbereiden die in ConfigMap wordt geladen. Maak een bestand met de naam proxysql.cnf en voeg de volgende regels toe:

datadir="/var/lib/proxysql"

admin_variables=
{
    admin_credentials="proxysql-admin:adminpassw0rd;cluster1:secret1pass"
    mysql_ifaces="0.0.0.0:6032"
    refresh_interval=2000
    cluster_username="cluster1"
    cluster_password="secret1pass"
    cluster_check_interval_ms=200
    cluster_check_status_frequency=100
    cluster_mysql_query_rules_save_to_disk=true
    cluster_mysql_servers_save_to_disk=true
    cluster_mysql_users_save_to_disk=true
    cluster_proxysql_servers_save_to_disk=true
    cluster_mysql_query_rules_diffs_before_sync=3
    cluster_mysql_servers_diffs_before_sync=3
    cluster_mysql_users_diffs_before_sync=3
    cluster_proxysql_servers_diffs_before_sync=3
}

mysql_variables=
{
    threads=4
    max_connections=2048
    default_query_delay=0
    default_query_timeout=36000000
    have_compress=true
    poll_timeout=2000
    interfaces="0.0.0.0:6033;/tmp/proxysql.sock"
    default_schema="information_schema"
    stacksize=1048576
    server_version="5.1.30"
    connect_timeout_server=10000
    monitor_history=60000
    monitor_connect_interval=200000
    monitor_ping_interval=200000
    ping_interval_server_msec=10000
    ping_timeout_server=200
    commands_stats=true
    sessions_sort=true
    monitor_username="proxysql"
    monitor_password="proxysqlpassw0rd"
    monitor_galera_healthcheck_interval=2000
    monitor_galera_healthcheck_timeout=800
}

mysql_galera_hostgroups =
(
    {
        writer_hostgroup=10
        backup_writer_hostgroup=20
        reader_hostgroup=30
        offline_hostgroup=9999
        max_writers=1
        writer_is_also_reader=1
        max_transactions_behind=30
        active=1
    }
)

mysql_servers =
(
    { address="192.168.0.21" , port=3306 , hostgroup=10, max_connections=100 },
    { address="192.168.0.22" , port=3306 , hostgroup=10, max_connections=100 },
    { address="192.168.0.23" , port=3306 , hostgroup=10, max_connections=100 }
)

mysql_query_rules =
(
    {
        rule_id=100
        active=1
        match_pattern="^SELECT .* FOR UPDATE"
        destination_hostgroup=10
        apply=1
    },
    {
        rule_id=200
        active=1
        match_pattern="^SELECT .*"
        destination_hostgroup=20
        apply=1
    },
    {
        rule_id=300
        active=1
        match_pattern=".*"
        destination_hostgroup=10
        apply=1
    }
)

mysql_users =
(
    { username = "wordpress", password = "passw0rd", default_hostgroup = 10, transaction_persistent = 0, active = 1 },
    { username = "sbtest", password = "passw0rd", default_hostgroup = 10, transaction_persistent = 0, active = 1 }
)

proxysql_servers =
(
    { hostname = "proxysql-0.proxysqlcluster", port = 6032, weight = 1 },
    { hostname = "proxysql-1.proxysqlcluster", port = 6032, weight = 1 }
)

Enkele van de bovenstaande configuratieregels worden per sectie hieronder uitgelegd:

admin_variables

Let op de admin_credentials variabele waarbij we een niet-standaard gebruiker hebben gebruikt, namelijk "proxysql-admin". ProxySQL reserveert de standaard "admin"-gebruiker alleen voor lokale verbinding via localhost. Daarom moeten we andere gebruikers gebruiken om op afstand toegang te krijgen tot de ProxySQL-instantie. Anders krijgt u de volgende foutmelding:

ERROR 1040 (42000): User 'admin' can only connect locally

We hebben ook de cluster_username . toegevoegd en cluster_password waarde in de admin_credentials regel, gescheiden door een puntkomma om automatische synchronisatie mogelijk te maken. Alle variabelen voorafgegaan door cluster_* zijn gerelateerd aan ProxySQL native clustering en spreken voor zich.

mysql_galera_hostgroups

Dit is een nieuwe richtlijn die is geïntroduceerd voor ProxySQL 2.x (onze ProxySQL-image draait op 2.0.5). Als je ProxySQL 1.x wilt gebruiken, verwijder dan dit deel en gebruik in plaats daarvan de plannertabel. We hebben de configuratiedetails al uitgelegd in deze blogpost, ProxySQL 2.0 uitvoeren en configureren voor MySQL Galera Cluster op Docker onder "ProxySQL 2.x-ondersteuning voor Galera Cluster".

mysql_servers

Alle regels spreken voor zich en zijn gebaseerd op drie databaseservers die draaien in MySQL Galera Cluster, zoals samengevat in de volgende Topologie-screenshot genomen van ClusterControl:

proxysql_servers

Hier definiëren we een lijst met ProxySQL-peers:

  • hostnaam - hostnaam/IP-adres van peer
  • poort - Peer's beheerderspoort
  • gewicht - Momenteel niet gebruikt, maar in de roadmap voor toekomstige verbeteringen
  • commentaar - Gratis commentaarveld

In de Docker/Kubernetes-omgeving zijn er meerdere manieren om hostnamen of IP-adressen van containers te ontdekken en te koppelen en deze in deze tabel in te voegen, hetzij door ConfigMap, handmatig invoegen, via entrypoint.sh-scripting, omgevingsvariabelen of op een andere manier te gebruiken. In Kubernetes is het, afhankelijk van de gebruikte ReplicationController of Deployment-methode, wat lastig om de oplosbare hostnaam van de pod vooraf te raden, tenzij je op StatefulSet draait.

Bekijk deze tutorial over StatefulState pod ordinale index die een stabiele oplosbare hostnaam biedt voor de gemaakte pods. Combineer dit met headless service (hieronder uitgelegd), het oplosbare formaat van de hostnaam zou zijn:

{app_name}-{index_number}.{service}

Waarbij {service} een headless-service is, die uitlegt waar "proxysql-0.proxysqlcluster" en "proxysql-1.proxysqlcluster" vandaan komen. Als u meer dan 2 replica's wilt hebben, voegt u dienovereenkomstig meer items toe door een oplopend indexnummer toe te voegen ten opzichte van de StatefulSet-toepassingsnaam.

Nu zijn we klaar om het configuratiebestand naar ConfigMap te pushen, dat tijdens de implementatie in elke ProxySQL-pod wordt gemount:

$ kubectl create configmap proxysql-configmap --from-file=proxysql.cnf

Controleer of onze ConfigMap correct is geladen:

$ kubectl get configmap
NAME                 DATA   AGE
proxysql-configmap   1      7h57m

ProxySQL Monitoring-gebruiker maken

De volgende stap voordat we met de implementatie beginnen, is het maken van een ProxySQL-monitoringgebruiker in ons databasecluster. Aangezien we op het Galera-cluster draaien, voert u de volgende instructies uit op een van de Galera-knooppunten:

mysql> CREATE USER 'proxysql'@'%' IDENTIFIED BY 'proxysqlpassw0rd';
mysql> GRANT USAGE ON *.* TO 'proxysql'@'%';

Als u de MySQL-gebruikers niet heeft aangemaakt (zoals gespecificeerd in het gedeelte mysql_users hierboven), moeten we deze ook aanmaken:

mysql> CREATE USER 'wordpress'@'%' IDENTIFIED BY 'passw0rd';
mysql> GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'%';
mysql> CREATE USER 'sbtest'@'%' IDENTIFIED BY 'passw0rd';
mysql> GRANT ALL PRIVILEGES ON sbtest.* TO 'proxysql'@'%';

Dat is het. We zijn nu klaar om de implementatie te starten.

Een StatefulSet implementeren

We beginnen met het maken van twee ProxySQL-instanties of replica's voor redundantiedoeleinden met StatefulSet.

Laten we beginnen met het maken van een tekstbestand met de naam proxysql-ss-svc.yml en de volgende regels toevoegen:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: proxysql
  labels:
    app: proxysql
spec:
  replicas: 2
  serviceName: proxysqlcluster
  selector:
    matchLabels:
      app: proxysql
      tier: frontend
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: proxysql
        tier: frontend
    spec:
      restartPolicy: Always
      containers:
      - image: severalnines/proxysql:2.0.4
        name: proxysql
        volumeMounts:
        - name: proxysql-config
          mountPath: /etc/proxysql.cnf
          subPath: proxysql.cnf
        ports:
        - containerPort: 6033
          name: proxysql-mysql
        - containerPort: 6032
          name: proxysql-admin
      volumes:
      - name: proxysql-config
        configMap:
          name: proxysql-configmap
---
apiVersion: v1
kind: Service
metadata:
  annotations:
  labels:
    app: proxysql
    tier: frontend
  name: proxysql
spec:
  ports:
  - name: proxysql-mysql
    nodePort: 30033
    port: 6033
    protocol: TCP
    targetPort: 6033
  - name: proxysql-admin
    nodePort: 30032
    port: 6032
    protocol: TCP
    targetPort: 6032
  selector:
    app: proxysql
    tier: frontend
  type: NodePort

Er zijn twee secties van de bovenstaande definitie:StatefulSet en Service. De StatefulSet is de definitie van onze pods of replica's en het koppelpunt voor ons ConfigMap-volume, geladen vanuit proxysql-configmap. De volgende sectie is de servicedefinitie, waar we definiëren hoe de pods moeten worden weergegeven en gerouteerd voor het interne of externe netwerk.

Maak de ProxySQL stateful set en service:

$ kubectl create -f proxysql-ss-svc.yml

Controleer de status van de pod en de service:

$ kubectl get pods,svc
NAME             READY   STATUS    RESTARTS   AGE
pod/proxysql-0   1/1     Running   0          4m46s
pod/proxysql-1   1/1     Running   0          2m59s

NAME                      TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                         AGE
service/kubernetes        ClusterIP   10.96.0.1        <none>        443/TCP                         10h
service/proxysql          NodePort    10.111.240.193   <none>        6033:30033/TCP,6032:30032/TCP   5m28s

Als je naar het logboek van de pod kijkt, zou je zien dat we overspoeld werden met deze waarschuwing:

$ kubectl logs -f proxysql-0
...
2019-08-01 19:06:18 ProxySQL_Cluster.cpp:215:ProxySQL_Cluster_Monitor_thread(): [WARNING] Cluster: unable to connect to peer proxysql-1.proxysqlcluster:6032 . Error: Unknown MySQL server host 'proxysql-1.proxysqlcluster' (0)

Het bovenstaande betekent eenvoudigweg dat proxysql-0 "proxysql-1.proxysqlcluster" niet kon oplossen en er geen verbinding mee kon maken, wat wordt verwacht omdat we onze headless-service niet hebben gemaakt voor DNS-records die nodig zijn voor inter-ProxySQL-communicatie.

Kubernetes Headless-service

Om ervoor te zorgen dat ProxySQL-pods de verwachte FQDN kunnen oplossen en er rechtstreeks verbinding mee kunnen maken, moet het oplossingsproces het toegewezen doel-pod-IP-adres kunnen opzoeken en niet het virtuele IP-adres. Dit is waar headless service in beeld komt. Bij het maken van een headless-service door "clusterIP=None" in te stellen, wordt er geen taakverdeling geconfigureerd en wordt er geen cluster-IP (virtuele IP) toegewezen voor deze service. Alleen DNS wordt automatisch geconfigureerd. Wanneer u een DNS-query uitvoert voor een headless-service, krijgt u de lijst met de IP-adressen van de pods.

Hier is hoe het eruit ziet als we de headless service DNS-records opzoeken voor "proxysqlcluster" (in dit voorbeeld hadden we 3 ProxySQL-instanties):

$ host proxysqlcluster
proxysqlcluster.default.svc.cluster.local has address 10.40.0.2
proxysqlcluster.default.svc.cluster.local has address 10.40.0.3
proxysqlcluster.default.svc.cluster.local has address 10.32.0.2

Terwijl de volgende uitvoer het DNS-record toont voor de standaardservice genaamd "proxysql", die wordt omgezet in de clusterIP:

$ host proxysql
proxysql.default.svc.cluster.local has address 10.110.38.154

Om een ​​headless-service te maken en deze aan de pods te koppelen, moet men de ServiceName definiëren in de StatefulSet-declaratie en moet de Service-definitie "clusterIP=None" hebben, zoals hieronder wordt weergegeven. Maak een tekstbestand met de naam proxysql-headless-svc.yml en voeg de volgende regels toe:

apiVersion: v1
kind: Service
metadata:
  name: proxysqlcluster
  labels:
    app: proxysql
spec:
  clusterIP: None
  ports:
  - port: 6032
    name: proxysql-admin
  selector:
    app: proxysql

Creëer de headless-service:

$ kubectl create -f proxysql-headless-svc.yml

Alleen ter verificatie hebben we op dit moment de volgende services:

$ kubectl get svc
NAME              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                         AGE
kubernetes        ClusterIP   10.96.0.1       <none>        443/TCP                         8h
proxysql          NodePort    10.110.38.154   <none>        6033:30033/TCP,6032:30032/TCP   23m
proxysqlcluster   ClusterIP   None            <none>        6032/TCP                        4s

Bekijk nu een van de logbestanden van onze pod:

$ kubectl logs -f proxysql-0
...
2019-08-01 19:06:19 ProxySQL_Cluster.cpp:215:ProxySQL_Cluster_Monitor_thread(): [WARNING] Cluster: unable to connect to peer proxysql-1.proxysqlcluster:6032 . Error: Unknown MySQL server host 'proxysql-1.proxysqlcluster' (0)
2019-08-01 19:06:19 [INFO] Cluster: detected a new checksum for mysql_query_rules from peer proxysql-1.proxysqlcluster:6032, version 1, epoch 1564686376, checksum 0x3FEC69A5C9D96848 . Not syncing yet ...
2019-08-01 19:06:19 [INFO] Cluster: checksum for mysql_query_rules from peer proxysql-1.proxysqlcluster:6032 matches with local checksum 0x3FEC69A5C9D96848 , we won't sync.

U zou merken dat de Cluster-component in staat is om een ​​nieuwe controlesom van de andere peer, proxysql-1.proxysqlcluster op poort 6032, op te lossen, te verbinden en te detecteren via de headless-service genaamd "proxysqlcluster". Houd er rekening mee dat deze service poort 6032 alleen binnen het Kubernetes-netwerk vrijgeeft en daarom extern onbereikbaar is.

Op dit moment is onze implementatie nu voltooid.

Verbinding maken met ProxySQL

Er zijn verschillende manieren om verbinding te maken met ProxySQL-services. De load-balanced MySQL-verbindingen moeten vanuit het Kubernetes-netwerk naar poort 6033 worden gestuurd en poort 30033 gebruiken als de client verbinding maakt vanaf een extern netwerk.

Om verbinding te maken met de ProxySQL-beheerdersinterface vanaf een extern netwerk, kunnen we verbinding maken met de poort die is gedefinieerd onder NodePort-sectie, 30032 (192.168.100.203 is het primaire IP-adres van host kube3.local):

$ mysql -uproxysql-admin -padminpassw0rd -h192.168.100.203 -P30032

Gebruik de clusterIP 10.110.38.154 (gedefinieerd onder "proxysql"-service) op poort 6032 als u deze wilt openen vanaf andere pods in het Kubernetes-netwerk.

Voer vervolgens de ProxySQL-configuratiewijzigingen uit zoals u wilt en laad ze naar runtime:

mysql> INSERT INTO mysql_users (username,password,default_hostgroup) VALUES ('newuser','passw0rd',10);
mysql> LOAD MYSQL USERS TO RUNTIME;

U ziet de volgende regels in een van de pods die aangeven dat de configuratiesynchronisatie is voltooid:

$ kubectl logs -f proxysql-0
...
2019-08-02 03:53:48 [INFO] Cluster: detected a peer proxysql-1.proxysqlcluster:6032 with mysql_users version 2, epoch 1564718027, diff_check 4. Own version: 1, epoch: 1564714803. Proceeding with remote sync
2019-08-02 03:53:48 [INFO] Cluster: detected peer proxysql-1.proxysqlcluster:6032 with mysql_users version 2, epoch 1564718027
2019-08-02 03:53:48 [INFO] Cluster: Fetching MySQL Users from peer proxysql-1.proxysqlcluster:6032 started
2019-08-02 03:53:48 [INFO] Cluster: Fetching MySQL Users from peer proxysql-1.proxysqlcluster:6032 completed

Houd er rekening mee dat de automatische synchronisatie alleen plaatsvindt als er een configuratiewijziging is in ProxySQL-runtime. Daarom is het essentieel om de instructie "LOAD ... TO RUNTIME" uit te voeren voordat u de actie kunt zien. Vergeet niet om de ProxySQL-wijzigingen op de schijf op te slaan voor persistentie:

mysql> SAVE MYSQL USERS TO DISK;

Beperking

Merk op dat er een beperking is aan deze setup omdat ProxySQL geen ondersteuning biedt voor het opslaan/exporteren van de actieve configuratie naar een tekstconfiguratiebestand dat we later zouden kunnen gebruiken om in ConfigMap te laden voor persistentie. Hier is een feature request voor. Ondertussen kunt u de wijzigingen handmatig naar ConfigMap pushen. Anders zou u, als de pods per ongeluk zouden worden verwijderd, uw huidige configuratie verliezen omdat de nieuwe pods zouden worden opgestart door wat dan ook gedefinieerd in de ConfigMap.

Speciale dank aan Sampath Kamineni, die het idee van deze blogpost heeft aangewakkerd en inzicht heeft gegeven in de gebruiksscenario's en implementatie.


  1. Hoe duplicaten in SQL te verwijderen

  2. U kunt nu toegang gebruiken met Microsoft Azure MFA!

  3. Hoe een bepaald aantal rijen in de tabel te markeren bij gelijktijdige toegang?

  4. Hoe controleer je of IDENTITY_INSERT is ingesteld op AAN of UIT in SQL Server?