TIDB:分布式事務(wù)算法Percolator學(xué)習(xí)筆記

在進(jìn)入正題之前,先來思考下跨節(jié)點的數(shù)據(jù)如何實現(xiàn)同進(jìn)退(ACID),如果對分布式事務(wù)本身有一定了解可跳過這里。如圖:

在這里插入圖片描述

假設(shè)單機數(shù)據(jù)庫的容量受限港粱,需要將其中的數(shù)據(jù)(abcde,表示五條記錄旦签,不一定在同一張表)分散到不同分片1(ac)查坪、2(bd)、3(e) ,各個分片可能分布到不同的節(jié)點宁炫,以達(dá)到擴展容量的目的偿曙。僅僅擴展容量是不夠的,如果每個分片只有單個節(jié)點有數(shù)據(jù)羔巢,單點故障時望忆,將出現(xiàn)數(shù)據(jù)丟失的風(fēng)險,因此需要每個分片都有多個副本如(分片1-0竿秆,分片1-1启摄,分片1-2)分散到不同的節(jié)點,并且通過一致性算法(raft袍辞,paxos)保證多個副本的數(shù)據(jù)一致鞋仍。
現(xiàn)在來考慮同時對跨分片的數(shù)據(jù)讀寫事務(wù)操作:
T1: update a,b;
T2: update b,e;
T3: update b,a;


在單機數(shù)據(jù)庫里,對于一條記錄搅吁,會有集中的地方管理鎖信息“如MySQL: innodb_row_lock”,事務(wù)提交時很容易檢測到其是否已經(jīng)被加鎖了落午。但當(dāng)某個事物的多條記錄分布在不同節(jié)點谎懦,事情就變得不一樣,假設(shè)每個節(jié)點都各自存儲了自身所含所有記錄的鎖信息溃斋,那么當(dāng)事務(wù)T1,更新記錄a和b時界拦,就要分別對這兩條記錄上鎖,由于鎖信息跨節(jié)點梗劫,因此就必須考慮如何確認(rèn)跨節(jié)點記錄是否被上鎖和如何搶占鎖的問題享甸。

在單機數(shù)據(jù)庫中,分樂觀鎖和悲觀鎖梳侨,這里可以參考一下:(假設(shè)a記錄已上鎖)
樂觀鎖:在向跨節(jié)點的b記錄上鎖時蛉威,不管b是否已經(jīng)被上鎖,直接請求加鎖走哺,如果鎖已存在則回滾事務(wù)蚯嫌,然后重新從a開始事務(wù)。
悲觀鎖:在向跨節(jié)點的b記錄上鎖時,先詢問b是否已經(jīng)被上鎖择示,當(dāng)b所在節(jié)點反饋不存在b記錄的鎖時束凑,則請求對b加鎖,否則進(jìn)入等待栅盲。
那么問題來了汪诉,樂觀鎖方案中,如果b更新頻繁谈秫,那么該事務(wù)回滾重試的概率大大增加摩瞎,嚴(yán)重影響效率。悲觀鎖方案中孝常,在詢問得到反饋b沒有上鎖的過程中旗们,很可能其他的事務(wù)在這個時間差內(nèi)給b加了鎖,如何保證詢問結(jié)果反饋過程中构灸,其他事務(wù)不能搶占(考慮是不是可以將跨節(jié)點的鎖信息匯總到某一處上渴,避免兩階段確認(rèn)?)喜颁,另外當(dāng)出現(xiàn)T1和T3兩個事務(wù)并發(fā)執(zhí)行稠氮,悲觀事務(wù)下出現(xiàn)了死鎖問題該怎么解決(T1占有a的鎖,等待b的鎖半开,T3占有b的鎖隔披,等待a的鎖)。
既然有鎖寂拆,那就不可避免得討論MVCC的問題奢米,如何在有鎖的情況下,實現(xiàn)跨節(jié)點數(shù)據(jù)的高效訪問纠永,假設(shè)像MySQL一樣使用readview鬓长,得如何參考(統(tǒng)一的地方保存readview?每個節(jié)點各自保存readview尝江?)涉波,還是有其他更好的方式。同時炭序,事務(wù)隔離級別能得到何種程度的實現(xiàn)啤覆,能否四種隔離級別都能實現(xiàn)。最后惭聂,當(dāng)鎖等待超時窗声,如何清理鎖,MVCC版本控制彼妻,過期版本的數(shù)據(jù)如何清理嫌佑?
以上的疑問豆茫,寫到這里可能還沒有答案,帶著這些疑問屋摇,來看看tidb如何應(yīng)用percolator實現(xiàn)分布式事務(wù)揩魂。

