複製的原理其實很簡單,僅分爲如下三步:mysql
在主庫上把數據更改記錄到二進制日誌binary log中,具體是在每次準備提交事務完成數據更新前,主庫將數據更新的事件記錄到二進制日誌中去,Mysql會按照事務提交的順序來記錄二進制日誌的。日誌記錄好以後,主庫通知存儲引擎提交事務。sql
從庫會啓動一個IO線程,該線程會鏈接到主庫。而主庫上的binlog dump線程會去讀取主庫本地的binlog日誌文件中的更新事件。發往從庫,從庫接收到日誌以後會將其記錄到本地的中繼日誌relay-log當中。數據庫
從庫中的SQL線程讀取中繼日誌relay-log中的事件,將其重放到從庫中。(在5.6版本以前SQL線程是單線程的,使得主從之間延遲更大)緩存
日誌文件中記錄的究竟是什麼呢? mysql支持了兩種日誌格式,這兩種日誌格式也體現了各自的複製方式安全
基於語句的複製至關於邏輯複製,即二進制日誌記錄了操做的語句,經過這些語句在從庫進行重放來實現複製。這種方式簡單,二進制日誌佔用空間少,使得帶寬小傳輸效率較高。 可是基於語句的更新依賴於其餘因素,好比插入數據時利用時間戳函數調用當前時間做爲時間值也會出現問題,由於因爲主從之間的延遲致使時間值不一致。存儲過程和觸發器也可能出現問題。因此在開發當中咱們應該將邏輯儘可能放在代碼層,而不該放到mysql中,不易擴展。bash
基於行的複製至關於物理複製,即二進制日誌記錄了實際更新數據的每一行。這樣致使行復制的壓力比較大,由於日誌佔用空間較大,傳輸佔用帶寬也較高。可是比基於語句複製更加精確,能夠屏蔽一些因爲主庫從庫之間的差別致使的不一致。如剛纔提到的時間戳函數。網絡
語句複製:多線程
行復制:架構
# 若是在雙主複製結構中沒有設置ID的話就會致使循環同步問題
server_id=1
# 即日誌中記錄的是語句仍是行更新或者是混合
binlog_format=mixed
# 在進行n次事務提交之後,Mysql將執行一次fsync的磁盤同步指令。將緩衝區數據刷新到磁盤。
# 爲0的話由Mysql本身控制頻率。
sync_binlog=n
# 爲0的話,log buffer將每秒一次地寫入log file中而且刷新到磁盤。
# mysqld進程崩潰會丟失一秒內的全部事務。
# 爲1的話,每次事務log buffer會寫入log file並刷新到磁盤。(較爲安全)
# 在崩潰的時候,僅會丟失一個事務。
# 爲2的話,每次事務log buffer會寫入log file,但一秒一次刷新到磁盤
innodb_flush_logs_at_trx_commit=0
# 阻止從庫崩潰後自動啓動複製,給一些時間來修復可能的問題,
# 崩潰後再自動複製可能會致使更多的問題。而且自己就是不一致的
skip_slave_start=1
# 是否將從庫同步的事件也記錄到從庫自身的bin-log中
# 容許備庫將重放的事件也記錄到自身的二進制日誌中去,能夠將備庫當作另一臺主庫的從庫
log_slave_update
# 日誌過時刪除時間,延遲嚴重的話會致使日誌文件佔用磁盤
expire_logs_days=7
複製代碼
innodb_flush_logs_at_trx_commit的三個參數很容易弄混。如下是詳細的解析:併發
mysql先將日誌寫到log buffer緩衝區當中,再將log buffer緩衝區的數據寫到log file日誌文件中,此時寫入的是內存中的log file,最終仍需操做系統將內存中的數據刷寫到磁盤上。
推薦使用:innodb_flush_logs_at_trx_commit=2以及sync_binlog=500性能會較快。innodb_flush_logs_at_trx_commit以及sync_binlog都爲1的話,較爲安全。
網絡方面:將從庫分佈在相同局域網內或網絡延遲較小的環境中。
硬件方面:從庫配置更好的硬件,提高隨機寫的性能。
配置方面:從庫配置sync_binlog=0,innodb_flush_log_at_trx_commit=2,logs-slave-updates=0,增大innodb_buffer_pool_size,讓更多操做在Mysql內存中完成,減小磁盤操做。或者升級Mysql5.7版本使用並行複製。
架構方面:好比在事務當中儘可能對主庫讀寫,其餘非事務中的讀在從庫。消除一部分延遲帶來的數據庫不一致。增長緩存下降一些從庫的負載。