複製資訊記錄表|全方位認識 mysql 系統庫

沃趣科技發表於2019-10-25


在上一期《時區資訊記錄表|全方位認識 mysql 系統庫》中,我們詳細介紹了mysql系統庫中的時區資訊記錄表,本期我們將為大家帶來系列第七篇《複製資訊記錄表|全方位認識 mysql 系統庫》,下面請跟隨我們一起開始 mysql 系統庫的系統學習之旅吧!

1、複製資訊表概述

複製資訊表用於在從庫在複製主庫的資料期間,用於儲存從主庫轉發到從庫的二進位制日誌事件、記錄有關中繼日誌當前狀態和位置的資訊。 一共有三種型別的日誌,如下:

  • master.info檔案或者mysql.slave_master_info表:用於儲存從庫的IO執行緒連線主庫的連線狀態、帳號、IP、埠、密碼以及IO執行緒當前讀取主庫binlog的file和position等資訊(被稱為IO執行緒資訊日誌。預設情況下,IO執行緒的連線資訊和狀態儲存在master.info檔案中(預設位置在datadir下,可以使用master_info_file選項執行master.info檔案路徑),如果需要儲存在mysql.slave_master_info表中,需要在server啟動之前設定master-info-repository = TABLE)。

  • relay-log.info檔案或者mysql.slave_relay_log_info表: 從庫的IO執行緒從主庫獲取到最新的binlog事件資訊會先寫入到從庫本地的relay log中,SQL執行緒再去讀取relay log解析並重放,而relay_log.info檔案或者mysql.slave_relay_log_info表就是用於記錄最新的relay log的file和position以及SQL執行緒當前重放的事件對應主庫binlog的file和position(relay log即被稱為中繼日誌,SQL執行緒位置被稱為SQL執行緒資訊日誌。預設情況下,relay log的位置資訊和SQL執行緒的位置資訊儲存在relay-log.info檔案中(預設位置在datadir下,可以使用relay_log_info_file選項執行relay-log.info檔案路徑),如果需要儲存在mysql.slave_relay_log_info表中,需要在server啟動之前設定relay-log-info-repository = TABLE)。

設定relay_log_info_repository和master_info_repository設定為TABLE可以提高資料庫本身或者所在主機意外終止之後crash recovery的能力(這兩張表是innodb表,可以保證crash之後表中的位置資訊不丟失),且可以保證資料一致性。

從庫crash時,SQL執行緒可能還有一部分relay log重放延遲,另外,IO執行緒的位置也可能正處於一個事務的中間,並不完整,所以必須在從庫上啟用引數relay-log-recovery=ON,啟用該引數之後,從庫crash recovery時會清理掉SQL執行緒未重放完成的relay log,並以SQL執行緒的位置為準重置掉IO執行緒的位置重新從主庫請求。

這兩張表在資料庫例項啟動時如果無法被mysqld初始化,則mysqld允許繼續啟動,但會在錯誤日誌中寫入警告資訊,這種情況在MySQL從不支援該表的版本升級到支援該表的版本時常常遇見。

PS:

  • 不要嘗試手動更新slave_master_info或slave_relay_log_info表,否則後果自負。

  • 從庫中複製執行緒在持續工作時,不允許任何可能對這兩張表加寫鎖的語句執行,但允許對這兩張表做只讀的語句執行。

2、複製資訊表詳解

由於本期所介紹的表中存放的複製資訊,在我們日常的資料庫維護過程當中尤其重要,所以,下文中會在每張表的介紹過程中適度進行一些擴充套件。

2.1. slave_master_info

該表提供查詢IO執行緒讀取主庫的位置資訊,以及從庫連線主庫的IP、賬號、埠、密碼等資訊。

下面是該表中儲存的資訊內容。

root@localhost : mysql 01:08:29> select * from slave_master_info\G;
*************************** 1. row ***************************
       Number_of_lines: 25
       Master_log_name: mysql-bin.000292
        Master_log_pos: 194
                  Host: 192.168.2.148
             User_name: qfsys
         User_password: letsg0
                  Port: 3306
         Connect_retry: 60
           Enabled_ssl: 0
                Ssl_ca:
            Ssl_capath:
              Ssl_cert:
            Ssl_cipher:
               Ssl_key:
