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.