mysql master/slave crash_safe replication :你不懂我 我不怪你
written by 小旋風
業界很多的兄弟都對
mysql 趨之若鶩,甚是喜歡,因為它的 可愛(安裝包小 小巧玲瓏),單純(安裝簡單、使用簡單 易上手),真誠(開源),善解人意(功能強勁、持續改進)。
你卻因為不理解誤以為她 “不專一”(主從不一致,其實是可以主從一致的),逐漸對她若離若棄。 她在燈火闌珊處翹首以盼你的驀然回首,你卻冷冷的一笑而過,她只能黯然
傷神念叨著:“你不懂我,我不怪你”。其實不怪你才怪。
下面小編就帶你去認知mysql carsh_safe replication 的內心世界
crash-safe replication 定義
當master/salve 任何一個節點發生宕機等意外情況,
服務器重啟后master/salve數據 仍然保持一致性。
包含
master crash-safe replication
slave crash-safe replication
master crash-safe replication
需要配置3個參數。
innodb-flush-log-at-trx-commit=1
sync_binlog=1
innodb-xa-support=1
詳解:
master crash-safe
replication 只要保證事務和其二進制的持久性就 ok。
為了保證持久性,必須要保證 每提交一個事務 都要 持久化 redo log 到 重做日志文件 和 bin log 到 二進制日志文件(保證主從庫數據一致性)。
并且要確保 每commit 一個事務時 保存2個文件的原子性,由于是不同的文件需要開啟分布式事務。
innodb-flush-log-at-trx-commit=1
每commit 一個事務 都要調用fsync 把其產生的redo log 信息保存到 磁盤上的 重做日志文件上。
從而保證事務的持久性。發生故障重啟mysql server 通過redo log進行恢復。
sync_binlog=1
每commit 一個事務 保存其二進制日志到二進制文件,保證主從數據一致性
innodb-xa-support=1
開啟分布式事務
slave crash-safe replication
需要配置3個參數
innodb-flush-log-at-trx-commit=1
relay_log_info_repository=table
relay_log_recovery=on
slave 非正常關閉 經常會出現的問題:
不斷的1062 主鍵沖突錯誤
why?
skip-slave-error=1062 ???
主從數據不一致
是不是經常碰到slave 宕掉后,復制報1062 主鍵沖突。可能你會直接執行 SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1 跳過一個錯誤。為什么想過沒有呢 ?
小編一向認為 為什么 要比 是什么來的重要,我們要知其然知其所以然,這樣才可以避免錯誤。下面就隨俺理理吧
SQL thrend 主要做2件事
1: 回放 relay log 中事務信息
2: 更新 relay_log.info文件里的信息。確保下次重啟服務,讓
SQL thrend 曉得從那個relay log 文件 的那個位置繼續開始回放
why:
問題就出現在步驟2上,跟新
relay_log.info 文件是緩存寫,其中 由 參數 sync_relay_log_info 控制寫到
relay_log.info文件的時機。
其默認值是1000,意思是 每執行10000個 relay log 中的事務才寫一次盤。就算是把
sync_relay_log_info=1 也是有可能重復執行1個事物的。
并且這樣頻繁的刷盤,會導致系統性能嚴重下降不可取。
salve 報
1062 場景實例解析:
假設 slave 上現在SQL thread 已經回放了95000 個事務,
此時的 relay_log.info文件 記錄的位置是30500【第90000 個事務位置】那么此時salve 宕機了,
重啟后 SQL thread 讀取 relay_log.info 得到已經執行到 某個 relay log 文件 的30500 位置 即 第90000 個事務位置,然后又重新執行90000-95000 的事務,又因為
有主鍵約束自然就報 主鍵沖突了。
主從數據不一致 why
同樣是上面的問題,如果沒有主鍵約束,insert 數據就會重復執行,從庫就會多出重新執行的 insert 數據。
一般 bin log 都是基于row 的, insert 不是冪等的 ,update 是冪等的。冪等:f(x)=f(f(x)) 也就是此時 導致master/salve 不一致的都是insert 語句且表中沒有主鍵
解決方案:
MySQL 5.6 crash safe : relay_log_info_repository=table
relay-info.log的信息保存在InnoDB的事務表
BEGIN;
apply log event;
apply log event;
UPDATE mysql.slave_relay_log_info
SET Master_log_pos = Exec_Master_Log_Pos,
Master_log_name = Relay_Master_Log_File,
Relay_log_name = Relay_Log_File,
Relay_log_pos = Relay_Log_Pos;
COMMIT
這樣就使得 執行 relay log 中的 事務 log event 與 更新 relay_log.info 的原子性。
IO thread
接收binary log event
更新master-info.log
緩存寫
sync_master_info
解決方案
relay_log_recovery=on
確保binary log還在master服務器上
這與SQL thread 同理 ,會重復接受binary log event,解決的方案是relay_log_recovery=on 配合 之前的 relay_log_info_repository=table
即每次重啟服務IO thread 會讀取mysql.slave_relay_log_info表 中的 Master_log_name Master_log_pos 即 IO thread 會重新到
master 上從指定 二進制文件 Master_log_name 的指定位置Master_log_pos 繼續拉數據,前提是master 對應的二進制的文件還在。