GTID複製的工作原理

来源:https://www.cnblogs.com/leohahah/archive/2019/09/17/11533952.html
-Advertisement-
Play Games

參考自:https://dev.mysql.com/doc/refman/5.7/en/replication-gtids-lifecycle.html 筆記說明: 本文翻譯自官網,當然會根據語義做一些解釋或總結簡化,有些地方為了理解順暢也有刪減,有些地方直接翻為中文略顯生硬,如有疑問請直接參考上述 ...


參考自:https://dev.mysql.com/doc/refman/5.7/en/replication-gtids-lifecycle.html

筆記說明:

本文翻譯自官網,當然會根據語義做一些解釋或總結簡化,有些地方為了理解順暢也有刪減,有些地方直接翻為中文略顯生硬,如有疑問請直接參考上述鏈接中的原文。

本文主要介紹GTID的生成方式、基於GTID的主從同步時的工作機制,對於如何搭建GTID主從複製以及GTID主從複製為何可以實現並行複製的原理未做詳細介紹,後者原理可以參考innodb二階段日誌提交機制和組提交解析理解。

關於如何搭建基於GTID的主從複製以及在主從同步失敗時進行搶救,參考:How to create/restore a slave using GTID replication in MySQL 5.6

基於GTID的主從同步在出現問題時,除了手動的重新開啟下同步進程你能做的操作很少,相比之下原始的基於binlog pos的複製比較靈活,為了避免這種情況發生有必要探究一下基於GTID複製的工作機制,以便在主從同步異常時有效的進行修複。

本文的主要目的就是搞清GTID的生成和使用機制,搞清基於GTID複製的主要流程和核心參數,保證在GTID複製出現問題時可以通過靈活的處理相關參數來拯救主從複製。

一、GTID的生命周期如下:

1. 當事務於主庫執行時,系統會為事務分配一個由server uuid加序列號組成的GTID(當然讀事務或者被主動過濾掉的事務不會被分配GTID),寫binlog日誌時此GTID標志著一個事務的開始。GTID的格式如下所示:

GTID = source_id:transaction_id
# source_id為server的uuid
# transaction_id是一個表示事務執行順序的序列號,例如第一個執行的事務transaction_id為1,第10個為10
# GTID = <server uuid>:1-10表示從1-10的10個事務的集合,稱作gtid set

2. binlog中寫GTID的event被稱作Gtid_log_event,當binlog切換或者mysql服務關閉時,之前binlog中的所有gtid都會被加入mysql.gtid_executed表中。此表內容如下(slave中此表記錄數會有多條,取決於主從個數):

mysql> select * from mysql.gtid_executed;
+--------------------------------------+----------------+--------------+
| source_uuid                          | interval_start | interval_end |
+--------------------------------------+----------------+--------------+
| 71cf4b9d-8343-11e8-97f1-a0d3c1f25190 |              1 |    653948549 |
+--------------------------------------+----------------+--------------+

3. 當GTID被分配且事務被提交後,他會被迅速的以一種外部的、非原子性的方式加入@@GLOBAL.gtid_executed參數中,這個參數包含了所有被提交的GTID事務(其實他是一個GTID範圍值,例如71cf4b9d-8343-11e8-97f1-a0d3c1f25190:1-10),@@GLOBAL.gtid_executed也被用於主從複製,表示資料庫當前已經執行到了哪個事務。相比之下mysql.gtid_executed不能用於標識主庫當前事務進度,畢竟他只有在binlog切換時才會將日誌中的GTID加入(mysql服務關閉也相當於binlog切換)。

4. 在主從首次同步時(master_auto_position=1),slave會通過gtid協議將自己已經執行的gtid set(@@global.gtid_executed)發給master,master比較後從首個未被執行的GTID事務開始主從同步。

5. 當事務隨binlog被傳輸至slave後,slave每次讀到Gtid_log_event就把自己的gtid_next參數設為此GTID,需要註意的是這裡的gtid_next是在複製進程的session context中自動設置的(由binlog提供的語句),不同於show variables like 'gtid_next';這裡看到的結果預設為AUTOMATIC,是當前會話本身的gtid_next,這是個session級別的參數。

