
MySQL主從復制架構
目前MySQL支持兩種復制類型:
1.傳統方式:
基於主庫的bin-log將日志事件和事件位置復制到從庫,從庫再加以應用來達到主從同步的目的。2.Gtid方式(MySQL>=5.7推薦使用):
基於GTID的復制中,從庫會告知主庫已經執行的事務的GTID的值,然后主庫會將所有未執行的事務的GTID的列表返回給從庫,並且可以保證同一個事務只在指定的從庫執行一次。
MySQL復制有多種類型:
1.異步復制
一個主庫,一個或多個從庫,數據異步同步到從庫。2.同步復制
在MySQL cluster中特有的復制方式。3.半同步復制
在異步復制的基礎上,確保任何一個主庫上的事物在提交之前至少有一個從庫已經收到該事物並日志記錄下來。4.延遲復制
在異步復制的基礎上,人為設定主庫和從庫的數據同步延遲時間,即保證數據延遲至少是這個參數。
下面是基於二進制日志點的異步復制:
MySQL主從復制原理:
我們在MySQL中配置了主從之后,只要我們對Master節點進行了寫操作,這個操作將會被保存到MySQL的binary-log(bin-log)日志當中,當slave連接到master的時候,master機器會為slave開啟binlog dump線程。當master 的 binlog發生變化的時候,Master的dump線程會通知slave,並將相應的binlog內容發送給Slave。而Slave節點在主從同步開啟的時候,會創建兩個線程,一個I/O線程,一個SQL線程。
I/O線程:該線程鏈接到master機器,master機器的binlog發送到slave的時候,IO線程會將該日志內容寫在本地的中繼日志(Relay log)中。
SQL線程:該線程讀取中繼日志中的內容,並且根據中繼日志中的內容對Slave數據庫做相應的操作。
可能造成的問題:在寫請求相當多的情況下,可能會造成Slave數據和Master數據不一致的情況,這是因為日志傳輸過程中的短暫延遲、或者寫命令較多,系統速度不匹配造成的。
這大致就是MySQL主從同步的原理,真正在其中起到作用的實際上就是這兩個日志文件,binlog和中繼日志(Relay log)。
一. 配置主從數據庫服務器參數:
- Master服務器參數:
[mysqld] log-bin = /www/server/data/mysql-bin binlog_format = mixed server-id = 100 #expire_logs_days = 10 #日志過期時間 #max_binlog_size = 200M #日志最大容量,可以不設置,有默認值,設置后MySQL無法重啟,我遇到情況 binlog_do_db = test #binlog_do_db 指定記錄二進制日志的數據庫,即需要復制的數據庫名,如果復制多個數據庫,重復設置這個選項即可
2. Slave服務器參數:
[mysqld] log-bin = /www/server/data/mysql-bin binlog_format = mixed server-id = 200 #expire_logs_days = 10 #日志過期時間 #max_binlog_size = 200M #日志最大容量,可以不設置,有默認值,設置后MySQL無法重啟,我遇到情況 relay_log = /www/server/data/relay-bin #指定relay_log日志的存放路徑和文件前綴 ,不指定的話默認以主機名作為前綴 read_only = on skip_slave_start = on #下面兩個參數是把主從復制信息存儲到innodb表中,默認情況下主從復制信息是存儲到文件系統中的,如果從服務器宕機,很容易出現文件記錄和實際同步信息不同的情況,存儲到表中則可以通過innodb的崩潰恢復機制來保證數據記錄的一致性 master_info_repository = TABLE relay_log_info_repository = TABLE
二. 在Master服務器上建立復制賬號:
- 需要設置REPLICATION SLAVE權限:
CREATE USER '賬號'@'2.7.4.5' IDENTIFIED BY '密碼'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'1.1.1.1'; flush privileges; #刷新權限
三. 在Slave服務器的操作:
- 查看master的 binlog的文件名和binlog偏移量
輸入 show master status; 查看master的 binlog的文件名和binlog偏移量
2. 配置slave服務器:
mysql> CHANGE MASTER TO -> MASTER_HOST='1.1.1.1', -> MASTER_USER='賬號', -> MASTER_PASSWORD='密碼', -> MASTER_LOG_FILE='mysql-bin.00001', -> MASTER_LOG_POS=66; #注意,這里的master_log_file,就是binlog的文件名,輸入上圖中的mysql-bin.00001,每個人的都可能不一樣。 #注意,這里的master_log_pos是binlog偏移量,輸入上圖中的66,每個人的都可能不一樣。
四. master和salve數據庫的數據保持一致(主庫已經有數據的解決方案)
主從數據庫的數據要保持一致,不然主從同步會出現bug...
- 主庫已經有數據的解決方案:
第一種方案是選擇忽略主庫之前的數據,不做處理。這種方案只適用於不重要的可有可無的數據,並且業務上能夠容忍主從庫數據不一致的場景。
第二種方案是對主庫的數據進行備份,然后將主數據庫中導出的數據導入到從數據庫,然后再開啟主從復制,以此來保證主從數據庫數據一致。
下面是第二種方案的操作:
- 鎖定主數據庫,只允許讀取不允許寫入,這樣做的目的是防止備份過程中或備份完成之后有新數據插入,導致備份數據和主數據數據不一致。
- mysql> flush tables with read lock;
2. 通過mysql主服務器上的全備初始化從服務器上數據:
[root@localhost data]# cd /data/db_backup/ [root@localhost db_backup]# mysqldump -uroot -p --master-data=1 --single-transaction --routines --triggers --events --all-databases > all.sql Enter password:
3. 解鎖主數據庫:
unlock tables;
4. 把數據全量導入slave數據庫,保證主從數據一致
五. 開始主從同步:
在從服務器MySQL命令行
輸入 start slave; 開啟從同步 然后輸入 show slave status\G; 查看從節點狀態
六. 注意事項:
如果出現IO線程一直在Connecting狀態,可以看看是不是倆台機器無法相互連接,如果可以相互連接,那么有可能是Slave賬號密碼寫錯了,重新關閉Slave然后輸入上面的配置命令再打開Slave即可。
如果出現SQL線程為NO狀態,那么有可能是從數據庫和主數據庫的數據不一致造成的,或者事務回滾,如果是后者,先關閉stop slave,然后先查看master的binlog和position,然后輸入配置命令,再輸入set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
,再重新start slave;
即可,如通過是前者,那么就排查一下是不是存在哪張表沒有被同步,是否存在主庫存在而從庫不存在的表,自己同步一下再重新配置一遍即可。
Could not find first log file name in binary log index file
如果查看從庫狀態發現此問題,請查看主庫狀態,將其中的File和Position字段通過在從庫中執行以下SQL語句寫入從庫配置中。
change master to master_log_file='mysql-bin.000001',master_log_pos=3726
ERROR 1872 (HY000): Slave failed to initialize relay log info structure from the repository
如果啟動slave時出現此錯誤,主要可能是因為保存着以前slave用的relay-log,可以執行以下語句來啟動slave。
reset slave; start slave;
七. 總結:
1.MySQL 從5.6(MySQL>=5.7 在5.7完善,建議使用)引入了GTID(Global Transaction IDs)使其復制功能的配置、監控及管理變得更加易於實現,且更加健壯。配置方法和基於日志的主從復制大體一樣,所以不做重復。MySQL5.7推薦使用GTID配置主從復制。
2.由於高並發下,MySQL主從復制,會導致主從同步延時的問題。MySQL 在這一塊有兩個機制,一個是半同步復制,用來解決主庫數據丟失問題;一個是並行復制,用來解決主從同步延時問題。具體的解決辦法下篇文章論述。。。
mysql主主半同步
1.半同步概述
先了解下mysql的幾種復制
異步復制
MySQL復制默認是異步復制,Master將事件寫入binlog,提交事務,自身並不知道slave是否接收是否處理;
缺點:不能保證所有事務都被所有slave接收。
同步復制
Master提交事務,直到事務在所有slave都已提交,才會返回客戶端事務執行完畢信息;
缺點:完成一個事務可能造成延遲。
半同步復制
當Master上開啟半同步復制功能時,至少有一個slave開啟其功能。當Master向slave提交事務,且事務已寫入relay-log中並刷新到磁盤上,slave才會告知Master已收到;若Master提交事務受到阻塞,出現等待超時,在一定時間內Master 沒被告知已收到,此時Master自動轉換為異步復制機制;
注:半同步復制功能要在Master和slave上開啟才會起作用,只開啟一邊,依然是異步復制。
下面詳細說明主主半同步:
通過mysql的半同步插件,在兩個數據庫之間相互設置半同步,實現主主半同步架構。
這里做相對於半同步的好處在於,兩個數據庫處於完全對等的地位,可以很方便的做自動切換。
有一點需要注意的是,推薦設置read-only,讓同時只有一個數據庫可寫。如果兩個同時寫,如果出現了同步不一致,這時恢復數據需要對比兩個數據庫。
自動切換可以使用keepalived做vip的漂移
同步過程
1. 在每次准備提交事務完成數據更新前,主庫將數據更新的事件記錄到二進制日志中。MySQL會按照事務提交的順序來記錄二進制日志。在記錄二進制日志后,主庫會告訴存儲引擎可以提交事務了
2. 從庫會啟動一個工作線程,I/O線程跟主庫建立一個普通的客戶端連接,然后再主庫上啟動一個特殊的二進制轉儲(binlog dump)線程,這個二進制轉儲線程會讀取主庫上二進制日志中的事件。如果該線程追趕上了主庫,就進入睡眠狀態,直到主庫發送信號通知有新事件產生再次喚醒
3. 從庫SQL線程從中繼日志中讀取事件,並在從庫上執行,完成復制
半同步相對異步來說,能解決數據不丟失的情況,但是不能很好的解決切換問題
MySQL默認的復制是異步復制
主庫在執行完客戶端提交的事務后會立即將結果返給給客戶端,並不關心從庫是否已經接收並處理
配置了自動切換可能出現的問題:如果主庫出現異常,此時主上已經提交的事務可能並沒有同步到從庫上,此時強行將從提升為主,就會導致新主庫上的數據不完整
推薦的解決方案是,可寫數據庫切換的時候檢查同步狀態
2.配置主主半同步
測試環境:數據庫mysql 5.7.20,CentOS7.2.1511(dvd)
1.准備數據庫
yum install mysql-community-server
mysql-community-server-5.7.20-1.el7.x86_64
注意:安裝server的時候,client也會被自動裝上。但是裝client,不會裝server
使用無密碼方式創建數據目錄
目錄一定要不存在
注意:CentOS7中mysql的多實例管理可以直接通過systemctl進行。在my.cnf配置中,section必須有@關鍵字才能進行管理,所以這里創建數據目錄也統一使用實例名字
mysqld --initialize-insecure --user=mysql --datadir=/var/lib/mysqld@3320
配置my.cnf文件[mysqld@3320] #注意section中要有@符號
datadir = /var/lib/mysqld@3320 #數據目錄
socket = /var/lib/mysqld@3320/mysqld@3320.sock
port = 3320
pid-file = /var/run/mysqld@3320/mysqld@3320.pid
log-error = /var/log/mysqld.log
skip-name-resolve = 1
# bin-log相關配置
log-bin = mysql-bin
binlog_cache_size = 128K
innodb_flush_log_at_trx_commit = 1
binlog_format = MIXED
expire_logs_days = 7
max_binlog_size = 500M
log-slave-updates = 0
slave-skip-errors = 1062,1032
# relay-log配置
relay_log_recovery = 1
relay-log = mysqld@3320-relay-bin
# 數據庫的配置
user = mysql
language = /usr/share/mysql/english
default-storage-engine = InnoDB
character-set-server = UTF8
master_info_repository = TABLE
relay_log_info_repository = TABLE
tmpdir = /var/tmp
# 設置read-only為可讀可寫
read-only = 0
#mysql5.7后必須要有server-id才能啟動
server-id = 1
接下來可以啟動數據庫了
systemctl start mysqld@3320
2.創建用戶
我們創建數據目錄的方式是沒有密碼的。所以可以直接登陸
注意:只能使用sock文件方式登錄
mysql -uroot -S /var/lib/mysqld@3320/mysqld@3320.sock
我們先設置root賬戶的密碼。再創建一個用於配置半同步
SET password='admin';
grant all on *.* to 'root'@'127.0.0.1' identified by 'admin' with grant option;
flush privileges;
退出再登陸,看root密碼是否創建成功
grant replication client, replication slave on *.* to 'SemiSync'@'%' identified by 'admin';
#遠程同步賬號需要reload,super權限
3.安裝半同步插件
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so'
通過show plugins可以查看到安裝的插件
安裝完插件后修改my.cnf配置文件,在文件中加入下列選項
#啟用binlog,啟動半同步
sync_binlog = 1
rpl_semi_sync_master_enabled = 1
rpl_semi_sync_slave_enabled = 1
另外一個節點重復上述步驟,創建一個相同的實例
注意:server_id 需要不同,半同步插件也需要安裝,因為我們配置的是主主半同步
4.配置半同步
設置192.168.184.54為主,192.168.184.40為從
先在54上執行show master status,查看binlog文件及位置,顯示如下
注意在這一步要確認沒有數據寫入,不然會導致不同步。通常在這里會鎖表防止有新數據產生
然后在40上設置從
使用show slave status\G查看半同步狀態。
這里的如果圖中(沒有截取完整的命令輸出)最后兩行不是Yes的話,可以在輸出命令的Last_IO_Error或者Last_SQL_Error選項中查看錯誤提示。再根據提示處理
到這里,單向的半同步就配置好了,接下來在另外一個節點設置相同的半同步。這樣就組成了主主半同步
現在就可以測試數據同步了