Ssl_verify_server_cert: 0
             Heartbeat: 5
                  Bind:
    Ignored_server_ids: 0
                  Uuid: ec123678-5e26-11e7-9d38-000c295e08a0
           Retry_count: 86400
               Ssl_crl:
           Ssl_crlpath:
 Enabled_auto_position: 0
          Channel_name:
           Tls_version:
1 row in set (0.00 sec)

表欄位與show slave status輸出欄位、master.info檔案中的行資訊對應關係及其表欄位含義如下:

master.info檔案中的行數 mysql.slave_master_info表欄位 show slave status命令輸出欄位 欄位含義描述
1 Number_of_lines [None] 表示master.info中的資訊行數或者slave_master_info表中的資訊欄位數
2 Master_log_name Master_Log_File 表示從庫IO執行緒當前讀取主庫最新的binlog file名稱
3 Master_log_pos Read_Master_Log_Pos 表示從庫IO執行緒當前讀取主庫最新的binlog position
4 Host Master_Host 表示從庫IO執行緒當前正連線的主庫IO或者主機名
5 User_name Master_User 表示從庫IO執行緒用於連線主庫使用者名稱
6 User_password [None] 表示從庫IO執行緒用於連線主庫的使用者密碼
7 Port Master_Port 表示從庫IO執行緒所連線主庫的網路埠
8 Connect_retry Connect_Retry 表示從庫IO執行緒斷線重連主庫的間隔時間,單位為秒,預設值為60
9 Enabled_ssl Master_SSL_Allowed 表示主從之間的連線是否支援SSL
10 Ssl_ca Master_SSL_CA_File 表示CA(Certificate Authority )認證檔名
11 Ssl_capath Master_SSL_CA_Path 表示CA(Certificate Authority )認證檔案路徑
12 Ssl_cert Master_SSL_Cert 表示SSL認證證書檔名
13 Ssl_cipher Master_SSL_Cipher 表示用於SSL連線握手中可能使用到的密碼列表
14 Ssl_key Master_SSL_Key 表示SSL認證的金鑰檔名
15 Ssl_verify_server_cert Master_SSL_Verify_Server_Cert 表示是否需要校驗server的證書
16 Heartbeat [None] 表示主從之間的複製心跳包的間隔時間,單位為秒
17 Bind Master_Bind 表示從庫可用於連線主庫的網路介面,預設為空
18 Ignored_server_ids Replicate_Ignore_Server_Ids 表示從庫複製需要忽略哪些server-id,注意:這是一個列表,第一個數字表示需要忽略的例項server-id總數
19 Uuid Master_UUID 表示主庫的UUID
20 Retry_count Master_Retry_Count 表示從庫最大允許重連主庫的次數
21 Ssl_crl [None] SSL證書撤銷列表檔案的路徑
22 Ssl_crl_path [None] 包含ssl證書吊銷列表檔案的目錄路徑
23 Enabled_auto_position Auto_position 表示從庫是否啟用在主庫中自動尋找位置的功能(使用1時啟動自動尋找位置,如果使用auto_position=0,則不會自耦東找位置)
24 Channel_name Channel_name 表示從庫複製通道名稱,一個通道代表一個複製源
25 Tls_Version Master_TLS_Version 表示在Master上的TLS版本號

2.2. slave_relay_log_info

該表提供查詢SQL執行緒重放的二進位制檔案對應的主庫位置和relay log當前最新的位置。

下面是該表中儲存的資訊內容。

root@localhost : mysql 10:39:31> select * from slave_relay_log_info\G
*************************** 1. row ***************************
  Number_of_lines: 7
   Relay_log_name: /home/mysql/data/mysqldata1/relaylog/mysql-relay-bin.000205
    Relay_log_pos: 14097976
  Master_log_name: mysql-bin.000060
   Master_log_pos: 21996812
        Sql_delay: 0
Number_of_workers: 16
               Id: 1
     Channel_name:
1 row in set (0.00 sec)

表欄位與show slave statu s輸出欄位、relay-log.info檔案中的行資訊對應關係及其表欄位含義如下:

