sql >> Databáze >  >> RDS >> MariaDB

Nativní Clustering ProxySQL s Kubernetes

ProxySQL podporuje nativní clustering od verze 1.4.2. To znamená, že více instancí ProxySQL podporuje cluster; jsou si navzájem vědomi stavu a jsou schopni automaticky zpracovat změny konfigurace synchronizací až po nejaktuálnější konfiguraci na základě verze konfigurace, časového razítka a hodnoty kontrolního součtu. Podívejte se na tento blogový příspěvek, který ukazuje, jak nakonfigurovat podporu clusteringu pro ProxySQL a jak byste mohli očekávat, že se bude chovat.

ProxySQL je decentralizovaný proxy server, který se doporučuje nasadit blíže k aplikaci. Tento přístup je docela dobře škálovatelný i pro stovky uzlů, protože byl navržen tak, aby byl snadno rekonfigurovatelný za běhu. Chcete-li efektivně spravovat více uzlů ProxySQL, musíte se ujistit, že jakékoli změny provedené na jednom z uzlů by měly být aplikovány na všechny uzly ve farmě. Bez nativního klastrování je třeba ručně exportovat konfigurace a importovat je do ostatních uzlů (ačkoli to můžete zautomatizovat sami).

V předchozím příspěvku na blogu jsme se zabývali clusterováním ProxySQL prostřednictvím Kubernetes ConfigMap. Tento přístup je víceméně velmi efektivní s přístupem centralizované konfigurace v ConfigMap. Cokoli načtené do ConfigMap bude namontováno do modulů. Aktualizaci konfigurace lze provést pomocí verzování (upravit obsah proxysql.cnf a načíst jej do ConfigMap s jiným názvem) a poté odeslat do modulů v závislosti na plánování a strategii aktualizace metody nasazení.

V rychle se měnícím prostředí však tento přístup ConfigMap pravděpodobně není tou nejlepší metodou, protože pro načtení nové konfigurace je nutné přeplánování modulu pro opětovné připojení svazku ConfigMap, což by mohlo ohrozit službu ProxySQL jako celek. Řekněme například, že v našem prostředí naše přísná politika hesel vyžaduje vynutit vypršení platnosti uživatelského hesla MySQL každých 7 dní, což bychom museli každý týden aktualizovat ProxySQL ConfigMap pro nové heslo. Jako vedlejší poznámka, uživatel MySQL uvnitř ProxySQL vyžaduje uživatele a heslo, aby odpovídaly tomu na backendových serverech MySQL. Zde bychom měli začít využívat podporu nativního clusteringu ProxySQL v Kubernetes, abychom automaticky aplikovali změny konfigurace bez potíží s verzováním ConfigMap a přeplánováním pod.

V tomto příspěvku na blogu vám ukážeme, jak spustit nativní clustering ProxySQL s bezhlavou službou na Kubernetes. Naši architekturu na vysoké úrovni lze ilustrovat následovně:

Máme 3 uzly Galera běžící na holé metalové infrastruktuře nasazené a spravované ClusterControl:

  • 192.168.0.21
  • 192.168.0.22
  • 192.168.0.23

Všechny naše aplikace běží jako pody v rámci Kubernetes. Cílem je zavést dvě instance ProxySQL mezi aplikaci a náš databázový cluster, které budou sloužit jako reverzní proxy. Aplikace se poté připojí k ProxySQL pods prostřednictvím služby Kubernetes, která bude vyvážena zátěží a převzetím služeb při selhání napříč řadou replik ProxySQL.

Následuje shrnutí našeho nastavení Kubernetes:

[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

Konfigurace proxySQL pomocí ConfigMap

Nejprve si připravíme základní konfiguraci, která se nahraje do ConfigMap. Vytvořte soubor s názvem proxysql.cnf a přidejte následující řádky:

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 }
)

Některé z výše uvedených konfiguračních řádků jsou vysvětleny v části níže:

proměnné_správců

Věnujte pozornost admin_credentials proměnná, kde jsme použili jiného než výchozího uživatele, což je "proxysql-admin". ProxySQL si vyhrazuje výchozího uživatele „admin“ pro lokální připojení pouze přes localhost. Pro vzdálený přístup k instanci ProxySQL tedy musíme použít jiné uživatele. Jinak by se zobrazila následující chyba:

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

