A MySQL replikációs és clusterezési lehetőségeinek bemutatása 1.

Munkánk során gyakran kerülünk olyan helyzetbe, amikor a normál felhasználási szokásoknál alkalmazott módszerek nem működőképesek, nem nyújtanak megfelelő szolgáltatásokat. Ilyenkor kell sokkal hibatűrőbb, nagyobb rendelkezésre állású rendszereket terveznünk, készítenünk, amelyek egyik fontos építő eleme az adatokat kiszolgáló relációs adatbázis-kezelő. Ma már az ingyenes MySQL is hatékony replikációs és fürtözési technológiákat biztosít a rendszertervezők/fejlesztők felé, jelen cikkünkben ezek közül a replikációval ismertetjük meg olvasóinkat.

MySQL Replikáció

Bemutatás

A MySQL-ben meglévő replikációs megoldások olyan esetekben használhatók, amikor akár biztonsági másolat, akár terheléselosztás céljából szükséges egy vagy több adatbázis automatikus egyirányú szinkronizációja. Gyakori, hogy nagy forgalmú – elsősorban közösségi jellegű Internetes – alkalmazásoknál az adatbázis írási műveletek egy ún. master adatbázison hajtódnak végre, míg a nagyságrendekkel nagyobb számú lekérdezési művelet a master-ekről szinkronizált nagyobb számú slave adatbázis kiszolgálókról kerül végrehajtásra. Nagyobb terhelésű adatbázis kiszolgálók esetében az ütemezett automatikus mentések replikált slave-ről történő végrehajtása is csökkentheti a master kiszolgáló terhelését.

A MySQL beépített replikációs megoldásának alkalmazásával csak egy master kiszolgáló lehet, de több slave is csatlakozhat hozzá. Több slave alkalmazásánál a replikáció párhuzamosan hajtódik végre. A replikáció során a master-en a maximális adatbázis kapcsolatok számába bele számít(anak) a replikációs user(ek) csatlakozása(i)!

A replikáció egy irányú: a slave-en létrehozott önálló adatbázistáblák nem kerülnek replikációra a master-en! (Más kérdés, hogy nem „illik” replikált táblán írási műveletet végrehajtani slave oldalon, sőt lehetőség szerint ez tiltani is kell, lásd a

FLUSH TABLES WITH READ LOCK;

és a

SET GLOBAL read_only = ON;

utasításokat.)

Ha a slave kiesik a szinkronból, akkor a következő indulásakor (a slave kiszolgáló mysqld service-ének indulásakor) feldolgozza az addig keletkezett master binlog adatokat, így ilyenkor kell egy kis idő, amíg „utoléri” magát.

Ha a master kiesik a szinkronból, a slave az utolsó commit-ig tartalmaz mindent, így read-only kiszolgálóként használható. (Érdemes erre felkészíteni az alkalmazásunk (amennyiben az alkalmazott üzleti logika ezt megengedi): a felhasználók számára az olvasási műveleteket továbbra is elérhetővé tenni, míg az adatbázis írási műveletekkel járó felhasználói interakciókat erre az időszakra letiltani.)

Alapesetben a master-en tranzakció szintű izolációs szint szerinti replikáció valósul meg, tehát minden elkezdett tranzakció a bináris logba bekerül, s végrehajtása után (és ha nem volt rollback) kezdi meg a binlog-ból a replikációt. Így a slave-en folyamatosan konzisztens marad az adatbázis: csak a lezárt tranzakciók kerülnek át.

Amennyiben mélyebb izolációs szintre szeretnénk vinni a replikációt (tranzakción belüli műveleteket is replikálni, illetve nem tranzakciós adatbázist (pl. MyISAM) replikálni), úgy a binlog_direct_non_transactional_updates globális változó értékadásával megtehetjük ezt. FONTOS: ilyen esetekben a replikáció jóval nagyobb adatforgalommal és feldolgozandó bináris log mennyiséggel jár!

Tranzakciós master adatbázist lehet nem tranzakciós slave-be replikálni, de visszafelé ez már nem igaz. Ennek ellenére javasolt a két adatbázisnak azonos DB engine-el rendelkeznie. Ha mégis eltérő DB engine-ket kell használnunk, akkor a kialakításban ismertetett 6. lépés során a slave-en történő adatbetöltés után az

