MySQL 主從複製解決了什麼問題?出現同步延遲如何解決?

主從複製解決的問題
數據分佈:通過複製將數據分佈到不同地理位置

負載均衡:讀寫分離以及將讀負載到多臺從庫

備份:可作爲實時備份

高可用性:利用主主複製實現高可用

複製原理
複製的原理其實很簡單,僅分爲以下三步:

在主庫上把數據更改記錄到二進制日誌binary log中,具體是在每次準備提交事務完成數據更新前,主庫將數據更新的事件記錄到二進制日誌中去,Mysql會按照事務提交的順序來記錄二進制日誌的。日誌記錄好之後,主庫通知存儲引擎提交事務。

從庫會啓動一個IO線程,該線程會連接到主庫。而主庫上的binlog dump線程會去讀取主庫本地的binlog日誌文件中的更新事件。發往從庫,從庫接收到日誌之後會將其記錄到本地的中繼日誌relay-log當中。

從庫中的SQL線程讀取中繼日誌relay-log中的事件,將其重放到從庫中。(在5.6版本之前SQL線程是單線程的,使得主從之間延遲更大)

兩種複製方式
日誌文件中記錄的到底是什麼呢?mysql支持了兩種日誌格式,這兩種日誌格式也體現了各自的複製方式

基於語句複製
基於語句的複製相當於邏輯複製,即二進制日誌記錄了操作的語句,通過這些語句在從庫進行重放來實現複製。

這種方式簡單,二進制日誌佔用空間少,使得帶寬小傳輸效率較高。但是基於語句的更新依賴於其他因素,比如插入數據時利用時間戳函數調用當前時間作爲時間值也會出現問題,因爲由於主從之間的延遲導致時間值不一致。存儲過程和觸發器也可能出現問題。

所以在開發當中我們應該將邏輯儘量放在代碼層,而不應放到mysql中,不易擴展。

基於行復制
基於行的複製相當於物理複製,即二進制日誌記錄了實際更新數據的每一行。這樣導致行復制的壓力比較大,因爲日誌佔用空間較大,傳輸佔用帶寬也較高。但是比基於語句複製更加精確,可以屏蔽一些由於主庫從庫之間的差異導致的不一致。如剛纔提到的時間戳函數。

二者對比:
語句複製

傳輸效率高,減少延遲。

在從庫更新不存在的記錄時,語句賦值不會失敗。而行復制會導致失敗,從而更早發現主從之間的不一致。

設表裏有一百萬條數據,一條sql更新了所有表,基於語句的複製僅需要發送一條sql,而基於行的複製需要發送一百萬條更新記錄

行復制

不需要執行查詢計劃。

不知道執行的到底是什麼語句。

例如一條更新用戶總積分的語句,需要統計用戶的所有積分再寫入用戶表。如果是基於語句複製的話,從庫需要再一次統計用戶的積分,而基於行復制就直接更新記錄,無需再統計用戶積分。

因爲兩種方式各有優缺點,所以mysql在這兩種複製模式進行動態的切換。默認是語句。

配置要點

# 如果在雙主複製結構中沒有設置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,最終仍需操作系統將內存中的數據刷寫到磁盤上。

參數0:mysql每秒都會將log buffer的數據寫入到log file中並且刷新到磁盤。意味着mysql崩潰的時候將會丟失一秒內的所有事務。

參數1:每次事務提交都會將log buffer寫入到log file並刷新到磁盤。意味着在mysql崩潰的時候,僅會丟失一個事務。

參數2:每次事務提交都會將log buffer寫入到log file但不同時寫入到磁盤,由mysql自行控制每秒將log file刷寫到磁盤上,當mysql崩潰的時候操作系統沒崩潰的時候,log_file中僅會丟失一個事務,操作系統仍會將log file刷寫到磁盤,而如果操作系統也崩潰或斷電的話,則會丟失一秒內的事務。

推薦使用:

innodb_flush_logs_at_trx_commit=2
sync_binlog=500

性能會較快

innodb_flush_logs_at_trx_commit=1
sync_binlog=1

較爲安全

延遲問題
延遲的產生
當主庫的TPS併發較高時,由於主庫上面是多線程寫入的,而從庫的SQL線程是單線程的,導致從庫SQL可能會跟不上主庫的處理速度(生產者比消費者快,導致商品堆積)。

延遲的解決
網絡方面:將從庫分佈在相同局域網內或網絡延遲較小的環境中。

硬件方面:從庫配置更好的硬件,提升隨機寫的性能。

配置方面:

從庫配置

sync_binlog=0
innodb_flush_log_at_trx_commit=2
logs-slave-updates=0
增大 innodb_buffer_pool_size

讓更多操作在Mysql內存中完成,減少磁盤操作。或者升級Mysql5.7版本使用並行複製。

架構方面:比如在事務當中儘量對主庫讀寫,其他非事務中的讀在從庫。消除一部分延遲帶來的數據庫不一致。增加緩存降低一些從庫的負載。

筆者個人心得,如有錯誤懇請評論指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章