relay-log.info檔案中的行數 mysql.slave_relay_log_info表欄位 show slave status命令輸出欄位 欄位含義描述
1 Number_of_lines [None] 表示relay-log.info中的資訊行數或者slave_relay_log_info表中的資訊欄位數,用於版本化表定義
2 Relay_log_name Relay_Log_File 表示當前最新的relay log檔名稱
3 Relay_log_pos Relay_Log_Pos 表示當前最新的relay log檔案對應的最近一次完整接收的event的位置
4 Master_log_name Relay_Master_Log_File 表示SQL執行緒當前正在重放的中繼日誌對應的主庫binlog 檔名
5 Master_log_pos Exec_Master_Log_Pos 表示SQL執行緒當前正在重放的中繼日誌對應主庫binlog 檔案中的位置
6 Sql_delay SQL_Delay 表示延遲複製指定的從庫必須延遲主庫多少秒
7 Number_of_workers [None] 表示從庫當前並行複製有多少個worker執行緒
8 Id [None] 用於內部唯一標記表中的每一行記錄,目前總是1
9 Channel_name Channel_name 表示從庫複製通道名稱,用於多源複製,一個通道對應一個主庫源

什麼是中繼日誌:

  • 中繼日誌(relay log)與二進位制日誌(binlog,即,binary log)中,儲存的event資料是一樣的(但中繼日誌中還儲存了更多的資訊),也是由一組包含描述資料庫變更的事件資料的檔案組成,這些檔名字尾帶連續編號,此外,還有一個包含所有正在使用的中繼日誌檔名稱的索引檔案。

  • 中繼日誌中的資料存放格式與二進位制日誌相同,都可以使用mysqlbinlog命令來提取資料,預設情況下,中繼日誌儲存在datadir下,檔名格式為: host_name-relay-bin.nnnnnn,其中host_name是從庫伺服器主機名,nnnnnn是檔案字尾序列號。連續的中繼日誌檔案從000001開始的連續序列號建立。使用索引檔案來跟蹤當前正在使用的中繼日誌檔案。預設的中繼日誌索引檔名儲存在datadir下,檔名格式為:host_name-relay-bin.index。

    * 中繼日誌檔案和中繼日誌索引檔名稱可分別使用--relay-log和--relay-log-index引數選項指定值覆蓋預設值,如果檔名使用預設值,則要注意主機名稱不能修改,否則會報無法開啟中繼日誌的錯誤,建議使用引數選項指定固定的檔名稱字首。如果已經出現了這種情況發生報錯了,那麼需要修改index檔案中的中繼日誌檔名和datadir下的中繼日誌檔名字首為新的主機名,然後重啟從庫。

在什麼情況下會產生新的中繼日誌檔案。

  • I/O執行緒啟動時。

  • 使用語句: FLUSH LOGS或mysqladmin flush-logs命令時。

  • 當前中繼日誌檔案的大小變得“太大”時,日誌滾動規則如下:

    * 如果max_relay_log_size系統變數的值大於0,那麼中繼日誌按照此引數指定的大小進行滾動。

    * 如果max_relay_log_size系統變數的值為0,則中繼日誌按照max_binlog_size系統變數指定的大小進行滾動。

SQL執行緒在執行完relay log之後,會自行決定何時清理掉這些已經執行完成的relay log檔案,但如果使用FLUSH LOGS語句或mysqladmin flush-logs命令強制滾動中繼日誌時,SQL執行緒可能會同時清理掉已經執行完成的relay log檔案。

2.3. slave_worker_info

該表提供查詢多執行緒複製時的worker執行緒狀態資訊,與performance_schema.replication_applier_status_by_worker表的區別是: slave_worker_info表記錄worker執行緒重放的relay log和主庫binlog位置資訊,而performance_schema.replication_applier_status_by_worker表記錄的是worker執行緒重放的GTID位置資訊。

下面是該表中儲存的資訊內容。

root@localhost : mysql 01:09:39> select * from slave_worker_info limit 1\G;
*************************** 1. row ***************************
                        Id: 1
            Relay_log_name:
             Relay_log_pos: 0
           Master_log_name:
            Master_log_pos: 0
 Checkpoint_relay_log_name:
  Checkpoint_relay_log_pos: 0
Checkpoint_master_log_name:
 Checkpoint_master_log_pos: 0
          Checkpoint_seqno: 0
     Checkpoint_group_size: 64
   Checkpoint_group_bitmap:
              Channel_name:
1 row in set (0.00 sec)

表欄位含義。

  • Id: 表中資料的ID,也是worker執行緒的ID,對應著performance_schema.replication_applier_status_by_worker表的WORKER_ID欄位(如果複製停止,則該欄位值仍然存在,不像performance_schema.replication_applier_status_by_worker表中THREAD_ID欄位值會清空)。

  • Relay_log_name: 每個worker執行緒當前最新執行到的relay log檔名。

  • Relay_log_pos: 每個worker執行緒當前最新執行到的relay log檔案中的position。

  • Master_log_name: 每個worker執行緒當前最新執行到的主庫binary log檔名。

  • Master_log_pos: 每個worker執行緒當前最新執行到的主庫binary log檔案中的position。

  • Checkpoint_relay_log_name: 每個worker執行緒最新檢查點的relay log檔名。

  • Checkpoint_relay_log_pos: 每個worker執行緒最新檢查點的relay log檔案中的position。

  • Checkpoint_master_log_name: 每個worker執行緒最新檢查點對應主庫的binary log檔名。

  • Checkpoint_master_log_pos: 每個worker執行緒最新檢查點對應主庫的binary log檔案中的position。

  • Checkpoint_seqno: 每個worker執行緒當前最新執行完成的事務號,這個事務號的大小值是相對於每個worker執行緒自己的最新檢查點而言的,並不是真正的事務號。

  • Checkpoint_group_size: 表示每個worker執行緒的執行佇列大於這個欄位值時,就會觸發當前worker執行緒執行一次檢查點。

  • Checkpoint_group_bitmap: 用於從庫crash之後recovery的關鍵值,它是一個點陣圖值,表示每個worker執行緒在自己的最新檢查點中已經執行的事務。

  • Channel_name: 複製通道名稱,多主複製時,顯示指定的複製通道名稱,單主複製時該欄位為空。


該表中記錄的內容對從庫多執行緒複製crash recovery至關重要,所以下文對該表中記錄的內容如何作用於crash recovery過程進行一些必要的說明。


從庫多執行緒複製如何做複製分發。

  • 我們知道在MySQL 5.7中加入了基於事務的並行複製(基於行),主庫在binlog的GTID事件中新加入了last_commit和sequence_number標記,用於表示在每個binlog中的每個group中的提交順序(每個binlog中重置這兩個計數標記),在每個給定的binlog中,每個group中的last_commit總是為上一個group中最大的sequence_number、總是為當前group中最小的sequence_number - 1(在每個binlog中,last_commit總是從0開始計數,sequence_number總是從1開始計數)。

  • 從庫relay log中記錄的主庫binlog,不會改變主庫的server id、時間戳資訊以及last_commit和sequence_number值,這樣,從庫SQL執行緒在執行binlog重放時,就可以依據這些資訊決定從庫是否需要嚴格按照主庫提交順序進行提交(從庫重放的事務只是分發順序按照主庫提交順序,但是從庫自己在提交這些事務時是否按照主庫提交順序進行提交,還需要看從庫自己的slave_preserve_commit_order變數設定,設定為1則嚴格按照relay log中的順序進行提交,設定為0從庫會自行決定提交順序)。

  • SQL執行緒並行分發原理。

    * SQL協調器執行緒讀取到一個新的事務,取出last_commit和sequence_number值。

    * SQL協調器執行緒判斷取出的新事務的當前last_commit是否大於當前已執行完成的sequence_number中的最小值(Low water mark,簡稱LWM,也叫低水位線標記)。

    * 如果SQL協調器執行緒讀取到的當前事務的last_commit大於當前已執行完成的sequence_number值,則說明上一個group中的事務還沒有全部執行完成,此時SQL協調器執行緒需要等待所有的worker執行緒執行完成上一個group中的事務,等待LWM變大,直到當前讀取到的事務的last_commit與當前已執行完成的事務的最小sequence_number值相等才可以繼續分發新的事務給空閒的worker執行緒(並行複製是針對每個group內的事務才可以並行複製,所以,group之間是序列的,一個group未執行完成之前,下一個group的事務是需要進行等待的。 只有同一個group內的事務之間才可以並行執行。根據上文中的描述,每個group中的事務的last_commit總是為當前group中最小的sequence_number - 1,即,如果SQL協調器執行緒讀取到的當前事務的last_commit小於當前已執行完成事務的最小的sequence_number 就說明當前所有worker執行緒正在執行的事務處於同一個group中,那麼也就是說SQL協調器執行緒可以繼續往下尋找空閒的worker執行緒進行分發,否則SQL協調器執行緒就需要進行等待)。

    * SQL協調器執行緒透過統計worker執行緒返回的狀態資訊,尋找一個空閒的worker執行緒,如果沒有空閒的執行緒,則SQL協調器執行緒需要進行等待,知道找到一個空閒的worker執行緒為止(如果有多個worker執行緒,則SQL協調器執行緒隨機選擇一個空閒的worker執行緒進行分發)。

    * 將當前讀取到的事務的binlog event分發給選定的空閒worker執行緒,之後worker執行緒會去應用這個事務,然後SQL協調器執行緒繼續讀取新的binlog event(注意,SQL協調器執行緒分發是按照event為單位的,不是事務單位,所以,如果當一個事務的第一個event分發給了給定worker執行緒之後,後續讀取到的新的event如果同屬於一個事務,則進入下一個事務之前的所有event都會分發給同一個worker執行緒處理。 當一個事務中所有的binlog event組分發完成,讀取到下一個新的事務時,SQL協調器執行緒會重複以上判斷流程)。

從庫多執行緒複製的crash recovery。

  • 從前面多執行緒複製分發的原理我們可以知道,處於同一個group中的事務是並行應用的,且事務是隨機分配的,在從庫正常執行過程當中,如果任意掐一刻下去,那麼所有worker執行緒正在執行的事務中,哪些是已經執行完成的,哪些還未執行完成其實是無法使用單個位置來確定(因為從庫並行複製時有可能是亂序提交: 需要看slave_preserve_commit_order變數如何設定),也就是說所有worker執行緒中正在執行的最大位置和最小位置之間可能有斷點。那MySQL是如何解決從庫crash recovery的斷點續做問題的呢?

  • MySQL 為了解決這個問題,對worker執行緒的執行狀態做了很多記錄工作,首先,維護了一個佇列,這個佇列叫做GAQ(Group Assigned Queue),當SQL協調器執行緒在分配某一個事務時,首先會將這個事務加入到這個佇列,然後,才會去按照規則來尋找一個空閒的worker執行緒來執行,如下圖(鄭重宣告: 該圖來自書籍《MySQL 運維內參》):

    複製資訊記錄表|全方位認識 mysql 系統庫

每一個事務在分發到worker執行緒之後,都會分配一個編號,這個編號在某一段時間內,都是相對固定的,這個編號一旦被分配,就不會再改變。 在事務被某個worker執行緒執行完成之後,它的位置資訊就會被flush一次,這與5.5版本中的relay_log_info記錄的原理是類似的(relay_log_info中存放了從庫當前SQL執行緒重放的位置),但是現在是多執行緒,每個worker執行緒的執行位置不能直接存放在relay_log_info中了,relay_log_info中存放的是所有worker執行緒彙總之後的位置,每個worker執行緒獨立的位置資訊存放在了mysql.slave_worker_info表中,在該表中,有多少個並行複製執行緒,就有多少行記錄(如果是多主複製,則每個複製通道都有slave_parallel_workers變數指定的記錄數)。

mysql.slave_worker_info表中,Checkpoint開頭的欄位記錄了每個worker執行緒的檢查點相關的資訊(這裡與innodb儲存引擎的檢查點不同,但是概念相通),worker執行緒的檢查點的作用是什麼呢?

  • 前面說了SQL協調器執行緒在分配事務給worker執行緒之前會將事務先存放到GAQ佇列中,但是這個佇列的長度是有限的(是不是很熟悉? 跟redo log的總大小是有限的概念類似),不可能無限制的增長下去,所以必須要在這個佇列中,找到一個位置點,這個位置點就是GAQ的起點位置,這個位置點之前的binlog就表示已經執行完成了。確定這個位置的過程,就叫做檢查點。在多執行緒複製的執行過程中,隨著每個worker執行緒不斷第應用事務的binlog,檢查點在GAQ中被不斷地向前推進,每個worker執行緒透過Checkpoint_point_bitmap欄位記錄自己已經執行過的事務和每個已執行事務與之對應的當時的最新檢查點的相對位置,這樣一來,當複製意外終端之後,重新開始複製時,就可以透過所有的worker執行緒記錄的Checkpoint_point_bitmap欄位來計算出哪些事務是已經執行過的,哪些事務是還未執行的,即透過所有worker執行緒記錄的Checkpoint_point_bitmap資訊執行一次檢查點操作就可以找到一個合適的恢復位置,執行檢查點的大概過程如下(注意:這裡是執行檢查點的過程,與從庫crash recovery過程無關):

    * 在GAQ佇列中,從尾部開始掃描,如果是已經執行過的事務,則直接將其從佇列中刪除。

    * 持續掃描GAQ佇列,直到找到一個未執行過的事務為止即停止掃描。

    * 上述步驟中掃描動作停止前掃描到的最後一個事務被確定為檢查點的最新位置,並且別標記為LWM(低水位線標記)。

    * 將當前LWM這個事務對應的位置(master_log_pos和relay_log_pos位置)設定為此次檢查點對應的位置。

    * 透過所有的worker執行緒檢查自己的檢查點,也就是檢視每個worker執行緒自己的Checkpoint_seqno欄位值,這個欄位值是每個worker執行緒在執行事務提交時更新的,更新的欄位值為每個worker執行緒在做事務提交時對應的最新檢查點的相對位置。

    * 將本次執行檢查點的位置記錄到mysql.slave_relay_log_info表中,作為全域性bin log應用的位置。

  • 現在,我們來看從庫crash recovery的過程:

    * 首先,讀取mysql.slave_master_info、mysql.slave_relay_log_info、mysql.slave_worker_info表中的資訊讀取出來,從mysql.slave_master_info表中找到連線主庫的資訊,從mysql.slave_relay_log_info表中找到全域性最新的複製位置以及worker執行緒個數,從mysql.slave_worker_info表中找到每一個worker執行緒對應的複製資訊位置。

    * 然後,根據mysql.slave_relay_log_info表中的位置(這個位置就是全域性最新的檢查點位置)為準來判斷所有worker執行緒的位置,在這個位置之前的worker執行緒位置就表示已經執行過的了,直接剔除,在這個位置之後的worker執行緒位置就表示這些事務是還沒有執行過的(根據每個worker執行緒在mysql.slave_worker_info表中記錄的Checkpoint_seqno和Checkpoint_group_bitmap欄位計算出自己哪些事務沒有執行過,然後透過每個worker執行緒在mysql.slave_worker_info表中記錄的其他checkpoint欄位資訊轉換為對應的全域性檢查點的位置。 然後根據所有worker執行緒的轉換位置資訊彙總為一個共同的bitmap,根據這個共同的bitmap來比對mysql.slave_relay_log_info表中的位置就可以提取出哪些事務還沒有執行過),找出了哪些事務還沒有執行之後,把這些事務序列地一個一個地去重新應用(應用一個更新一次mysql.slave_relay_log_info表,為什麼要序列,這是為了在恢復過程中如果再次跪了,還可以正確地恢復位置),應用完成之後清空mysql.slave_worker_info表。然後啟動複製執行緒,繼續從主庫拉取最新的binlog進行資料複製。

PS: 如果在主從複製架構中,有2個以上的從庫,且從庫永遠不做提升主庫的操作時,可以使用如下方法最佳化從庫延遲(在該場景下,從庫無需擔心資料丟失問題,因為有另外一個從庫兜底+不做主從切換,只需要專心提供快速應用主庫binlog與只讀業務即可)。

  • 關閉log_slave_updates引數,減少從庫binlog寫入量(如果不做級聯複製甚至可以同時關閉binlog)。

  • 設定innodb_flush_log_at_trx_commit為0或者2,減少事務提交時redo log的等待頻率。

  • 設定sync_binlog為預設值或者更大的值,減少事務提交時binlog的等待頻率。

  • 設定slave_preserve_commit_order引數為OFF(預設為OFF,設定為ON時要求開啟binlog和log_slave_updates引數),減少事務嚴格按照主庫順序提交時的提交等待時間。

2.4. gtid_executed

前面介紹的三張表中,存放的都不包括GTID資訊,在資料庫執行過程中,GTID相關的資訊是儲存在performance_schema下的相關表中,詳見"全方位認識 performance_schema"系列文章《複製狀態與變數記錄表 | performance_schema全方位介紹》。 但是performance_schema下的表都是記憶體表,記錄的資訊是易失的。gtid_executed表才是GTID資訊的持久表,該表提供查詢與當前例項中的資料一致的GTID集合(該表用於儲存所有事務分配的 GTID集合,GTID集合由UUID集合構成,每個UUID集合的組成為:uuid:interval[:interval]...,例如 :28b13b49-3dfb-11e8-a76d-5254002a54f2:1-600401, 3ff62ef2-3dfb-11e8-a448-525400c33752:1-110133)

  • GTID是在整個複製拓撲中是全域性唯一的,GTID中的事務號是一個單調遞增的無間隙數字。 正常情況下,客戶端的資料修改在執行commit時會分配一個GTID,且會記錄到binlog中,這些GTID透過複製元件在其他例項中進行重放時也會保留GTID來源不變。但是如果客戶端自行使用sql_log_bin變數關閉了binlog記錄或者客戶端執行的是一個只讀事務,那麼server不會分配GTID,在binlog中也不會有GTID記錄。

  • 當某個從庫接受到自己的GTID集合中已經包含的GTID時,會忽略這個已存在的GTID,並且不會報錯,事務也不會被執行。

從MySQL 5.7.5開始,GTID儲存在mysql資料庫的名為gtid_executed的表中。 對於每個GTID集合,預設情況下值記錄每個GTID集合的起始和結束的事務號對應的GTID,該表只在資料庫初始化或者執行update_grade升級的時候建立,不允許手工建立於修改。當例項本身有客戶端訪問資料寫入或者有從其他主庫透過複製外掛同步資料的時候,該表中會有新的GTID記錄寫入,另外,該表中的記錄還會在binlog滾動或者例項重啟的時候被更新(日誌滾動時該表需要把除了最新的binlog之外其他binlog中的所有GTID結合記錄到該表中,例項重啟時,需要把所有的binlog中的GTID集合記錄到該表中)。

由於有mysql.gtid_executed表記錄GTID(避免了binlog丟失的時候丟失GTID歷史記錄),所以,從5.7.5版本開始,在複製拓撲中的從庫允許關閉binlog,也允許在binlog開啟的情況下關閉log_slave_updates變數。

由於GTID必須要再gtid_mode為ON或者為ON_PERMISSIVE時才會生成,所以自然該表中的記錄也需要依賴於gtid_mode變數為ON或ON_PERMISSIVE時才會進行記錄,另外,該表中是否實時儲存GTID,取決於binlog日誌是否開啟,或者binlog啟用時是否啟用log_slave_updates變數,如下:

  • 當禁用二進位制日誌記錄(log_bin為OFF),或者啟用binlog但禁用log_slave_updates,則Server會在每個事物提交時把屬於該事物的GTID同時更新到該表中。 此時,該表的GTID週期性自動壓縮功能啟用,每達到gtid_executed_compression_period系統變數指定的事物數量壓縮一次該表中的GTID集合(也就是把每個UUID對應的事務號的記錄取一個最大值,取一個最小值,刪除中間值),要注意:週期性自動壓縮功能僅針對從庫,對主庫無效,因為主庫必須啟用binlog,且log_slave_updates引數不影響主庫。

  • 如果啟用二進位制日誌記錄(log_bin為ON)且log_slave_updates引數也啟用,則週期性自動壓縮功能失效,該表中的記錄只會在binlog日誌滾動或者伺服器關閉時才會進行壓縮,且會把除了最後一個binlog之外,其他所有binlog中包含的GTID集合寫入該表中。

  • 注意:

    * 如果啟用二進位制日誌記錄(log_bin為ON)且log_slave_updates引數也啟用,那麼該表不會實時記錄GTID,也就是說,完整的GTID集合,有一部分記錄在該表中,有一部分是記錄在binlog中的,如果一旦server發生crash,那麼在crash recovery時會讀取binlog中最新的GTID集合併合併到該表中。

    * 該表中的記錄在執行reset master語句時會被清空。

