如下圖1.png所示:
該過程的第一部分就是master記錄二進制日志。在每個事務更新數據完成之前,master在二日志記錄這些改變。MySQL將事務串行的寫入二進制日志,即使事務中的語句都是交叉執行的。在事件寫入二進制日志完成後,master通知存儲引擎提交事務。
下一步就是slave將master的binary log拷貝到它自己的中繼日志。首先,slave開始一個工作線程——I/O線程。I/O線程在master上打開一個普通的連接,然後開始binlog dump process。Binlog dump process從master的二進制日志中讀取事件,如果已經跟上master,它會睡眠並等待master產生新的事件。I/O線程將這些事件寫入中繼日志。
SQLslave thread(SQL從線程)處理該過程的最後一步。SQL線程從中繼日志讀取事件,並重放其中的事件而更新slave的數據,使其與master中的數據一致。只要該線程與I/O線程保持一致,中繼日志通常會位於OS的緩存中,所以中繼日志的開銷很小。
此外,在master中也有一個工作線程:和其它MySQL的連接一樣,slave在master中打開一個連接也會使得master開始一個線程。復制 過程有一個很重要的限制——復制在slave上是串行化的,也就是說master上的並行更新操作不能在slave上並行操作。
(1):數據分布
(2):負載均衡
(3):備份
(4):高可用和容錯
主從系統要保持一致:包括數據庫版本,操作系統版本,磁盤IO磁盤容量,網絡帶寬等。
[root@data02 ~]# cat /etc/redhat-release
CentOS release 6.2 (Final)
[root@data02 ~]#
主庫master
從庫slave
OS系統版本
CentOS release 6.2 (Final)
CentOS release 6.2 (Final)
數據庫版本
5.6.12-log
5.6.12-log
磁盤容量
50G
30G
主機ip地址
192.168.52.129
192.168.52.130
端口
3306
3306
內存
1G
1G
服務器類型
虛擬機
虛擬機
GRANT REPLICATION SLAVE,RELOAD,SUPER ON *.*TO repl@'192.168.52.130' IDENTIFIED BY 'repl_1234';
建立一個復制賬號,只允許從192.168.52.130上來訪問登錄主庫進行二進制日志傳輸同步。PS:如果mysql版本新舊密碼算法不同,可以設置set password for 'backup'@'10.100.0.200'=old_password('1234'))
因為當開始搭建的時候,主庫上已經有了數據,所以要先把主庫已經存在的數據先手動同步遷移到從庫上面去。搭建過程中,禁止在主庫從庫上進行任何對數據庫的ddl、dml等數據操作。
這裡可以用mysqldump也可以用xtrabackup導出主庫上面的數據:
在主庫上192.168.52.129上面進行數據備份,備份命令,要添加--safe-slave-backup參數:
innobackupex --user=backup--password="123456" --host=192.168.52.129 --socket=/tmp/mysql.sock--defaults-file=/etc/my.cnf /data/backups/mysql/repl/backup_slave --parallel=3--safe-slave-backup --no-timestamp
去備份目錄/data/backups/mysql/repl/backup_slave查看備份時候的主庫二進制信息,需要根據這個二進制信息來進行數據同步,如下所示:
[root@data01 test]# cd/data/backups/mysql/repl/backup_slave
[root@data01 backup_slave]# more xtrabackup_binlog_info
mysql-bin.000147 120
[root@data01 backup_slave]#
壓縮備份文件並且傳輸到從庫192.168.52.130上面:
tar -zcvf backup_slave.tar.gz backup_slave/
scp backup_slave.tar.gz192.168.52.130:/tmp/
在主庫上192.168.52.129上做基於主庫做數據備份
/usr/local/mysql/bin/mysqldump -ubackup--password=123456 --host=192.168.52.129 --single-transaction --flush-logs --master-data=2 --add-drop-table--create-option --quick --extended-insert=false --set-charset --disable-keys -A> /tmp/alldb.sql
壓縮備份文件,傳輸到從庫192.168.52.130上面去。
gzip /tmp/alldb.sql
scp /tmp/alldb.sql.gz 192.168.52.130:/tmp/
Vim /etc/my.cnf
server-id=129 # Server ID
log-bin =/home/data/mysql/binlog/mysql-bin
binlog-ignore-db=mysql # No sync databases
binlog-ignore-db=test # No sync databases
binlog-ignore-db=information_schema # No sync databases
binlog-ignore-db=performance_schema
binlog-do-db=user_db
保存退出,重啟mysql主庫,可以查看主庫的狀態,如下:
mysql> show master status; +------------------+----------+--------------+--------------------------------------------------+-------------------+ | File | Position | Binlog_Do_DB |Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+--------------------------------------------------+-------------------+ | mysql-bin.000151 | 120 | user_db |mysql,test,information_schema,performance_schema | | +------------------+----------+--------------+--------------------------------------------------+-------------------+ 1 row in set (0.00 sec) mysql> mysql> show master status\G; *************************** 1. row*************************** File: mysql-bin.000151 Position: 120 Binlog_Do_DB: user_db Binlog_Ignore_DB:mysql,test,information_schema,performance_schema Executed_Gtid_Set: 1 row in set (0.00 sec) ERROR: No query specified mysql>
Slave的配置與master庫類似,如下所示:
Vim /etc/my.cnf #------------------Master-Slaveconfig----------------- log-slave-updates=1 replicate-same-server-id=0 server-id=230 # Server ID log-bin=/home/data/mysql/binlog/mysql-bin.log relay-log=mysql-relay-bin master-info-repository=TABLE relay-log-info-repository=TABLE binlog-ignore-db=mysql # No sync databases binlog-ignore-db=test # No sync databases binlog-ignore-db=information_schema # No sync databases binlog-ignore-db=performance_schema binlog-do-db=user_db expire-logs-days=10 max_binlog_size = 10485760
server_id 是必須的,而且唯一。slave沒有必要開啟二進制日志,但是在一些情況下,必須設置,例如,如果slave為其它slave的master,必須設置 bin_log。在這裡,我們開啟了二進制日志,而且顯示的命名(默認名稱為hostname,但是,如果hostname改變則會出現問題)。
relay_log配置中繼日志,log_slave_updates表示slave將復制事件寫進自己的二進制日志(後面會看到它的用處)。
有些人開啟了slave的二進制日志,卻沒有設置log_slave_updates,然後查看slave的數據是否改變,這是一種錯誤的配置。所以,盡量使用read_only,它防止改變數據(除了特殊的線程)。但是,read_only並是很實用,特別是那些需要在slave上創建表的應用。
配置玩,重啟slave數據庫
mysql> show slave status; Empty set (0.05 sec) mysql>
沒有記錄,需要設置一些主從配置。
生成CHANGE MASTER語句,然後在從上執行,master信息,從備份集合裡面獲取:
xtrabackup備份的話,從xtrabackup_binlog_info裡面獲取,如下所示:
[root@data02 tmp]#tar -xvfbackup_slave.tar.gz [root@data02 tmp]#cd backup_slave [root@data02 backup_slave]# morextrabackup_binlog_info mysql-bin.000141 120 [root@data02 backup_slave]#
Mysqldump的啊,從sql文件的頭幾列獲取,如下所示:
[root@data02 tmp]#cd /tmp/ [root@data02 tmp]#gunzip alldb.sql.gz [root@data02 tmp]# more alldb.sql |grep"CHANGE MASTER TO MASTER_LOG_FILE" |grep "MASTER_LOG_POS"|more -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000141',MASTER_LOG_POS=120;
生成changemaster語句,如下:
CHANGE MASTER TO MASTER_HOST='192.168.52.129',
MASTER_USER='repl',
MASTER_PASSWORD='repl_1234',
MASTER_LOG_FILE='mysql-bin.000141',
MASTER_LOG_POS=120;
有報錯信息:
mysql> CHANGE MASTER TO MASTER_HOST='192.168.52.129',
-> MASTER_USER='repl',
-> MASTER_PASSWORD='repl_1234',
-> MASTER_LOG_FILE='mysql-bin.000141',
-> MASTER_LOG_POS=120;
ERROR 1794 (HY000): Slave is not configuredor failed to initialize properly. You must at least set --server-id to enableeither a master or a slave. Additional error messages can be found in the MySQLerror log.
mysql>
具體原因目前不詳,網上查找到的資料:數據庫打開這幾張表的默認引擎為MyISAM,但是這幾張表在建表時的引擎為INNODB
但是能確定的,這幾張表確實是在mysql5.6中新入的
innodb_index_stats,
innodb_tables_stats,
slave_master_info,
slave_relay_log_info,
slave_worker_info
解決方法:
登錄數據庫,進入mysql庫,執行如下SQL刪除5張表
記住,一定要是drop table if exists
drop table if exists innodb_index_stats;
drop table if exists innodb_table_stats;
drop table if exists slave_master_info;
drop table if exists slave_relay_log_info;
drop table if exists slave_worker_info;
執行完後,可以用show tables查看一下,看表的數據是否已經比刪除之前減少了,如果減少了,說明你成功了!
[root@data02 test] cd/home/data/mysql/data/mysql
[root@data02 mysql]# ll *.ibd
-rw-rw----. 1 mysql mysql 98304 1? 9 02:08 innodb_index_stats.ibd
-rw-rw----. 1 mysql mysql 98304 1? 9 02:08 innodb_table_stats.ibd
-rw-rw----. 1 mysql mysql 98304 1? 9 02:08 slave_master_info.ibd
-rw-rw----. 1 mysql mysql 98304 1? 9 02:08 slave_relay_log_info.ibd
-rw-rw----. 1 mysql mysql 98304 1? 9 02:08 slave_worker_info.ibd
[root@data02 mysql]#
強行刪除ibd文件:
[root@data02 mysql]# rm -f *.ibd
重啟數據庫,登錄mysql
source/usr/test/mysql/share/mysql_system_tables.sql
show tables;
發現表已經回來了,表數據大概總數量為28個。
之後執行change master to,OK,搞定,如下所示:
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.03sec)
mysql> CHANGE MASTER TOMASTER_HOST='192.168.52.129',MASTER_USER='repl',MASTER_PASSWORD='repl_1234',MASTER_LOG_FILE='mysql-bin.000141',MASTER_LOG_POS=120;
Query OK, 0 rows affected, 2 warnings (0.07sec)
mysql>
啟動slave
mysql> start slave;
Query OK, 0 rows affected (0.02 sec)
mysql>
在slave服務器上查看slave狀態:
mysql> show slave status\G
*************************** 1. row***************************
Slave_IO_State: Waiting formaster to send event
Master_Host: 192.168.52.129
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000151
Read_Master_Log_Pos: 346
Relay_Log_File:mysql-relay-bin.000018
Relay_Log_Pos: 509
Relay_Master_Log_File: mysql-bin.000151
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:business_db,user_db,plocc_system
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 346
Relay_Log_Space: 845
Until_Condition: None
這裡主要看:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 0
IO和SQL線程都是Yes以及Seconds_Behind_Master是0就表示從庫正常運行了。
在master服務器上查看:
mysql> show full processlist;
+----+-----------------+----------------------+------+-------------+------+-----------------------------------------------------------------------+-----------------------+
| Id | User | Host | db | Command | Time | State |Info |
+----+-----------------+----------------------+------+-------------+------+-----------------------------------------------------------------------+-----------------------+
| 1| event_scheduler | localhost | NULL | Daemon | 5874 |Waiting on empty queue | NULL |
| 21 | root | localhost | NULL | Query | 0 | init | show full processlist |
| 24 | repl | 192.168.52.130:45665 | NULL |Binlog Dump | 88 | Master has sent allbinlog to slave; waiting for binlog to be updated | NULL |
+----+-----------------+----------------------+------+-------------+------+-----------------------------------------------------------------------+-----------------------+
3 rows in set (0.03 sec)
mysql>
看到有192.168.52.130:45665的線程在同步二進制數據
去master(192.168.52.129)上操作,添加表記錄:
mysql> create table master_test select 1as a,'a' as b;
Query OK, 1 row affected (0.72 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql>
去slave(192.168.52.130)上查詢下,看表數據是否同步過來,看到數據已經同步過來了,如下所示:
mysql> select * fromuser_db.master_test;
+---+---+
| a | b |
+---+---+
| 1 | a |
+---+---+
1 row in set (0.06 sec)
mysql>
如果master運行很久了,需要添加新的slave服務器,那麼搭建新的slave,此時,有幾種方法可以使slave從另一個服務開始,例如,從master拷貝數據,從另一個slave克隆,從最近的備份開始一個slave。Slave與master同步時,需要三樣東西:
(1)master的某個時刻的數據快照;
(2)master當前的日志文件、以及生成快照時的字節偏移。這兩個值可以叫做日志文件坐標(log file coordinate),因為它們確定了一個二進制日志的位置,你可以用SHOW MASTER STATUS命令找到日志文件的坐標;
(3)master的二進制日志文件。
也可以通過以下幾中方法來克隆一個slave:
(1) 冷拷貝(cold copy)
停止master,將master的文件拷貝到slave;然後重啟master。缺點很明顯。
(2) 熱拷貝(warm copy)
如果你僅使用MyISAM表,你可以使用mysqlhotcopy拷貝,即使服務器正在運行。
如果有myisam和innodb表,可以在業務低峰期用tar包的方式來熱拷貝。
(3) 使用mysqldump
使用mysqldump來得到一個數據快照可分為以下幾步:
<3.a>鎖表:如果你還沒有鎖表,你應該對表加鎖,防止其它連接修改數據庫,否則,你得到的數據可以是不一致的。如下:
mysql> FLUSH TABLES WITH READ LOCK;
<3.b>在另一個連接用mysqldump創建一個你想進行復制的數據庫的轉儲:
見4.2.1小節
<3.c>對表釋放鎖。
mysql> UNLOCK TABLES;
(4) 使用xtrabackup
使用xtrabackup得到數據快照,見4.2.2小節
當設置log_slave_updates時,你可以讓slave扮演其它slave的master。此時,slave把SQL線程執行的事件寫進行自己的二進制日志(binary log),然後,它的slave可以獲取這些事件並執行它。如下圖6.png所示:
復制過濾可以讓你只復制服務器中的一部分數據,有兩種復制過濾:在master上過濾二進制日志中的事件;在slave上過濾中繼日志中的事件。如下圖7.png所示:
復制的體系結構有以下一些基本原則:
(1) 每個slave只能有一個master;
(2) 每個slave只能有一個唯一的服務器ID;
(3) 每個master可以有很多slave;
(4) 如果你設置log_slave_updates,slave可以是其它slave的master,從而擴散master的更新。
MySQL不支持多主服務器復制(MultimasterReplication)——即一個slave可以有多個master。但是,通過一些簡單的組合,我們卻可以建立靈活而強大的復制體系結構。
介紹一下基本的mysql主從的管理操作命令:
STOP SLAVE IO_THREAD; #停止IO進程
STOP SLAVE SQL_THREAD; #停止SQL進程
STOP SLAVE; #停止IO和SQL進程
START SLAVE IO_THREAD; #啟動IO進程
START SLAVE SQL_THREAD; #啟動SQL進程
START SLAVE; #啟動IO進程和SQL進程
RESET SLAVE;
#用於讓從屬服務器忘記其在主服務器的二進制日志中的復制位置, 它會刪除master.info和relay-log.info文件,以及所有的中繼日志,並啟動一個新的中繼日志,當你不需要主從的時候可以在從上執行這個操作。不然以後還會同步,可能會覆蓋掉你的數據庫。
SHOW SLAVE STATUS;
#這個命令主要查看Slave_IO_Running、Slave_SQL_Running、Seconds_Behind_Master、Last_IO_Error、Last_SQL_Error這些值來把握復制的狀態。
#經常會朋友mysql主從同步遇到錯誤的時候,比如一個主鍵沖突等,那麼我就需要在確保那一行數據一致的情況下臨時的跳過這個錯誤,那就需要使用SQL_SLAVE_SKIP_COUNTER = n命令了,n是表示跳過後面的n個事件,比如我跳過一個事件的操作如下:
STOP SLAVE;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
START SLAVE;
#有的時候主從同步有問題了以後,需要從log位置的下一個位置進行同步,相當於跳過那個錯誤,這時候也可以使用CHANGE MASTER命令來處理,只要找到對應的LOG位置就可以,比如:
CHANGE MASTER TOMASTER_HOST='10.1.1.75',MASTER_USER='replication',MASTER_PASSWORD='123456',MASTER_LOG_FILE='mysql-bin.000006',MASTER_LOG_POS=106;
START SLAVE;
PS:生產環境中這種操作盡量能避免就避免。
1. 不要亂使用SQL_SLAVE_SKIP_COUNTER命令。
這個命令跳過之後很可能會導致你的主從數據不一致,一定要先將指定的錯誤記錄下來,然後再去檢查數據是否一致,尤其是核心的業務數據。
2. 結合percona-toolkit工具pt-table-checksum定期查看數據是否一致。
這個是DBA必須要定期做的事情,呵呵,有合適的工具何樂而不為呢?另外percona-toolkit還提供了對數據庫不一致的解決方案,可以采用pt-table-sync,這個工具不會更改主的數據。還可以使用pt-heartbeat來查看從服務器的復制落後情況。
3. 使用replicate-wild-ignore-table選項而不要使用replicate-do-db或者replicate-ignore-db。
原因已經在上面做了說明。
4. 將主服務器的日志模式調整成mixed。
5. 每個表都加上主鍵,主鍵對數據庫的同步會有影響尤其是居於ROW復制模式。