共計(jì) 2810 個(gè)字符,預(yù)計(jì)需要花費(fèi) 8 分鐘才能閱讀完成。
本篇內(nèi)容主要講解“分布式數(shù)據(jù)庫(kù)對(duì) 2PC 的優(yōu)化方法是什么”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓丸趣 TV 小編來(lái)帶大家學(xué)習(xí)“分布式數(shù)據(jù)庫(kù)對(duì) 2PC 的優(yōu)化方法是什么”吧!
兩階段提交 (2PC)
兩階段提交協(xié)議主要有 2 種,一種是應(yīng)用層的 TCC,比如阿里巴巴的 seata 就實(shí)現(xiàn)了 TCC 模式,這種模式的特點(diǎn)是每個(gè)服務(wù)都需要提供 try/confirm/cancel 這 3 個(gè)實(shí)現(xiàn),這 3 個(gè)實(shí)現(xiàn)需要在業(yè)務(wù)代碼中實(shí)現(xiàn),對(duì)業(yè)務(wù)侵入高。
今天我分享的是面向資源的 2PC 協(xié)議,最早由 Jim Gray 提出,整個(gè)事務(wù)分為 2 個(gè)階段,prepare 階段和 commit 階段,這 2 個(gè)階段由協(xié)調(diào)節(jié)點(diǎn)和 DB 資源管理器協(xié)作完成。
這里我們還是以經(jīng)典的電商系統(tǒng)為例,整個(gè)系統(tǒng)分為訂單、賬戶和庫(kù)存 3 個(gè)服務(wù),我們收到客戶的購(gòu)買請(qǐng)求后,協(xié)調(diào)節(jié)點(diǎn)需要協(xié)調(diào)訂單服務(wù)生成訂單,賬戶服務(wù)扣減商品款,庫(kù)存服務(wù)扣減商品庫(kù)存,假如這 3 個(gè)服務(wù)的數(shù)據(jù)庫(kù)在不同切片上,這個(gè)協(xié)調(diào)過(guò)程具體如下:
1.prepare 階段
協(xié)調(diào)節(jié)點(diǎn)向所有服務(wù)發(fā)送 prepare 請(qǐng)求,每個(gè)服務(wù)收到 prepare 請(qǐng)求后會(huì)嘗試執(zhí)行本地事務(wù),但不會(huì)真正提交本地事務(wù)。這個(gè)嘗試執(zhí)行的過(guò)程會(huì)檢查到是否具備執(zhí)行事務(wù)的條件,比如資源是否被鎖定等,當(dāng)所有服務(wù)都嘗試執(zhí)行成功后會(huì)給協(xié)調(diào)節(jié)點(diǎn)返回一個(gè) yes,如下圖:
2.commit/rollback 階段
如果 prepare 階段所有服務(wù)有返回了 yes,那么協(xié)調(diào)節(jié)點(diǎn)就會(huì)通知各個(gè)服務(wù)執(zhí)行 commit 操作,這時(shí)各個(gè)服務(wù)就會(huì)真正的提交本地事務(wù)。如下圖:
如果 prepare 階段有服務(wù)返回了 no,協(xié)調(diào)節(jié)點(diǎn)就需要通知所有服務(wù)進(jìn)行本地事務(wù)回滾。
2PC 存在問(wèn)題
上面我們簡(jiǎn)單地分析了 2PC 協(xié)議的執(zhí)行過(guò)程,那么 2PC 有什么問(wèn)題呢?
1. 性能問(wèn)題
本地事務(wù)在 prepare 階段鎖定資源,比如賬戶服務(wù)要扣減 xiaoming 這個(gè)賬戶的金額 100 元,那必須把 xiaoming 這個(gè)賬戶先鎖定。這樣如果有其他事務(wù)也要修改 xiaoming 這個(gè)賬戶,就必須等待前面的事務(wù)完成。這樣就造成了延遲和性能下降。
2. 協(xié)調(diào)節(jié)點(diǎn)單點(diǎn)故障
協(xié)調(diào)節(jié)點(diǎn)是單節(jié)點(diǎn)的,如果發(fā)生故障,整個(gè)事務(wù)會(huì)一直阻塞。比如第一個(gè)階段 prepare 成功了,但是第二個(gè)階段協(xié)調(diào)節(jié)點(diǎn)發(fā)出 commit 指令之前宕機(jī)了,所有服務(wù)的數(shù)據(jù)資源處于鎖定狀態(tài),后面的事務(wù)只能等待。
3. 數(shù)據(jù)不一致
如果第一階段 prepare 成功了,但是第二階段 commit 的時(shí)候,如果協(xié)調(diào)節(jié)點(diǎn)通知庫(kù)存服務(wù)失敗了,這樣就相當(dāng)于生成了訂單,扣減了賬戶,但是沒(méi)有扣減庫(kù)存。這導(dǎo)致了數(shù)據(jù)的不一致。
Percolator 模型
主流的 NewSQL 數(shù)據(jù)庫(kù),比如 TiDB,是用 Percolator 模型來(lái)解決的。如下官網(wǎng)鏈接:
https://pingcap.com/blog-cn/percolator-and-txn/
Percolator 模型來(lái)自于 Google 論文:
《Large-scale Incremental Processing Using Distributed Transactions and Notifications》
原文可以看下面連接,網(wǎng)上也有好多翻譯版的:
https://www.cs.princeton.edu/courses/archive/fall10/cos597B/papers/percolator-osdi10.pdf
Percolator 的前提是本地事務(wù)的數(shù)據(jù)庫(kù)支持多版本并發(fā)控制協(xié)議,也就是 mvcc。現(xiàn)在主流數(shù)據(jù)庫(kù)比如 mysql、oracle 都是支持的。
a) 初始階段
還是看上面我們提到的經(jīng)典電商案例,初始階段,我們假設(shè)訂單數(shù)量是 0,賬戶服務(wù)是 1000,庫(kù)存服務(wù)是 100,客戶下了 1 個(gè)訂單后,訂單服務(wù)增加 1 個(gè)訂單,賬戶服務(wù)扣除金額 100,庫(kù)存服務(wù)扣除商品數(shù)量 1。各個(gè)切片的初始數(shù)據(jù)如下表:
: 前面的是時(shí)間戳或者數(shù)據(jù)版本,后面是數(shù)據(jù)值。這 3 張表中,第一條記錄不保存真正的數(shù)據(jù),而是保存了指向真正數(shù)據(jù)的指針,比如訂單表中,6 這個(gè)版本的數(shù)據(jù)指向了 5 個(gè)版本的數(shù)據(jù),訂單數(shù)量是 0。
b)prepare 階段
在 prepare 階段,協(xié)調(diào)節(jié)點(diǎn)向每個(gè)服務(wù)發(fā)送了 prepare 命令,這 3 張表分別進(jìn)入了 prepare 階段。在 prepare 階段,Percolator 定義了主鎖的概念,每個(gè)分布式事務(wù)只能有一個(gè)服務(wù)獲得主鎖,比如本案例的訂單服務(wù),其他服務(wù)的鎖指向這個(gè)主鎖的指針,如下表:
prepare 階段,每個(gè)服務(wù)會(huì)寫日志,并且根據(jù)時(shí)間戳記錄事務(wù)的私有版本,這樣其他事務(wù)就不能操作這三條數(shù)據(jù)了。
c)commit 階段
在 commit 階段,協(xié)調(diào)節(jié)點(diǎn)只需要跟訂單服務(wù)通信,因?yàn)橛唵畏?wù)擁有 primary lock,也就是說(shuō)協(xié)調(diào)節(jié)點(diǎn)只跟擁有 primary lock 的切片通信。這時(shí)數(shù)據(jù)如下表:
這時(shí)我們注意到除了 order 服務(wù)的鎖沒(méi)有了,而且增加了版本 8 指向版本 7,說(shuō)明訂單服務(wù)已經(jīng)沒(méi)有私有版本了,但是賬戶服務(wù)和庫(kù)存服務(wù)的私有版本還在。Percolator 的獨(dú)特之處就是在這里,它會(huì)啟動(dòng)異步線程來(lái)更新賬戶服務(wù)和庫(kù)存服務(wù)。最終數(shù)據(jù)如下表:
因?yàn)閰f(xié)調(diào)節(jié)點(diǎn)只需要跟獲取 primary lock 的切片進(jìn)行通信,要么成功要么失敗這樣就避免了 commit 時(shí)節(jié)點(diǎn)不能全部成功導(dǎo)致的數(shù)據(jù)不一致問(wèn)題。
而 prepare 階段記錄了日志,如果某個(gè)切片 commit 失敗,可以根據(jù)日志進(jìn)行再次 commit,這樣就保證了數(shù)據(jù)最終一致。
如果協(xié)調(diào)節(jié)點(diǎn)宕機(jī)了,異步線程可以做資源的釋放工作,避免了因單點(diǎn)故障通信失敗造成的資源不能釋放。
這里我們要注意 2 點(diǎn):
primary lock 的選擇是隨機(jī)的,比如本例中并不一定會(huì)選擇訂單服務(wù)
協(xié)調(diào)節(jié)點(diǎn)發(fā)送 commit 后訂單服務(wù)先提交成功,這時(shí)如果其他事務(wù)要讀取賬戶服務(wù)和庫(kù)存服務(wù)的 2 條數(shù)據(jù),雖然 2 條數(shù)據(jù)上面還有 lock,但是查找 primary@order.bal 發(fā)現(xiàn)已提交,所以是可以讀取的。
總結(jié)
2PC 協(xié)議有 3 個(gè)問(wèn)題,性能問(wèn)題、單點(diǎn)故障和數(shù)據(jù)不一致。
Percolator 模型簡(jiǎn)化了協(xié)調(diào)節(jié)點(diǎn)和切片的通信流程,讓協(xié)調(diào)節(jié)點(diǎn)只跟其中一個(gè) primary 切片通信,一方面,減少了通信開(kāi)銷,另一方面,避免了因?yàn)閱吸c(diǎn)故障,commit 階段部分節(jié)點(diǎn)通信失敗導(dǎo)致的數(shù)據(jù)不一致問(wèn)題。
Percolator 在 prepare 階段記錄了日志,這樣即使協(xié)調(diào)節(jié)點(diǎn)故障了,恢復(fù)后也可以根據(jù)日志來(lái)做事務(wù)恢復(fù)。
Percolator 使用異步線程來(lái)做資源的釋放工作,這樣即使協(xié)調(diào)節(jié)點(diǎn)故障了,也不用擔(dān)心資源得不到釋放。
知名的 NewSQL 數(shù)據(jù)庫(kù) TiDB 就是參照 Percolator 模型來(lái)對(duì) 2PC 協(xié)議進(jìn)行優(yōu)化的。
但是我們要知道,2PC 的性能問(wèn)題還是存在的,好在主流的分布式數(shù)據(jù)庫(kù)都做了優(yōu)化,性能損耗只會(huì)越來(lái)越小。
到此,相信大家對(duì)“分布式數(shù)據(jù)庫(kù)對(duì) 2PC 的優(yōu)化方法是什么”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是丸趣 TV 網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!