1. 程式人生 > 資料庫 >淺析MySQL的WriteSet並行複製

淺析MySQL的WriteSet並行複製

【歷史背景】

  歲月更迭中我已經從事MySQL-DBA這個工作三個年頭,見證MySQL從“基本可用”,“邊緣系統可以用MySQL”,“哦操!你怎麼不用MySQL”;

  正所謂!“一個數據庫的境遇既取決於歷史的程序,取決於它的自我奮鬥!”,關於“歷史的程序”在此不表,關於“自我奮鬥”這裡也只想談一下並行複製的幾個關鍵時間結點

  總的來說MySQL關於並行複製到目前為止經歷過三個比較關鍵的時間結點“庫間併發”,“組提交”,“寫集合”;真可謂是江山代有人才出,前浪死在沙灘上;總的來說就後面的比前面的不知道高到哪裡去了!

【庫間併發】

  庫間併發的理論依據是這樣的 ---- 一個例項內可能會有多個庫(schema),不同的庫之間沒有什麼依賴關係,所以在slave那邊為每一個庫(schema)單獨起一個SQL執行緒,這樣就能通過多執行緒並行複製的方式來提高主從複製的效率。

  這個理論聽起來沒問題,但是事實上一個例項也就一個業務庫,所以這種庫間併發就沒什麼作用了;也就是說這個方式的適用場景比較少,針對這個不足直到“組提交”才解決!

【組提交】

  組提交的理論依據是這樣的 --- 如果多個事務他們能在同一時間內提交,這個就間接說明了這個幾個事務鎖上是沒有衝突的,也是就說他們各自持有不同的鎖,互不影響;邏輯上我們幾個事務看一個組,在slave以“組”為單位分配給SQL執行緒執行,這樣多個SQL執行緒就可以並行跑了;而且不在以庫為並行的粒度,效果上要比“庫間併發”要好一些。

  這個事實上也有一些問題,因為它要求庫上要有一定的併發度,不然就有可能變成每個組裡面只有一個事務,這樣就有序列沒什麼區別了,為了解決這個問題MySQL提供了兩個引數就是希望在提交時先等一等,儘可能的讓組內多一些事務,以提高並行複製的效率。

  “binlog_group_commit_sync_no_delay_count” 設定一個下水位,也就是說一個組要湊足多少個事務再提交;為子防止永遠也湊不足

  那麼多個事務MySQL還以時間為維度給出了另一個引數“binlog_group_commit_sync_delay”這個引數就是最多等多久,超過這個時間長度後就算沒有湊足也提交。 

  親身經歷呀! 這兩個引數特別難找到合的值,就算今天合適,過幾天業務上有點變化後,又可能變的不合適了;如果MySQL能自己達到一個自適應的效果就好了;這個自適用要到WriteSet才完成(WriteSet並不是通過自動調整這兩個引數來完成,它採用了完全不同的解決思路)。

【WriteSet】

  WriteSet解決了什麼問題?當然是解決了“組提交”的問題啦! 說了和沒說一個樣,好下面我們來舉個例子(比較學院派);假設你第一天更新了id == 1 的那一行,第二天你更新了id == 2 的那一行,第三天有個slave過來同步你的資料啦! 以“組提交”的尿性,這兩個更新會被打包到不同的“組”,也就是說會有兩個組;由於每個組內只有一個事務,所以邏輯上就串行了,起來!

  身為DBA的你一可以看出來這兩個事實上是可以打包到同一個組裡來的,因為他們互不衝突,就算打包到同一個組也不引起資料的不一致。 於是你有兩個辦法

  辦法1): 妹妹你大膽的把“binlog_group_commit_sync_no_delay_count”設定成 2,也就是說一個組至少要包含兩個事務,並且把“binlog_group_commit_sync_delay”設定成24小時以上!如果你真的做了,你就可以回家了,你的資料庫太慢了(第一條update等了一天),才完成!

  辦法2): 叫MySQL用一本小本子記下它最近改了什麼,如果現在要改的資料和之前的資料不衝突,那麼他們就可以把包到同一個組;還是我們剛才的例子,由於第二天改的值的id==2所以它和第一天的不衝突,那麼它完全可以把第二天的更新和第一天的更新打包到同一個組。這樣組裡面就有兩個事務了,在slave第三天回放時就會有一種並行的效果。

  這本小本子這麼牛逼可以做大一點嗎?當然!binlog_transaction_dependency_history_size 這個引數就小本子的容量了;那我的MySQL有這本小本子嗎? 如果你的mysql比mysql-5.7.22新的話,小本子就是它生來就有的。

  也就是說“WriteSet”是站在“組提交”這個巨人的基礎之間建立起來的,而且是在master上做的自“適應”打包分組,所以你只要在master上新增兩個引數

binlog_transaction_dependency_tracking = WRITESET         #  COMMIT_ORDER     
transaction_write_set_extraction    = XXHASH64

理論說完了,下面我們看一下實踐。

【WriteSet實踐】

  基於WriteSet的並行複製環境怎麼搭建我這裡就不說了,也就是比正常的“組提交”在master上多加兩個引數,不講了;我這裡想直接給出兩種並行複製方式下的行為變化。

  1): 我們要執行的目標SQL如下

create database tempdb;
use tempdb;
create table person(id int not null auto_increment primary key,name int);

insert into person(name) values(1);
insert into person(name) values(2);
insert into person(name) values(3);
insert into person(name) values(5);

  2): 看一下組提交對上面SQL的分組情況

淺析MySQL的WriteSet並行複製

  3): 看write_set的對“組提交”優化後的情況

淺析MySQL的WriteSet並行複製

  可以看到各個insert是可以並行執行的,所以它們被分到了同個組(last_committed相同);last_committed,sequence_number,這兩個值在binlog裡面記著就有,我在解析binlog的時候習慣使用如下選項

mysqlbinlog -vvv --base64-output='decode-rows' mysql-bin.000002  

【總結】

  WriteSet是在“組提交”方式上建立起來的,一種新的並行複製實現;相比“組提交”來說更加靈活;當然,由於併發度上去了,相比“組提交”WriteSet在效能上會更加好一些,在一些WriteSet沒有辦法是否衝突時,能平滑過度到“組提交”模式。

以上就是淺析MySQL的WriteSet並行複製的詳細內容,更多關於MySQL WriteSet並行複製的資料請關注我們其它相關文章!