接下來進(jìn)入正題,以下內(nèi)容均是在TiDB的基礎(chǔ)上參考的炮温。

一火脉、percolator概覽

首先大概說下背景,谷歌搜索基于其倒序索引系統(tǒng)柒啤,谷歌采用map-reduce設(shè)計了一個批量創(chuàng)建索引的系統(tǒng)倦挂,解決海量數(shù)據(jù)索引創(chuàng)建的問題,但該系統(tǒng)并不擅長處理分布式海量索引數(shù)據(jù)實時更新担巩。該系統(tǒng)存在問題我們目前并不是很了解方援,但是該問題有了一個指向:能否有一個支撐大量分布式數(shù)據(jù),支持并發(fā)訪問涛癌,支持跨節(jié)點數(shù)據(jù)實時事務(wù)更新的分布式數(shù)據(jù)庫犯戏。這也是我們上面問題的解決方向。

1拳话、percolator數(shù)據(jù)結(jié)構(gòu)

Percolator 在 Bigtable 上抽象了 5 Columns 去存儲數(shù)據(jù)先匪,其中有 3 和事務(wù)相關(guān):

c:lock (后文中簡稱L列):
事務(wù)產(chǎn)生的鎖,映射關(guān)系為${key,start_ts}=>${lock_type,primary_key,..etc}

  • key:數(shù)據(jù)的key
  • start_ts:事務(wù)開始時間(分布式系統(tǒng)需要能提供全局唯一的時間戳弃衍,用來保證事務(wù)不沖突)
  • lock_type:事務(wù)執(zhí)行時呀非,會從所有執(zhí)行寫操作的行中隨機選一行作為primary,lock_type賦值為:primary_lock,其與的行l(wèi)ock_type賦值為secondary_lock镜盯。
  • primary_key:當(dāng)lock_type為secondary_lock時岸裙,該值指向primary行。

c:write(后文中簡稱W列)
已提交的數(shù)據(jù)信息形耗,存儲數(shù)據(jù)所對應(yīng)的時間戳,映射關(guān)系為
${key,commit_ts}=>${start_ts}

  • key :數(shù)據(jù)的key;
  • commit_ts: 事務(wù)的提交時間(同樣需要提供全局唯一的時間戳)
  • start_ts:該事務(wù)開始時間哥桥,通過這個時間+key,可以從c:data列找到對應(yīng)的數(shù)據(jù)

c:data(后文中簡稱D列)
具體存儲的數(shù)據(jù),映射關(guān)系為:
{key,start_ts} =>{value}

  • key: 真實的key
  • start_ts : 對應(yīng)事務(wù)的開始時間
  • value: 真實的數(shù)據(jù)值

大致看下數(shù)據(jù)組織形式:


在這里插入圖片描述

2激涤、Percolator 事務(wù)流程

2.1、寫操作流程

寫流程分兩個階段(兩階段提交):prewrite與commit兩個階段

2.1.1判呕、prewrite階段
  • 事務(wù)T開始倦踢,從全局時間授權(quán)模塊(Timestamp Oracle(TSO))獲取start_ts,在所有需要寫操作的行中選一個作為primary侠草,其他的均為secondary辱挥。
  • 對primary行寫入L列。即上鎖边涕,上鎖前會檢查是否有沖突:
    • 該行已有其他客戶端(session)上鎖(primary_lock或secondary_lock)
    • 該行最新W列的commit_ts>當(dāng)前事務(wù)T的start_ts(說明當(dāng)前事務(wù)開始后晤碘,有其他的事務(wù)先提交了對改行的修改)
      當(dāng)出現(xiàn)以上兩種情況時褂微,說明發(fā)生沖突,上鎖失敗园爷,回退當(dāng)前事務(wù)宠蚂。否則上鎖成功,當(dāng)前事務(wù)寫入L列(key=>T.key,start_ts=>T.start_ts,lock_type=>primary_lock,primary_key=>null童社。因為改行本身就是primary行求厕,因此primary行指向null)
  • 上鎖成功后,寫入D列更新即新版本的數(shù)據(jù)扰楼,以start_ts為版本號呀癣。由于當(dāng)前數(shù)據(jù)未提交,D列對外不可見弦赖。(不可見的意思就是沒有寫W列项栏,客戶端查詢通過W列查找版本號)
  • primary行上鎖流程結(jié)束后,開始secondary行的prewrite流程蹬竖,流程與primary行上鎖流程相似沼沈,但是鎖類型不一樣,且鎖的內(nèi)容會多出對primary行的指向(lock_type=>secondary_lock案腺,primary_key=>primary_key)
  • prewrite流程任何一步發(fā)生錯誤庆冕,都會回滾,刪除新加的L列和新加的D列劈榨。

由上流程可以看出访递,數(shù)據(jù)的寫入(寫D列)是在prewrite流程完成,為什么在prewrite階段就寫了數(shù)據(jù)呢同辣?為何不在commit階段寫拷姿?別急,繼續(xù)往下看旱函。

2.1.2响巢、commit階段
  • commit階段開始時,從全局時間授權(quán)模塊獲取commit_ts,commit_ts>start_ts.
  • commit primary行棒妨,寫入對應(yīng)的W列數(shù)據(jù)(key踪古,commit_ts,start_ts)表明版本號start_ts對應(yīng)的數(shù)據(jù)已提交券腔。
  • 刪除primary行的L列
  • 如果primary行提交失敗伏穆,整個事務(wù)回滾,刪除新加的L列和新加的D列纷纫。如果primary行提交成功枕扫,則可異步提交其余的secondary行,secondary行的提交失敗了也無所謂辱魁。

這里就可以看出烟瞧,在primary行commit成功后(寫入W列诗鸭,刪除L列),secondary行的commit就可以異步提交了参滴,即便異步commit secondary行階段發(fā)生異常(或者下次訪問時還沒來得及)沒有清理鎖强岸,沒有W列也沒有關(guān)系,可以在下次讀寫的時候卵洗,根據(jù)secondary行的L列信息找到primary行(通過primary_key+start_ts)判斷是否已經(jīng)提交該事務(wù)(因此需要先寫W列再刪L列请唱,如果primary行存在L列,說明事務(wù)還未提交过蹂,如果不存在L列十绑,但存在對應(yīng)W列,說明事務(wù)已提交酷勺,如果primary行同時不存在對應(yīng)L列和W列本橙,說明該事務(wù)回滾了)。
如果在commit階段寫入D列數(shù)據(jù)脆诉,假設(shè)是一行一行的提交并刪除L列甚亭,那么肯定會出現(xiàn)部分可見部分不可見的情況,比如primary行commit了击胜,寫了D列并可見亏狰,其余的行還沒有寫入D列,就沒法通過檢測primary行commit的情況偶摔,來判斷其余行的數(shù)據(jù)的可見性了額暇唾,因為沒有D列的數(shù)據(jù)。那么這種方式就得等所有行的D列都寫入后才能開始刪鎖向客戶端響應(yīng)事務(wù)狀態(tài)辰斋,這樣的話策州,就大大增加了這一部分?jǐn)?shù)據(jù)加鎖的時間了,同時也可能因為網(wǎng)絡(luò)原因只有部分行完成了commit響應(yīng)導(dǎo)致事務(wù)超時宫仗。
這里埋一個疑問够挂,如果primary行的數(shù)據(jù)提交后被刪除了,沒有及時清理鎖的secondary行該如何確定自身是否需要提交呢藕夫?

以上流程每行出現(xiàn)的L列孽糖、W列、D列毅贮,都會通過一致性算法(raft)復(fù)制多個副本到多個節(jié)點梭姓。

2.2、讀操作流程

兩階段提交嫩码,prewrite寫D列,但不可見罪既,commit階段寫W列后可見铸题,W列表示一個可見性铡恕,另一個類似于索引。當(dāng)下一個事務(wù)T2讀寫查詢時丢间,將進(jìn)行如下流程:

  • 檢查該行在T2.start_ts 這個時間點之前是否有L列探熔,如果有則等待解鎖,或者等待超時嘗試清除烘挫。不可繞過L列直接訪問W列查找更老版本start_ts_old的數(shù)據(jù)诀艰,否則產(chǎn)生幻讀(該L列對應(yīng)的版本提交后,T2.start_ts與start_ts_old之間就有多一個版本的數(shù)據(jù))
  • 該行不存在鎖時饮六,讀取至T2.start_ts的最新數(shù)據(jù)其垄,從start_ts開始倒序查找W列,找到對應(yīng)的列中的start_ts卤橄,通過該值從D列找到對應(yīng)的數(shù)據(jù)绿满。

二、MVCC版本控制與鎖清除窟扑、過期版本數(shù)據(jù)清除

1喇颁、TiDB的MVCC

由上面的內(nèi)容可知,在某一行的W列中嚎货,包含一個commit_ts橘霎,一個start_ts。前者是數(shù)據(jù)真正對外可見的標(biāo)志殖属,后者是寫入該數(shù)據(jù)的事務(wù)開始時間姐叁。兩者都是全局唯一,均可作為當(dāng)期數(shù)據(jù)的版本號忱辅,但以可用性來講七蜘,用commit_ts作為版本號更為直接。
當(dāng)系統(tǒng)運行一段時間墙懂,某行數(shù)據(jù)經(jīng)歷Tn次事務(wù)更新橡卤,在沒有清除歷史版本數(shù)據(jù)的情況下,就有Tn個版本的D列和W列损搬,此時如果有第Tn+1事務(wù)開始讀該行碧库,開始時間為Tn+1.start_ts。
假設(shè)Tn.commit_ts <Tn+1.start_ts,那么Tn版本的數(shù)據(jù)對于Tn+1是可見的巧勤,同時(Tn.commit_ts Tn+1.start_ts]這個時間段內(nèi)嵌灰,該行不能有L列,否則Tn+1對該行的讀將會阻塞颅悉,以防產(chǎn)生幻讀沽瞭。但是如果L列出現(xiàn)在(Tn+1.start_ts,+∞)時間段則不阻塞讀。通過該機制很容易實現(xiàn)對歷史版本數(shù)據(jù)的訪問剩瓶。

總的來說就是驹溃,新寫入的數(shù)據(jù)不會覆蓋舊的數(shù)據(jù)城丧,而且通過版本號來區(qū)分版本,即便是delete或者truncate操作豌鹤,數(shù)據(jù)也不會馬上清除亡哄,而是等待GC的任務(wù)執(zhí)行來清理。

2布疙、鎖清除與過期版本數(shù)據(jù)清除

