這片博文會詳細說明MySQL複製的過程以及複製的原理!mysql
會詳細說明如下幾種複製模式:傳統的MySQL複製,MySQL5.6的半同步輔助以及MySQL5.7的無損複製。sql
複製解決的基本問題是讓一臺服務器的數據與其餘服務器的數據保持同步。一臺主庫的數據能夠同步到多臺備庫上,備庫自己也能夠被設置成另一臺服務器的主庫。主庫和備庫之間能夠有多種不一樣的組合方式。數據庫
mysql支持兩種方式的複製;基於行的複製和基於語句的複製。基於語句的複製在以前的版本中就已經存在,可是基於行的複製在mysql5.1以後,纔開始支持!這兩種方式都是經過在主庫上記錄二進制日誌,在備庫重放日誌的方式來實現異步數據的複製! 這意味着,在同一時間點備庫上的數據可能與主庫存在不一致的,而且沒法保證主備之間的延遲。緩存
上面咱們提到過複製是基於二進制日誌進行的,那麼複製到底是如何工做的?總的來講,複製有三個步驟安全
複製過程如圖(圖片來自網絡,這個圖很經典,幾乎每片將mysql主從的都會有的)服務器
第一步:在主庫上記錄二進制日誌。在每次準備提交事務完成數據更新前,主庫將數據更新的事件按照事務提交的順序寫入二進制日誌,寫入二進制日誌以後,主庫會告訴存儲引擎能夠提交事務了!網絡
第二步:備庫將主庫的二進制日誌複製到本地的中繼日誌中。首先,備庫會啓動一個工做線程(I/O線程),I/O線程跟主庫創建一個普通的客戶端鏈接,而後在主庫上啓動一個特殊的二進制轉儲線程(dump 線程),dump線程會讀取主庫上二進制日誌中的事件。它不會對事件盡心輪詢,若是該線程追遇上了主庫,它將進入休眠狀態,直到主庫發送信號量通知其有新的事件產生時纔會被喚醒,備庫I/O線程會將接收到的事件記錄到中繼日誌中。多線程
第三:備庫的SQL線程會重放中繼日誌中的事件,從而實現主庫的數據在從庫的複製。架構
這種複製架構實現了獲取事件和重放事件的解耦(生產者與消費者模型),容許這兩個事件異步進行。也就是說I/O線程獨立於SQL線程以外工做。可是因爲這種架構限制了複製過程,其中最重要的就是在主庫上併發運行的查詢在備庫上只能串行執行,由於只有一個SQL線程來重放中繼日誌中的事件。而這一點也是mysql複製的性能瓶頸所在,所以在mysql5.6和mysql5.7中都對此作了優化,後面咱們會說到的!併發
#在mysql的複製過程當中,基本上來講有三個主要線程!
master轉儲線程:當slave IO線程鏈接master時,master建立這個線程。負責從master的binlog文件讀取記錄,而後發送給slave。每一個鏈接到master的slave都有一個轉儲線程
slave IO線程:負責鏈接master並請求全部master上的更新轉儲到中繼日誌,以便SQL線程進行進一步的處理。每一個slave都有一個IO線程。一旦鏈接創建,這個線程就一直都在,
這樣slave就能當即收到master的全部更新。
slave SQL線程:這個線程讀取中繼日誌中的更新,而後在從庫上應用這些更新。這個線程負載協調其餘mysql線程,保證這些更新不與mysql服務器上的其餘活動產生衝突。
下面咱們搭建一個傳統的異步複製
mysql的主從搭建很簡單,只說一下搭建的步驟:
如果兩個全新的服務器,沒有任何數據:(全新的服務器,數據自己就是一致的狀態)
l 第一步:分別開啓二進制日誌
l 第二步:修改兩個服務器的server-id,兩臺服務器的id設置要不同。
l 第三步:在做爲master的服務器上建立用來作主從複製的用戶。
l 第四步:在從上鍊接master服務器,而後在從上執行start slave。
mysql> select @@version; #咱們測試用的數據庫的版本 +-----------+ | @@version | +-----------+ | 5.7.23 | +-----------+ 1 row in set (0.00 sec) mysql> show databases; #這臺數據庫上有數據 +--------------------+ | Database | +--------------------+ | information_schema | | djtest | | employees | | hostinfo | | mysql | | mytest | | performance_schema | | sys | +--------------------+ 8 rows in set (0.00 sec)
第一步:把當前服務器服務器中全部的數據備份,而後在新建的從庫上進行恢復,使兩臺服務器處於一致的狀態!
[root@mgt01 ~]# mysqldump -uroot -p123456 --single-transaction --all-databases > all.sql mysqldump: [Warning] Using a password on the command line interface can be insecure. [root@mgt01 ~]# scp all.sql 192.168.1.121:/root/ root@192.168.1.121's password: all.sql 100% 161MB 32.3MB/s 00:05 [root@mgt01 ~]# #在從庫執行恢復 [root@mgt02 ~]# mysql -uroot -p123456 < all.sql mysql: [Warning] Using a password on the command line interface can be insecure. [root@mgt02 ~]#
第二步:開啓主庫的而二進制日誌,如果作級聯複製從庫也須要開啓二進制日誌(後面再說)
#在主庫配置文件設置 log-bin= #二進制日誌默認是在datadir指定的目錄下面的 server-id=13 #在主從環境中,每臺服務器的server-id要設置的不同 #在從庫配置文件設置 server-id=13
第三步:在主庫上建立用來複制的帳號:
mysql> grant all privileges on *.* to "repl"@"192.168.1.121" identified by "123456"; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> show warnings; +---------+------+------------------------------------------------------------------------------------------------------------------------------------+ | Level | Code | Message | +---------+------+------------------------------------------------------------------------------------------------------------------------------------+ | Warning | 1287 | Using GRANT for creating new user is deprecated and will be removed in future release. Create new user with CREATE USER statement. | +---------+------+------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) mysql> flush privileges; Query OK, 0 rows affected (0.00 sec) mysql>
第四步:從庫鏈接主庫
首先查看主庫二進制的日誌點:
mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mgt01-bin.000001 | 598 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) mysql>
而後在從庫上執行以下命令:
mysql> change master to master_host="192.168.1.120", master_user="repl",master_password="123456",master_log_file="mgt01-bin.000001",master_log_pos=598; Query OK, 0 rows affected, 2 warnings (0.08 sec)
#這裏的兩個警告,只是說明了一些傳輸安全信息
mysql> start slave; #開啓複製
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G #從上查看狀態
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.1.120
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mgt01-bin.000001
Read_Master_Log_Pos: 598
Relay_Log_File: mgt02-relay-bin.000002
Relay_Log_Pos: 320
Relay_Master_Log_File: mgt01-bin.000001
Slave_IO_Running: Yes #代表IO線程和SQL線程已經工做了
Slave_SQL_Running: Yes
。。。。。。。。
測試以下:
#在主庫作以下操做 mysql> insert into tb1 values(1, @@hostname, "test"); Query OK, 1 row affected (0.04 sec) mysql> select * from tb1; +------+-------+------+ | id | name | info | +------+-------+------+ | 1 | mgt01 | test | +------+-------+------+ 1 row in set (0.00 sec) #在從庫查看數據 mysql> select * from tb1; +------+-------+------+ | id | name | info | +------+-------+------+ | 1 | mgt01 | test | +------+-------+------+ 1 row in set (0.00 sec) #如果基於語句的複製,這兩個數據應該不同的,可是如今是同樣的,說明是基於行的複製! mysql> show variables like "binlog_format"; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | binlog_format | ROW | +---------------+-------+ 1 row in set (0.00 sec)
一個簡易的主從架構已經完成!
下面咱們會詳細說明與MySQL主從複製相關的幾個文件(二進制日誌文件會單獨列出來說的)
中繼日誌是鏈接master和slave的信息,是複製的核心。
中繼日誌除了含有二進制日誌和索引文件之外,中繼日誌還維護兩個文件來跟蹤複製的進度,即中繼日誌信息文件和master日誌信息文件,這個兩個文件名字由my.cnf的兩個參數配置。
relay_log_info_file=filename;若是沒有指定文件名,則默認爲:relay-log.info。 master-info-file=filename:這個參數設置master日誌信息文件。默認文件名爲master.info。
查看一下maste.info信息以下:
master.info文件包含master的讀位置,以及鏈接master和啓動複製必須的全部信息。當slave的IO線程啓動時,若是有master.info文件,則線程先從這個文件讀取信息。
master.info文件中的信息優於my.cnf文件。也就是說,若是改變了配置文件中的信息,重啓服務器,將會從master.info讀取信息而不是配置文件。
所以不推薦在配置文件中使用change master to參數配置,而是直接使用命令。因爲某種緣由,須要把複製參數放到配置文件中,並且但願slave啓動的時候讀取這些
參數,則必須在編輯配置文件以前執行reset slave命令。
請謹慎執行reset slave命令!這個命令會刪除master.info和relay-log.info文件,以及全部的中繼日誌文件!
查看relay-log.info的信息
[root@test2 mysql]# cat relay-log.info 7 ./test2-relay-bin.000002 #當前正在讀取的中繼日誌 320 #當前正在讀取的中級日誌的position位置 test3-bin.000003 #這個在主從複製時change master命令指向的master的二進制日誌的文件名和日誌位置 1669 0 0 1
relay-log.info文件跟蹤複製的進度,並由SQL線程負責更新。
若是某些文件不可用時,在slave啓動的時候,可以根據配置文件和change master to命令參數重建這些文件。僅僅使用配置文件並執行change命令是不夠的,只有執行了start slave命令, master.info文件和relay-log.info文件纔會被建立。
也就是能夠這樣說:master.info對應的是I/O線程,而relay-log.info對應的是SQL線程!
控制slave複製的幾個命令:
START / STOP SLAVE START / STOP slave io_thread START/ STOP slave sql_thread
slave_parallel_workers參數
上面提到過在MySQL5.6以前的異步複製中,只有一個IO線程,一個用於回放中繼日誌的SQL線程,SQL線程的回放效率成爲性能的瓶頸!在MySQL5.6中引入了slave_parallel_workers參數,這個參數能夠設置用於回放中繼日誌的線程數量。
可是MySQL5.6的多線程複製倒是基於schema,也就是說只有在master上多個schema,那麼這個多線程複製纔會有做用,可是線上環境大可能是一個schema中含有多張表,所以這個時候多線程將沒法發揮應有的做用;MySQL5.7中引入了slave_parallel_type參數,這個參數能夠設置爲LOGICAL_CLOCK,基於邏輯的複製,才能真正發揮多線程的做用。
mysql> show variables like "slave_parallel_type"; +---------------------+----------+ | Variable_name | Value | +---------------------+----------+ | slave_parallel_type | DATABASE | #默認是基於schema +---------------------+----------+ 1 row in set (0.01 sec) mysql>
配置slave參數:
#並行複製參數配置
slave_parallel_workers=3 slave_parallel_type=LOGICAL_CLOCK
#設置了並行複製以後,能夠看到有3個SQL線程在等待處理中繼日誌
mysql> show processlist; +----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+ | 1 | system user | | NULL | Connect | 68 | Waiting for master to send event | NULL | | 2 | system user | | NULL | Connect | 68 | Slave has read all relay log; waiting for more updates | NULL | | 3 | system user | | NULL | Connect | 68 | Waiting for an event from Coordinator | NULL | | 4 | system user | | NULL | Connect | 68 | Waiting for an event from Coordinator | NULL | | 5 | system user | | NULL | Connect | 68 | Waiting for an event from Coordinator | NULL | | 8 | root | localhost | NULL | Query | 0 | starting | show processlist | +----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+ 6 rows in set (0.01 sec)
#在數據庫目錄下面也產生了對應個數的中繼日誌信息(線上環境建議爲16或32)
[root@test2 mysql]# ls worker-relay-log.info.*
worker-relay-log.info.1 worker-relay-log.info.2 worker-relay-log.info.3
以上就是傳統的異步複製
半同步複製的原理是在複製繼續運行以前,確保至少有一個slave將變動寫到磁盤。也就是說,對每一個連接來講,若是發生master崩潰,至多隻有一個事務丟失。
半同步複製並不會阻止事務的提交,而是直到事務寫入至少一個slave中繼日誌才向客戶端發送響應。事務發送到slave以前是先提交到存儲引擎,而在一個slave肯定事務已經寫入磁盤以後,才向客戶端發送提交確認。
半同步複製,只有在任一個slave已經肯定存儲了上一個事務,而後向主發送確認迴應,主纔會繼續向slave中傳遞事務信息。所以半同步複製,最多隻會丟失一個事務。
配置半同步複製:
第一:首先配置好主從架構。
第二:安裝插件,在mysql5.6及以後的版本已經融合入mysql中,能夠直接安裝。
第三:主和從都要開啓複製,而後重啓服務器。
#查看當前MySQL是否開啓自動加載的功能! mysql> show variables like "have_dynamic_loading"; +----------------------+-------+ | Variable_name | Value | +----------------------+-------+ | have_dynamic_loading | YES | +----------------------+-------+ 1 row in set (0.00 sec)
安裝插件:
mysql> install plugin rpl_semi_sync_master soname "semisync_master.so"; ERROR 1125 (HY000): Function 'rpl_semi_sync_master' already exists mysql> install plugin rpl_semi_sync_slave soname "semisync_slave.so"; Query OK, 0 rows affected (0.03 sec)
而後開啓半同步複製:
#在主和從上分別添加以下參數 在主上添加 rpl-semi-sync-master-enabled = 1 在從上添加 rpl-semi-sync-slave-enabled = 1
查看參數:
mysql> show variables like "%semi%"; +-------------------------------------------+------------+ | Variable_name | Value | +-------------------------------------------+------------+ | rpl_semi_sync_master_enabled | ON | | rpl_semi_sync_master_timeout | 10000 | | rpl_semi_sync_master_trace_level | 32 | | rpl_semi_sync_master_wait_for_slave_count | 1 | | rpl_semi_sync_master_wait_no_slave | ON | | rpl_semi_sync_master_wait_point | AFTER_COMMIT | | rpl_semi_sync_slave_enabled | OFF | | rpl_semi_sync_slave_trace_level | 32 | +-------------------------------------------+------------+ 8 rows in set (0.01 sec)
#參數說明
rpl_semi_sync_master_enabled: 主服務器開啓半同步複製。
rpl_semi_sync_slave_enabled : 從服務器開啓半同步複製。
rpl_semi_sync_master_timeout: 超過10s slave沒有迴應,半同步複製會變爲異步複製
rpl_semi_sync_master_trace_level:開啓半同步複製時的調試級別,默認是32.
rpl_semi_sync_master_wait_no_slave :master的每一個事務是否都須要slave的接收確認!
rpl_semi_sync_master_wait_for_slave_count:
rpl_semi_sync_master_wait_point: 最後兩個參數樹MySQL5.7加入的,半同步複製升級爲無損複製。後面再說明
半同步複製因阻塞變爲異步複製:只會在第一個事務產生rpl_semi_sync_master_timeout時長的阻塞,變爲半同步複製以後,事務就不會再阻塞。
root@employees 06:17:58>update employees set first_name="wang" where emp_no = 23485; #半同步複製 Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 root@employees 06:18:07>update employees set first_name="qian" where emp_no = 23485; #斷開主從的鏈接,事務開始阻塞,這裏設置了 rpl_semi_sync_master_timeou時長爲50s,阻塞50s後插入 Query OK, 1 row affected (50.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 root@employees 06:21:22>update employees set first_name="zhao" where emp_no = 12986; #以後的事務再也不阻塞 Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0
半同步複製具體特性:(摘自http://www.ywnds.com/?p=7023)
經過上面幾點特徵,能夠知道半同步的實質是,在主庫被阻塞的過程當中(等待從庫反饋確認消息),主庫處理線程不會返回去處理當前事務。當阻塞被激活以後,系統纔會把控制權交給當前線程,而後繼續處理當前事務餘下的事情。處理完成以後,此時主庫的事務已經提交,同時至少會有一個從庫也已經收到了這個事務的Binlog,這樣就儘量地保證了主庫和從庫的數據一致性。
丟失一個事務:
上面咱們提到過,半同步複製至多會丟失一個事務,也就是說當master已經提交了事務t1(事務t1已經在master上持久化了),這時候dump線程會推送二進制日誌給slave,若是在這個推送的過程當中master主機crash掉了,這時候咱們若想讓一臺slave來作master時,由於事務t1沒有在任何的一個slave上存在,也就是這時候事務t1丟失了!
事務的提交主要分爲兩個主要步驟: 1. 準備階段(Storage Engine(InnoDB) Transaction Prepare Phase) 此時SQL已經成功執行,並生成xid信息及redo和undo的內存日誌。而後調用prepare方法完成第一階段,papare方法實際上什麼也沒作,將事務狀態設爲TRX_PREPARED,並將redo log刷磁盤。 2. 提交階段(Storage Engine(InnoDB)Commit Phase) 2.1 記錄協調者日誌,即Binlog日誌。 若是事務涉及的全部存儲引擎的prepare都執行成功,則調用TC_LOG_BINLOG::log_xid方法將SQL語句寫到binlog(write()將binary log內存日誌數據寫入文件系統緩存,fsync()將binary log文件系統緩存日誌數據永久寫入磁盤)。此時,事務已經鐵定要提交了。不然,調用ha_rollback_trans方法回滾事務,而SQL語句實際上也不會寫到binlog。 2.2 告訴引擎作commit。 最後,調用引擎的commit完成事務的提交。會清除undo信息,刷redo日誌,將事務設爲TRX_NOT_STARTED狀態。
半同步複製就是在2.2以後推送了二進制日誌到slave!
爲了防止這一個事務的丟失,MySQL5.7引入了無損複製!
如今咱們已經知道,在半同步環境下,主庫是在事務提交以後等待Slave ACK,因此纔會有數據不一致問題。因此這個Slave ACK在什麼時間去等待,也是一個很關鍵的問題了。所以MySQL針對半同步複製的問題,在5.7.2版本引入了Loss-less Semi-Synchronous,在調用binlog sync以後,engine層commit以前等待Slave ACK。這樣只有在確認Slave收到事務Binlog後,事務纔會提交。另外,在commit以前等待Slave ACK,同時能夠堆積事務,利於Group Commit,有利於提高性能。
半同步複製與無損複製的主要區別在於半同步複製在InnoDB commit後等待Slave ACK(須要收到至少一個Slave節點回復的ACK),無損複製在binlog sync後與Slave確認。雖然都一樣避免不了數據丟失的風險,可是因爲ack確認的位置不一樣,這樣就有一個大的區別在於其餘事務是否看得見這個事務的修改操做,半同步複製因爲在InnoDB commit後ack,此時事務已經提交,對其餘事務可見,若是此時主庫宕機併發生主從切換,那麼用戶在新主庫找不到剛剛那個事務修改後的數據,就能夠稱得上數據丟失了,由於用戶已經看見過。而無損複製因爲在binlog sync後進行binlog發送和ack確認,此時因爲事務並無提交,對於其餘事務來講不可見,因此就算髮生主從切換,新主庫雖然也沒有剛剛那個事務修改後的數據,但用戶並無看見新數據,因此也就稱不上數據丟失了。
須要注意的是無損複製,用戶提交的事務寫入了二進制日誌,可是進行commit提交;也就是MySQL5.7在crash recovery時,主動拋棄了這條可能引發數據庫不一致的事務!
兩個參數介紹:
rpl_semi_sync_master_wait_for_slave_count:
rpl_semi_sync_master_wait_point:
rpl_semi_sync_master_wait_for_slave_count: MySQL5.7以後加入的,多少個slave確認以後,主才繼續下一個二進制日誌推送。
rpl_semi_sync_master_wait_point:這個值有兩個取值,after-commit和after-sync; after-commit表示的半同步複製,after-sync表示的是無損複製!
半同步複製與無損複製的對比總結:
1. ACK的時間點不一樣
2. 主從數據一致性
所以5.7引入了無損複製(after_sync)模式,帶來的主要收益是解決after_commit致使的Master crash後數據丟失問題,所以在引入after_sync模式後,全部提交的數據已經都被複制,故障切換時數據一致性將獲得提高。
中繼日誌的回放與寫入
SQL線程
當slave的SQL線程從中繼日誌回放一個事件時,第一會把這個事件在數據庫中進行回放,第二會把這個事件結束點二進制信息寫入relay-log.info文件中,若是每回放一個事件,就寫一次relay-log.info文件,所以磁盤的寫入速度比較慢,所以在併發較高的狀況下,slave就會產生和主的延遲,MySQL引入了一個參數sync_relay_log_info,這個參數默認值是10000,表示回放10000次時把日誌點刷新入文件。
SQL線程回放了中繼日誌的1,2,3三個事件(這兩個事件已經寫入了從庫),可是在2,3兩個事件並無寫入relay_log_info_file文件,這時候若是slave服務器發生crash 重啓,這時候slave會從新去抓取2,3兩個事件,而後再執行就會發生1062錯誤。
形成這樣主要是由於,回放是寫入數據庫,而寫日誌點則是寫入file文件的,這兩個沒法作到一致性。
若是把sync_relay_log_info設置爲1時候,仍是會有最後一個event重複執行的可能,而且會形成性能降低!
所以從mysql5.6開始:relay_log_info_repository能夠設置爲TABLE,把中繼日誌的回放,和中繼日誌信息的寫入放入表中,這樣能夠把這兩個操做設置變成原子性的,就能夠避免這種狀況的發生!線上環境建議設置爲TABLE。
mysql> show variables like "%relay%_log_info%"; +---------------------------+----------------+ | Variable_name | Value | +---------------------------+----------------+ | relay_log_info_file | relay-log.info | | relay_log_info_repository | FILE | #建議設置爲table。 | sync_relay_log_info | 10000 | +---------------------------+----------------+ 3 rows in set (0.00 sec)
I/O線程
I/O線程會寫入master.info和relay-log-info,如果每拉一個event就寫一次,效率會很低,MySQL5.6引入了以下參數!
mysql> show variables like "%master_info%"; +------------------------+-------+ | Variable_name | Value | +------------------------+-------+ | master_info_repository | FILE | #這個建議設置爲table,這樣的性能會比file性能高大概2倍左右 | sync_master_info | 10000 | #每拉10000次event寫入文件一次 +------------------------+-------+ 2 rows in set (0.00 sec)
master配置: binlog-do-db= binlog-ignore-db= max_binlog_szie=2048M binlog_format=ROW transaction-isolation=READ-COMMITTED expire_logs_days=7 server-id=111 binlog_cache_size= sysnc_binlog=1 # must set to 1, default is 0 innodb_flush_log_at_trx_commit=1 innodb_support_xa = 1 slave配置 log_slave_upates replicate-do-db replicate-ignore-db replicate-do-table replicate-ignore-table server-id master_info_ repository = TABLE relay_log_recovery = 1 #I/O thread crash safe relay_log_info_repository = TABLE # SQL thread crash safe read_only = 1 super_read_only = on #mysql5.7 加入的 relay_log_recovery=1
跳過錯誤
上面咱們搭好了主從的架構!
在主上作以下操做:
mysql> use mytest; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> create table tb1(a int auto_increment primary key); #建立一個自增加的列 Query OK, 0 rows affected (0.04 sec) mysql> insert into tb1 select null; Query OK, 1 row affected (0.02 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into tb1 select null; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into tb1 select null; Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into tb1 select null; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into tb1 select null; Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into tb1 select null; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> select * from tb1; +---+ | a | +---+ | 1 | | 2 | | 3 | | 4 | | 5 | | 6 | +---+ 6 rows in set (0.00 sec)
查看從上的數據
mysql> select * from tb1; #數據已經同步到從上了 +---+ | a | +---+ | 1 | | 2 | | 3 | | 4 | | 5 | | 6 | +---+ 6 rows in set (0.00 sec)
#主從架構中只有在主上寫入數據,從上只讀數據,在這裏咱們在從上插入沒有。沒有設置read_only參數 mysql> insert into tb1 select null; #由於是自增的,因此插入之的數據爲7! Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql>
而後咱們在主上,再插入一條數據7,
mysql> insert into tb1 select null; #由於自增的,因此實際插入的值爲7! Query OK, 1 row affected (0.02 sec) Records: 1 Duplicates: 0 Warnings: 0 #自增主鍵,在slave上已經插入了一個數值7,這時候主上又同步一個數據7,因此報錯,1062錯誤!
mysql> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 10.0.102.214 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: test3-bin.000004 Read_Master_Log_Pos: 9277 Relay_Log_File: test2-relay-bin.000009 Relay_Log_Pos: 4874 Relay_Master_Log_File: test3-bin.000004 Slave_IO_Running: Yes Slave_SQL_Running: No Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 1062 Last_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction 'ANONYMOUS' at master log test3-bin.000004, end_log_pos 9246. See error log and/or performance_schema.replication_applier_status_by_worker table for more details about this failure or others, if any. Skip_Counter: 0 Exec_Master_Log_Pos: 9019 Relay_Log_Space: 9863 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: NULL Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 1062 Last_SQL_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction 'ANONYMOUS' at master log test3-bin.000004, end_log_pos 9246. See error log and/or performance_schema.replication_applier_status_by_worker table for more details about this failure or others, if any. Replicate_Ignore_Server_Ids: Master_Server_Id: 5 Master_UUID: 4687e05d-f37f-11e8-8fc7-fa336351fc00 Master_Info_File: /data/mysql/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: 181202 18:09:40 Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec)
這時候由於咱們知道錯誤的緣由,是由於主鍵重複,解決辦法,咱們可讓slave機器,忽略此次二進制日誌的寫入!
mysql> show variables like "%skip%"; +------------------------+-------+ | Variable_name | Value | +------------------------+-------+ | skip_external_locking | ON | | skip_name_resolve | OFF | | skip_networking | OFF | | skip_show_database | OFF | | slave_skip_errors | OFF | #slave忽略的錯誤 | sql_slave_skip_counter | 0 | #slave忽略的次數 +------------------------+-------+ 6 rows in set (0.01 sec) mysql> set sql_slave_skip_counter=1; #設置爲1,由於是全局變量須要加global! ERROR 1229 (HY000): Variable 'sql_slave_skip_counter' is a GLOBAL variable and should be set with SET GLOBAL mysql> set global sql_slave_skip_counter=1; Query OK, 0 rows affected (0.00 sec) mysql> start slave sql_thread; #從新啓動sql線程Query OK, 0 rows affected (0.01 sec)mysql> show slave status\G #複製已經恢復正常*************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 10.0.102.214 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: test3-bin.000004 Read_Master_Log_Pos: 9277 Relay_Log_File: test2-relay-bin.000009 Relay_Log_Pos: 5132 Relay_Master_Log_File: test3-bin.000004 Slave_IO_Running: Yes Slave_SQL_Running: Yes.......