主備複製過程當中有很大可能會出現各類問題,接下來咱們就討論一些比較廣泛的問題,以及當遇到這些問題時,如何解決或者預防問題發生。mysql
問題描述:服務器崩潰、斷電、磁盤損壞、內存或網絡錯誤等問題,致使數據損壞或丟失。 問題緣由:非正常關機致使沒有把數據及時的寫入硬盤。sql
這種問題,通常能夠分爲幾種狀況致使:數據庫
問題未發生,避免方案:設置主庫的 sync_binlog 選項爲 1。此選項表示 MySQL 是否控制 binlog 的刷新。當設置爲 1 時,表示每次事務提交,MySQL 都會把 binlog 刷下去,是最安全,性能損耗也最大的設置。 問題已發生,解決方案:指定備庫從下一個二進制日誌的開頭從新讀日誌。可是一些日誌事件將永久性丟失。可使用 Percona Toolkit 中的 pt-table-checksum 工具來檢查主備一致性,以便於修復。安全
備庫意外關閉重啓時,會去讀 master.info 文件以找到上次中止複製的位置。可是在乎外關閉的狀況下,這個文件存儲的信息多是錯誤的。此外,備庫也可能會嘗試從新執行一些二進制文件,這可能會致使惟一索引錯誤。咱們能夠經過 Percona Toolkit 中的 pt-slave-restart 工具,幫助備庫從新執行日誌文件。bash
若是使用的是 InnoDB 表,能夠在重啓後觀察 MySQL 的錯誤日誌。InnoDB 在恢復過程當中會打印出恢復點的二進制日誌座標,可使用這個值來決定備庫指向主庫的偏移量。服務器
若是主庫上的二進制日誌損壞,除了忽略損壞的位置外,別無選擇。在忽略存貨位置後,咱們能夠經過 FLUSH LOGS 命令在主庫開始一個新的日誌文件,而後將備庫指向該文件的開始位置。網絡
若是主庫上的日誌是無缺的,有兩種解決方案: 1) 手工處理。找到 master binlog 日誌的 pos 點,而後從新同步。工具
2) 自動處理。mysql5.5 考慮到 slave 宕機中繼日誌損壞這一問題,只要在 slave 的的配置文件 my.cnf 裏增長一個參數 relay_log_recovery=1 便可。性能
因爲各類各樣的緣由,MySQL 的複製碰到服務器崩潰、斷電、磁盤損壞、內存或網絡錯誤時,很難恢復當時丟失的數據。幾乎都須要從某個點開始重啓複製。優化
若是沒有再 my.cnf 裏定義服務器 ID,雖然能夠經過 CHANGE MASTER TO 來設置備庫,但在啓動複製時會遇到:
mysql> START SLAVE;
ERROR 1200 (HY000): The server us bit configured as slave; fix in config file or with CHANGE MASTER TO
複製代碼
這個報錯可能會讓人困惑。由於咱們可能已經經過 CHANGE MASTER TO 設置了備庫,而且經過 SHOW MASTER STATUS 也確認了,爲何還會有這樣的報錯呢?咱們經過 SELECT @@server_id 能夠得到一個值,要注意的是,這個值只是默認值,咱們必須爲備庫顯式地設置服務器 ID。也就是在 my.cnf 裏顯示的設置服務器 ID。
若是在主庫上有備庫上不存在的數據庫或數據表,複製就很容易中斷,反之亦然。 對於前者,假設在主庫上有一個 single_master 表,備庫沒有。在主庫上對此表進行操做後,備庫在嘗試回放這些操做時就會出現問題,致使複製中斷。
對於後者,假設備庫上有一個 single_slave 表,主庫沒有。在主庫上執行建立 single_slave 表的語句時,備庫在回放該建表語句時就會出現問題。
對於此問題,咱們能作的就是作好預防:
臨時表和基於語句的複製方式不相容。若是備庫崩潰或者正常關閉,任何複製線程擁有的臨時表都會丟失。重啓備庫後,全部依賴於該臨時表的語句都會失敗。
複製時出現找不到臨時表的異常時,能夠作:
臨時表的特性:
保留一個專用的數據庫,在其中建立持久表,把它們做爲僞臨時表,以模擬臨時表特性。只須要經過 CONNETCTION_ID() 的返回值,給臨時表建立惟一的名字。
僞臨時表的優劣勢 優點:
劣勢:
使用共享鎖,串行化更新,保證備庫複製時數據一致。
某些狀況下,加鎖讀能夠防止混亂。假設有兩張表:tab1 沒有數據,tab2 只有一行數據,值爲 99。此時,有兩個事務更新數據。事務 1 將 tab2 的數據插入到 tab1,事務 2 更新 tab2。
上述過程當中,第二步很是重要。事務 2 嘗試去更新 tab2 表,這須要在更新的行上加排他鎖(寫鎖)。排他鎖與其餘鎖不相容,包括事務 1 在行記錄上加的共享鎖。所以事務 2 須要等待事務 1 完成。備庫在根據 binlog 進行復制時,會按一樣的順序先執行事務 1,再執行事務 2。主備數據一致。
一樣的過程,若是事務 1 在第一步時沒有加共享鎖,流程就變成:
mysqldump --single-transaction --all-databases --master-data=1 --host=server1 | mysql --host=server2 要注意的是,上述過程當中,事務 2 先提交,先寫入 binlog。在備庫複製時,一樣先執行事務 2,將 tab2 的記錄值更新爲 100。而後執行事務 1,讀取 tab2 數據,插入 tab1,因此最終的結果是,tab1 的記錄值和 tab2 的記錄值都是 100。很明顯,數據和主庫有差別。
建議在大多數狀況下將 innodb_unsafe_for_binlog 的值設置爲 0。基於行的複製因爲記錄了數據的變化而非語句,所以不會存在這個問題。
產生延遲的兩種方式
前者一般是因爲一條執行時間過長的 SQL 致使,然後者即便在沒有慢語句也會出現。
對於前者,咱們能夠經過備庫上的慢查詢日誌來進行優化。在備庫上開啓 log_slow_slave_statement 選項,能夠在慢查詢日誌中記錄複製線程執行的語句。
而對於後者,沒有針對性的解決方案,只能經過各類方式提升備庫的複製效率。而當咱們想去對備庫作優化時,會發現,除了購買更快的磁盤和 CPU,並無太多的調優空間。只能經過 MySQL 選項禁止某些額外的工做以減小備庫的複製。能夠經過下面幾種方式: