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

主從複製解決的問題

  • 數據分佈:經過複製將數據分佈到不一樣地理位置
  • 負載均衡:讀寫分離以及將讀負載到多臺從庫
  • 備份:可做爲實時備份
  • 高可用性:利用主主複製實現高可用

複製原理

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

  • 在主庫上把數據更改記錄到二進制日誌binary log中,具體是在每次準備提交事務完成數據更新前,主庫將數據更新的事件記錄到二進制日誌中去,Mysql會按照事務提交的順序來記錄二進制日誌的。日誌記錄好以後,主庫通知存儲引擎提交事務。
  • 從庫會啓動一個IO線程,該線程會鏈接到主庫。而主庫上的binlog dump線程會去讀取主庫本地的binlog日誌文件中的更新事件。發往從庫,從庫接收到日誌以後會將其記錄到本地的中繼日誌relay-log當中。
  • 從庫中的SQL線程讀取中繼日誌relay-log中的事件,將其重放到從庫中。(在5.6版本以前SQL線程是單線程的,使得主從之間延遲更大)

兩種複製方式

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

基於語句複製

基於語句的複製至關於邏輯複製,即二進制日誌記錄了操做的語句,經過這些語句在從庫進行重放來實現複製。數據庫

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

因此在開發當中咱們應該將邏輯儘可能放在代碼層,而不該放到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版本使用並行複製。

  • 架構方面:好比在事務當中儘可能對主庫讀寫,其餘非事務中的讀在從庫。消除一部分延遲帶來的數據庫不一致。增長緩存下降一些從庫的負載。

筆者我的心得,若有錯誤懇請網友評論指正。

來源:juejin.cn/post/6844903968259178504

相關文章
相關標籤/搜索