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

歡迎訪問 生活随笔!

生活随笔

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

数据库

mysql同步row模式_ROW模式的SQL无法正常同步的问题总结

發布時間:2025/3/21 数据库 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql同步row模式_ROW模式的SQL无法正常同步的问题总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

ROW模式的SQL無法正常同步的問題總結

最近處理數據庫問題時遇到一起mysql從機ROW模式的SQL無法正常同步的問題,今天剛好有時間,將整個過程總結一下,方便后面的同學學習!

一、問題起因

最近有一個業務的實例在比對數據的時候數據庫、表、以及行數都是一樣的,只是有多個表的checksum值不一致,主從狀態也正常。初步判斷可能是運維之前有做過skip的操作導致,對從機進行了重做后發現問題依舊,于是對binlog的內容進行了分析跟進,來找到不能同步的根本原因。分析binlog的過程如下:

?選擇一條checksum主從不一致的表的一條最近的記錄

從上面兩張圖中可以很清楚的看出兩條記錄的內容不一致,那么為什么會不一致呢?我們來追蹤binlog看看

?通過binlog進行追蹤master上這條記錄的執行情況

在master上找到了對應的update的記錄。下面到從機上找一下對應的relay日志和binlog看看是否有正常復制和執行。

?在slave的relay日志和binlog中都查找對應master上的那條binlog的執行情況

在slave上發現一個奇怪的現象,在relay日志中能找到對應的更新這條語句的SQL,也就是說在master上的binlog已經通過從機的IO線程將對應的update語句同步到了relay日志中。但是在slave的binlog中沒有找到運行這條SQL的記錄,并且從機上的位置早就已經超過了那個update的位置,排除了slave端延遲的問題。

跟蹤多條ROW模式的SQL均是此問題,而STATEMENT的SQL不會出現異常的問題,從機上的所有的binlog顯示都是STATEMENT的SQL。主從binlog的比較也能看出確實有異常(備注:開啟了log-slave-updates參數),如下截圖所示:

Master上的binlog的數量和大小:

Slave上的binlog的數量和大小:

匯總問題如下:

Slave無法同步Master上的ROW模式的SQL

二、排查過程

出現這個奇怪的靈異問題,首先想到的是mysql某個版本的bug,找各個版本的服務器進行重現該問題,發現相同的SQL在其他服務器都沒有此問題。但是當采用其他的各個版本或者相同版本的mysql作為那臺有問題的master的從機,就都出現了不能同步ROW模式的SQL的問題。因此基本可以排除版本的問題。

那么是什么原因在從機上ROW模式的SQL沒有執行呢?什么場景會觸發這種問題呢?

經過開發同學zhiyangli和edgeyang的源碼定位終于找到了問題原因,問題原因是sql線程將relay log保存的64位table id轉換成32位溢出,導致在hash結構中找不到對應的表而不進行任何操作,具體的邏輯為:binlog中table_id是一個ulong類型(無符號長整形),在slave進行重做binlog events之前,會先將這個ulong的table_id(為了避免混淆,用m_table_id表示)傳給一個它內部維護的一個數據結構RPL_TABLE_LIST,這個里面有一個變量table_id用來存儲binlog中的m_table_id,問題出現了:數據結構的變量table_id是一個uint(無符號整形),如果m_table_id超過uint的范圍會發生截斷。而MySQL內部在構造hash,從hash表中取值是這樣的做法:set_table(table_id),get_table(m_table_id),在兩個階段用到的key因為發生了數據截斷所以必然也就不能取到預期的值。也就是說之前用uint型的table_id構建出來的key-value的hash對,用ulong型的m_table_id是無法查詢到的。也就是如果binlog中顯示的tableid超過2的32次方就是42億的時候就會觸發這個bug。通過重啟能臨時解決問題。如下截圖就是有問題的master產生的binlog:

從這個圖中我們可以看出table id已經遠遠超過了42億了,達到了109億。

三、深入分析

既然是由于tableid導致,那么tableid是什么東西,為什么要有tableid這個東西呢,以及為什么STATEMENT模式的就不需要tableid呢?另外為什么tableid為上漲得那么厲害超過42億?帶著這些問題,下面就來慢慢分析和解答:

在引入table id之前我們先來說一下mysql的binlog格式