TiDB本身包含GC機制用來清理歷史數(shù)據(jù)(默認(rèn)配置下蚊惯,GC 每 10 分鐘觸發(fā)一次,每次 GC 會保留最近 10 分鐘內(nèi)的數(shù)據(jù))灵临。流程如下:

  • 計算safe point時間點(如何計算截型?每行記錄safe point不一樣?)

  • 清理鎖俱诸,首先對于primary_lock菠劝,如果鑒定超時,則直接刪除并且回滾對應(yīng)事務(wù)睁搭,其次secondary_lock, 如果對應(yīng)的primary行已提交赶诊,對secondary_lock對應(yīng)的行也應(yīng)該提交,否則回滾园骆;如果 Primary 仍然是上鎖的狀態(tài)(沒有提交也沒有回滾)舔痪,則應(yīng)當(dāng)將該事務(wù)視為超時失敗而回滾。
    這里回到上面的問題锌唾,如果secondary_lock找不到primary行怎么辦锄码;是否可認(rèn)為primary行因回滾而刪除而不是因為GC而被刪除?這里需要明確的是晌涕,需要清理的都是位于上一次safepoint和此次safepoint之間的版本數(shù)據(jù)滋捶。因此需要先清理鎖,保證secondary_lock能夠找到primary行余黎,這樣的話重窟,只要找不到primary行就可以認(rèn)為該secondary_lock對應(yīng)的事務(wù)回滾了。

  • 進(jìn)行GC清理惧财。刪除所有Key在safePoint之前的數(shù)據(jù)(每個 key 保留 safe point 前的最后一次寫入巡扇,除非最后一次寫入是刪除),對于drop和truncate的大量連續(xù)數(shù)據(jù)刪除垮衷,將通過連續(xù)區(qū)間刪除的方式厅翔。
    (v2.1以前GC是對每一個region操作,v3.0之后搀突,只對region leader 操作GC)

三刀闷、樂觀事務(wù)與悲觀事務(wù)

TiDB 新特性漫談:悲觀事務(wù)一文中,作者用了一個比方:去餐廳吃飯,來說明樂觀事務(wù)和悲觀事務(wù):
樂觀事務(wù): 不管有沒有位涩赢,直接去餐廳戈次,去到要是沒有位子就回來。
悲觀事務(wù): 先電聯(lián)餐廳確定有沒有位置筒扒,預(yù)訂位置,然后再去绊寻。
如果餐廳的位置很多(沖突率低)花墩,那么直接去餐廳有座的概率就高,但是一旦每座就要白跑一趟澄步;加入餐廳經(jīng)常人滿為患冰蘑,直接去大概率就是要白跑一趟,這種情況下村缸,打電話提前問下沒有座位祠肥,然后支付定金預(yù)定代價更低。
這也引申出兩種事務(wù)模型的適用場景:對于并發(fā)事務(wù)沖突率高的場景(某部分?jǐn)?shù)據(jù)頻繁修改)的場景梯皿。悲觀事務(wù)控制可以避免因沖突而回滾的問題仇箱,但在沖突率比較低的場景,悲觀事務(wù)比樂觀事務(wù)性能要差东羹。

1剂桥、樂觀事務(wù)

percolator本身就是基于樂觀事務(wù)模型的實現(xiàn),來看下我從TiDB官網(wǎng)偷來的圖:


在這里插入圖片描述

由第一章可知道percolator通過兩階段提交保證事務(wù)原子性(prewrite和commit兩個階段)属提,在傳統(tǒng)的2PC概念里权逗,需要有一個專門的協(xié)調(diào)者(事務(wù)管理者)來記錄事務(wù)狀態(tài),協(xié)調(diào)者如若宕機冤议,事務(wù)的狀態(tài)將得不到保證斟薇。然而在percolator中弱化了這一概念,取而代之的是通過L列和W列來標(biāo)志事務(wù)的狀態(tài)(參考第一章中為何可以異步提交secondary行)恕酸。