ALTER TABLE ... ENGINE=engine_type;

utasítással tudjuk az egyes táblákat átállítani az új engine-re, majd a

SET default_storage_engine=engine_type;

utasítással az adatbázis alapértelmezett engine-jét is be tudjuk állítani.

A MySQL replikáció kialakításánál mindig (!) a master elindítása és rendelkezésre állása után kell manuálisan (vagy a slave-en létrehozott, indítási script segítségével) létrehozni a replikációt és a szinkronizációt az aktuális bináris log pozíció alapján.

Megvalósítás

Két, VirtualBox-ban futtatott Debianra (7.6-os verzió, i386) telepítettem egy-egy MySQL kiszolgálót. A két virtualizált számítógép mysqlmaster és mysqlslave nevekkel lett létrehozva, mindkettő a VirtualBox ún. host-olt hálózati kártya szolgáltatásán keresztül volt elérhető ez által biztosítva, hogy elérjék egymást is és a host gépet is.

Megjegyzés: ebben a hálózati kártya üzemmódban a host-olt gép, mint DHCP kiszolgáló két 192.168.56.*-ban végződtetett IP címet oszt ki a két virtualizált számítógépnek, kívülről (gazdagéptől felfelé) a két gép nem látszik és nem elérhető.

Az alábbiakban ismertetett megoldás során egyedileg, MySQL konzolból futási időben hozzuk létre a replikációt.

1, A mysqlmaster kiszolgálón le kell állítani a mysqld service-t:

$ sudo service mysql stop

2, A mysqlmaster kiszolgálón a(z) /etc/mysql/my.cnf állományban be kell állítani a következőket:

#tetszőleges egyedi azonosító szám is szerepelhet itt (legjobb példa pl a kiszolgáló
#IP címét használni pontok nélkül).
server-id = 19216856101
#a mysql adatbázis (vagy mások is) log-ból való kizárása replikáció szempontjából
binlog_ignore_db = mysql

3, A mysqlmaster kiszolgálón el kell indítani a mysqld service-t:

$ sudo service mysql start

4, Létre kell hozni egy, a replikációra szolgáló usert és engedélyezni kell a távoli hozzáférést (a példában bármely host-ról engedélyezzük, a gyakorlatban ezt célszerű egy dedikált IP címre szűkíteni):

CREATE USER replicant@'%' IDENTIFIED BY 'password';
GRANT SELECT, PROCESS, FILE, SUPER, REPLICATION CLIENT,
REPLICATION SLAVE, RELOAD ON *.* TO replicant@'%';
FLUSH PRIVILEGES;

5, A mysqlslave kiszolgálón le kell állítani a mysqld service-t:

$ sudo service mysql stop

6, A mysqlslave kiszolgálón a(z) /etc/mysql/my.cnf állományban be kell állítani a következőket:

#tetszőleges egyedi azonosító szám is szerepelhet itt, ami eltér a master-étől
#(legjobb példa pl a kiszolgáló IP címét használni pontok nélkül)
server-id = 19216856102

7, Hozzuk létre a mysqlmaster kiszolgálón a replikálni kívánt adatbázist, töltsük fel adatokkal, majd mysqldump-al másoljuk át a mysqlslave kiszolgálóra (amin előtte el kell indítani a mysqld-t.) és importáljuk be. Így a két adatbázis kiszolgáló adattartalma most megegyezik.

8, A mysqlmaster kiszolgálón futtassuk le a következő SQL parancsot (lock-oljuk a táblákat, hogy a master-slave kapcsolat kiépüléséig ne írhassanak bele):

FLUSH TABLES WITH READ LOCK;

9, A mysqlmaster kiszolgálón futtassuk le a következő SQL parancsot:

SHOW MASTER STATUS;

Az eredményből jegyezzük meg a file és position adattagokat!!!

10, A mysqlslave kiszolgálón biztos ami biztos, állítsuk le a replikációt (elvileg még be sem kapcsoltuk, de nem árt leellenőrizni ezzel az SQL utasítással):

STOP SLAVE;

11, A mysqlslave kiszolgálón futtassuk le a következő SQL parancsot a replikációt beállítandó (itt a 9-es lépésben megkapott file és position értékeket kell használni):

