日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL主从复制原理学习

發布時間:2023/12/8 数据库 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL主从复制原理学习 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、主從復制過程

master 服務器將數據的改變記錄二進制 binlog 日志,當 master 上的數據發生改變時,則將其改變寫入二進制日志中;

slave 服務器會在一定時間間隔內對 master 二進制日志進行探測其是否發生改變,如果發生改變,則開始一個 I/OThread 請求 master 二進制事件;

同時主節點為每個 I/O 線程啟動一個 dump 線程,用于向其發送二進制事件,并保存至從節點本地的中繼日志中,從節點將啟動 SQL 線程從中繼日志中讀取二進制日志,在本地重放,使得其數據和主節點的保持一致,最后 I/OThread 和 SQLThread 將進入睡眠狀態,等待下一次被喚醒。

1.1 binlog

主從復制是在binlog的基礎上進行的
binlog格式可以設置為:statement、row、mixed三種

  • Statement 基于語句,只記錄對數據做了修改的SQL語句,能夠有效的減少binlog的數據量,提高讀取、基于binlog重放的性能
  • Row 只記錄被修改的行,所以Row記錄的binlog日志量一般來說會比Statement格式要多。基于Row的binlog日志非常完整、清晰,記錄了所有數據的變動,但是缺點是可能會非常多,例如一條update語句,有可能是所有的數據都有修改;再例如alter table之類的,修改了某個字段,同樣的每條記錄都有改動。
  • Mixed Statement和Row的結合,怎么個結合法呢。例如像update或者alter table之類的語句修改,采用Statement格式。其余的對數據的修改例如update和delete采用Row格式進行記錄。
# 臨時關閉當前session的log-bin mysql> set session sql_log_bin=0; # 使用 purge 進行切割,這樣之前的binlog就會都被清理掉 mysql> purge binary logs to 'log-bin.000003';

1.2 relaylog

二、異步復制、半同步復制

2.1 slave io_thread

1.根據master的ip和port,slave_io線程連接到master,如果連接不上,會發起重試
間隔時間:master_connect_retry(默認 60s)
2.發送sql命令 設置主庫master_heartbeat_period(默認slave_net_timeout/2)以及計算主從時間差 clock_diff_with_master(主從機器的系統時間差+網絡延遲)
3.io線程發送com_binlog_dump協議請求
4.waiting for master to send event
5.queueing master event to the relay log喚醒sql線程
6.修改master log pos的值 flush master_info(FLUSH頻率為sync_master_info的值)將主庫信息寫入master_log_info表
7.繼續步驟3 循環

2.2 主庫binlog_dump流程

1.DUMP線程收到COM BINLOG DUMP報文,解析上送filename和pos,并設置心跳包間隔時間master heartbeat period以及發送ROTATE EVENT更新從庫的masterlog_name
2.進入"Sending binlog event to slave"狀態,準備發送event到SlavelO線程
3.獲取讀取的binlog的尾指針位置,如果已達到hot binlog即最新的binlog文件)的尾部,則處于"Master has sent all binlog to slave; waiting for more updates"等待主庫產生binlog
4.獲取到尾指針,將相關的event發送到SlavelO一個文件結束
5.繼續下個文件執行步驟3,如此循環 純真笑容

2.3 slave_sql線程流程

1.對SlaveSQL線程進行參數初始化,并設置需要開始讀取relaylog的name和 pos.
2.進入"Reading event from the relay log"狀態,開始讀取event
3.如果沒有新event,進入"Slave has read all relay loq: waiting for more updates"狀態,等待Slave_IO線程寫入新event
4.讀取到event設置lastmastertimestamp以及sql線程的starttime計算主從延時的重要依據)并判斷是否需要跳過event的apply
5.根據event的數據在從庫進行apply應用處理
6.對于非xid的event,更新讀取relaylog的文件指針即event relaylog pos值當一個事務結束時候,會flushinfo(true)將rli信息強制寫入relayloginfo表(默認 relay_log_info_repository=TABLE)
7.再次讀取下個event進入步驟2如此循環 純真笑容