1.1堪滨、 percolator的prewrite階段主要做了兩件事,寫數(shù)據(jù)(寫D列尸疆,但是沒有W列椿猎,對外不可見)和加鎖(寫L列),這也是會出現(xiàn)沖突的階段寿弱。
  • 首先在TIDB-server中犯眠,會先對落在同一個TIDB-server執(zhí)行的不同事務(wù)進(jìn)行沖突檢測,如有沖突將不會再tikv中開始percolator的兩階段提交症革。但是TiDB-Server無法感知到其他TiDB-Server的檢測情況筐咧,所以分布在其他TiDB-Server執(zhí)行的事務(wù)檢測沖突就得到tikv中判斷了。當(dāng)然也可以關(guān)閉TiDB-Server的沖突檢測,全部在tikv層檢測量蕊。

  • 寫寫沖突:寫寫沖突存在兩種情況:1铺罢、事務(wù)T1與事務(wù)T2,同時寫某行時残炮,T2先寫了L列韭赘,T1此時會檢測到?jīng)_突執(zhí)行回滾;2势就、在T1獲取start_ts1后到發(fā)起prewrite這段時間內(nèi)泉瞻,T2迅速獲取start_ts2占有鎖,并執(zhí)行完兩階段提交苞冯,此時會存在最新W列的commit_ts>T1.start_ts1袖牙,此時也會回滾。

  • 讀寫沖突:事務(wù)T獲取到start_ts舅锄,開始查詢[0,start_ts]期間的最新數(shù)據(jù)鞭达,結(jié)果發(fā)現(xiàn)這個期間存在L列,此時發(fā)生讀寫沖突皇忿。

    對于讀寫沖突畴蹭,可以參考第一章2.2中有說到如何解決。而對于寫寫沖突禁添,在樂觀事務(wù)模型中無法避免撮胧,可通過合并小事務(wù),減少不同事務(wù)間的發(fā)生沖突的幾率老翘,但是事務(wù)不能過大芹啥,大事務(wù)容易導(dǎo)致OOM問題,同時數(shù)據(jù)準(zhǔn)備時間長跟其他事務(wù)發(fā)生沖突的幾率也會增大铺峭,同時事務(wù)提交的時間也增大墓怀。官方建議100-500行之間一個事務(wù),但是具體得根據(jù)業(yè)務(wù)特性卫键,比如插入遠(yuǎn)遠(yuǎn)多于更新的業(yè)務(wù)系統(tǒng)傀履,該值可以考慮加大。

1.2莉炉、在commit階段钓账,也做了兩件事,讓數(shù)據(jù)對外可見(寫W列)絮宁,刪除L列梆暮。

這個階段容易出現(xiàn)鎖超時或者因為網(wǎng)絡(luò)問題導(dǎo)致鎖殘留的問題。但只要保證primary行完成提交绍昂,事務(wù)就可以任務(wù)提交完成啦粹,否則整個事務(wù)回退偿荷。(可參考第二章鎖清除的內(nèi)容)

樂觀事務(wù)模型中,在高沖突率的場景唠椭,事務(wù)很容易提交失敗跳纳。TiDB 樂觀事務(wù)提供了重試機制,但tidb默認(rèn)不重試事務(wù)贪嫂,重試時將重新獲取start_ts寺庄,必將導(dǎo)致無法保證可重復(fù)讀。為解決高沖突場景重試的問題撩荣,在tidb v3.0之后的版本中铣揉,實現(xiàn)了悲觀事務(wù),并從v3.0.8 開始餐曹,新創(chuàng)建的 TiDB 集群默認(rèn)使用悲觀事務(wù)模型。

2敌厘、悲觀事務(wù)

如果要解決percolator的prewrite階段的鎖沖突導(dǎo)致的回滾問題台猴,那么就要開始兩階段提交前就要先檢測鎖沖突的情況。但是TIDB是個分布式系統(tǒng)俱两,即便同一個tidb-server上的不同事務(wù)可以檢測鎖沖突饱狂,但是不同的tidb-server上的不同事務(wù)之間,就要有一個共同的地方保存鎖信息共享鎖信息宪彩。事實上TIDB也是這么做的休讳。我又偷了一張官網(wǎng)的圖:

在這里插入圖片描述

TiDB的悲觀事務(wù)是在樂觀事務(wù)的基礎(chǔ)上改過來的,可以看出跟樂觀事務(wù)不同是上圖紅圈的部分尿孔,即開始2PC之前就進(jìn)行鎖沖突檢測俊柔。
由圖可以看出,TIDB將鎖存儲在tikv中以便所有的TIDB-server共享活合,并通過raft算法將鎖內(nèi)容復(fù)制到多個節(jié)點防止單點故障雏婶。
在悲觀事務(wù)下,在percolator的prewrite階段將不會出現(xiàn)寫寫沖突白指,但是依然存在讀寫沖突的情況留晚。