6. 當開啟並行複製時,slave會讀取並檢查事務的GTID確保當前GTID事務未被在slave執行過,且沒有並行進程在讀取並執行此事務,如果有並行複製進程正在應用此事務那麼slave server只會允許一個進程繼續執行,@@GLOBAL.gtid_owned參數展示了當前哪個並行複製進程在執行什麼事務。

7. 同樣的,在slave上如果開啟了binlog,GTID也會以Gtid_log_event事件寫入binlog,同時binlog切換或者mysql服務關閉時,當前binlog中的所有gtid都會被加入mysql.gtid_executed表中。

8. 在備庫上如果未開啟binlog,那麼GTID會被直接持久化到mysql.gtid_executed表中,在這種情況下slave的mysql.gtid_executed表包含了所有已經被執行的事務。需要註意的是在mysql5.7中,向mysql.gtid_executed表插入GTID的操作與DML操作是原子性的,對於DDL操作則不是,因此如果slave在執行DDL操作的過程中異常中斷那麼GTID機制可能會失效。在mysql8.0中這個問題已經得到解決,DDL操作的GTID插入也是原子性的。

9. 同第3條中所說的一樣,slave上的事務被執行後GTID也會被迅速的以一種外部的、非原子性的方式加入@@GLOBAL.gtid_executed參數中,在slave的binlog未開啟時mysql.gtid_executed中記載的已提交事務事實上與@@GLOBAL.gtid_executed記載的是一致的,如果slave的binlog已開啟那麼mysql.gtid_executed的GTID事務集就沒有@@GLOBAL.gtid_executed全了。

主從同步補充說明:

slave會完全繼承master的GTID,因此如果slave的binlog開啟那麼即便事務在slave上什麼也沒做,還是會產生一個Gtid_log_event,只不過之後會跟一個空事務,即begin;commit;。

這種slave空事務的可能產生場景是在master上手動設置了gtid_next並且什麼都沒做,這樣就會在binlog里產生一個空事務,雖然這個空事務什麼都沒做,slave依然要把他寫入自己的binlog中。

這樣做的好處是可以使mysql.gtid_executed和@@GLOBAL.gtid_executed記載的gtid set保持連貫。另一個好處是在主從同步中斷後重新開啟同步時可以防止再次同步那些過濾掉的GTID事務。

這可以印證一種slave跳過錯誤事務的方法,即stop slave;set gtid_next='要跳過的事務GTID';begin;commit;set gtid_next=AUTOMATIC;start slave;但是在跳過錯誤事務之前,請使用show binlog events in 'log_name' from pos limit ...語句和mysqlbinlog工具確保你要跳過的事務不包含重要的數據更改。 

並行複製的情境下,slave的GTID事務的提交順序可能與主庫不一樣,因為binlog的組提交機制允許同一組內的日誌記載的事務並行執行,其原理這裡不詳細描述,這會導致@@global.gtid_executed參數的值可能包含gtid gap,即@@global.gtid_executed中包含的事務序列號可能是不連貫的,如果使用stop slave來停止主從同步那麼複製進行會先把這些gap填上再停止,但如果主庫或從庫是異常關機的那麼這些gap可能會依然存在,這會導致你需要重新搭建主從複製,除非你自己確認這些gap事務是無影響可以跳過的。

二、一些GTID分配的其他情況:

GTID並非只會被分配給事務,一個事務也可能會被分配多個GTID。

首先解釋第一句:

除了正常的DML,DDL事務外,創建、修改、刪除一個database也會被分配一個GTID,此外procedure, function, trigger, event, view, user, role等對象的增刪改也會被分配一個GTID,此外grant操作也會被分配一個GTID。

另外對於類似myisam類型的表,雖然不涉及事務也還是會被分配GTID的,而且一旦此類不支持事務的存儲引擎的表的更改發生binlog落盤的錯誤時,binlog就會記載一次gap,對於這個binlog gap也會分配一個GTID給這個log event。

如之前所說的,master上rollback的事務不會被分配GTID,此外通過SET @@SESSION.sql_log_bin = 0;主動關閉會話binlog當然也不會為事務分配GTID了,畢竟連binlog都不會產生。

然後解釋第二句:

對於XA事務(分散式事務),一個事務會有多個GTID,而且就算其中一段事務被回滾也會被分配一個GTID。

此外在以下幾種情況下一條語句會產生多個事務,因此會被分配多個GTID:

  • 一個存儲過程中包含多個事務。
  • 使用一條drop table語句drop多個不同類型的表。
  • CREATE TABLE ... SELECT語句,create table產生一個GTID,插入數據產生一個GTID。

三、系統參數gtid_next和gtid_purged以及gtid_executed:

gtid_next:

  • 當gtid_next設為AUTOMATIC(預設)時,每個事務被提交時都會分配一個自增的GTID(這裡主要是說master),如果事務被回滾那麼GTID不會被分配。
  • 如果將gtid_next設為一個合法的GTID值,那麼mysql server就會將此GTID設為你當前事務的GTID,即便你不作任何操作甚至設置sql_log_bin=0,此GTID也會被記錄入binlog。

需要註意的是如果你手動的將@@session.gtid_next設為一個GTID值,那麼在執行完事務後請務必重新將其設置為AUTOMATIC。

當slave的SQL thread進程應用事務時,他們會根據binlog日誌的記載將自己的@@SESSION.gtid_next設為即將要重放的事務的GTID,等到重放完畢後,還會把這個GTID加入@@global.gtid_executed。

總結下就是:此參數在事實上提供了手動跳過事務的方法,在主從同步需要跳過錯誤事務時很有用。

gtid_purged和gtid_executed:

此參數表示所有已經被提交但是在所有binlog中都找不到相關GTID的事務們,gtid_purged是gtid_executed的一個子集,其涉及到的場景主要是:

  • slave上禁用了binlog,那麼所有重放的GTID事務都會被加入gtid_purged。
  • 包含相應GTID事務的binlog已經被刪除,這些已提交事務會被加入gtid_purged。
  • 通過SET @@GLOBAL.gtid_purged語句手動的將某些gtid加入gtid_purged的gtid set。

你可以通過修改@@GLOBAL.gtid_purged的值告訴slave:雖然已經無法在binlog中找到相關的GTID記錄了,但放心這些gtid set內的事務已經被應用過了,本人親自作保的!

此參數一個經典的應用場景是:你在搭建主從時使用mysqldump在slave server上恢復了備份,但是因為備份前未開啟GTID導致恢復後的資料庫並沒有gtid_executed和gtid_purged信息,因此指定gtid_mode=ON以及master_auto_position=1開啟GTID同步時slave嘗試同步master從uuid:1開始的所有GTID事務,這當然不是我們想要的也肯定會遇到錯誤。在mysql 5.7之後你可以通過只修改@@GLOBAL.gtid_purged的值來為slave同步的master_auto_position=1指明起始GTID(我認為官網這句話的意思是在5.7之前可能要連gtid_executed一併指定,具體未測試懶得做測試啦)。

gtid_executed和gtid_purged的值是在資料庫服務啟動時初始化的,每個binlog的初始event(其實是第2個啦,第一個是pos=4的Format_desc)都是Previous_gtids_log_event(通過SHOW BINLOG EVENTS [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]查看),這個event包含了之前所有binlog files的GTID set(一般是uuid:1-<最新的事務序列號>),gtid_executed只需要看最新一個binlog的Previous_gtids_log_event的值即可,gtid_purged的值則是最新的binlog文件的Previous_gtids_log_event的值減去最老binlog文件的Previous_gtids_log_event的值。

gtid_executed的值會隨著事務的生成不斷更新,但不包含@@GLOBAL.gtid_owned的GTID,@@GLOBAL.gtid_owned表示當前資料庫正在執行的GTID事務。

在MySQL5.7.7版本之前,gtid_executed和gtid_purged的值可能會錯誤的生成,這姑且一個BUG,你可能需要將 binlog_gtid_simple_recovery 設為FALSE重新啟動DB伺服器來處理這個BUG,將此參數設為FALSE後,DB server在啟動時會遍歷所有binlog文件以便正確計算gtid_executed和gtid_purged的值,如果你有很多未開啟GTID模式時就存在的binlog,可能會導致重啟花費很長時間。