CHANGE MASTER TO MASTER_HOST='név vagy ip cím',
MASTER_USER='replicant', MASTER_PASSWORD='password', MASTER_LOG_FILE='file',
MASTER_LOG_POS=position;
START SLAVE;
SHOW SLAVE STATUS;

Ha mindent jól csináltunk, akkor az utolsó parancs status sorában a „Waiting for master to send event.” üzenettel kell, hogy a mysqlslave visszajelezze: működik a replikáció.

12, A mysqlmaster kiszolgálón futtassuk le a következő SQL parancsot (a 8-as pontban létrehozott lock-olás feloldására):

UNLOCK TABLES;

A master-slave kapcsolat biztonságos leállítása

1, A mysqlslave kiszolgálón állítsuk le a replikációt:

STOP SLAVE;

2, A mysqlslave kiszolgálón írjuk ki a változásokat:

FLUSH TABLES;

3, Most már leállítható a mysqlslave kiszolgáló:

/etc/init.d/mysql stop

A master-slave kapcsolat biztonságos elindítása

1, A mysqlslave kiszolgálón indítsuk el a mysql-t:

/etc/init.d/mysql start

2, A mysqlslave kiszolgálón indítsuk el a slave kapcsolatot:

START SLAVE;

3, Ellenőrizzük le, hogy működik-e:

SHOW SLAVE STATUS;

Monitorozás

A MySQL kiszolgálók között kialakított master-slave replikációk monitorozása megoldható a következők használatával:

Példák

SSL használata a replikáció során

Alapesetben a MySQL-ben a replikáció nem használ SSL protokolt az adatok átvitele során, azonban a /etc/mysql/my.cnf -ben ez beállítható. FONTOS: a master-slave replikáció felépítése előtt kell ezt végrehajtani!

Az SSL beállításának lépései:

1, Első lépésként ellenőrizzük mindkét serveren, hogy támogatja-e az SSL-t (Linux konzolban kiadandó shell parancs):

$ sudo mysqld --ssl –help

2, SSL certificate-ek létrehozása az mysqlmaster kiszolgálón a /etc/mysql/certs jegyzékbe:

$ sudo su
$ apt-get install openssl
$ cd /etc/mysql
$ mkdir certs
$ cd certs

3, Létrehozzuk a CA certificate-et a mysqlmaster kiszolgálón 1000 napos lejárati dátummal:

$ openssl genrsa 2048 > ca-key.pem
$ openssl req -new -x509 -nodes -days 1000 -key ca-key.pem > ca-cert.pem

4, Létrehozzuk a mysqlmaster kiszolgálón a master certificate-jét 1000 napos lejárati dátummal és a CA felhasználásával:

$ openssl req -newkey rsa:2048 -days 1000 -nodes -keyout master-key.pem > master-req.pem
$ openssl x509 -req -in master-req.pem -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > master-cert.pem

5, Létrehozzuk a mysqlmaster kiszolgálón a slave certificate-jét 1000 napos lejárati dátummal és a CA felhasználásával:

$ openssl req -newkey rsa:2048 -days 1000 -nodes -keyout slave-key.pem > slave-req.pem
$ openssl x509 -req -in slave-req.pem -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > slave-cert.pem

6, A mysqlmaster kiszolgálón a /etc/mysql/my.cnf-ben beállítjuk a tanúsítványok használatát:

[mysqld]
ssl-ca=/etc/mysql/certs/ca-cert.pem
ssl-cert=/etc/mysql/certs/master-cert.pem
ssl-key=/etc/mysql/certs/master-key.pem

7, Újraindítjuk a mysqlmaster-en a MySQL-t:

$ sudo service mysql stop

8, Leellenőrizzük a mysqlmaster-en, hogy SSL-el lehet-e kapcsolódni a MySQL-hez:

$ sudo mysql -u root -p --ssl-ca=/etc/mysql/certs/ca-cert.pem
mysql> SHOW STATUS LIKE 'ssl_cipher';
+---------------+--------------------+
| Variable_name | Value              |
+---------------+--------------------+
| Ssl_cipher    | DHE-RSA-AES256-SHA |
+---------------+--------------------+
1 row in set (0.00 sec)
mysql> exit;

9, A replikációs user létrehozásánál használjuk a REQUIRE SSL; kapcsolót is.

10, A mysqlslave kiszolgálón létrehozzuk a /etc/mysql/certs jegyzéket és átmásoljuk bele a slave-*.pem állományokat.