Také jsme přidali username_clusteru a cluster_password hodnotu v admin_credentials řádek oddělený středníkem, aby se umožnila automatická synchronizace. Všechny proměnné s předponou cluster_* souvisí s nativním shlukováním ProxySQL a jsou samozřejmé.

mysql_galera_hostgroups

Toto je nová směrnice zavedená pro ProxySQL 2.x (náš obraz ProxySQL běží na 2.0.5). Pokud byste chtěli spustit na ProxySQL 1.x, odeberte tuto část a použijte místo ní tabulku plánovače. Podrobnosti o konfiguraci jsme již vysvětlili v tomto blogovém příspěvku Jak spustit a nakonfigurovat ProxySQL 2.0 pro MySQL Galera Cluster na Dockeru v části "ProxySQL 2.x Support for Galera Cluster".

mysql_servers

Všechny řádky jsou samozřejmé, což je založeno na třech databázových serverech běžících v MySQL Galera Cluster, jak je shrnuto na následujícím snímku obrazovky topologie převzatém z ClusterControl:

proxysql_servers

Zde definujeme seznam ProxySQL peerů:

  • název hostitele – název hostitele/IP adresa partnera
  • port – Administrátorský port partnera
  • hmotnost – v současnosti se nepoužívá, ale je v plánu pro budoucí vylepšení
  • komentář – volné pole komentáře

V prostředí Docker/Kubernetes existuje několik způsobů, jak zjistit a propojit názvy hostitelů nebo IP adresy kontejnerů a vložit je do této tabulky, buď pomocí ConfigMap, ručního vkládání, pomocí skriptování entrypoint.sh, proměnných prostředí nebo jinými způsoby. V Kubernetes, v závislosti na použité metodě ReplicationController nebo Deployment, je uhodnout předem rozlišitelný název hostitele podu poněkud složité, pokud neběžíte na StatefulSet.

Podívejte se na tento výukový program o ordinálním indexu pod StatefulState, který pro vytvořené pody poskytuje stabilní rozlišitelný název hostitele. Zkombinujte to s bezhlavou službou (vysvětleno níže), rozlišitelný formát názvu hostitele by byl:

{app_name}-{index_number}.{service}

Kde {service} je bezhlavá služba, která vysvětluje, odkud pocházejí „proxysql-0.proxysqlcluster“ a „proxysql-1.proxysqlcluster“. Pokud chcete mít více než 2 repliky, přidejte odpovídajícím způsobem další položky připojením vzestupného indexového čísla vzhledem k názvu aplikace StatefulSet.

Nyní jsme připraveni odeslat konfigurační soubor do ConfigMap, který bude připojen do každého modulu ProxySQL během nasazení:

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

Ověřte, zda je naše ConfigMap správně načtena:

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

Vytvoření uživatele monitorování ProxySQL

Dalším krokem před zahájením implementace je vytvoření monitorovacího uživatele ProxySQL v našem databázovém clusteru. Protože běžíme na clusteru Galera, spusťte následující příkazy na jednom z uzlů Galera:

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

Pokud jste nevytvořili uživatele MySQL (jak je uvedeno výše v sekci mysql_users), musíme je vytvořit také:

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'@'%';

A je to. Nyní jsme připraveni zahájit nasazení.

Nasazení StatefulSet

Začneme vytvořením dvou ProxySQL instancí nebo replik pro účely redundance pomocí StatefulSet.

Začněme vytvořením textového souboru s názvem proxysql-ss-svc.yml a přidejte následující řádky:

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

Výše uvedená definice má dvě části – StatefulSet a Service. StatefulSet je definice našich modulů nebo replik a bod připojení pro náš svazek ConfigMap, načtený z proxysql-configmap. Další částí je definice služby, kde definujeme, jak by měly být moduly vystaveny a směrovány pro interní nebo externí síť.

Vytvořte stavovou sadu a službu ProxySQL:

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

Ověřte stav modulu a služby:

$ 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

Když se podíváte na protokol modulu, všimnete si, že nás zaplavilo toto varování:

$ 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)

Výše uvedené jednoduše znamená, že proxysql-0 nebyl schopen vyřešit "proxysql-1.proxysqlcluster" a připojit se k němu, což se očekává, protože jsme nevytvořili naši bezhlavou službu pro záznamy DNS, které budou potřeba pro komunikaci mezi proxy SQL.

