日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
聊聊TiDB的分布式事務(wù)模型

聊聊TiDB的分布式事務(wù)模型

作者: jinjunzhu 2021-02-01 09:35:53

運(yùn)維

數(shù)據(jù)庫運(yùn)維

分布式 務(wù)場景的復(fù)雜化,必然導(dǎo)致樂觀事務(wù)沖突變多,這也是TiDB后續(xù)版本轉(zhuǎn)向悲觀事務(wù)的重要原因。TiDB中樂觀事務(wù)和悲觀事務(wù)可以共存。

成都創(chuàng)新互聯(lián)公司是一家專業(yè)從事成都網(wǎng)站制作、成都網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司。作為專業(yè)網(wǎng)站建設(shè)公司,成都創(chuàng)新互聯(lián)公司依托的技術(shù)實(shí)力、以及多年的網(wǎng)站運(yùn)營經(jīng)驗(yàn),為您提供專業(yè)的成都網(wǎng)站建設(shè)、成都全網(wǎng)營銷推廣及網(wǎng)站設(shè)計(jì)開發(fā)服務(wù)!

本文轉(zhuǎn)載自微信公眾號「程序員jinjunzhu」,作者 jinjunzhu 。轉(zhuǎn)載本文請聯(lián)系程序員jinjunzhu公眾號。

在傳統(tǒng)關(guān)系型數(shù)據(jù)庫領(lǐng)域,我們常常通過配置事務(wù)的隔離級別來解決臟讀、幻讀、不可重復(fù)讀的問題。不同的事務(wù)隔離級別對應(yīng)解決問題的力度是不一樣的,下表是不同事務(wù)隔離級別對臟讀、幻讀、不可重復(fù)讀的容忍度,我們一起看一下:

注意:

Repeatable read的讀鎖會一直到事務(wù)結(jié)束才釋放;

Read committed的讀鎖不等到事務(wù)結(jié)束,而是讀取完成后立即釋放。

當(dāng)然,傳統(tǒng)數(shù)據(jù)庫解決并發(fā)控制的手段還有mvcc,這里就不展開了。

上面我提到了讀鎖,寫鎖、GAP鎖,實(shí)際上鎖的種類遠(yuǎn)遠(yuǎn)不止這些。對于我們開發(fā)者來講,經(jīng)常會談到樂觀鎖和悲觀鎖。樂觀鎖實(shí)際上是不加鎖的,悲觀鎖需要真正的加鎖。而在分布式數(shù)據(jù)庫領(lǐng)域,同樣需要并發(fā)控制,同樣也有樂觀事務(wù)和悲觀事務(wù)。

就TiDB來說,v3.0版本開始支持悲觀事務(wù),從v3.0.8開始,新搭建的TiDB集群已經(jīng)默認(rèn)使用悲觀事務(wù)了。

傳統(tǒng)數(shù)據(jù)庫加鎖

傳統(tǒng)數(shù)據(jù)庫的樂觀鎖,主要是在表中加入一個(gè)版本號字段,在更新的時(shí)候根據(jù)更新結(jié)果來進(jìn)行判斷是否成功。比如我們有一張表table_a, 我們在其中加一個(gè)version字段,下面是table_a表的1條記錄

表格

id name version
1jinjunzhu4

我們更新這條id=1的記錄,SQL如下:

  
 
 
 
  1. update table_a set name='xiaoming',version = version + 1 where id=1 and version=4 

這時(shí)如果SQL執(zhí)行結(jié)果返回更新行數(shù)是0,說明別的事務(wù)已經(jīng)更新了version字段,寫沖突產(chǎn)生,業(yè)務(wù)代碼必須處理這個(gè)沖突。高并發(fā)下如果對同一條記錄的修改操作非常多,勢必造成大量寫失敗。所以樂觀鎖更適合讀多寫少的場景。

傳統(tǒng)數(shù)據(jù)庫的悲觀鎖,是用物理加鎖的方式,還是上面的表,不需要version字段了,假如有2條記錄:

id name
1jinjunzhu
2xiaoming

這時(shí)加入我們要同時(shí)更新id=1的記錄和id=2的記錄,如果在一個(gè)事務(wù)內(nèi)完成,加鎖sql如下:

  
 
 
 
  1. select * from table_a where id in(1, 2) for update; 
  2. update table_a set name = 'zhangsan' where id=1; 
  3. update table_a set name = 'lisi' where id=2; 

悲觀鎖的問題是遇到長事務(wù),其他事務(wù)需要較長時(shí)間的鎖等待,所以oracle提供了下面的優(yōu)化,即發(fā)現(xiàn)待修改數(shù)據(jù)被鎖定后立刻返回失?。?/p>

  
 
 
 
  1. select * from table_a for update nowait 

Percolator模型

Percolator模型是Google提出的構(gòu)建在BigTable之上的分布式事務(wù)解決方案。Google的論文如下,文章鏈接見延伸閱讀[1]:

  
 
 
 
  1. 《Large-scale Incremental Processing Using Distributed Transactions and Notifications》 