11, A mysqlslave kiszolgálón a /etc/mysql/my.cnf-ben beállítjuk a tanúsítványok használatát:

[mysqld]
ssl-ca=/etc/mysql/certs/ca-cert.pem
ssl-cert=/etc/mysql/certs/slave-cert.pem
ssl-key=/etc/mysql/certs/slave-key.pem

12, A master-slave kapcsolat felépítése során szintén meg kell adni az SSL használatának paramétereit, pl:

CHANGE MASTER TO MASTER_HOST='név vagy ip cím', MASTER_USER='replicant',
MASTER_PASSWORD='password', MASTER_LOG_FILE='file', MASTER_LOG_POS=position, MASTER_SSL=1,
MASTER_SSL_CA = 'ca-cert.pem', MASTER_SSL_CAPATH = '/etc/mysql/certs', 
MASTER_SSL_CERT = slave-cert.pem', MASTER_SSL_KEY = 'slave-key.pem';

Időzített replikáció – késleltetés

A slave-en beállítható a

CHANGE MASTER TO MASTER_DELAY = N;

utasítással (N a késleltetés ideje másodpercben). Ilyen esetekben N másodperc után kerülnek csak feldolgozásra a master binlogjába kerülő tranzakciók. Használata főleg a gyakori rollback-et alkalmazó üzleti rendszereknél hatásos.

Terheléselosztás

MySQL replikáció terheléseloszlása

Forrás: MySQL dokumentáció – 17.3.3 Using Replication for Scale-Out

A fenti ábrán látható a leggyakoribb felhasználási módja a master-slave replikációnak. Ilyen esetekben szükséges, hogy az alkalmazásunk és a MySQL kiszolgálók közé beékeljünk egy ún. load balancer / terhelés elosztó réteget is. Erre MySQL környezetben a MySQL Proxy alkalmazás is felhasználható más LB megoldásokon (pl. HAProxy) kívül.

A MySQL Proxy konfigurációjában a proxy-read-only-backend-addresses érték beállításával szabályozható, hogy az olvasási lekérdezések csak a slave-ekről szolgálhatók ki, a master-t pedig a proxy-backend-addresses kulcshoz rendeljük.

Eltérő adatbázisok replikációja külön slave-ekre

Ha egy master adatbázis kiszolgálóról különböző adatbázisokat más-más slave adatbázis kiszolgálóra kívánunk replikálni, akkor a következőket kell beállítani:

MySQL eltérő adatbázisok replikációja

Forrás: MySQL dokumentáció – 17.3.4 Replicating Different Databases to Different Slaves

Tilos a --replicate-do-db kapcsoló használata az egyes slave-eken, helyette a --replicate-wild-do-table=databaseA.%. beállítással kell megadni, hogy a databaseA adatbázist replikálja.

Ilyen esetekben minden slave ugyanazt a közös master binlog-ot olvassa fel, de mindegyik csak a saját beállításaiban megadott adatbázisokra vonatkozó műveleteket hajtja végre.

Egyszerre master-ként és slave-ként működő kiszolgáló

Egy adatbázis kiszolgáló lehet egyszerre master is és slave is. Pl. az alábbi példában a Master1 „hot backup”-ja a Master2, amire terhelés elosztás miatt 3 darab slave csatlakozik:

MySQL megosztott replikáció

Forrás: MySQL dokumentáció – 17.3.5 Improving Replication Performance

Ilyen esetekben a Master2-n a --log-slave-updates kapcsolóval engedélyezni kell, hogy az általa replikált adatokból új binlog-ot képezzen a slave-ek számára.

Failover hibatűrő rendszer kialakítása

Alapértelmezés szerinti működés:

MySQL failover 1

Forrás: MySQL dokumentáció – 17.3.6 Switching Masters During Failover

Helyes konfiguráció esetén a Master kiesése esetén a Slave1 (vagy más, dedikált kiszolgáló) automatikusan átveszi a szerepét:

MySQL failover 2

Forrás: MySQL dokumentáció – 17.3.6 Switching Masters During Failover

Ennek konfigurációjához azonban az ún. „Global Transaction Identifiers – GTIDs” technikát kell használni a MySQL-ben, bővebben lásd a MySQL dokumentációt.