InnoDB Master-Master 複製在電源故障測試後不一致
午後大佬們
我目前正在使用 InnoDB 作為數據庫引擎對 Master-Master 複製設置進行壓力測試。
我們正在使用這個簡單的腳本進行測試,我們從遠端伺服器在 Linux CLI 中執行它。
<?php while(true) { try { $conn = mysql_connect('10.0.10.210', 'test', 'test'); if ($conn) { mysql_select_db('testdb'); $random = rand(0, 1000); $res = mysql_query("INSERT INTO test VALUES(0, 'test', $random)"); if ($res) { echo "\n inserted " . microtime(); } else { echo "\n not inserted " . microtime(); } mysql_close($conn); } else { echo "\n can not connect"; } } catch (Exception $ex) { echo "\n can not insert" . microtime(); } } var_dump($res); echo "ok";
我們面臨的問題是,我們試圖關閉其中一台主機,只使用拔掉電源,即硬關機。
我們還使用 MySQL-MMM 進行故障轉移,但這與我們面臨的問題無關,但我將解釋我們現在使用的過程。
- Master-Master 完美執行,server1 具有虛擬 IP 10.0.10.210 並提供寫入和讀取服務
2)我們通過拔掉電纜關閉了server1,虛擬IP被移動到server2,一切正常,並且在停機約20秒後繼續插入。
3)我們再次啟動server1,它上升並取回虛擬IP地址,1-2秒停機後繼續插入。
這樣做的問題是我們失去了在 server1 停機期間發生的所有插入,如果我輸入“STOP SLAVE; START SLAVE;” 我收到這些錯誤:
[ERROR] Slave I/O: Got fatal error 1236 from master when reading data from binary log: 'Client requested master to start replication from impossible position', Error_code: 1236
如果我使用與 mysqld.log 文件所說的內容相對應的偏移量手動檢查二進制日誌:
[root@db1 mysql]# mysqlbinlog --offset=623435 db1-mysql-bin.000001 /*!40019 SET @@session.max_insert_delayed_threads=0*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; DELIMITER /*!*/; # at 4 #121030 12:55:16 server id 1 end_log_pos 106 Start: binlog v 4, server v 5.1.61-log created 121030 12:55:16 at startup # Warning: this binlog is either in use or was not closed properly. ROLLBACK/*!*/; BINLOG ' VOqPUA8BAAAAZgAAAGoAAAABAAQANS4xLjYxLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAABU6o9QEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC '/*!*/; ERROR: Error in Log_event::read_log_event(): 'read error', data_len: 112, event_type: 2 DELIMITER ; # End of log file ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
我知道二進制日誌文件沒有正確關閉,但 InnoDB 不應該處理這個問題嗎?當然,硬關機並不是什麼罕見的事情,至少在我看來不是這樣。我正在執行 EXT4 文件系統。
到目前為止,這只是一個實驗室設置,實際上我們在最先進的(不是淹沒的……)數據中心中執行它,並採取了所有必要的預防措施。
任何關於此事的線索將不勝感激,謝謝。
我的.cnf
[mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock user=mysql symbolic-links=0 sync_binlog=1 # REPLICATION SETTINGS server_id = 2 replicate-same-server-id = 0 auto-increment-increment = 2 auto-increment-offset = 2 replicate-do-db = test binlog-ignore-db = mysql log-bin=db2-mysql-bin relay-log=db2-relay-log relay-log-index=relay-log-index [mysqld_safe] log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid
更新
我現在已經將文件系統從 EXT4 切換到 XFS,它確實處理了數據的失去,但現在我遇到了另一個問題,但是非常小,應該很容易解決。
在我完成關閉 server1 的過程後,故障轉移到 server2,啟動 server1,回滾到 server1。一切都在正常工作,server1 準確地從 server2 停止的地方開始,唯一的問題是 server2 停止同步 server1,所以情況正好相反。
如果我執行 STOP SLAVE;啟動奴隸;它開始同步,幾秒鐘後與 server1 相同,但它為什麼不自動執行此操作?
經過一番思考,我發現從伺服器無法區分靜默(空閒)主機和崩潰主機之間的區別,除非給出錯誤,因此 TCP 連接將保持線上,直到達到從伺服器預設 TCP 超時。
在我的盒子上,這是預設設置
[root@db1 ~]# sysctl -e net.ipv4.tcp_keepalive_time net.ipv4.tcp_keepalive_time = 7200
所以我把它整理出來
echo 30 > /proc/sys/net/ipv4/tcp_keepalive_time echo 2 > /proc/sys/net/ipv4/tcp_keepalive_probes echo 1 > /proc/sys/net/ipv4/tcp_keepalive_intvl
這使得它每 30 秒發送一次 SYN 包以查看連接是否仍在回复,並且會更快地啟動同步方式。不要忘記重新啟動 MySQL 程序以便重新打開套接字,並將其添加到 rc 腳本中以便在重新啟動後保留設置。
有很多旋鈕需要調整,所以這裡有一個 URL,其中包含有關該主題的更多資訊。 http://dom.as/2006/09/12/mysql-tcp-network-tuning/
如果您對如何設置感興趣,請閱讀此處。 http://mute.nu/2012/how-to-set-up-a-2-node-apache-and-mysql-fail-over-environment/
總而言之,將 MySQL 數據目錄放在 XFS 上並調整 TCP 保持活動設置,一切就緒。
複製和二進制日誌記錄獨立於 innodb 發生,不幸的是,這可能會導致問題。
查看:http ://dev.mysql.com/doc/refman/5.5/en/replication-options-binary-log.html#sysvar_sync_binlog
根據您的描述,我懷疑您的伺服器的 sync_binlog 設置為 0。將其保留為 0 意味著 mysql 將依賴文件系統來處理刷新到磁碟。實際上,這意味著二進制日誌數據通常會在文件系統記憶體中。核心會在某個時間間隔將其刷新到磁碟,但在電源故障的情況下,其中的任何內容都會失去。
將 sync_binlog 設置為 1 將強制 mysql 在每次送出後使用 fdatasync 將 binlog 事件刷新到文件系統。這更安全(因為在電源故障的情況下您最多會失去 1 個事務),但會創建更多的磁碟活動。基準測試並查看對您的工作負載有何影響。了解這兩種情況的權衡將有望幫助您做出明智的決定。
希望有幫助。