(一)Mysql的binlog格式

搞mysql的同學都知道,mysql的binlog分為三種格式,一種是STATEMENT格式,一種是ROW格式,最后一種是結合STATEMENT和ROW的MIXED格式。下面比對一下各個格式的優缺點:

1.STATEMENT

a)優點

只記錄執行的SQL語句本身,binlog量少,節省IO,性能比較好

b)缺點

對一些卻確定的函數比如uuid()、limit、user()等不能保證主從數據的一致性。

2.ROW

a)優點

Row格式非常清楚地記錄下每一行數據的修改細節,能保證主從數據的一致性。

b)缺點

Binlog太多,IO性能受限制,另外對從機的主從延遲也是一個挑戰。

3.MIXED

結合了STATEMENT和ROW模式的有點。

(二)Table id是個啥東西

先來看兩個binlog中的SQL語句

STATEMENT格式的binlog:

從mysql的binlog中發現statement的SQL是沒有table id的,從STATEMENT中記錄的SQL,我們可以看出,通過SQL就知道更改表的對應位置,因此不需要通過table id去查找到對應的表的結構信息。

ROW格式的binlog:

從截圖中可以看出ROW模式中含有table id的概念,ROW模式引入table id是為了在執行insert/update/delete解析的時候能夠知道具體的表信息,因為我們通過binlog可以看到,語句并不能反應出列名信息。因此通過table id來關聯表結構信息。從table_map_id代碼中也能看table id就是專門用于ROW格式的:

ulong table_map_id; /*for row-based replication*/

(三)Tablemap和table id

ROW模式的binlog中有如下兩行信息:

Table id就是table map映射key ID,從binlog中可以看到mysql分2個events分別記錄這些信息events 1,記錄了操作哪些庫哪些表。其中會將這些信息緩存到一個hash map內,key為tabke_id,value為table類(保存了庫名,表名等信息),events 2記錄了操作哪些行。每次執行events 2的時候,mysql通過table_id先去hash map查找相關的table信息。找到庫表后再操作具體的行。一個table map events可以對應多個row events,以此減少binlog占用空間。

(四)Table id增長和cache的關系

從代碼中可以看出table id的分配在函數assign_new_table_id(),每次分配都是對上一次的table id自增,代碼如下:

一般是DDL語句會導致table id增加。

下來再看看table id和cache的關系,網上有代碼分析了,table id是保存在cache中,當cache中有該表定義時,表對應的table id是不變的,而當cache中沒有改表定義時,該值根據上一次操作的table id自增1獲得的。Cache指的是table cache,由table_definition_cache組成,這里就會引出一個問題,當table cache過小而表的數量又很多的場景,會導致表定義將被頻繁置換出cache,被置換出的表如果有操作時,重新加載時,table id的值就會發生改變。因此,table id與實際操作的數據表沒有直接對應關系,而與操作的數據表是否在table cache中有關。

總結有如下兩個方面會導致table id增加:

?DDL語句執行的時候。

?Table cache設置太小,表定義被頻繁置換出cache,導致table id增加。

?執行flush tables

(五)為什么table id超過42億同步就有問題呢?

這里涉及到mysql的bug,在定義table id的時候采用的ulong型,為8byte。而在同步的SQL線程中設置的table id為uint型,為4byte,因此同步的SQL線程中如果超過2^32的話就溢出了,主機的update等就無法同步更新到從機。具體代碼如下:

四、問題解決

知道了問題原因就好解決了,主要有如下兩種解決辦法:

1.修改代碼修復uint的問題。

2.重啟實例,并將table cache調大。

五、問題跟進處理

對于一個平臺來講,雖然遇到的機會比較少,但是這種問題側出現反應了我們平臺還是有一些監控的盲點和漏洞,需要對table id進行監控,另外對table cache的默認配置400還是非常小的。因此接下來三個任務:

1.更改線上的版本,修復uint的問題。

2.對于存量的需要將table cache進行一次整體的調整。

3.推動添加table id的監控,防止類似的問題出現。

六、參考資料

總結

以上是生活随笔為你收集整理的mysql同步row模式_ROW模式的SQL无法正常同步的问题总结的全部內容,希望文章能夠幫你解決所遇到的問題。

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