Služba Kubernetes Headless

Aby byly ProxySQL pody schopny vyřešit očekávaný FQDN a připojit se k němu přímo, musí být proces řešení schopen vyhledat přiřazenou IP adresu cílového podu a ne virtuální IP adresu. Zde přichází na scénu bezhlavá služba. Při vytváření bezhlavé služby nastavením "clusterIP=None" není nakonfigurováno žádné vyrovnávání zátěže a pro tuto službu není přidělena žádná IP adresa clusteru (virtuální IP). Automaticky je nakonfigurován pouze DNS. Když spustíte DNS dotaz na bezhlavou službu, získáte seznam IP adres podů.

Takto to vypadá, když vyhledáme DNS záznamy bezhlavé služby pro "proxysqlcluster" (v tomto příkladu jsme měli 3 instance ProxySQL):

$ 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

Zatímco následující výstup zobrazuje DNS záznam pro standardní službu s názvem "proxysql", která se překládá na clusterIP:

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

Chcete-li vytvořit službu bez hlavy a připojit ji k modulům, musíte definovat název služby uvnitř deklarace StatefulSet a definice služby musí mít "clusterIP=None", jak je uvedeno níže. Vytvořte textový soubor s názvem proxysql-headless-svc.yml a přidejte následující řádky:

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

Vytvořte bezhlavou službu:

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

Jen pro ověření, v tuto chvíli máme spuštěny následující služby:

$ 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

Nyní se podívejte na jeden z logů našeho modulu:

$ 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.

Všimli byste si, že komponenta Cluster je schopna vyřešit, připojit a detekovat nový kontrolní součet od druhého partnera, proxysql-1.proxysqlcluster na portu 6032 prostřednictvím bezhlavé služby zvané „proxysqlcluster“. Všimněte si, že tato služba zpřístupňuje port 6032 pouze v rámci sítě Kubernetes, a proto je externě nedostupný.

V tuto chvíli je naše nasazení dokončeno.

Připojování k ProxySQL

Existuje několik způsobů, jak se připojit ke službám ProxySQL. Připojení MySQL s vyváženou zátěží by měla být odeslána na port 6033 ze sítě Kubernetes a použít port 30033, pokud se klient připojuje z externí sítě.

Pro připojení k administrátorskému rozhraní ProxySQL z externí sítě se můžeme připojit k portu definovanému v části NodePort, 30032 (192.168.100.203 je primární IP adresa hostitele kube3.local):

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

Pokud k němu chcete přistupovat z jiných modulů v síti Kubernetes, použijte clusterIP 10.110.38.154 (definovaný pod službou „proxysql“) na portu 6032.

Poté proveďte změny konfigurace ProxySQL, jak chcete, a načtěte je do runtime:

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

V jednom z panelů si všimnete následujících řádků označujících dokončení synchronizace konfigurace:

$ 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

Mějte na paměti, že k automatické synchronizaci dojde pouze v případě, že dojde ke změně konfigurace v běhovém prostředí ProxySQL. Proto je životně důležité spustit příkaz "LOAD ... TO RUNTIME" dříve, než uvidíte akci. Nezapomeňte uložit změny ProxySQL na disk pro zachování:

mysql> SAVE MYSQL USERS TO DISK;

Omezení

Všimněte si, že toto nastavení má omezení kvůli tomu, že ProxySQL nepodporuje ukládání/export aktivní konfigurace do textového konfiguračního souboru, který bychom mohli později použít k načtení do ConfigMap pro zachování. K tomu existuje požadavek na funkci. Mezitím můžete změny vložit do ConfigMap ručně. V opačném případě, pokud by byly moduly omylem smazány, ztratili byste svou aktuální konfiguraci, protože nové moduly by byly zaváděny podle toho, co je definováno v ConfigMap.

Zvláštní poděkování patří Sampathovi Kaminenimu, který podnítil myšlenku tohoto blogového příspěvku a poskytl informace o případech použití a implementaci.


  1. Chování GROUP BY, když v klauzuli SELECT nejsou přítomny žádné agregační funkce

  2. Funkce SYS_GUID() v Oracle

  3. Potíže se znaky UTF-8; co vidím, není to, co jsem uložil

  4. Oracle - Proč zmizí úvodní nula čísla při převodu na TO_CHAR