我們以經(jīng)典的電商系統(tǒng)為例,假如系統(tǒng)中有訂單、賬戶和庫存3張表,用戶一次購物需要增加1條訂單記錄,賬戶表需要扣減金額,庫存表需要扣減庫存,而這3張表要操作的記錄分別在分布式數(shù)據(jù)庫的3個(gè)切片上,這時(shí)就需要應(yīng)對分布式事務(wù)了。

我們看一下Percolator算法模型:

初始階段

初始階段,我們假設(shè)訂單表記錄訂單數(shù)量是0,賬戶表記錄賬戶金額1000,庫存表記錄商品數(shù)量是100,客戶下了1個(gè)訂單后,訂單表增加1個(gè)訂單,賬戶表扣除金額100,庫存表扣減商品數(shù)量1。各個(gè)表的初始數(shù)據(jù)如下表:

上面表格中,":"前面是用時(shí)間戳表示的數(shù)據(jù)版本,后面是數(shù)據(jù)值。第一列是表名,第二列的低版本保存了數(shù)據(jù),第三列列保存了事務(wù)操作給數(shù)據(jù)加的鎖。第四列的高版本保存了指向保存數(shù)據(jù)版本的指針,比如6這個(gè)版本保存了指向了5這個(gè)版本數(shù)據(jù)的指針 6:data@5。

Prewrite階段

在Prewrite階段,協(xié)調(diào)節(jié)點(diǎn)向每個(gè)切片發(fā)送Prewrite命令。Percolator定義了 primary lock 即主鎖的概念,Prewrite階段,每個(gè)分布式事務(wù)只能有一個(gè)要修改的數(shù)據(jù)行可以獲得主鎖,本案例假如訂單表獲得了主鎖,其他表的鎖是指向這個(gè)主鎖的指針,叫做 secondary lock,如下表:

Prewrite階段,每個(gè)要修改的數(shù)據(jù)行會寫日志,并且根據(jù)時(shí)間戳記錄事務(wù)的私有版本,這里的私有版本就是7,這樣其他事務(wù)就不能操作這三條數(shù)據(jù)了。

注意,獲取主鎖時(shí),如果出現(xiàn)了下面的情況,就會加鎖失?。?/p>

1.其他事務(wù)已經(jīng)加鎖;

2.本次事務(wù)開始之后,要更新的數(shù)據(jù)被其他數(shù)據(jù)更新了。

commit階段

在commit階段,協(xié)調(diào)節(jié)點(diǎn)只需要跟擁有primary lock的切片進(jìn)行通信,所以本案例只需要跟訂單表所在切片通信。這時(shí)數(shù)據(jù)如下表:

我們注意到order表的鎖沒有了,而且增加了版本8指向版本7。說明訂單表已經(jīng)提交成功,沒有私有版本了,但是賬戶表和庫存表的私有版本還在。這是因?yàn)镻ercolator模型并不會同步commit賬戶表和庫存表,而是啟動異步線程來commit這兩張表并清理鎖。如果訂單表提交失敗,賬戶表和庫存表也都需要回滾。

提交成功后,最終數(shù)據(jù)如下表:

commit階段,因?yàn)閰f(xié)調(diào)節(jié)點(diǎn)只需要跟擁有主鎖的切片(這里是訂單表所在切片)進(jìn)行通信,保證了原子性,這樣就避免了commit時(shí)節(jié)點(diǎn)不能全部成功導(dǎo)致的數(shù)據(jù)不一致問題。

而Prewrite階段記錄了日志和私有版本,如果賬戶表和庫存表所在切片commit失敗,可以根據(jù)日志進(jìn)行再次commit,這樣就保證了數(shù)據(jù)最終一致。

這里要注意2點(diǎn):

1.主鎖的選擇是隨機(jī)的,比如本例中并不一定會選擇訂單表;

2.協(xié)調(diào)節(jié)點(diǎn)發(fā)送commit后訂單表先提交成功,這時(shí)如果其他事務(wù)要讀取賬戶服務(wù)和庫存服務(wù)的2條數(shù)據(jù),雖然2條數(shù)據(jù)上面還有l(wèi)ock,但是查找primary@order.bal發(fā)現(xiàn)已提交,所以是可以讀取的。不過讀取時(shí)需要做一下secondary lock清理工作。

TiDB樂觀事務(wù)模型

上面我們分析了Percolator模型,TiDB的樂觀事務(wù)正是使用了Percolator模型。

TiDB支持MVCC,事務(wù)啟動的時(shí)候,會使用一個(gè)時(shí)間戳start_ts作為當(dāng)前事務(wù)ID,同時(shí)作為MVCC的快照版本,之后的讀請求會讀取當(dāng)前快照版本下的數(shù)據(jù),數(shù)據(jù)校驗(yàn)成功后客戶端進(jìn)行兩階段commit,我們看一下下面的時(shí)序圖:

