一次關于 MySQL 主從模式采用 GTID 的實踐記錄

一雹食、背景

為了保證高可用缓屠,之前在測試環(huán)境部署了一套 MySQL 雙主模式奇昙,當一個主庫服務出現(xiàn)異常,可以將流量切到另外一個主庫敌完,兩個主庫之間相互同步數(shù)據(jù)储耐。

雙主模式

雙主模式的原理圖如下:

圖片

但是經(jīng)常出現(xiàn)數(shù)據(jù)沖突的問題,于是我們又把雙主模式改為了主從讀寫分離模式滨溉。主庫作為讀寫庫什湘,再加上一個從庫用來做 I/O 密集型的任務(如大量的數(shù)據(jù)統(tǒng)計操作)。如下圖所示:

圖片

另外從庫復制的模式采用位點的方式:指定 binlog 文件和 binlog 位置晦攒,這樣從庫就知道了復制的起始位置闽撤。(下文會講解這種方式)

雖然改為了主從模式,但依舊遇到了些問題:

  • 問題 1:從庫 B 復制數(shù)據(jù)時脯颜,出現(xiàn)了主鍵沖突問題哟旗,導致同步失敗,從庫停止復制栋操。猜測因主庫配置的 binlog 日志的格式為 mixed闸餐,從庫同步時出現(xiàn)不一致的情況。
  • 問題 2:從庫 B 停止復制后矾芙,導致很多數(shù)據(jù)未同步到從庫舍沙,出現(xiàn)主從大量數(shù)據(jù)不一致的情況。
  • 問題 3:從庫 B 想要恢復復制剔宪,必須先解決同步失敗的問題才能恢復拂铡。排查難度較大壹无,耗時。
  • 問題 4:從庫 B 恢復時和媳,必須知道同步位點格遭,也就是從哪個 binlog 文件和 binlog 位置斷開復制的,且即使找到了位點留瞳,也不是精確的拒迅。
  • 問題 5:從庫 B 因同步異常導致停止復制到恢復復制這段期間,主庫 A 自動清理了幾天前的 binlog 日志她倘,而這些日志從庫 B 還未來得及同步璧微,進而導致再次同步失敗。
  • 問題 6:主從存在同步延遲硬梁。

這篇我們來探討下問題 4 和問題 6前硫。

其中問題 4 是一個比較頭疼的問題,我們一般是通過查看從庫 B 當前的同步狀態(tài)拿到同步位點荧止,然后設置同步位點后屹电。但是重新啟動同步的時候又會出現(xiàn)同步異常,比如從庫 B 可能會出現(xiàn) Duplicate entry ‘id_of_R’ for key ‘PRIMARY’ 錯誤跃巡,提示出現(xiàn)了主鍵沖突危号,然后停止同步。

為了減少位點同步引入的復雜度素邪,我們切換成了 GTID 模式外莲。

對于問題 6,本篇也僅限于探討如何觀察延遲兔朦,對于如何減少延遲不在本篇探討范圍之內(nèi)偷线。

接下來我們來展開看下位點同步的痛點。

二沽甥、位點同步的痛點

2.1 通過位點同步的原理圖

為了更清晰地理解主從采用位點同步的原理声邦,這里有一個原理圖:

圖片

1、主庫會生成多個 binlog 日志文件安接。

2翔忽、從庫的I/O 線程請求指定文件和指定位置的 binlog 日志文件(位點)。

3盏檐、主庫 dump 線程獲取指定位點的 binlog 日志歇式。

4、主庫按照從庫發(fā)送給來的位點信息讀取 binlog胡野,然后推送 binlog 給從庫材失。

5、從庫將得到的 binlog 寫到本地的 relay log (中繼日志) 文件中硫豆。

6龙巨、從庫的 SQL 線程讀取和解析 relay log 文件笼呆。

7、從庫的 SQL 線程重放 relay log 中的命令旨别。

當我們使用位點同步的方式時诗赌,兩種場景下的操作步驟比較復雜。

2.2 痛點

痛點1:首次開啟主從復制的步驟復雜

  • 第一次開啟主從同步時秸弛,要求從庫和主庫是一致的铭若。
  • 找到主庫的 binlog 位點。
  • 設置從庫的 binlog 位點递览。
  • 開啟從庫的復制線程叼屠。

痛點2:恢復主從復制的步驟復雜

  • 找到從庫復制線程停止時的位點。
  • 解決復制異常的事務绞铃。無法解決時就需要手動跳過指定類型的錯誤镜雨,比如通過設置slave_skip_errors=1032,1062。當然這個前提條件是跳過這類錯誤是無損的儿捧。(1062 錯誤是插入數(shù)據(jù)時唯一鍵沖突荚坞;1032 錯誤是刪除數(shù)據(jù)時找不到行)

不論是首次開啟同步時需要找位點和設置位點,還是恢復主從復制時菲盾,設置位點和忽略錯誤西剥,這些步驟都顯得過于復雜,而且容易出錯亿汞。所以 MySQL 5.6 版本引入了 GTID,徹底解決了這個困難揪阿。

三疗我、GTID 方案

3.1 GTID 是什么?

