<b>背景</b>
gtid 可以說是 mysql 5.6 版本的一個殺手級特性,它給主備複制帶來了極大的便利,rds隻讀執行個體就是強依賴于這個特性。然而gtid在給我們帶來便利的同時,也埋下了許多坑,最近幾期核心月報中gtid的頻繁出現也說明了這一點,對其我們可以說是既愛又恨。
gtid 并不是免費午餐,要使用它是要有代價的,為了保證gtid這個體系能夠運轉起來,需要做許多相關的工作,比如binlog裡每個事務要多記 gtid_event 這種事件、寫binlog的時候要生成 gtid、要維護幾個gtid集合(logged, purged, owned)、thd類要多加gtid的成員變量等等,這些對性能和資源開銷方面都有影響。
<b>優化分析</b>
mysqld 是通過對 binlog.index 中記錄的 binlog 檔案做2次周遊來實作初始化的,第一次是從後向前,即從最新的binlog開始,到最老的binlog,對每個binlog從頭到尾讀一遍,初始化 gtid_executed 集合;第二次是從前往後,同樣對每個binlog從頭到尾讀一遍,用來初始化gtid_purged 集合。每一遍的最好情況都是隻讀一個binlog檔案,對gtid_executed 集合來說,隻需要最新的binlog就行了,因為每個binlog開始會記錄 previous_gitd_set,這個集合加上目前binlog内部記錄的 gtid_event,就是所有已經執行的,也即 gtid_executed; 對gitd_purged來說,理想情況更簡單,隻需要讀最老binlog檔案的頭部的previous_gtid event即可,檔案裡面的 gtid_event 根本不需要。
最壞情況是什麼呢,就是一堆binlog檔案裡,隻有其中一個檔案裡有gtid,其它都沒有,這樣的話,對于2遍掃描,都需要掃到這個binlog,才能确定這2個集合。
比如 a b c d e f 這幾個,每個對應一個binlog檔案,其中隻有d含有gtid,其它的都沒有,這樣的話,每一遍的掃描都要讀到檔案d才能确定。
官方的優化是,不管什麼情況下,每一遍的掃描,最多隻讀一個檔案,不會再多讀,如果最新和最老的檔案都沒有gtid,就把gtid_executed和gtid_purged設為空。
<b>優化場景</b>
下面我們來看下,這個優化有沒有用 。
我們還是用 a b c d e f 這幾個表示binlog檔案,小寫表示檔案沒有包含gtid,大寫表示有。
開始沒有開gtid,後來開了:a, b, c, d, e, f 這樣的模式,gtid_executed 隻讀 f,gtid_purged 隻讀a, 前者是f全集,後者是空的,如果沒有這個優化的話,gtid_executed 也是讀一個檔案,gtid_purged 要從a讀到f,最終還是空的,優化是有效果的
開始有,後來沒有:a, b, c, d, e, f,這種情況下 gtid_executed 集合被初始化成空集,gtid_purged 也是空集,初始化結果是錯的
開始沒有,中間有最後也沒有:a, b, c, d, e, f 這種情況,2個集合都被初始化成空的,結果也是錯的
一直有:a,b,c,d,e,f,這種本來就是最好情況,本來每次周遊就隻讀一個檔案的,加不加這個優化都一樣
其它情況可以自己推算下
總的來說這個優化是比較雞肋的,有的情況下還會算錯,官方的優化 patch 帶了個開關控制,預設是關的,這個隻是對個别場景比較适合,比如上面的場景1。