寫請求遇到悲觀鎖時,等待解鎖或者鎖超時即可告嘲。但是并發(fā)事務(wù)請求鎖資源時错维,可能存在死鎖情況,比如T1: update a,b;T3: update b,a;T1經(jīng)過sql解析后橄唬,向tikv寫入a行的鎖赋焕,同時T2向tikv寫入了b行的鎖,此時T1/T2相互等待對方釋放鎖轧坎,出現(xiàn)了死鎖的情況宏邮。
在樂觀事務(wù)中,經(jīng)過tidb-server 的解析,在prewrite階段遇到鎖沖突會回滾重試(鎖超時時間很短)蜜氨,這個方式避免了死鎖械筛。
在悲觀事務(wù)中需要能夠檢測并發(fā)的不同事務(wù)之間是否有循環(huán)依賴的關(guān)系存在,并在檢測到循環(huán)依賴時(從tikv存儲的鎖信息中飒炎,很容易判斷不同事務(wù)之間是否存在循環(huán)依賴的鎖關(guān)系)提供仲裁埋哟,中止其中一個事務(wù)或讓其重試(因其還沒進(jìn)入2PC階段,因此代價很低)郎汪。TIDB的死鎖檢測機制是異步進(jìn)行的赤赊,不影響正常寫鎖和后續(xù)流程進(jìn)行,因此對不存在死鎖的事務(wù)不會產(chǎn)生延遲煞赢。

