A MySQL replikációs és clusterezési lehetőségeinek bemutatása 2.
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 és 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 fürtözéssel ismertetjük meg olvasóinkat.
MySQL Cluster
Bemutatás
A MySQL-ben használt klaszterezési technológiában három különálló infrastrukturális feladatot ellátó kiszolgálót különböztetünk meg:
- Data node (Linux alatt a mysql-cluster-server-datanode csomag): feladata az adatbázisok tárolása, gondoskodik azok szinkronizációjáról, transzparens módon szolgálja ki az SQL node-okat, terheléselosztás révén gondoskodik a minél hatékonyabb működtetésről, valamint képes a leállást követő újraszinkronizációra.
- SQL node (vagy application node) (Linux alatt a mysql-cluster-server-sqlnode csomag, de ez megfelel a mysql-server csomagnak): Az alkalmazások felől elérhető kiszolgáló(k). Ők kezelik a data node-okról érkező adatfolyamokat és szolgálják ki az egyes eléréseket.
- Management node (Linux alatt a mysql-cluster-server-mgmtnode csomag): Konfigurációs felada-tok és monitorozás céljára szolgáló kiszolgáló(k). A klaszter indítása és leállítása során kiemelt szerepük van, addig nem csatlakoztatható egy gép data node-ként a klaszterbe, amíg legalább egy management node nem indult el.
MySQL-ben cluster csak NDB engine-el használható, amely jelenleg is számos megszorítást tartalmaz a többi népszerű adatbázis engine-hez képest, de ezek száma folyamatosan csökken.
A MySQL cluster lehetővé teszi, hogy a több data node-ból kialakított cluster-eket akár egymásra replikáljuk és az SQL node-ok számára transzparens módon szolgáltassunk a clusterek között váltogatva.
MySQL Cluster létrehozása
- A létrehozandó cluster-ben két data node-lesz:
db0
ésdb1
. - A load balancer-ként funkcionáló dedikált kiszolgáló:
mysql-proxy
. - Mindkét node egyben management funkciókat is el fog látni. (Két management node-al nagyobb rendelkezésre állást tudunk megvalósítani, mivel bármelyik kiesése esetén a cluster továbbra is menedzselhető marad a másik által.)
- Létrehozunk egy MySQL Proxy-n alapuló load balancer eljárást.
- Végezetül felhasználói script-ekkel automatizáljuk a kiszolgálók elindulásának és a cluster felépítésének folyamatát.
Nem túl elterjedt, hogy egy kiszolgálón kerüljön kialakításra a management és a data node is, azonban a fenti konfigurációval (két data node, és mindkettő management is egyben) teljes értékű failover rendszer alakítható ki két kiszolgálóval is.
Előkészületek (ezt mindkét kiszolgálón meg kell tenni):
- hozzunk létre egy új felhasználói csoportot a kiszolgálókat futtató dedikált felhasználók számára:
groupadd mysql
- hozzunk létre egy, a mysql kiszolgálókat futtató felhasználót az előbbi csoportban:
useradd -g mysql mysql
- állítsuk be a megfelelő jogosultságokat a cluster telepítése során beállított adatok tárolását végző jegyzékeken:
chown mysql:root /opt/oracle/disk/mysql_cluster/mysqld_data
- next-next-finish módon csomagból telepítsük fel a MySQL Cluster-t, FONTOS: a telepítés végén ne indítsuk el a mysql-t!
1, Mindkét kiszolgálón módosítsuk a /etc/mysql/my.cnf
konfigurációs állományt a következő módon:
[mysqld] basedir=/usr/local/mysql #az az adatkönyvtár amit a telepítés során megadtunk. datadir=/opt/oracle/disk/mysql_cluster/mysqld_data event_scheduler=on #csak ndb engine-el működik a cluster default-storage-engine=ndbcluster [ndbcluster] # a management node-ok nevei vagy ip címei felsorolva ndb-connectstring=db0,db1 key_buffer = 512M key_buffer_size = 512M sort_buffer_size = 512M table_cache = 1024 read_buffer_size = 512M [mysql_cluster] # a management node-ok nevei vagy ip címei felsorolva ndb-connectstring=db0,db1
2, Adjunk futási jogosultságot az ndb_mgm
eszköznek a db0
kiszolgálón:
cd /usr/local/mysql chmod +x bin/ndb_mgm*
3, Hozzuk létre a cluster konfigurációs beállításait leíró állományt a db0
kiszolgálón:
mkdir /var/lib/mysql-cluster vim /var/lib/mysql-cluster/config.ini
4, Állítsuk be az alábbi paramétereket a 3. lépésben létrehozott fájl-ban:
[NDBD DEFAULT] NoOfReplicas=2 DataDir=/var/lib/mysql-cluster # fontos: induláskor az ndb ezt le is fogja foglalni! DataMemory=8G IndexMemory=4G [MYSQLD DEFAULT] [NDB_MGMD DEFAULT] [TCP DEFAULT] [NDB_MGMD] HostName=db0 # az első management node neve vagy ip címe NodeId=1 # az első management node azonosítója [NDB_MGMD] HostName=db1 # a második management node neve vagy ip címe NodeId=2 # a második management node azonosítója [NDBD] HostName=db0 # az első data node neve vagy ip címe NodeId=3 # az első data node azonosítója [NDBD] HostName=db1 # a második data node neve vagy ip címe NodeId=4 # a második data node azonosítója [MYSQLD] [MYSQLD]
5, A management node ezzel beállítva, elindítható. FONTOS, hogy első és csak az első indításkor az –initial
paraméterrel kell indítani a ndb_mgmd
-t a db0
kiszolgálón:
ndb_mgmd -f /var/lib/mysql-cluster/config.ini --initial --config-dir=/var/lib/mysql-cluster/
Ha mindent jól csináltunk, akkor a „MySQL Cluster Management Server verziószám„ üzenetet kell megkapunk.
6, Ismételjük meg a 2.-től 5.-ig lépéseket a db1
kiszolgálón is.
7, Indítsuk le a db0
kiszolgálón a data node-okat is:
/usr/local/mysql/bin/ndbd --initial
Ha mindent jól csináltunk, az
[ndbd] INFO -- Angel connected to 'localhost:1186' [ndbd] INFO -- Angel allocated nodeid: 3
üzenetet kell kapnunk.
8, Indítsuk el a db1
kiszolgálón is a data node-ot: ott értelem szerűen a nodeid: 4
üzenettel kell bejelentkeznie a data node-nak.
9, Indítsuk el mindkét kiszolgálón a mysql-t (az sql node-ot):
/etc/init.d/mysql.server start
10, Ahhoz, hogy a két clusteren külön-külön is tudjunk dolgozni, szükséges, hogy a mysql jogosultságai, felhasználói is NDB adatbázis engine-ben legyenek tárolva. Ehhez hajtsuk végre a következő módosításokat a db0
kiszolgálón:
use mysql; ALTER TABLE mysql.user ENGINE=NDBCLUSTER; ALTER TABLE mysql.db ENGINE=NDBCLUSTER; ALTER TABLE mysql.host ENGINE=NDBCLUSTER; ALTER TABLE mysql.tables_priv ENGINE=NDBCLUSTER; ALTER TABLE mysql.columns_priv ENGINE=NDBCLUSTER; ALTER TABLE mysql.procs_priv ENGINE=NDBCLUSTER; ALTER TABLE mysql.proxies_priv ENGINE=NDBCLUSTER;
11, Még mindig a db0
kiszolgáló MySQL adatbázisában dolgozva állítsuk be az esemény vezérlőt:
SET GLOBAL event_scheduler=1; CREATE EVENT `mysql`.`flush_priv_tables` ON SCHEDULE EVERY 30 second ON COMPLETION PRESERVE DO FLUSH PRIVILEGES;
12, Mivel a mysql adatbázisban tárolt jogosultságok még nem szinkronizálódtak át a db1
-re (nem is tudnak átszinkronizálódni, mivel nincs meg hozzá a megfelelő jogosultságuk), azokat kézzel kell átvinnünk:
root@db0~# /etc/init.d/mysql.server stop root@db1~# /etc/init.d/mysql.server stop root@db0~# scp -r mysqld_data/ db1:/opt/oracle/disk/mysql_cluster/ root@db0~# /etc/init.d/mysql.server start root@db1~# /etc/init.d/mysql.server start
13, Ezek után ellenőrizzük le a cluster management-ben, hogy él a kapcsolat a node-ok között:
root@db0:~# ndb_mgm -- NDB Cluster -- Management Client -- ndb_mgm> show Connected to Management Server at: db0:1186 Cluster Configuration --------------------- [ndbd(NDB)] 2 node(s) id=3 @ipcím (verzió) id=4 @ipcím (verzió) [ndb_mgmd(MGM)] 2 node(s) id=1 @ipcím (verzió) id=2 @ipcím (verzió) [mysqld(API)] 2 node(s) id=5 @ipcím (verzió) id=6 @ipcím (verzió)
A MySQL Cluster működésének tesztelése
Hozzunk létre pár adatot a db0
-n:
root@db0:~# mysql Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 mysql> use test Database changed mysql> CREATE TABLE testdata (i INT) ENGINE=NDBCLUSTER; mysql> INSERT INTO testdata () VALUES (1);
Ellenőrizzük le a meglétüket a db1
-en:
root@db1:~# mysql Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 3 mysql> use test mysql> SELECT * FROM testdb; +------+ | i | +------+ | 1 | +------+ 1 row in set (0.00 sec)
Látható, hogy a két szerver szinkronizálta az adatokat egymás között.
Nézzük meg mi történik, ha leállítjuk a db0
-s data node-ot:
root@db0:~# /etc/init.d/mysql.server stop root@db0:~# ndb_mgm -- NDB Cluster -- Management Client -- ndb_mgm> show Connected to Management Server at: db0:1186 Cluster Configuration --------------------- [ndbd(NDB)] 2 node(s) id=3 @ipcím (verzió) id=4 @ipcím (verzió) [ndb_mgmd(MGM)] 2 node(s) id=1 @ipcím (verzió) id=2 @ipcím (verzió) [mysqld(API)] 2 node(s) id=5 (not connected, accepting connect from any host) id=6 @ipcím (verzió)
A leállított db0
data node mellett hozzunk létre új adatokat a db1
-en:
root@db1:~# mysql Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 4 mysql> use test; mysql> INSERT INTO testdb () VALUES (99); mysql> INSERT INTO testdb () VALUES (999); mysql> INSERT INTO testdb () VALUES (100);
Indítsuk el a db0
-n a data node-ot és kérdezzük le az adatokat:
root@db0:~# /etc/init.d/mysql.server start root@db0:~# mysql Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 mysql> use test; mysql> SELECT * FROM testdb; +------+ | i | +------+ | 99 | | 999 | | 1 | | 100 | +------+ 4 rows in set (0.00 sec)
Mint látható az indulást követően szinkronizálódtak az adatok a két node között.
Load balancer MySQL Proxy-val
1, Telepítsük fel a MySQL Proxy-t és hozzuk létre a konfigurációs állományát a mysql-proxy
kiszolgálón:
root@mysql-proxy:~# apt-get install mysql-proxy root@mysql-proxy:~# mkdir /etc/mysql-proxy root@mysql-proxy:~# cd /etc/mysql-proxy root@mysql-proxy:/etc/mysql-proxy# vim mysql-proxy.conf
2, Állítsuk be a létrehozott konfigurációs állományban a következőket:
[mysql-proxy] daemon = true keepalive = true # a proxy elérhetősége proxy-address = mysql-proxy:3306 # master (tehát írható / olvasható) adatbázis(ok) data node-ja(i) proxy-backend-addresses = db0:3306, db1:3306
3, Indítsuk el a MySQL Proxy-t:
root@mysql-proxy:~# <code>mysql-proxy</code> --defaults-file=/etc/mysql-proxy/mysql-proxy.conf
Indítás ütemezése, automatizálása
Mivel se az ndbb
, se az ndb-mgmd
nem indul el automatikusan, ráadásul a cluster data node-jai csak abban az esetben tudnak bejelentkezni a cluster-be, ha legalább egy management node-ot már látnak: szükséges ezek indítását automatizálni. Erre jó megoldás lehet az /etc/init.d/
jegyzékbe létrehozott indító script-ek használata. Fontos, hogy a következő fájl-ok létrehozása után futtatási jogot adjunk rájuk:
chmod +x /etc/init.d/<filename>
valamint az
update-rc.d <filename>
paranccsal érvénybe léptessük a változtatásokat.
Az ndbd indítására: /etc/init.d/ndbd
#!/bin/bash # Provides: ndbd # Required-Start: $local_fs $network $syslog $remote_fs # Required-Stop: $local_fs $network $syslog $remote_fs # Short-Description: mysql cluster manager client # Description: mysql cluster manager client ndbd_bin=/usr/local/mysql/bin/ndbd if ! test -x $ndbd_bin; then echo "Can't execute $ndbd_bin"; exit; fi start_ndbd(){ number_of_ndbd_pids=`ps aux|grep -iv "grep"|grep -i "/usr/local/mysql/bin/ndbd"|wc -l` if [ $number_of_ndbd_pids -eq 0 ]; then $ndbd_bin echo "ndbd started." else echo "ndbd is already running." fi } stop_ndbd(){ number_of_ndbd_pids=`ps aux|grep -iv "grep"|grep -i "/usr/local/mysql/bin/ndbd"|wc -l` if [ $number_of_ndbd_pids -ne 0 ]; then ndbd_pids=`pgrep ndbd` for ndbd_pid in $(echo $ndbd_pids); do kill $ndbd_pid 2> /dev/null done number_of_ndbd_pids=`ps aux|grep -iv "grep"|grep -i "/usr/local/mysql/bin/ndbd"|wc -l` if [ $number_of_ndbd_pids -eq 0 ]; then echo "ndbd stopped." else echo "Could not stop ndbd." fi else echo "ndbd is not running." fi } case "$1" in 'start' ) start_ndbd ;; 'stop' ) stop_ndbd ;; 'restart' ) stop_ndbd start_ndbd ;; *) echo "Usage: $0 {start|stop|restart}" >&2 ;; esac
Az ndb-mgmd indítására: /etc/init.d/ndb-mgmd
#!/bin/bash # Provides: ndb_mgmd # Required-Start: $local_fs $network $syslog $remote_fs # Required-Stop: $local_fs $network $syslog $remote_fs # Short-Description: mysql cluster manager # Description: mysql cluster manager ndb_mgmd=/usr/local/mysql/bin/ndb_mgmd config_file=/var/lib/mysql-cluster/config.ini config_dir=/var/lib/mysql-cluster if ! test -x $ndb_mgmd; then echo "Can't execute $ndb_mgmd" exit; fi start_ndb_mgmd(){ number_of_ndb_mgmd_pids=`ps aux|grep -iv "grep"|grep -i "$ndb_mgmd"|wc -l` if [ $number_of_ndb_mgmd_pids -eq 0 ]; then $ndb_mgmd -f $config_file --config-dir=$config_dir echo "ndb_mgmd started." else echo "ndb_mgmd is already running." fi } stop_ndb_mgmd(){ number_of_ndb_mgmd_pids=`ps aux|grep -iv "grep"|grep -i "$ndb_mgmd"|wc -l` if [ $number_of_ndb_mgmd_pids -ne 0 ]; then ndb_mgmd_pids=`pgrep ndb_mgmd` for ndb_mgmd_pid in $(echo $ndb_mgmd_pids); do kill $ndb_mgmd_pid 2> /dev/null done number_of_ndb_mgmd_pids=`ps aux|grep -iv "grep"|grep -i "$ndb_mgmd"|wc -l` if [ $number_of_ndb_mgmd_pids -eq 0 ]; then echo "ndb_mgmd stopped." else echo "Could not stop ndb_mgmd." fi else echo "ndb_mgmd is not running." fi } case "$1" in 'start' ) start_ndb_mgmd ;; 'stop' ) stop_ndb_mgmd ;; 'restart' ) stop_ndb_mgmd start_ndb_mgmd ;; *) echo "Usage: $0 {start|stop|restart}" >&2 ;; esac
A mysql-proxy
indítására: /etc/init.d/mysql-proxy
#! /bin/bash # Required-Start: $local_fs $network $syslog $remote_fs # Required-Stop: $local_fs $network $syslog $remote_fs # Short-Description: MySQL Proxy # Description: MySQL Proxy mysql_proxy=/usr/bin/mysql-proxy config_file=/etc/mysql-proxy/mysql-proxy.conf if ! test -x $mysql_proxy; then echo "Can't execute $mysql_proxy" exit; fi start_mysql_proxy(){ number_of_mysql_proxy_pids=`ps aux|grep -iv "grep"|grep -i "/usr/bin/mysql-proxy"|wc -l` if [ $number_of_mysql_proxy_pids -eq 0 ]; then $mysql_proxy --defaults-file=$config_file echo "mysql-proxy started." else echo "mysql-proxy is already running." fi } stop_mysql_proxy(){ number_of_mysql_proxy_pids=`ps aux|grep -iv "grep"|grep -i "/usr/bin/mysql-proxy"|wc -l` if [ $number_of_mysql_proxy_pids -ne 0 ]; then mysql_proxy_pids=`pgrep mysql-proxy` for mysql_proxy_pid in $(echo $mysql_proxy_pids); do kill $mysql_proxy_pid 2> /dev/null done number_of_mysql_proxy_pids=`ps aux|grep -iv "grep"|grep -i "/usr/bin/mysql-proxy"|wc -l` if [ $number_of_mysql_proxy_pids -eq 0 ]; then echo "mysql-proxy stopped." else echo "Could not stop mysql-proxy." fi else echo "mysql-proxy is not running." fi } case "$1" in 'start' ) start_mysql_proxy ;; 'stop' ) stop_mysql_proxy ;; 'restart' ) stop_mysql_proxy start_mysql_proxy ;; *) echo "Usage: $0 {start|stop|restart}" >&2 ;; esac