MySQL multi master replikacija
Strategija padaryti du identiškus MySQL serverius, pasinaudojant MySQL multi master replikacija. Techniškai tai du serveriai veikiantys kaip Master > Slave ir atvirkščiai. Kiekvienas jų yra tiek Master tiek Slave, ir taip sukuriamas atbulinis duomenų sinchronizavimo mechanizmas užtikrinantis 100% replikaciją. Taip pat šiame straipsnyje aprašomos galimai iškylančios problemos bei jų sprendimas, kad replikacija būtų kuo stabilesnė.
Naudosime du serverius:
- node1 - Y.Y.Y.Y
- node2 - X.X.X.X
Pasiruošimas[keisti]
Pirmaiusia reikėtų žinoti jog prieš pradedant visą replikavimo procesą reikia perkopijuoti produkcinės DB duomenis į Slave serverį, tai galima padaryti paprastu mysqldump, arba jeigu versijos yra identiškos tiesiog saugiu sftp ryšiu perkelti MySQL failus (/var/lib/mysql) į Slave serverį. Pastaruoju atveju turite išjungti Master MySQL serverį, kad saugiai tai padaryti, išjungti trumpam vistiek reiks, dėl MySQL konfigūracijos keitimo. Bet jeigu manote, kad kopijuojamų duomenų yra perdaug 10-50GB> tuomet galite viską dumpinti į didelį sql'ą. Sukišti į Slave serverį, kol pirmajį Master'į laikysite su užlokintą nuo pakeitimų (su įjungtu binary logu).
mysql> FLUSH TABLES WITH READ LOCK;
Persikopijavus ir paleidus Slave serverį, galima daryti "quit" pastarojoje sesijoje, ir lentelės atsirakins.
Master configas (buvęs productionas)[keisti]
/etc/mysql/mysql.conf.d/mysqld.cnf Atkreipkite dėmesį į paryškintas eilutes
[mysqld_safe] socket = /var/run/mysqld/mysqld.sock nice = 0 [mysqld] # * Basic Settings user = mysql pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock port = 3306 basedir = /usr datadir = /var/lib/mysql tmpdir = /tmp lc-messages-dir = /usr/share/mysql skip-external-locking bind-address = 0.0.0.0 # * Fine Tuning key_buffer_size = 16M max_allowed_packet = 16M thread_stack = 192K thread_cache_size = 8 myisam-recover-options = BACKUP query_cache_limit = 1M query_cache_size = 16M log_error = /var/log/mysql/error.log server-id = 1 binlog_format = mixed log_bin = /var/log/mysql/mysql-bin.log expire_logs_days = 10 max_binlog_size=10G # keli hackai padesiantys lengviau replikuoti mysql innodb_flush_log_at_trx_commit=1 sync_binlog=1 slave_exec_mode=IDEMPOTENT relay_log_info_repository=TABLE
Po konfigūracijos pakeitimo perkrauname mysql:
service mysql restart
Kitas master configas (naujasis slave)[keisti]
/etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld_safe] socket = /var/run/mysqld/mysqld.sock nice = 0 [mysqld] # * Basic Settings user = mysql pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock port = 3306 basedir = /usr datadir = /var/lib/mysql tmpdir = /tmp lc-messages-dir = /usr/share/mysql skip-external-locking bind-address = 0.0.0.0 # * Fine Tuning key_buffer_size = 16M max_allowed_packet = 16M thread_stack = 192K thread_cache_size = 8 myisam-recover-options = BACKUP # * Query Cache Configuration query_cache_limit = 1M query_cache_size = 16M # * Logging and Replication general_log_file = /var/log/mysql/mysql.log general_log = 1 log_error = /var/log/mysql/error.log server-id = 2 binlog_format = mixed log_bin = /var/log/mysql/mysql-bin.log max_binlog_size=10G expire_logs_days = 10 relay-log=mysqld-relay-bin report-host=node1 slave_exec_mode=IDEMPOTENT relay_log_info_repository=TABLE
Po konfigūracijos pakeitimo perkrauname mysql:
service mysql restart
Replikacija[keisti]
Pirmajame serveryje pasileidžiame mysql klienta (pasijungiame kaip root), antrajame taip pat, iš pirmojo pažiūrime master status:
SHOW MASTER STATUS;
Duodame leidimą replikacijai:
grant replication slave on *.* to 'repl'@'Y.Y.Y.Y' identified by 'SLAPTAŽODIS‘;
Antrajame serveryje rašome:
change master to master_host = 'X.X.X.X', master_user='repl', master_password='SLAPTAŽODIS', master_log_file='mysql-bin.000005', master_log_pos=769;
Butinai užrašome tikslų master log ir log pos iš pirmojo serverio master statuso (nuo tos vietos jis pradės replikuotis), paleidžiame slave
start slave;
Taip pat leidžiame prėima pirmajam serveriui būti šito serverio slave'u:
grant replication slave on *.* to 'repl2’@’X.X.X.X' identified by 'SLAPTAŽODIS‘;
Taip pat pažiūrime master status'ą
mysql> show master status; +------------------+-----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+-----------+--------------+------------------+-------------------+ | mysql-bin.000002 | 254 | | | | +------------------+-----------+--------------+------------------+-------------------+ 1 row in set (0.01 sec)
Pirmajame serveryje darome atgalinę replikaciją (užrašydami antrojo serverio master statuso binary failą bei jo poziciją:
change master to master_host = 'Y.Y.Y.Y', master_user='repl2', master_password='SLAPTAŽODIS', master_log_file='mysql-bin.000002', master_log_pos=254; start slave;
Replikacija turetų pradėti vykti, jeigu abiejuose serveriuose matome (parašius show slave status\G;)
Slave_IO_Running: Yes Slave_SQL_Running: Yes
Jeigu nepavyko, kartojame ir būtinai žiūrime logą /var/log/mysql/error.log
Laikui bėgant problemos dėl incremental ID'u bei kitų bėdų[keisti]
Nors su šiais konfigais turėtume to išvengti bet dėl visa pikta, kas valandą ant crontab'o galime užkabinti šį scriptą kuris išspręs problemas bent jau kol ateis adminas:
#/bin/bash
mysql_user=root
mysql_host=localhost
mysql_port=3306
mysql_socket=/var/run/mysqld/mysqld.sock
cmd=mysql
[ -n "$mysql_host" ] && cmd="$cmd --host=$mysql_host"
[ -n "$mysql_port" ] && cmd="$cmd --port=$mysql_port"
[ -n "$mysql_socket" ] && cmd="$cmd --socket=$mysql_socket"
[ -n "$mysql_user" ] && cmd="$cmd --user=$mysql_user"
#[ -n "$mysql_pass" ] && cmd="$cmd --password=$mysql_pass"
#echo $cmd
while(true);
do
Last_SQL_Error=`$cmd -e "show slave status\G" | grep "Last_SQL_Error:" | awk 'BEGIN{FS=":"}{print $2}' | tr -d ' '`
#Last_SQL_Error=""
if [ -z "$Last_SQL_Error" ]; then
break
fi
Master_UUID=`$cmd -e "show slave status\G" | grep "Master_UUID" | awk 'BEGIN{FS=":"}{print $2}'`
Executed_Gtid_Set=`$cmd -e "show slave status\G" | grep "Executed_Gtid_Set" | grep $Master_UUID | awk 'BEGIN{FS=" "}{print $2}'`
Executed_id_Last=`echo $Executed_Gtid_Set | awk 'BEGIN{FS=":"}{print $NF}' | awk 'BEGIN{FS="-"}{print $2}'`
Executed_Gtid_Last=${Master_UUID}:${Executed_id_Last}
Executed_id_Next=`echo $Executed_id_Last + 1 | bc`
GTID_NEXT=${Master_UUID}:${Executed_id_Next}
$cmd << EOF
stop slave;
SET GTID_NEXT='$GTID_NEXT';
BEGIN;
COMMIT;
SET GTID_NEXT='AUTOMATIC';
start slave;
EOF
echo $Last_SQL_Error
echo $Executed_Gtid_Set
echo $GTID_NEXT
sleep 1
done
Problemos[keisti]
Jai iškyla problemų ar sutrinka replikacija ir reikia ją perkrauti pasiskaitom čia kaip išvengti sunkumų.