sql >> Databasteknik >  >> RDS >> MariaDB

Hur man kör och konfigurerar ProxySQL 2.0 för MySQL Galera Cluster på Docker

ProxySQL är en intelligent och högpresterande SQL-proxy som stöder MySQL, MariaDB och ClickHouse. Nyligen har ProxySQL 2.0 blivit GA och den kommer med nya spännande funktioner som GTID-konsekventa läsningar, frontend SSL, Galera och MySQL Group Replication inbyggt stöd.

Det är relativt enkelt att köra ProxySQL som Docker-container. Vi har tidigare skrivit om hur man kör ProxySQL på Kubernetes som en hjälparcontainer eller som en Kubernetes-tjänst, som är baserad på ProxySQL 1.x. I det här blogginlägget kommer vi att använda den nya versionen ProxySQL 2.x som använder ett annat tillvägagångssätt för Galera Cluster-konfiguration.

ProxySQL 2.x Docker Image

Vi har släppt en ny ProxySQL 2.0 Docker-bildbehållare och den är tillgänglig i Docker Hub. README ger ett antal konfigurationsexempel, särskilt för Galera och MySQL-replikering, före och efter v2.x. Konfigurationsraderna kan definieras i en textfil och mappas till containerns sökväg på /etc/proxysql.cnf för att laddas in i ProxySQL-tjänsten.

Bilden "senaste" taggen pekar fortfarande på 1.x tills ProxySQL 2.0 officiellt blir GA (vi har inte sett någon officiell releaseblogg/artikel från ProxySQL-teamet än). Vilket innebär att när du installerar ProxySQL-avbildning med den senaste taggen från Severalnines, kommer du fortfarande att få version 1.x med den. Notera att de nya exempelkonfigurationerna även möjliggör ProxySQL-webbstatistik (introducerad i 1.4.4 men fortfarande i betaversion) - en enkel instrumentpanel som sammanfattar den övergripande konfigurationen och statusen för själva ProxySQL.

ProxySQL 2.x-stöd för Galera Cluster

Låt oss prata mer om Galera Clusters inbyggda support. Den nya mysql_galera_hostgroups-tabellen består av följande fält:

  • writer_hostgroup : ID för värdgruppen som kommer att innehålla alla medlemmar som är skribenter (read_only=0).
  • backup_writer_hostgroup : Om klustret körs i multi-writer-läge (dvs. det finns flera noder med read_only=0) och max_writers är inställt på ett mindre antal än det totala antalet noder, flyttas de ytterligare noderna till denna backup-skrivarvärdgrupp.
  • reader_hostgroup : ID för värdgruppen som kommer att innehålla alla medlemmar som är läsare (dvs. noder som har read_only=1)
  • offline_hostgroup : När ProxySQL-övervakning fastställer att en värd är OFFLINE, kommer värden att flyttas till offline_hostgroup.
  • aktiv : ett booleskt värde (0 eller 1) för att aktivera en värdgrupp
  • max_writers : Styr det maximala antalet tillåtna noder i skrivarvärdgruppen, som tidigare nämnts kommer ytterligare noder att flyttas till backup_writer_hostgroup.
  • författare_är_även_läsare : När 1 kommer en nod i writer_hostgroup också att placeras i reader_hostgroup så att den kommer att användas för läsningar. När den är inställd på 2 kommer noderna från backup_writer_hostgroup att placeras i reader_hostgroup, istället för nod(erna) i writer_hostgroup.
  • max_transactions_behind : bestämmer det maximala antalet skrivuppsättningar som en nod i klustret kan ha i kö innan noden SHUNNERAS för att förhindra inaktuella läsningar (detta bestäms genom att fråga efter variabeln wsrep_local_recv_queue Galera).
  • kommentar : Textfält som kan användas för alla ändamål som definieras av användaren

Här är ett exempel på konfiguration för mysql_galera_hostgroups i tabellformat:

Admin> select * from mysql_galera_hostgroups\G
*************************** 1. row ***************************
       writer_hostgroup: 10
backup_writer_hostgroup: 20
       reader_hostgroup: 30
      offline_hostgroup: 9999
                 active: 1
            max_writers: 1
  writer_is_also_reader: 2
max_transactions_behind: 20
                comment: 

