Att hantera stora transaktioner var alltid en smärtpunkt i Galera Cluster. Sättet som Galera-skrivuppsättningscertifiering fungerar orsakar problem när transaktioner är långa eller när en enda rad ofta ändras på flera noder. Som ett resultat måste transaktioner rullas tillbaka och försöka igen, vilket orsakar prestandasänkningar. Lyckligtvis har detta problem åtgärdats i Galera 4, en ny version av Galera från Codership. Det här biblioteket används i MariaDB 10.4, så att installera MariaDB 10.4 är det enklaste sättet att testa de nyligen introducerade funktionerna. I det här blogginlägget kommer vi att ta en titt på hur streaming-replikeringen kan användas för att mildra problem som brukade vara ett standardproblem i tidigare Galera-versioner.
Vi kommer att använda tre noder av MariaDB Galera-klusterversion 10.4.6, som kommer med Galera-version av 26.4.2.
MariaDB [(none)]> show global status like 'wsrep_provider%';
+-----------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value |
+-----------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+
| wsrep_provider_capabilities | :MULTI_MASTER:CERTIFICATION:PARALLEL_APPLYING:TRX_REPLAY:ISOLATION:PAUSE:CAUSAL_READS:INCREMENTAL_WRITESET:UNORDERED:PREORDERED:STREAMING:NBO: |
| wsrep_provider_name | Galera |
| wsrep_provider_vendor | Codership Oy <[email protected]> |
| wsrep_provider_version | 26.4.2(r4498) |
+-----------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.001 sec)
Det finns tre huvudsakliga smärtpunkter som streaming replikering är avsedd att hantera:
- Långa transaktioner
- Stora transaktioner
- Hot spots i tabeller
Låt oss överväga dem en efter en och se hur strömmande replikering kan hjälpa oss att hantera dem, men låt oss först fokusera på skrivuppsättningscertifieringen - grundorsaken till att dessa problem dyker upp.
Writeset-certifiering i Galera Cluster
Galera-klustret består av flera skrivbara noder. Varje transaktion som utförs på Galera-klustret bildar en skrivuppsättning. Varje skrivuppsättning måste skickas till alla noder i klustret för certifiering - en process som säkerställer att alla noder kan tillämpa en given transaktion. Skrivuppsättningar måste köras på alla klusternoder så om det finns någon konflikt kan transaktionen inte utföras. Vilka är typiska orsaker till att transaktionen inte kan genomföras? Tja, de tre punkterna vi listade tidigare:
- Långa transaktioner – längre tid att transaktionen tar, mer sannolikt är det att under tiden en annan nod kommer att utföra uppdateringar som så småningom kommer i konflikt med skrivuppsättningen och hindrar den från att klara certifieringen
- Stora transaktioner – för det första är stora transaktioner också längre än små, så det utlöser det första problemet. Det andra problemet, strikt relaterat till de stora transaktionerna, är volymen av förändringarna. Fler rader kommer att uppdateras, mer troligt är att någon skrivning på en annan nod kommer att resultera i en konflikt och hela transaktionen måste återställas.
- Hot spots i tabeller – mer sannolikt kommer en given rad att uppdateras, mer sannolikt kommer en sådan uppdatering att ske samtidigt på flera noder vilket resulterar i att några av transaktionerna återställs
Huvudfrågan här är att Galera inte introducerar någon låsning på andra noder än den initiala noden, där transaktionen öppnades. Certifieringsprocessen bygger på en förhoppning om att om en nod skulle kunna utföra en transaktion så borde andra kunna göra det också. Det är sant men, som vi diskuterade, finns det hörnfall där sannolikheten för att detta inträffar är avsevärt reducerad.
I Galera 4, med strömmande replikering, har beteendet ändrats och alla lås tas i alla noder. Transaktioner kommer att delas upp i delar och varje del kommer att certifieras på alla noder. Efter framgångsrik certifiering kommer rader att låsas på alla noder i klustret. Det finns ett par variabler som styr hur exakt detta görs - wsrep_trx_fragment_size och wsrep_trx_fragment_unit definierar hur stort fragmentet ska vara och hur det ska definieras. Det är mycket finkornig kontroll:du kan definiera fragmentenheter som bytes, satser eller rader vilket gör det möjligt att köra certifieringen för varje rad som ändras i transaktionen. Låt oss ta en titt på hur du kan dra nytta av streamingreplikeringen i verkligheten.
Arbeta med strömmande replikering
Låt oss överväga följande scenario. Vi har en transaktion att köra som tar minst 30 sekunder:
BEGIN; UPDATE sbtest.sbtest1 SET k = k - 2 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; SELECT SLEEP(30); COMMIT;
Sedan, medan det körs, kommer vi att köra SQL som berör liknande rader. Detta kommer att utföras på en annan nod:
BEGIN; UPDATE sbtest.sbtest1 SET k = k - 1 WHERE id < 20 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 20 ; COMMIT;
Vad skulle resultatet bli?
Den första transaktionen återställs så snart den andra genomförs:
MariaDB [sbtest]> BEGIN; UPDATE sbtest.sbtest1 SET k = k - 2 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; SELECT SLEEP(30); COMMIT;
Query OK, 0 rows affected (0.001 sec)
Query OK, 667 rows affected (0.020 sec)
Rows matched: 667 Changed: 667 Warnings: 0
Query OK, 667 rows affected (0.010 sec)
Rows matched: 667 Changed: 667 Warnings: 0
Query OK, 667 rows affected (0.009 sec)
Rows matched: 667 Changed: 667 Warnings: 0
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
Query OK, 0 rows affected (0.001 sec)
Transaktionen på den andra noden lyckades:
MariaDB [(none)]> BEGIN; UPDATE sbtest.sbtest1 SET k = k - 1 WHERE id < 20 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 20 ; COMMIT;
Query OK, 0 rows affected (0.000 sec)
Query OK, 7 rows affected (0.002 sec)
Rows matched: 7 Changed: 7 Warnings: 0
Query OK, 7 rows affected (0.001 sec)
Rows matched: 7 Changed: 7 Warnings: 0
Query OK, 0 rows affected (0.004 sec)
Vad vi kan göra för att undvika det är att använda strömmande replikering för den första transaktionen. Vi kommer att be Galera att certifiera varje radändring:
MariaDB [sbtest]> BEGIN; SET SESSION wsrep_trx_fragment_size=1 ; SET SESSION wsrep_trx_fragment_unit='rows' ; UPDATE sbtest.sbtest1 SET k = k - 2 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 2000 ; SELECT SLEEP(30); COMMIT; SET SESSION wsrep_trx_fragment_size=0;
Query OK, 0 rows affected (0.001 sec)
Query OK, 0 rows affected (0.000 sec)
Query OK, 0 rows affected (0.000 sec)
Query OK, 667 rows affected (1.757 sec)
Rows matched: 667 Changed: 667 Warnings: 0
Query OK, 667 rows affected (1.708 sec)
Rows matched: 667 Changed: 667 Warnings: 0
Query OK, 667 rows affected (1.685 sec)
Rows matched: 667 Changed: 667 Warnings: 0
Som ni ser fungerade det bra den här gången. På den andra noden:
MariaDB [(none)]> BEGIN; UPDATE sbtest.sbtest1 SET k = k - 1 WHERE id < 20 ; UPDATE sbtest.sbtest1 SET k = k + 1 WHERE id < 20 ; COMMIT;
Query OK, 0 rows affected (0.000 sec)
Query OK, 7 rows affected (33.942 sec)
Rows matched: 7 Changed: 7 Warnings: 0
Query OK, 7 rows affected (0.001 sec)
Rows matched: 7 Changed: 7 Warnings: 0
Query OK, 0 rows affected (0.026 sec)
Vad som är intressant, du kan se att UPPDATERINGEN tog nästan 34 sekunder att utföra - detta orsakades av det faktum att den initiala transaktionen, genom streamingreplikeringen, låste alla modifierade rader på alla noder och vår andra transaktion fick vänta på den första att slutföra trots att båda transaktionerna utfördes på olika noder.
Detta är i princip det när det kommer till strömmande replikering. Beroende på kraven och trafiken kan du använda det på ett mindre strikt sätt - vi certifierade varje rad men du kan ändra det till var n:e rad eller varje påstående. Du kan till och med bestämma mängden data som ska certifieras. Detta bör vara tillräckligt för att matcha kraven i din miljö.
Det finns ett par saker till som vi vill att du ska tänka på och komma ihåg. Först och främst är strömmande replikering inte på något sätt en lösning som bör användas som standard. Detta är anledningen till att det som standard är inaktiverat. Det rekommenderade användningsfallet är att manuellt besluta om transaktioner som skulle dra nytta av streamingreplikeringen och aktivera den på sessionsnivå. Detta är anledningen till att våra exempel slutar med:
SET SESSION wsrep_trx_fragment_size=0;
Denna sats (som ställer in wsrep_trx_fragment_size till 0) inaktiverar strömmande replikering för aktuell session.
En annan sak som är värd att komma ihåg - om du råkar använda strömmande replikering kommer den att använda 'wsrep_streaming_log'-tabellen i 'mysql'-schemat för att konstant lagra data som strömmar. Med den här tabellen kan du få en uppfattning om data som överförs över klustret med hjälp av strömmande replikering.
Till sist prestationen. Detta är också en av anledningarna till att du inte vill använda strömmande replikering hela tiden. Huvudorsaken till det är låsning - med strömmande replikering måste du skaffa radlås på alla noder. Detta tar tid att få låsen och om du skulle behöva återställa transaktionen kommer det också att sätta press på alla noder att utföra återställningen. Vi körde ett mycket snabbt test av prestandapåverkan som streamingreplikeringen har. Miljön är helt och hållet ett test, så anta inte att dessa resultat är desamma på maskinvaran av produktionskvalitet, det är mer för dig att se vad effekten kan bli.
Vi testade fyra scenarier:
- Baslinje, ställ in global wsrep_trx_fragment_size=0;
- set global wsrep_trx_fragment_unit='rows'; set global wsrep_trx_fragment_size=1;
- set global wsrep_trx_fragment_unit='statements'; set global wsrep_trx_fragment_size=1;
- set global wsrep_trx_fragment_unit='statements'; set global wsrep_trx_fragment_size=5;
Vi använde sysbench r/w test:
sysbench /root/sysbench/src/lua/oltp_read_write.lua --threads=4 --events=0 --time=300 --mysql-host=10.0.0.141 --mysql-user=sbtest --mysql-password=sbtest --mysql-port=3306 --tables=32 --report-interval=1 --skip-trx=off --table-size=100000 --db-ps-mode=disable run
Resultaten är:
- Transaktioner:82,91 per sek., frågor:1658,27 per sek. (100 %)
- Transaktioner:54,72 per sek., frågor:1094,43 per sek. (66 %)
- Transaktioner:54,76 per sek., frågor:1095,18 per sek. (66 %)
- Transaktioner:70,93 per sek., frågor:1418,55 per sek. (86 %)
Som du kan se är effekten betydande, prestandan sjunker till och med med 33 %.
Vi hoppas att du tyckte att det här blogginlägget var informativt och att det gav dig några insikter i streamingreplikeringen som kommer med Galera 4 och MariaDB 10.4. Vi försökte täcka användningsfall och potentiella nackdelar relaterade till denna nya teknik.