悲觀事務(wù)下抛计,與MySQLinnodb的部分差異,這部分內(nèi)容跟本文的原理內(nèi)容關(guān)系不大,僅做匯總記錄用照筑。

  • 有些 WHERE 子句中使用了 range吹截,TiDB 在執(zhí)行這類 DML 語句和 SELECT FOR UPDATE 語句時,不會阻塞 range 內(nèi)并發(fā)的 DML 語句的執(zhí)行凝危。
    舉例:
    CREATE TABLE t1 (
    id INT NOT NULL PRIMARY KEY,
    pad1 VARCHAR(100)
    );
    INSERT INTO t1 (id) VALUES (1),(5),(10);
    BEGIN /*T! PESSIMISTIC /;
    SELECT * FROM t1 WHERE id BETWEEN 1 AND 10 FOR UPDATE;
    BEGIN /
    T! PESSIMISTIC */;
    INSERT INTO t1 (id) VALUES (6); -- 僅 MySQL 中出現(xiàn)阻塞波俄。
    UPDATE t1 SET pad1='new value' WHERE id = 5; -- MySQL 和 TiDB 處于等待阻塞狀態(tài)。
    產(chǎn)生這一行為是因為 TiDB 當(dāng)前不支持 gap locking(間隙鎖)蛾默。
  • TiDB 不支持 SELECT LOCK IN SHARE MODE,使用這個語句執(zhí)行的時候懦铺,效果和沒有加鎖是一樣的,不會阻塞其他事務(wù)的讀寫支鸡。
  • DDL 可能會導(dǎo)致悲觀事務(wù)提交失敗冬念。MySQL 在執(zhí)行 DDL 語句時,會被正在執(zhí)行的事務(wù)阻塞住苍匆,而在 TiDB 中 DDL 操作會成功刘急,造成悲觀事務(wù)提交失敗。(說明TiDB 沒有實現(xiàn)類似MySQL的 MDL機制
  • START TRANSACTION WITH CONSISTENT SNAPSHOT 之后浸踩,MySQL 仍然可以讀取到之后在其他事務(wù)創(chuàng)建的表叔汁,而 TiDB 不能。

四检碗、事務(wù)隔離級別

1据块、可重復(fù)讀

TiDB 實現(xiàn)了快照隔離 (Snapshot Isolation, SI) 級別的一致性。為與 MySQL 保持一致折剃,又稱其為“可重復(fù)讀”另假。TiDB的事務(wù)隔離級別也是通過MVCC檢測版本可見性。

  • 只能讀到該事務(wù)啟動時已經(jīng)提交的其他事務(wù)修改的數(shù)據(jù)
  • 未提交的數(shù)據(jù)或在事務(wù)啟動后其他事務(wù)提交的數(shù)據(jù)是不可見的
  • 處于可重復(fù)讀隔離級別的事務(wù)不能并發(fā)的更新同一行怕犁,當(dāng)事務(wù)提交時發(fā)現(xiàn)該行在該事務(wù)啟動后边篮,已經(jīng)被另一個已提交的事務(wù)更新過己莺,那么該事務(wù)會回滾(因當(dāng)前事務(wù)的start_ts < 最新已提交事務(wù)的commit_ts。)

此處與MySQL不同戈轿,MySQL在可重復(fù)讀隔離級別下凌受,并發(fā)的兩個不同的事務(wù)生成的不同readview是可以更新同一條記錄的。MySQL的可重復(fù)讀隔離級別針對的是快照讀思杯,而對于update胜蛉,select for update此類當(dāng)前讀并不隔離。因此MySQL可重復(fù)讀的一致性要弱于TiDB色乾。

2誊册、讀已提交

從 TiDB v4.0.0-beta 版本開始,TiDB 支持使用 Read Committed 隔離級別暖璧。read Committed 隔離級別僅在悲觀事務(wù)模式下生效案怯。在樂觀事務(wù)模式下設(shè)置事務(wù)隔離級別為 Read Committed 將不會生效,事務(wù)將仍舊使用可重復(fù)讀隔離級別澎办。
(這里暫時還沒搞明白為何樂觀事務(wù)模式下設(shè)置事務(wù)隔離級別為 Read Committed 將不會生效)

參考

Percolator 論文筆記
經(jīng)典論文翻譯導(dǎo)讀之《Large-scale Incremental Processing Using Distributed Transactions and Notifications》

Percolator分布式事務(wù)模型原理與應(yīng)用
Percolator 和 TiDB 事務(wù)算法
TiDB 鎖沖突問題處理
TiKV 的 MVCC(Multi-Version Concurrency Control)機制
GC 機制
TiDB 樂觀事務(wù)模型
TiDB 樂觀事務(wù)原理與實踐
TiDB樂觀事務(wù)
樂觀事務(wù)模型下寫寫沖突問題排查
TiDB 4.0 新特性前瞻(二)白話“悲觀鎖”
TiDB 悲觀事務(wù)模型
TiDB 新特性漫談:悲觀事務(wù)
悲觀事務(wù)
TiDB 事務(wù)隔離級別
兩階段提交與三階段提交
關(guān)于分布式事務(wù)殴泰、兩階段提交協(xié)議、三階提交協(xié)議

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末浮驳,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子捞魁,更是在濱河造成了極大的恐慌至会,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谱俭,死亡現(xiàn)場離奇詭異奉件,居然都是意外死亡,警方通過查閱死者的電腦和手機昆著,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門县貌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人凑懂,你說我怎么就攤上這事煤痕。” “怎么了接谨?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵摆碉,是天一觀的道長。 經(jīng)常有香客問我脓豪,道長巷帝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任扫夜,我火速辦了婚禮楞泼,結(jié)果婚禮上驰徊,老公的妹妹穿的比我還像新娘。我一直安慰自己堕阔,他們只是感情好棍厂,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著印蔬,像睡著了一般勋桶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上侥猬,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天例驹,我揣著相機與錄音,去河邊找鬼退唠。 笑死鹃锈,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的瞧预。 我是一名探鬼主播屎债,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼垢油!你這毒婦竟也來了盆驹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤滩愁,失蹤者是張志新(化名)和其女友劉穎躯喇,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體硝枉,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡廉丽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了妻味。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片正压。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖责球,靈堂內(nèi)的尸體忽然破棺而出焦履,到底是詐尸還是另有隱情,我是刑警寧澤棕诵,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布裁良,位于F島的核電站,受9級特大地震影響校套,放射性物質(zhì)發(fā)生泄漏价脾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一笛匙、第九天 我趴在偏房一處隱蔽的房頂上張望侨把。 院中可真熱鬧犀变,春花似錦、人聲如沸秋柄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽骇笔。三九已至省店,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間笨触,已是汗流浹背懦傍。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留芦劣,地道東北人粗俱。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像虚吟,于是被迫代替她去往敵國和親寸认。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容