因此還是推薦在mysql5.7.8之後的版本上啟用GTID複製,以前的版本能用傳統複製就用傳統複製吧。

四、通過reset master重置GTID的自增序列號

如果你想要重置GTID的事務序列號,那麼需要執行下reset master,這會清除@@global.gtid_executed和@@global.gtid_purged的值,並且會清除以前的binlog和序列號,重新開啟一個類似於binlog.0001的binlog,如果未開啟binlog,那麼reset master至少也會清除掉@@global.gtid_executed和@@global.gtid_purged的值。

請謹慎的使用reset master以防止主從同步的事務丟失,為很好的把握此語句的使用情景需要非常瞭解他的作用和影響,以下為使用reset master時的一些註意事項:

在reset master之前,請確保你已經備份了當前資料庫的binlog文件和binlog index file,同時確保記下當前的@@global.gtid_executed和@@global.gtid_purged值。

reset master實際上做了以下操作:

  • 將gtid_purged參數設為空字元
  • 將gtid_executed設為空字元
  • 清空mysql.gtid_executed表
  • 如果DB server開啟了binlog,那麼reset master還會清除所有binlog文件和binlog index file,然後以初始的自增序列號1開啟一個新的binlog

此外要說明的是,無論是reset slave還是reset slave all都不會清除@@global.gtid_executed和@@global.gtid_purged的值。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • vim /usr/lib/systemd/system/docker.service ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock systemctl daemon-reload // 1 ...
  • 許多學習過redhat 7的同學們,在使用centos的時候總會遇到一些問題,因為centos在安裝時會預設開啟一些服務,今天我們就來更改下centos 7.0的SSH埠。 操作步驟: 遠程登錄到centos 7.0終端; 修改 /etc/ssh 文件夾中的 sshd_config文件 在文件中找 ...
  • 現在很多企業和公司管理伺服器時都是通過網路監控軟體對伺服器的狀態進行監控,在監控的時候大多是通過SNMP協議(簡單網路管理協議)進行的,那麼在我們的伺服器端就需要開啟此項服務,併進行簡單的設置。 以下是windows2008 SNMP服務的開啟和設置方式 一、開啟服務: 進入系統後,進入控制面板,點 ...
  • 一·大數據概述 隨著信息技術發展的巨大變革,企業和學術機構紛紛加大技術、資金和人員投入,加強對大數據關鍵技術的研發與運用。 大數據的發展歷程總體上劃分為三個重要階段:萌芽期、成熟期和大規模應用期。 二.大數據概念 大數據的4個特點:數據量大、數據類型繁多、處理速度快和價值密度低。 三.大數據與雲計算 ...
  • 資料庫是一個存儲數據的倉庫,主要用在:金融機構、游戲網站、購物網站、論壇網站,現在的主流資料庫有:MySQL、SQL_Server、Oracle、Mariadb、DB2、MongoDB ... 那麼我們在生產環境中,如何選擇使用哪個資料庫 1. 是否開源 開源軟體:MySQL、Mariadb、Mon ...
  • 數據類型是定義列中可以存儲什麼數據以及該數據實際怎麼存儲的基本規則。Mysql的常用數據類型主要有: 數據類型 說明 CHAR 1~255個字元的定長串,它的長度必須在創建時指定,否則MySQL假定為CHAR(1) VARCHAR 可變長度,最多不超過255位元組,如在創建時指定VARCHAR(n), ...
  • 本次主要記錄一下linux下mysql資料庫的一些問題,也是之前經常用到的知識,這裡簡單總結一些問題,方便自己以後的回顧。原來一直使用的是阿裡雲的RDS資料庫mysql版,主要是因為上次阿裡雲做活動可以免費用6個月,所以就體驗了一把,反正是免費嘛。最近也是到期了,反正自己也有伺服器,就不必再單獨開一 ...
  • 1.下載並安裝MySQL官方的 Yum Repository 2.MySQL資料庫設置 啟動MySQL 查找MySQL的預設密碼 進入資料庫 輸入初始密碼,如下命令修改密碼 此時還有一個問題,之前安裝了Yum Repository,以後每次yum操作都會自動更新,需要把這個卸載掉 進入資料庫允許遠程 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...