2.4 半同步復制

  • 用戶在 client 處執行 commit 提交了事務,主庫寫入了 redo 文件,對應"redo prepare: write"
  • binlog: write—— master 節點寫入 binlog 文件。 redo prepare: fsync——
  • 傳說中的兩階段提交的第一階段 prepare 刷盤(從 OS 層 page cache 持久化刷新到硬盤)了。
  • binlog:fsync—— binlog 刷盤。
  • 拷貝 binlog 到 slave 寫入到 relaylog 文件,寫完則返回 ACK 給master 節點,表示收到這個 binlog 了,relaylog 根據參數sync_relay_log=10000每 10000個事務刷一次刷盤(因為我們只討論主庫 crash 的情況,這個從庫 relay 刷盤行為我們不用管)
  • 根據參數設置rpl_semi_sync_master_wait_point=AFTER_SYNC,所以在這個位置點開始等待 slave 節點完成"relaylog: write",然后返回個 ACK 給 master。
  • master 節點收到 ACK 后,知道從庫收到這個binlog 后就可以提交事務了,發起"redo commit:write",傳說中的兩階段提交的第二階段 commit階段,commit 到文件。
  • master 回復客戶端 ACK: commit OK。
  • 2.4.1 sync binlog

    • 當sync_binlog為0的時候,binlog sync磁盤由OS負責.

    • 當sync_binlog值大于1的時候,sync binlog操作可能并沒有使binlog落盤(需要達到sync_binlog值之后才會進行fsync).如果沒有實際落盤,事務在提交前,Master crash了,Master再次啟動后原事務就會被回滾。但可能Dump線程已將events同步到Slave,并且Slave已經應用了這些events,這也會導致Slave數據比Master多,主備同步失敗。

    2.4.2 sync relay log

    • 參數解釋

    當sync_relay_log為0的時候,relaylog sync磁盤由OS負責.

    當sync_relay_log>1的時候,semisync返回給Master的position可能沒有fsync到磁盤.

    sync_relay_log=1的時候,會保證semisync返回給Master的positiony已經fsync到磁盤.

    • 異常舉例:

    在gtid_mode下,在sync_binlog=1的情況下,sync_relay_log不是1的時候,僅發生Master或Slave的一次Crash并不會發生數據丟失或者主備同步失敗情況。

    如果發生Slave沒有sync relay log,Master端事務提交,然后Slave端Crash。這樣Slave端就會丟失掉已經回復Master ACK的事務events。

    但當Slave再次啟動,如果沒有來得及從Master端同步丟失的事務Events,Master就Crash。這個時候,用戶訪問Slave就會發現數據丟失.

    如果完全要保證半同步的主從數據的一致性需要設置sync_binlog和sync_relay_log都為1,但是這會帶來性能的瓶頸(尤其是sync_relay_log為1 每同步一個event就需要fsync).所以實際的應用中,會根據數據一致性和性能的綜合考慮設置合理的值.

    三、常見主從報錯與解決方式

    3.1 Last error主從數據不一致

    查看導致last error產生的信息

    #方法1——通過binlog查詢 show binlog events in 'mysql-bin.032102' from 730019106 limit 10; #找到對應行,該行中Info信息就是1973位置所做操作 #方法2——通過ps表查詢 select * from performance_schema.replication_applier_status_by_worker where LAST_ERROR_NUMBER=1396

    如果確認可以跳過或者短時間無法解決

    # 跳過指定數量的事務,通常為1跳過當前出錯事務 mysql > stop slave ; mysql > set global sql_slave_skip_counter=1 mysql > start slave ;# 跳過指定類型的錯誤或者所有錯誤 vi /etc/my.cnf [mysqld] slave-skip-errors=1062,1146,2341 #跳過指定錯誤類型 slave-skip-errors=all #跳過所有錯誤,不建議使用# GTID模式下跳過事務 stop slave; set gtid_next='fb6d07d2-a253-1212-b2fh-29255eg3f3g:23' #show slave status信息中retrieved_gtid_set里的gtid為 fb6d07d2-a253-1212-b2fh-29255eg3f3g:18-23 begin;commit; #手動指定gtid_next,如果gtid已經存在于實例的GTID集合中,該事務會被忽略;如果沒有存在于GTID集合中就將這個gtid分配給接下來要執行的事務,系統不需要給這個事務生成新的GTID set gtid_next='AUTOMATIC'; #修改回自動獲取GTID start slave;# 使用gtid_purged跳過事務 show slave status \G; #先查看executed_gtid_set的值,該值有兩行,看下面那行 show variables like '%gtid_purged%' #查看主庫purged值,假設末尾是1-33 reset master #清空從庫binlog和gtid_executed狀態 set global gtid_purged='xxxxxxxxxxxxxxxxxxxxxxxxx:1-33'; 跳過1-33的事務 start slave; #主從狀態恢復后需手動補跳過的事務所產生的數據

    3.2 連接主庫報錯

    Last_IO_Errno: 1040 Last_IO_Error: error reconnecting to master 'repl@10.0.0.51:3307' - retry-time: 10 retries: 7

    通過復制用戶 手動連接
    判斷是否是主庫連接數過多還是防火墻不同

    3.3 relay log損壞

    Last_SQL_Error: Error initializing relay log position: I/O error reading the header from the binary log Last_SQL_Error: Error initializing relay log position: Binlog has bad magic number; It's not a binary log file that can be used by this version of MySQL

    找到同步的binlog和POS點,然后重新做同步,這樣就可以有新的relaylog

    Relay_Master_Log_File: mysql-bin.000010 Exec_Master_Log_Pos: 821 mysql> stop slave; Query OK, 0 rows affected (0.01 sec) mysql> CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000010',MASTER_LOG_POS=821; Query OK, 0 rows affected (0.01 sec) mysql> start slave;

    3.4 主庫crash 從庫重復回放

    在開啟 GTID 模式下,如果指定 master_auto_position=1,start slave 時,從庫會把 Retrieved_Gtid_Set 和 Executed_Gtid_Set 的并集發送給主庫,主庫將收到的并集和自己的 gtid_executed 比較,把從庫 GTID 集合里缺失的事務全都發送給從庫。

    主機重啟后,事務重復回放,表明 Retrieved_Gtid_Set 和 Executed_Gtid_Set 的并集中有 GTID 事務丟失,導致重復獲取事務執行引發主鍵沖突錯誤。
    Retrieved_Gtid_Set 和 Executed_Gtid_Set 均為內存變量,MySQL 重啟后,Retrieved_Gtid_Set 初始化為空值,從而推斷出 Executed_Gtid_Set 有 GTID 事務丟失。

    Executed_Gtid_Set 來源于 gtid_executed 變量,gtid_executed 變量持久化介質有 mysql.gtid_executed 表和 binlog 日志

    當 log_bin=on ,log_slave_updates=on 時,只有在 binlog 切換時侯才會更新 mysql.gtid_executed 表,保存直到上一個 binlog 執行過的 GTID 集合。MySQL 重啟后,在默認參數 binlog_gtid_simple_recovery=1 時,gtid_executed 變量值從最后一個 binlog 文件計算獲得
    Worker 線程報 1062 主鍵沖突錯誤–> gtid_executed 信息陳舊–> binlog 未實時持久化

    3.5 級聯復制報錯

    針對雙主級聯復制,需要檢查從庫的read_only選項,雙主模式下的自增步長,以及log_slave_updates參數,否則雙主模式下,可能會有問題

    3.6 主從切換后gtid不一致

    從庫之前執行過命令導致產生了新的gtid,并且該gtid所在的binlog已經被清理
    導致發生主從切換之后,新從庫同步復制新主庫時,由于master_auto_position=1模式下,從庫會將當前已經執行過的gtid集合發送給主庫,主庫接收到從庫發送的gtid集合后,會與當前已經執行的gtid set求差值,并將沒有執行過的gtid發送給備庫,由于binlog被清理導致無法將gtid發送給從庫(gtid_purged沒有包含)
    解決:在新從庫手動跳過缺失的gtid(注:跳過缺失的gtid,意味著不在從庫執行缺失的事務,可能導致數據的丟失)
    數據恢復:利用主庫備份重做或者利用binlog備份 恢復到原來的日志目錄(需要的binlog要從第一個包含缺失的gtid日志到當前的全部日志)

    3.7 多線程復制報錯

    對于多線程復制,slave_pending_jobs_size_max變量設置用于保存尚未應用的event的工作隊列可用的最大內存量(以字節為單位)。設置此變量對未啟用多線程處理的復制沒有影響。設置此變量不會立即生效。必須要停掉復制之后,重新start slave。
    此變量的最小值為1024;默認值為16MB。最大可能值為18446744073709551615(16 EB)。
    此變量的值是軟限制,可以設置為與正常工作負載匹配。如果異常大的事件超過此大小,事務將被保留,直到所有工作線程都有空隊列,然后進行處理。如果內存富余,或者延遲較大時,可以適當調大;注意這個值要比主庫的max_allowed_packet大!
    當worker線程正在處理的event的總大小超過slave_pending_jobs_size_max變量的大小時,將發生此等待操作。此時可有在主庫看到線程的狀態為:Waiting for Slave Workers to free pending events

    Last_SQL_Error: Cannot schedule event Rows_query, relay-log name /data/mysql_4306/log/slave-relay-bin.004764, position 912733141 to Worker thread because its size 21520792 exceeds 18777088 of slave_pending_jobs_size_max. #從庫 set global slave_pending_jobs_size_max=

    總結

    以上是生活随笔為你收集整理的MySQL主从复制原理学习的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。