GTID 的全稱是 Global Transaction Identifier南捂,全局事務 ID吴裤,當一個事務提交時,就會生成一個 GTID溺健,相當于事務的唯一標識麦牺。

GTID 長這樣:

<pre data-tool="mdnice編輯器" style="margin: 10px 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; color: rgb(53, 53, 53); font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.8px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0.8px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">c5d74746-d7ec-11ec-bf8f-0242ac110002:1 </pre>

結(jié)構(gòu):

<pre data-tool="mdnice編輯器" style="margin: 10px 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; color: rgb(53, 53, 53); font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.8px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0.8px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">GTID=server_uuid:gno </pre>

server_uuid 是一個實例第一次啟動時自動生成的,是一個全局唯一的值鞭缭;

gno 是一個整數(shù)剖膳,初始值是 1,每次提交事務的時候分配給這個事務岭辣,并加 1吱晒。

每個 MySQL 實例都維護了一個 GTID 集合,用來對應“這個實例執(zhí)行過的所有事務”沦童。

3.2 GTID 的優(yōu)勢

  • 1仑濒、更簡單的實現(xiàn) failover叹话,不用以前那樣在需要找位點(log_file 和 log_pos)。

  • 2墩瞳、更簡單的搭建主從復制驼壶。

  • 3、比傳統(tǒng)的復制更加安全喉酌。

  • 4热凹、GTID是連續(xù)的沒有空洞的,保證數(shù)據(jù)的一致性瞭吃,零丟失碌嘀。

3.3 如何啟用 GTID

修改主庫和從庫的配置文件:

<pre data-tool="mdnice編輯器" style="margin: 10px 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; color: rgb(53, 53, 53); font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.8px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0.8px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">#GTID: gtid_mode=on enforce_gtid_consistency=on </pre>

從庫配置同步的參數(shù):

<pre data-tool="mdnice編輯器" style="margin: 10px 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; color: rgb(53, 53, 53); font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.8px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0.8px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">CHANGE MASTER TO MASTER_HOST=$host_name MASTER_PORT=$port MASTER_USER=$user_name MASTER_PASSWORD=$password master_auto_position=1 </pre>

其中 master_auto_position 標識主從關系使用的 GTID 協(xié)議。

相比之前的配置歪架,MASTER_LOG_FILE 和 MASTER_LOG_POS 參數(shù)已經(jīng)不需要了股冗。

3.4 GTID 同步方案

GTID 同步的原理圖。

GTID 方案:主庫計算主庫 GTID 集合和從庫 GTID 的集合的差集和蚪,主庫推送差集 binlog 給從庫止状。

當從庫設置完同步參數(shù)后,主庫 A 的GTID 集合記為集合 x攒霹,從庫 B 的 GTID 集合記為 y怯疤。從庫同步的邏輯如下:

圖片
  • 從庫 B 指定主庫 A,基于主備協(xié)議簡歷連接催束。
  • 從庫 B 把集合 y 發(fā)給主庫 A集峦。
  • 主庫 A 計算出集合 x 和集合 y 的差集,也就是集合 x 中存在抠刺,集合 y 中不存在的 GTID 集合塔淤。比如集合 x 是 1~100,集合 y 是 1~90速妖,那么這個差集就是 91~100高蜂。這里會判斷集合 x 是不是包含有集合 y 的所有 GTID,如果不是則說明主庫 A 刪除了從庫 B 需要的 binlog罕容,主庫 A 直接返回錯誤备恤。
  • 主庫 A 從自己的 binlog 文件里面,找到第一個不在集合 y 中的事務 GTID,也就是找到了 91。
  • 主庫 A 從 GTID = 91 的事務開始霎桅,往后讀 binlog 文件,按順序取 binlog滤淳,然后發(fā)給 B。
  • 從庫 B 的 I/O 線程讀取 binlog 文件生成 relay log砌左,SQL 線程解析 relay log脖咐,然后執(zhí)行 SQL 語句铺敌。

GTID 同步方案和位點同步的方案區(qū)別是:

  • 位點同步方案是通過人工在從庫上指定哪個位點,主庫就發(fā)哪個位點屁擅,不做日志的完整性判斷偿凭。
  • 而 GTID 方案是通過主庫來自動計算位點的,不需要人工去設置位點派歌,對運維人員友好弯囊。

四、如何判斷主從庫是否有延遲

上面提到的問題 6 是主從讀寫分離后胶果,從庫復制存在延遲匾嘱,接下來我們來探討下如何觀察主從延遲多少的問題。

方案一:判斷從庫的同步狀態(tài)參數(shù) seconds_behind_master 是否為 0早抠。(不準確)

方案二:對比位點確保主備無延遲霎烙。

方案三:對比 GTID 集合確保主備無延遲。

方案一:查看 seconds_behind_master

可以在從庫上執(zhí)行 slow slave status 命令來看執(zhí)行結(jié)果里面的 seconds_behind_master 參數(shù)的值蕊连,如下圖所示悬垃,Seconds_Behind_Master 等于 0

圖片

Seconds_Behind_Master 的單位是秒,所以精度不準確甘苍。