ProxySQL utför Galera hälsokontroller genom att övervaka följande MySQL-status/variabel:

  • skrivskyddad - Om PÅ, kommer ProxySQL att gruppera den definierade värden i reader_hostgroup om inte writer_is_also_reader är 1.
  • wsrep_desync - Om PÅ kommer ProxySQL att markera noden som otillgänglig och flytta den till offline_hostgroup.
  • wsrep_reject_queries - Om denna variabel är PÅ kommer ProxySQL att markera noden som otillgänglig och flytta den till offline_hostgroup (användbart i vissa underhållssituationer).
  • wsrep_sst_donor_rejects_queries - Om den här variabeln är PÅ kommer ProxySQL att markera noden som otillgänglig medan Galera-noden fungerar som en SST-donator och flytta den till offline_hostgroup.
  • wsrep_local_state - Om denna status returnerar annat än 4 (4 betyder synkroniserad), kommer ProxySQL att markera noden som otillgänglig och flytta den till offline_hostgroup.
  • wsrep_local_recv_queue - Om denna status är högre än max_transactions_behind kommer noden att undvikas.
  • wsrep_cluster_status - Om den här statusen återgår till annat än Primär kommer ProxySQL att markera noden som otillgänglig och flytta den till offline_hostgroup.

Med det sagt, genom att kombinera dessa nya parametrar i mysql_galera_hostgroups tillsammans med mysql_query_rules, har ProxySQL 2.x flexibiliteten att passa in i mycket fler Galera-användningsfall. Till exempel kan man ha en värdgrupp för en skribent, flera skribenter och flera läsare definierade som målvärdgruppen för en frågeregel, med möjligheten att begränsa antalet skribenter och bättre kontroll över det inaktuella läsbeteendet.

Jämför detta med ProxySQL 1.x, där användaren var tvungen att uttryckligen definiera en schemaläggare för att anropa ett externt skript för att utföra backend-hälsokontrollerna och uppdatera databasservrarnas tillstånd. Detta kräver viss anpassning av skriptet (användaren måste uppdatera ProxySQL admin användare/lösenord/port) plus att det berodde på ett extra verktyg (MySQL klient) för att ansluta till ProxySQL admin gränssnitt.

Här är ett exempel på konfiguration av Galera hälsokontrollskriptschemaläggare i tabellformat för ProxySQL 1.x:

Admin> select * from scheduler\G
*************************** 1. row ***************************
         id: 1
     active: 1
interval_ms: 2000
   filename: /usr/share/proxysql/tools/proxysql_galera_checker.sh
       arg1: 10
       arg2: 20
       arg3: 1
       arg4: 1
       arg5: /var/lib/proxysql/proxysql_galera_checker.log
    comment:

Dessutom, eftersom ProxySQL-schemaläggaren kör alla skript oberoende, finns det många versioner av hälsokontrollskript tillgängliga där ute. Alla ProxySQL-instanser som distribueras av ClusterControl använder standardskriptet som tillhandahålls av ProxySQL-installationspaketet.

I ProxySQL 2.x kan max_writers och writer_is_also_reader-variabler avgöra hur ProxySQL dynamiskt grupperar backend-MySQL-servrarna och kommer att direkt påverka anslutningsdistributionen och frågedirigeringen. Tänk till exempel på följande MySQL-backend-servrar:

Admin> select hostgroup_id, hostname, status, weight from mysql_servers;
+--------------+--------------+--------+--------+
| hostgroup_id | hostname     | status | weight |
+--------------+--------------+--------+--------+
| 10           | DB1          | ONLINE | 1      |
| 10           | DB2          | ONLINE | 1      |
| 10           | DB3          | ONLINE | 1      |
+--------------+--------------+--------+--------+

Tillsammans med följande Galera-värdgruppsdefinition:

Admin> select * from mysql_galera_hostgroups\G
*************************** 1. row ***************************
       writer_hostgroup: 10
backup_writer_hostgroup: 20
       reader_hostgroup: 30
      offline_hostgroup: 9999
                 active: 1
            max_writers: 1
  writer_is_also_reader: 2
max_transactions_behind: 20
                comment: 

Med tanke på att alla värdar är igång, kommer ProxySQL troligen att gruppera värdarna enligt nedan:

Låt oss titta på dem en efter en:

Konfiguration Beskrivning
writer_is_also_reader=0
  • Grupperar värdarna i två värdgrupper (writer och backup_writer).
  • Writer är en del av backup_writer.
  • Eftersom författaren inte är en läsare, ingenting i värdgrupp 30 (läsare) eftersom ingen av värdarna är inställda med read_only=1. Det är inte vanligt i Galera att aktivera skrivskyddad flagga.
writer_is_also_reader=1
  • Grupperar värdarna i 3 värdgrupper (writer, backup_writer och reader).
  • Variabel read_only=0 i Galera har ingen effekt, så författaren är också i värdgrupp 30 (läsare)
  • Writer är inte en del av backup_writer.
writer_is_also_reader=2
  • Liknande med writer_is_also_reader=1 men writer är en del av backup_writer.

Med denna konfiguration kan man ha olika val för värdgruppsdestination för att tillgodose specifika arbetsbelastningar. "Hotspot"-skrivningar kan konfigureras att gå till endast en server för att minska multi-master-konflikter, icke-konfliktskrivande kan distribueras lika på de andra masterna, de flesta läsningar kan fördelas jämnt på alla MySQL-servrar eller icke-skrivare, kritiska läsningar kan vidarebefordras till de mest uppdaterade servrarna och analytiska läsningar kan vidarebefordras till en slavreplik.

ProxySQL-distribution för Galera Cluster

Anta i det här exemplet att vi redan har ett Galera-kluster med tre noder distribuerat av ClusterControl som visas i följande diagram:

Våra Wordpress-applikationer körs på Docker medan Wordpress-databasen är värd på vårt Galera Cluster som körs på barmetallservrar. Vi bestämde oss för att köra en ProxySQL-behållare vid sidan av våra Wordpress-behållare för att få bättre kontroll på routing av Wordpress-databasfrågor och fullt ut utnyttja vår databasklusterinfrastruktur. Eftersom läs-skrivförhållandet är runt 80%-20%, vill vi konfigurera ProxySQL för att:

  • Vidarebefordra alla skrivningar till en Galera-nod (mindre konflikt, fokus på skrivning)
  • Balancera alla läsningar till de andra två Galera-noderna (bättre fördelning för större delen av arbetsbelastningen)

Skapa först en ProxySQL-konfigurationsfil inuti Docker-värden så att vi kan mappa den till vår behållare:

$ mkdir /root/proxysql-docker
$ vim /root/proxysql-docker/proxysql.cnf

Kopiera sedan följande rader (vi kommer att förklara konfigurationsraderna längre ner):

datadir="/var/lib/proxysql"

admin_variables=
{
    admin_credentials="admin:admin"
    mysql_ifaces="0.0.0.0:6032"
    refresh_interval=2000
    web_enabled=true
    web_port=6080
    stats_credentials="stats:admin"
}

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="proxysqlpassword"
    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="db1.cluster.local" , port=3306 , hostgroup=10, max_connections=100 },
    { address="db2.cluster.local" , port=3306 , hostgroup=10, max_connections=100 },
    { address="db3.cluster.local" , 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=30
        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 }
)

Låt oss nu besöka några av de mest konfigurerade sektionerna. För det första definierar vi Galera-värdgruppernas konfiguration enligt nedan:

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

Hostgroup 10 kommer att vara writer_hostgroup, hostgroup 20 för backup_writer och hostgroup 30 för läsare. Vi sätter max_writers till 1 så att vi kan ha en värdgrupp för en skrivare för värdgrupp 10 dit alla skrivningar ska skickas till. Sedan definierar vi writer_is_also_reader till 1 vilket kommer att göra alla Galera-noder som läsare också, lämpliga för frågor som kan distribueras lika till alla noder. Hostgroup 9999 är reserverad för offline_hostgroup om ProxySQL upptäcker ooperativa Galera-noder.

Sedan konfigurerar vi våra MySQL-servrar med standard till värdgrupp 10:

mysql_servers =
(
    { address="db1.cluster.local" , port=3306 , hostgroup=10, max_connections=100 },
    { address="db2.cluster.local" , port=3306 , hostgroup=10, max_connections=100 },
    { address="db3.cluster.local" , port=3306 , hostgroup=10, max_connections=100 }
)

Med ovanstående konfigurationer kommer ProxySQL att "se" våra värdgrupper enligt nedan:

Sedan definierar vi frågedirigeringen genom frågeregler. Baserat på vårt krav ska alla läsningar skickas till alla Galera-noder utom skribenten (värdgrupp 20) och allt annat skickas vidare till värdgrupp 10 för enskild skribent:

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

Slutligen definierar vi de MySQL-användare som kommer att skickas genom ProxySQL:

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

Vi sätter transaktion_persistent till 0 så att alla anslutningar som kommer från dessa användare kommer att respektera frågereglerna för läs- och skrivdirigering. Annars skulle anslutningarna hamna i en värdgrupp som motverkar syftet med lastbalansering. Glöm inte att skapa dessa användare först på alla MySQL-servrar. För ClusterControl-användare kan du använda funktionen Hantera -> Schema och användare för att skapa dessa användare.

Vi är nu redo att starta vår container. Vi kommer att mappa ProxySQL-konfigurationsfilen som bind mount när vi startar upp ProxySQL-behållaren. Följaktligen kommer körkommandot att vara:

$ docker run -d \
--name proxysql2 \
--hostname proxysql2 \
--publish 6033:6033 \
--publish 6032:6032 \
--publish 6080:6080 \
--restart=unless-stopped \
-v /root/proxysql/proxysql.cnf:/etc/proxysql.cnf \
severalnines/proxysql:2.0

Ändra slutligen Wordpress-databasen som pekar mot ProxySQL containerport 6033, till exempel:

$ docker run -d \
--name wordpress \
--publish 80:80 \
--restart=unless-stopped \
-e WORDPRESS_DB_HOST=proxysql2:6033 \
-e WORDPRESS_DB_USER=wordpress \
-e WORDPRESS_DB_HOST=passw0rd \
wordpress

Vid det här laget ser vår arkitektur ut ungefär så här:

Om du vill att ProxySQL-behållaren ska vara beständig, mappa /var/lib/proxysql/ till en Docker-volym eller bindningsmontering, till exempel:

$ docker run -d \
--name proxysql2 \
--hostname proxysql2 \
--publish 6033:6033 \
--publish 6032:6032 \
--publish 6080:6080 \
--restart=unless-stopped \
-v /root/proxysql/proxysql.cnf:/etc/proxysql.cnf \
-v proxysql-volume:/var/lib/proxysql \
severalnines/proxysql:2.0

Tänk på att körning med beständig lagring som ovan kommer att göra vår /root/proxysql/proxysql.cnf föråldrad vid den andra omstarten. Detta beror på ProxySQL flerskiktskonfiguration där om /var/lib/proxysql/proxysql.db finns, kommer ProxySQL att hoppa över laddningsalternativ från konfigurationsfilen och ladda det som finns i SQLite-databasen istället (såvida du inte startar proxysql-tjänsten med --initial flagga). Med det sagt måste nästa ProxySQL-konfigurationshantering utföras via ProxySQL-administratörskonsolen på port 6032, istället för att använda konfigurationsfilen.

Övervakning

ProxySQL-processlogg loggar som standard till syslog och du kan se dem genom att använda standardkommandot för docker:

$ docker ps
$ docker logs proxysql2

För att verifiera den aktuella värdgruppen, fråga tabellen runtime_mysql_servers:

$ docker exec -it proxysql2 mysql -uadmin -padmin -h127.0.0.1 -P6032 --prompt='Admin> '
Admin> select hostgroup_id,hostname,status from runtime_mysql_servers;
+--------------+--------------+--------+
| hostgroup_id | hostname     | status |
+--------------+--------------+--------+
| 10           | 192.168.0.21 | ONLINE |
| 30           | 192.168.0.21 | ONLINE |
| 30           | 192.168.0.22 | ONLINE |
| 30           | 192.168.0.23 | ONLINE |
| 20           | 192.168.0.22 | ONLINE |
| 20           | 192.168.0.23 | ONLINE |
+--------------+--------------+--------+

Om den valda skribenten går ner kommer den att överföras till offline_hostgroup (HID 9999):

Admin> select hostgroup_id,hostname,status from runtime_mysql_servers;
+--------------+--------------+--------+
| hostgroup_id | hostname     | status |
+--------------+--------------+--------+
| 10           | 192.168.0.22 | ONLINE |
| 9999         | 192.168.0.21 | ONLINE |
| 30           | 192.168.0.22 | ONLINE |
| 30           | 192.168.0.23 | ONLINE |
| 20           | 192.168.0.23 | ONLINE |
+--------------+--------------+--------+