第一階段,TiDB收到客戶端請求后,首先會從緩存的待修改key中找出第一個(gè)發(fā)送prewrite請求,這個(gè)key加primary lock后返回成功。然后TiDB會對這個(gè)事務(wù)其他的所有的key發(fā)送prewrite請求,這些key加secondary lock后返回成功。

第二階段,prewrite成功后,TiDB首先會從PD獲取一個(gè)時(shí)間戳作為當(dāng)前事務(wù)的commit_ts,然后向primary lock key發(fā)送commit請求,primary lock key提交數(shù)據(jù)成功后清理掉primary lock返回成功。TiDB收到primary lock key的成功消息后給客戶端返回成功。

樂觀事務(wù)的沖突檢測主要是在prewrite階段,如果檢測到當(dāng)前的key已經(jīng)加鎖,會有一個(gè)等待時(shí)間,這個(gè)時(shí)間過后如果還沒有獲取到鎖,就返回失敗。因此當(dāng)多個(gè)事務(wù)修改同一個(gè)key時(shí),必然導(dǎo)致大量的鎖沖突。

注意:TiDB也有重試機(jī)制,默認(rèn)是關(guān)閉的。TiDB的重試會重新獲取start_ts,但是不會重新讀取數(shù)據(jù),因此不能保證可重復(fù)讀的隔離級別。詳細(xì)參考TiDB官方文檔。

TiDB悲觀事務(wù)模型

TiDB從v3.0 版本開始,引入了悲觀事務(wù)。

注意:v3.0.7及之前版本創(chuàng)建的集群升級到更高版本后,默認(rèn)還是采用樂觀事務(wù),只有新創(chuàng)建集群才會默認(rèn)使用悲觀事務(wù)。我們也可以采用下面命令來開啟悲觀事務(wù)。下面第1個(gè)語句會修改TiDB系統(tǒng)參數(shù),后面2個(gè)語句會忽略系統(tǒng)參數(shù),優(yōu)先級更高:

SET GLOBAL tidb_txn_mode = 'pessimistic';

BEGIN PESSIMISTIC;

BEGIN OPTIMISTIC;

為了兼容mysql,TiDB的悲觀事務(wù)和mysql很類似。悲觀事務(wù)支持可重復(fù)讀和讀已提交兩種隔離級別,默認(rèn)使用可重復(fù)讀。TiDB中樂觀事務(wù)和悲觀事務(wù)可以共存,會優(yōu)先會采用樂觀事務(wù),只有鎖沖突時(shí),才會使用悲觀事務(wù)。

使用悲觀事務(wù)的語句如下:

  
 
 
 
  1. UPDATE、DELETE、INSERT、SELECT FOR UPDATE 

TiDB的悲觀事務(wù)有幾點(diǎn)需要注意:

  • SELECT FOR UPDATE語句會對已提交的最新的數(shù)據(jù)而非所修改的行加上悲觀鎖
  • TiDB不支持GAP鎖,所以在FOR UPDATE語句的WHERE條件使用范圍條件時(shí),還是可以插入的,比如下面的sql如果id不沖突,還是可以插入成功的:
  
 
 
 
  1. SELECT * FROM t1 WHERE id BETWEEN 1 AND 10 FOR UPDATE; 
  • 可以通過innodb_lock_wait_timeout變量設(shè)置等待鎖超時(shí)時(shí)間,默認(rèn)是50s
  • 不支持支持FOR UPDATE NOWAIT語法
  • 如果Point Get和Batch Point Get算子沒有讀到數(shù)據(jù),依然會對給定的主鍵或者唯一鍵加鎖,阻塞其他事務(wù)對相同主鍵加鎖或者進(jìn)行寫入操作
  • 在悲觀事務(wù)執(zhí)行期間,如果執(zhí)行DDL操作,是可以成功的,但之后事務(wù)會提交失敗
  • 悲觀事務(wù)的執(zhí)行時(shí)間有上限,默認(rèn)為10分鐘,可以通過參數(shù)配置

總結(jié)

業(yè)務(wù)場景的復(fù)雜化,必然導(dǎo)致樂觀事務(wù)沖突變多,這也是TiDB后續(xù)版本轉(zhuǎn)向悲觀事務(wù)的重要原因。TiDB中樂觀事務(wù)和悲觀事務(wù)可以共存。

延伸閱讀:

[1].https://www.cs.princeton.edu/courses/archive/fall10/cos597B/papers/percolator-osdi10.pdf

[2].https://docs.pingcap.com/zh/tidb/stable/pessimistic-transaction

[3].https://docs.pingcap.com/zh/tidb/stable/optimistic-transaction

[4].https://pingcap.com/blog-cn/percolator-and-txn/


網(wǎng)站欄目:聊聊TiDB的分布式事務(wù)模型
URL網(wǎng)址:http://www.5511xx.com/article/dhshcsc.html