所以為了保證查詢的數(shù)據(jù)是和主庫一致的尝蠕,就需要先判斷 seconds_behind_master 是否已經(jīng)等于 0,如果不等于 0载庭,就必須等到這個參數(shù)變?yōu)?0 才能執(zhí)行查詢請求看彼。

方案二:對比位點

可以通過查看從庫當前的同步位點來確認從庫同步是否有延遲。下圖是在從庫上執(zhí)行 show slave status \G命令后的結(jié)果:

圖片

Master_Log_FileRead_Master_Log_Pos 這兩個參數(shù)合起來表示的是讀到的主庫的最新位點囚聚,第一參數(shù)是代表讀取到了哪個文件闲昭,第二個是讀取到的文件的位置。

Relay_Master_Log_FileExec_Master_Log_Pos靡挥,這兩個參數(shù)合起來表示的是從庫執(zhí)行的最新位點。

如果紅色框起來的兩個參數(shù):Master_Log_FileRelay_Master_Log_File 相等鸯绿,則說明從庫讀到的最新文件和主庫上生成的文件相同跋破,這里都是 mysql-bin.000934。

如果藍色框起來的兩個參數(shù) Read_Master_Log_PosExec_Master_Log_Pos 相等瓶蝴,則說明從庫讀到的日志文件的位置和從庫上執(zhí)行日志文件的位置相同毒返,這里都是 59521082。

當上面兩組參數(shù)都相等時舷手,則說明沒有延遲拧簸。

方案三:對比 GTID 集合

方案三是對比 GTID 集合。首先我們在從庫上執(zhí)行 show slave status \G來查看 GTID 集合男窟。

如下圖所示:

圖片

Master_UUID 表示當前連接的主庫的 ID盆赤。

Auto_Position: 1 表示主備使用了 GTID 協(xié)議贾富。

Retrieved_Gtid_Set 表示從庫收到的所有日志的 GTID 集合。

Executed_Gtid_Set 表示從庫已經(jīng)執(zhí)行完成的 GTID 集合牺六。

如果 Executed_Gtid_Set 集合是包含 Retrieved_Gtid_Set颤枪,則表示從庫接收到的日志已經(jīng)同步完成。

比如上圖中 Retrieved_Gtid_Set 值為

<pre data-tool="mdnice編輯器" style="margin: 10px 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; color: rgb(53, 53, 53); font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.8px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0.8px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">c5d74746-d7ec-11ec-bf8f-0242ac110002:1-87323 </pre>

前面一段是主庫 id淑际,后面一段 1-87383 是 GTID 范圍畏纲。而Executed_Gtid_Set 的值有兩個集合

<pre data-tool="mdnice編輯器" style="margin: 10px 0px; padding: 0px; outline: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important; color: rgb(53, 53, 53); font-size: 15px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.8px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0.8px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">7083ae1f-d7ef-11ec-a329-0242ac110002:1-2, c5d74746-d7ec-11ec-bf8f-0242ac110002:1-87323 </pre>

Executed_Gtid_Set 的第二個集合和第一個集合完全一致,第一個集合 id 和 集合范圍是上次同步另外一個主庫的記錄春缕。這里說明從庫已經(jīng)和當前主庫同步完成了盗胀。

方案二對比位點和方案三的 GTID 比對都要比方案一的seconds_behind_master 更準確。但是還是沒有達到精確的程度锄贼,需要配合半同步復制(semi-sync replication)才能達到票灰。

小結(jié):本篇通過 GTID 的方式更好地實現(xiàn)了主從節(jié)點的同步,以及如何觀察主從同步的延遲咱娶。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末米间,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子膘侮,更是在濱河造成了極大的恐慌屈糊,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件琼了,死亡現(xiàn)場離奇詭異逻锐,居然都是意外死亡,警方通過查閱死者的電腦和手機雕薪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門昧诱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人所袁,你說我怎么就攤上這事盏档。” “怎么了燥爷?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵蜈亩,是天一觀的道長。 經(jīng)常有香客問我前翎,道長稚配,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任港华,我火速辦了婚禮道川,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己冒萄,他們只是感情好臊岸,可當我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著宦言,像睡著了一般扇单。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上奠旺,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天蜘澜,我揣著相機與錄音,去河邊找鬼响疚。 笑死鄙信,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的忿晕。 我是一名探鬼主播装诡,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼践盼!你這毒婦竟也來了鸦采?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤咕幻,失蹤者是張志新(化名)和其女友劉穎渔伯,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肄程,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡锣吼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蓝厌。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玄叠。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖拓提,靈堂內(nèi)的尸體忽然破棺而出读恃,到底是詐尸還是另有隱情,我是刑警寧澤代态,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布狐粱,位于F島的核電站,受9級特大地震影響胆数,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜互墓,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一必尼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦判莉、人聲如沸豆挽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帮哈。三九已至,卻和暖如春锰镀,著一層夾襖步出監(jiān)牢的瞬間娘侍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工泳炉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留憾筏,地道東北人。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓花鹅,卻偏偏與公主長得像氧腰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子刨肃,可洞房花燭夜當晚...
    茶點故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內(nèi)容