天天看點

myrocks之事務處理前言sequence numbersnapshotMVCC隔離級别鎖binlog XA & 2pc總結

title: mysql · myrocks · myrocks之事務處理

mysql目前支援的事務引擎有innodb,tokudb. rocksdb加入mysql陣營後,mysql支援的事務引擎增長至3個。

myrocks目前支援的事務隔離級别有read-committed和repeatable-read. 同innodb一樣,myrocks也支援mvcc機制。

可以說,myrocks提供了很好的事務支援,能夠滿足的一般業務的事務需求。

談到rocksdb事務,就必須提及rocksdb中的sequence number機制。rocksdb中的每一條記錄都有一個sequence number, 這個sequence number存儲在記錄的key中。

對于同樣的user key記錄,在rocksdb中可能存在多條,但他們的sequence number不同。

sequence number是實作事務處理的關鍵,同時也是mvcc的基礎。

snapshot是rocksdb的快照資訊,snapshot實際就是對應一個sequence number.

簡單的講,假設snapshot的sequence number為sa, 那麼對于此snapshot來說,隻能看到sequence number<=sa的記錄,sequence number>sa的記錄是不可見的。

snapshot 結構

snapshot 主要包含sequence number和snapshot建立時間,sequence number 取自目前的sequence number.

snapshot 管理

snapshot由全局雙向連結清單管理,根據sequence number排序。snapshot的建立和删除都需要維護雙向連結清單。

snapshot與compact

rocksdb的compact操作與snapshot有緊密聯系。以我們熟悉的innodb為例,rocksdb的compact類似于innodb的purge操作, 而snapshot類似于innodb的read view. innodb做purge操作時會根據已有的read view來判斷哪些undo log可以purge,而rocksdb的compact操作會根據已有snapshot資訊即全局雙向連結清單來判斷哪些記錄在compace時可以清理。

判斷的大體原則是,從全局雙向連結清單取出最小的snapshot sequence number sn. 如果已删除的老記錄sequence number <=sn, 那麼這些老記錄在compact時可以清理掉。

有了snapshot,mvcc實作起來就很順利了。記錄的sequence number天然的提供了記錄的多版本資訊。

每次查詢使用者記錄時,并不需要加鎖。而是根據目前的sequence number sn建立一個snapshot, 查詢過程中隻取小于或等于sn的最大sequence number的記錄。查詢結束時釋放snapshot.

關鍵代碼段

隔離級别也是通過snapshot來實作的。在innodb中,隔離級别為read-committed時,事務中每的個stmt都會建立一個read view, 隔離級别為repeatable-read時,隻在事務開啟時建立一次read view. rocksdb同innodb類似,隔離級别為read-committed時,事務中每的個stmt都會建立一個snapshot, 隔離級别為repeatable-read時,隻在事務開啟時第一個stmt建立一次snapshot.

關鍵代碼片段

隔離級别實作差異

在read committed隔離級别下,如果一個大事務要更新1000w行,當它更新了前900w行時,

同時另一個事務已經更新了後100w行,那麼myrocks會重新擷取快照,再次嘗試更新,這樣

而之前的處理方式是直接報死鎖錯誤。

innodb不會出現上述情況,當第一個大事更新是會持有b樹的index lock, 第二個事務會一直等待index lock直至第一個事務送出完成。

myrocks目前隻支援一種鎖類型:排他鎖(x鎖),并且所有的鎖資訊都儲存在記憶體中。

鎖結構

每個鎖實際上存儲的哪條記錄被哪個事務鎖住。

每個鎖實際是key和lockinfo的映射. 鎖資訊都儲存在map中

為了減少全局鎖資訊通路的沖突, rocksdb将鎖資訊進行按key hash分區,

同時每個column family 存儲一個這樣的lockmap.

鎖相關參數:

max_num_locks:事務鎖個數限制

expiration:事務過期時間

通過設定以上兩個參數,來控制事務鎖占用過多的記憶體。

死鎖檢測

rocksdb内部實作了簡單的死鎖檢測機制,每次加鎖發生等待時都會向下面的map中插入一條等待資訊,表示一個事務id等待另一個事務id.

同時會檢查wait_txn_map_是否存在等待環路,存在環路則發生死鎖。

死鎖檢測關鍵代碼片段

死鎖檢測相關參數

deadlock_detect:是否開啟死鎖檢測

deadlock_detect_depth:死鎖檢查深度,預設50

gap lock

innodb中是存在gap lock的,主要是為了實作repeatable read和唯一性檢查的。

而在rocksdb中,不支援gap lock(rocksdb insert是也會多對唯一鍵加鎖,以防止重複插入,

嚴格的來講也算是gap lock).

那麼在rocksdb一些需要gap lock的地方,目前是報錯和列印日志來處理的。

相關參數

gap_lock_write_log: 隻列印日志,不傳回錯誤

gap_lock_raise_error: 列印日志并且傳回錯誤

鎖示例

直接看例子

myrocks之事務處理前言sequence numbersnapshotMVCC隔離級别鎖binlog XA & 2pc總結

myrocks最近也支援了binlog xa.

在開啟binlog的情況下,myrocks送出時,會經曆兩階段送出階段。

prepare階段,根據server層生成的xid(由mysqlxid+server_id+qurey_id組成),在rockdb内部執行2pc操作,生成prepare(xid),endprepare()記錄。

commit階段,根據事務成還是失敗,生成commit(xid)或rollback(xid)記錄。

myrocks在事務處理方面還有些不完善的地方,比如鎖類型隻有單一的x鎖,不支援gap lock,純記憶體鎖占用記憶體等。 myrocks社群正在持續改進中,一起期待。