中超联赛广州恒大门票9月13日|中超积分榜16轮
數據庫

回饋開源,我如何排查一個MySQL Bug

廣告
廣告

X-Engine是阿里巴巴自研的高性能低成本存儲引擎,經過多年的努力,我們在集團內部以AliSQL(X-Engine)的形式(AliSQL是阿里的MySQL分支)支持了許多業務,為用戶帶來了顯著的成本和性能收益。

時至今日,阿里巴巴數據庫團隊已經向MySQL官方提交了許多有價值的bug及修復方案。我們繼承了這一優良傳統,在生產、測試中遇到MySQL相關的問題,總是積極地思考解決方案,并迅速與官方交流溝通,為開源社區的發展貢獻自己的力量。

下文將介紹我們剛發現的一個MySQL問題及修復方案。遇到相同情況的朋友需要注意了,也許不符合規范的數據已經寫入你們的數據庫了。

背景知識

如果MySQL參數sql_mode包含以下3項:

NO_ZERO_DATE

NO_ZERO_IN_DATE

STRICT_TRANS_TABLES

向DATE類型列,插入’0000-00-00’或者年/月/日3部分任意一部分為0,都將失敗。

異常:‘0000-00-00’竟然插入成功了

在MySQL 8.0.16上依次執行以下語句:

set sql_mode=”;

create table test (mydate DATE NOT NULL DEFAULT ‘0000-00-00’);
set sql_mode=default;

show variables like “sql_mode”;

insert into test values();

select * from test;

這里先將sql_mode設為空的目的是:建表時將mydate的default value設為’0000-00-00’,否則會因default value不符合NO_ZERO_DATE而建表失敗。

建表成功后將sql_mode設回default,包含:

ONLY_FULL_GROUP_BY

NO_ZERO_DATE

NO_ZERO_IN_DATE

STRICT_TRANS_TABLES

ERROR_FOR_DIVISION_BY_ZERO

NO_ENGINE_SUBSTITUTION

然而,這時竟然成功向test庫里插入了一條’0000-00-00’的DATE。顯然,NO_ZERO_DATE的語義被打破了。

抽絲剝繭,原來問題出在這

首先,我們定位到MySQL插入路徑,檢查default value是否合法的函數。

這個函數比較簡單,找出用戶insert lists不包含的、且有default value的列,檢查它們的default value是否合法。write_set是一個bitmap,標識了用戶insert lists里包含哪些列。

我用gdb在該函數處加了斷點,執行上述case,竟然發現write_set里全部bit被設為了1。這顯然不正常的現象,我的插入SQL語句insert into test values();insert list明明為空,write_set全為0才合理。看來有函數錯誤地修改了它。

于是乎,我用gdb給write_set的地址加了一個watchpoint,重新執行insert語句。這次定位到了修改write_set的地方:

該函數在檢查default value是否合法前執行,其作用是當binlog_format為ROW且binlog_row_image為FULL時,write_set會被全部設置為1。

參數binlog_format指定了binlog格式,有三個備選項:

ROW代表主備之間通過log_event同步;

STATEMENT代表主備之間通過SQL語句同步;

MIXED則是混合格式,默認用STATEMENT方式,一些特殊情況下用ROW方式。

由于主備通過STATEMENT同步(雖然它產生的binlog數量小),可能因上下文信息、環境不同等因素,導致結果不一致,因此安全起見,binlog_format默認為ROW。

參數binlog_row_image指定了ROW格式binlog要記錄哪些信息。它也有三個備選項:

FULL表示binlog記錄變更前后的所有列;

MINIMAL表示binlog只記錄唯一標識列和修改列;

NOBLOB表示BLOB是修改列或唯一標識列,才記錄,其它列與FULL相同全部記錄。

binlog_row_image默認為FULL。

當binlog_format為ROW且binlog_row_image為FULL 時,為了保證所有列都寫到binlog里,write_set竟然被全部設置為1。

write_set變量本是用來標識用戶插入列,又被賦予了控制寫binlog的重任。多重語義交織,很容易出bug。這也給我們編碼帶來啟示:每個變量應當有確切的語義。

修復建議

導致這個bug的原因是write_set用處太多。因此可以創建一個新的bitmap:binlog_write_set,專門用于控制寫binlog。

我還沒有學會寫個人說明!

資源混淆是如何影響到Kotlin協程的

上一篇

Gartner:2020年十大戰略技術趨勢

下一篇

你也可能喜歡

回饋開源,我如何排查一個MySQL Bug

長按儲存圖像,分享給朋友

ITPUB 每周精要將以郵件的形式發放至您的郵箱


微信掃一掃

微信掃一掃
中超联赛广州恒大门票9月13日 微信欢乐麻将怎么充值 20万理财一年的收益4万 小米股票代码 pk10交流群 幸运飞艇计划qq群 河北麻将怎么胡牌 斯诺克147比分直播 她理财12存单法安全吗 免费真人性直播平台 排列三怎么玩才赚 德州麻将单机游戏 万科股票行情 福利彩票25选7开奖 腾讯欢乐麻将辅助精灵 安全理财产品排行榜 安徽11选5官方