最近發(fā)現(xiàn)了一個主從相關的問題仙辟,在這里記錄一下境蜕。
一撑教、背景:在業(yè)務過程中產(chǎn)生的財務數(shù)據(jù)需要發(fā)送給財務團隊。然后公司已經(jīng)有相關的服務A偷遗,通過Binlog Dump實時獲取數(shù)據(jù)庫的增量日志墩瞳,并通過解析后獲取具體的數(shù)據(jù)變更,最后將變更記錄推送到Kafka中以供業(yè)務方消費鹦肿。于是我們的方案就是消費A服務產(chǎn)生的變更記錄矗烛,然后聯(lián)表查詢其他表的字段(因為財務團隊需要的數(shù)據(jù)包通常是多表的,但是A服務產(chǎn)生的變更記錄是基于單表)箩溃,聚合之后投遞出去瞭吃。
出現(xiàn)的問題:現(xiàn)在有一份財務需要的財務信息,包括c表和d表的信息涣旨。A服務解析出c表和d表的變更歪架,會產(chǎn)生兩份變更記錄,然后基于c表和d表的兩份變更記錄進行聯(lián)表霹陡,然后發(fā)現(xiàn)在c表進行聯(lián)表查詢d表的信息 的時候發(fā)現(xiàn)沒有查到d表的信息和蚪,但是c表中已經(jīng)包含有d表的相關主鍵id了止状。因此只能說明是由于主備延遲導致的。
二攒霹、分析:看代碼和數(shù)據(jù)庫記錄發(fā)現(xiàn)c表和d表的變更是基于同一個事務產(chǎn)生的怯疤,ctime和mtime都是一樣的。對于同一個事務來說催束,那么應該是同時提交到binlog中的集峦?但是binlog產(chǎn)生之后,但是從庫查詢的時候查不到抠刺,那基本說明就是主從延遲了塔淤,主從延遲其實最主要的原因是從relay log寫入到從庫表太慢導致,對于Binlog Dump和從庫同步來說速妖,都是從主庫進行同步的高蜂,但是Binlog Dump通過Kafka先到了我們的服務,但是從庫還差不到罕容,那就是從relay log寫入到從庫表中太慢了备恤。那么怎么看主從之間的延時呢?怎么監(jiān)控主從之間的延時情況杀赢?以及同一數(shù)據(jù)變更多次事務是怎么寫入binlog的呢烘跺?Dump binlog的基于文件位置和基于GTID有什么區(qū)別呢?
其實脂崔,binlog 的寫入邏輯比較簡單:事務執(zhí)行過程中,先把日志寫到 binlog cache梧喷,事務提交的時候砌左,再把 binlog cache 寫到 binlog 文件中。一個事務的 binlog 是不能被拆開的铺敌,因此不論這個事務多大汇歹,也要確保一次性寫入。這就涉及到了 binlog cache 的保存問題偿凭。
通過公司的MySQL監(jiān)控工具看了下相應庫的主從延時产弹,發(fā)現(xiàn)延時比較大的時候能夠達到1s,1s的時間足夠將消息處理完并發(fā)出去了弯囊,因此就會帶來上述問題痰哨。這樣帶來的問題就是可能會丟信息,因為c表查詢d表數(shù)據(jù)不存在匾嘱,就不會發(fā)消息斤斧,然后d表查c表查不到,相應字段會設為空霎烙,那么c表的字段就會丟失∏朔恚現(xiàn)在數(shù)據(jù)量少蕊连,只有一條數(shù)據(jù),丟數(shù)據(jù)的情況不多見游昼,如果數(shù)據(jù)很多的話風險就比較大甘苍。
三、怎么解決烘豌?
- 強制走主庫方案载庭;
- sleep 方案;
- 判斷主備無延遲方案扇谣;
- 配合 semi-sync 方案昧捷;
- 等主庫位點方案;
- 等 GTID 方案
另外可以優(yōu)化的地方就是盡可能減少主從延時的時間罐寨,思路基本就是較少大事務靡挥、使用基于事務組提交的事務并行復制、調節(jié)兩個參數(shù)binlog_group_commit_sync_delay鸯绿、binlog_group_commit_sync_no_delay_count
引用極客時間的文章
binlog_group_commit_sync_delay 參數(shù)跋破,表示延遲多少微秒后才調用 fsync;binlog_group_commit_sync_no_delay_count 參數(shù),表示累積多少次以后才調用 fsync瓶蝴。這兩個參數(shù)是用于故意拉長 binlog 從 write 到 fsync 的時間毒返,以此減少 binlog 的寫盤次數(shù)。在 MySQL 5.7 的并行復制策略里舷手,它們可以用來制造更多的“同時處于 prepare 階段的事務”拧簸。這樣就增加了備庫復制的并行度。也就是說男窟,這兩個參數(shù)盆赤,既可以“故意”讓主庫提交得慢些,又可以讓備庫執(zhí)行得快些歉眷。在 MySQL 5.7 處理備庫延遲的時候牺六,可以考慮調整這兩個參數(shù)值,來達到提升備庫復制并發(fā)度的目的汗捡。