該表中的記錄週期性執行壓縮示例。

# 假設表中有如下實時記錄的GTID記錄
mysql> SELECT * FROM mysql.gtid_executed;
+ -------------------------------------- + ---------- ------ + -------------- +
| source_uuid | interval_start | interval_end |
| -------------------------------------- + ---------- ------ + -------------- |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 37 | 37 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 38 | 38 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 39 | 39 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 40 | 40 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 41 | 41 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 42 | 42 |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 43 | 43 |
...
# 那麼,每達到gtid_executed_compression_period變數定義的事務個數時,啟用壓縮功能,GTID被壓縮為一行記錄,如下
+ -------------------------------------- + ---------- ------ + -------------- +
| source_uuid | interval_start | interval_end |
| -------------------------------------- + ---------- ------ + -------------- |
| 3E11FA47-71CA-11E1-9E33-C80AA9429562 | 37 | 43 |
...
# 注意:當gtid_executed_compression_period系統變數設定為0時,週期性自動壓縮功能失效,你需要預防該表被撐爆的風險

表欄位含義。

  • source_uuid: 代表資料來源的GTID集合。

  • interval_start: 每個UUID集合的最小事務號。

  • interval_end: 每個UUID集合的最大事務號。

對該表的壓縮功能由名為 thread/sql/compress_gtid_table 的專用前臺執行緒執行。 該執行緒使用SHOW PROCESSLIST無法檢視,但它可以在performance_schema.threads表中檢視到(執行緒 thread/sql/compress_gtid_table 大多數時候都處於休眠狀態,直到每滿gtid_executed_compression_period個事務之後,該執行緒被喚醒以執行前面所述的對mysql.gtid_executed表的壓縮。然後繼續進入睡眠狀態,直到下一次滿gtid_executed_compression_period個事務,然後被喚醒再次執行壓縮,以此類推,無限重複此迴圈。但如果當關閉binlog或者啟用binlog但關閉log_slave_updates變數時,gtid_executed_compression_period變數被設定為了0,那麼意味著該執行緒會始終處於休眠狀態且永不會喚醒),如下所示:

mysql> SELECT * FROM performance_schema.threads WHERE NAME LIKE '%gtid%'\G
*************************** 1. row ***************************
          THREAD_ID: 26
               NAME: thread/sql/compress_gtid_table
               TYPE: FOREGROUND
     PROCESSLIST_ID: 1
   PROCESSLIST_USER: NULL
   PROCESSLIST_HOST: NULL
     PROCESSLIST_DB: NULL
PROCESSLIST_COMMAND: Daemon
   PROCESSLIST_TIME: 1509
  PROCESSLIST_STATE: Suspending
   PROCESSLIST_INFO: NULL
   PARENT_THREAD_ID: 1
               ROLE: NULL
       INSTRUMENTED: YES
            HISTORY: YES
    CONNECTION_TYPE: NULL
       THREAD_OS_ID: 18677

2.5. ndb_binlog_index

該表提供查詢ndb叢集引擎相關的統計資訊,由於國內較少使用NDB儲存引擎,這裡不做過多介紹,有興趣的朋友可自行研究。

本期內容就介紹到這裡,本期內容參考連結如下:

https://dev.mysql.com/doc/refman/5.7/en/replication-gtids-concepts.html#replication-gtids-gtid-executed-table


"翻過這座山,你就可以看到一片海! "。 堅持閱讀我們的"全方位認識 mysql 系統庫"系列文章分享,你就可以系統地學完它。 謝謝你的閱讀,我們下期不見不散!



| 作者簡介

羅小波·沃趣科技高階資料庫技術專家

IT從業多年,主要負責MySQL 產品的資料庫支撐與售後二線支撐。曾參與版本釋出系統、輕量級監控系統、運維管理平臺、資料庫管理平臺的設計與編寫,熟悉MySQL體系結構,Innodb儲存引擎,喜好專研開源技術,多次在公開場合做過線下線上資料庫專題分享,發表過多篇資料庫相關的研究文章。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28218939/viewspace-2661510/,如需轉載,請註明出處,否則將追究法律責任。

相關文章