Ovanstående topologiförändringar kan illustreras i följande diagram:

Vi har även aktiverat webbstatistik-gränssnittet med admin-web_enabled=true. För att komma åt webbgränssnittet, gå helt enkelt till Docker-värden i port 6080, till exempel:http://192.168.0.200:8060 och du kommer att bli tillfrågad med användarnamn/lösenord popup. Ange inloggningsuppgifterna enligt definitionen under admin-stats_credentials och du bör se följande sida:

Genom att övervaka MySQL-anslutningspooltabellen kan vi få en översikt över anslutningsdistributionen för alla värdgrupper:

Admin> select hostgroup, srv_host, status, ConnUsed, MaxConnUsed, Queries from stats.stats_mysql_connection_pool order by srv_host;
+-----------+--------------+--------+----------+-------------+---------+
| hostgroup | srv_host     | status | ConnUsed | MaxConnUsed | Queries |
+-----------+--------------+--------+----------+-------------+---------+
| 20        | 192.168.0.23 | ONLINE | 5        | 24          | 11458   |
| 30        | 192.168.0.23 | ONLINE | 0        | 0           | 0       |
| 20        | 192.168.0.22 | ONLINE | 2        | 24          | 11485   |
| 30        | 192.168.0.22 | ONLINE | 0        | 0           | 0       |
| 10        | 192.168.0.21 | ONLINE | 32       | 32          | 9746    |
| 30        | 192.168.0.21 | ONLINE | 0        | 0           | 0       |
+-----------+--------------+--------+----------+-------------+---------+

Utdata ovan visar att värdgrupp 30 inte bearbetar någonting eftersom våra frågeregler inte har denna värdgrupp konfigurerad som målvärdgrupp.

Statistiken relaterad till Galera-noderna kan ses i tabellen mysql_server_galera_log:

Admin>  select * from mysql_server_galera_log order by time_start_us desc limit 3\G
*************************** 1. row ***************************
                       hostname: 192.168.0.23
                           port: 3306
                  time_start_us: 1552992553332489
                success_time_us: 2045
              primary_partition: YES
                      read_only: NO
         wsrep_local_recv_queue: 0
              wsrep_local_state: 4
                   wsrep_desync: NO
           wsrep_reject_queries: NO
wsrep_sst_donor_rejects_queries: NO
                          error: NULL
*************************** 2. row ***************************
                       hostname: 192.168.0.22
                           port: 3306
                  time_start_us: 1552992553329653
                success_time_us: 2799
              primary_partition: YES
                      read_only: NO
         wsrep_local_recv_queue: 0
              wsrep_local_state: 4
                   wsrep_desync: NO
           wsrep_reject_queries: NO
wsrep_sst_donor_rejects_queries: NO
                          error: NULL
*************************** 3. row ***************************
                       hostname: 192.168.0.21
                           port: 3306
                  time_start_us: 1552992553329013
                success_time_us: 2715
              primary_partition: YES
                      read_only: NO
         wsrep_local_recv_queue: 0
              wsrep_local_state: 4
                   wsrep_desync: NO
           wsrep_reject_queries: NO
wsrep_sst_donor_rejects_queries: NO
                          error: NULL

Resultatuppsättningen returnerar den relaterade MySQL-variabeln/statustillståndet för varje Galera-nod för en viss tidsstämpel. I den här konfigurationen konfigurerade vi Galeras hälsokontroll så att den körs varannan sekund (monitor_galera_healthcheck_interval=2000). Därför skulle den maximala failover-tiden vara cirka 2 sekunder om en topologiförändring sker i klustret.

Referenser

  • ProxySQL Native Galera Support
  • HA och klustringslösning:ProxySQL som en intelligent router för Galera och gruppreplikering
  • ProxySQL Docker-bild av Severalnines
  • Hur man övervakar ProxySQL med Prometheus och ClusterControl

  1. Skapa en tabellvärderad funktion i SQL Server

  2. PostgreSQL 9.2 JDBC-drivrutinen använder klientens tidszon?

  3. Hur konverterar jag från BLOB till TEXT i MySQL?

  4. rätt syntax att använda nära '?'