微服务Apache ServiceComb 数据一致性Saga演进介绍
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
ServiceComb數(shù)據(jù)一致性解決方案Saga演進(jìn)介紹
?
本文轉(zhuǎn)自 微服務(wù) 開源項(xiàng)目 Apache ServiceComb (incubating) 的官方博客:
http://servicecomb.incubator.apache.org/cn/docs/saga_pack_design/
?
傳統(tǒng)的單體應(yīng)用的微服務(wù)化改造過程中大多會(huì)面臨數(shù)據(jù)庫(kù)拆分,故而原來由數(shù)據(jù)庫(kù)保證的數(shù)據(jù)一致性也一定面臨重新設(shè)計(jì)和實(shí)現(xiàn),此時(shí)需要引入分布式數(shù)據(jù)一致性方案來解決。常見的解決方案主要有2PC,TCC,事件驅(qū)動(dòng)等,而在微服務(wù)開源項(xiàng)目 ServiceComb中提出并實(shí)現(xiàn)了使用Saga[1]來解決微服務(wù)的數(shù)據(jù)一致性難題,不同方案的對(duì)比可參考《ServiceComb中的數(shù)據(jù)最終一致性方案》[2]一文。Saga是一個(gè)數(shù)據(jù)最終一致性的解決方案,它允許我們成功地執(zhí)行所有事務(wù),或在任何事務(wù)失敗的情況下,補(bǔ)償已成功的事務(wù),并提供了ACID[3]中ACD的保證(由于事務(wù)是交錯(cuò)執(zhí)行的,可能會(huì)看到其他事務(wù)的部分結(jié)果,因此不能滿足隔離性要求)。因此,Saga適用于以下跨服務(wù)的事務(wù)場(chǎng)景:
- 嵌套調(diào)用。如網(wǎng)上購(gòu)物時(shí),會(huì)依次經(jīng)過下單、支付服務(wù)和第三方支付這幾個(gè)子事務(wù),其中,下單依賴于支付服務(wù)的返回狀態(tài),而支付服務(wù)也包含了多種可選的支付方式,并依賴于具體支付方式返回的結(jié)果。通過Saga,可以清晰地看到一個(gè)完整事務(wù)中各個(gè)服務(wù)之間的關(guān)系,在異常時(shí)也能快速定位出現(xiàn)問題的子事務(wù)。
- 高并發(fā)。如秒殺場(chǎng)景下,在成功扣除庫(kù)存和完成支付后方可認(rèn)為秒殺成功,若成功扣除庫(kù)存但支付失敗則自動(dòng)進(jìn)行補(bǔ)償(即恢復(fù)庫(kù)存)。鑒于Saga只有提交和補(bǔ)償兩種狀態(tài),成功場(chǎng)景下只需對(duì)每個(gè)子事務(wù)進(jìn)行一次調(diào)用即可,因此可以在高并發(fā)下保持高性能。
- 調(diào)用時(shí)間長(zhǎng)。如線上購(gòu)買電影票,選好座位后一般會(huì)有15分鐘的支付時(shí)間。Saga僅在子事務(wù)的提交階段對(duì)資源進(jìn)行短暫的鎖定,且通過超時(shí)機(jī)制確保事務(wù)超時(shí)后能自動(dòng)補(bǔ)償,即在規(guī)定時(shí)間內(nèi)沒有支付成功的話就自動(dòng)釋放鎖定的座位,極大地簡(jiǎn)化了業(yè)務(wù)出現(xiàn)異常時(shí)的處理邏輯。
Saga新版本演進(jìn)
新年新氣象,Apache ServiceComb(incubating) Saga[4](以下簡(jiǎn)稱Saga)進(jìn)行了演進(jìn)。相對(duì)于上一版[2],新演進(jìn)的設(shè)計(jì)主要有以下優(yōu)勢(shì):
- 極大提升易用性。開發(fā)者只需使用2-3個(gè)注解(即啟用事務(wù)服務(wù):EnableOmega、全局事務(wù)標(biāo)記:SagaStart和子事務(wù)標(biāo)記:Compensable)。
- 更方便擴(kuò)展。對(duì)微服務(wù)框架的支持更友好。
- 數(shù)據(jù)一致性與業(yè)務(wù)邏輯解耦。在演進(jìn)后的設(shè)計(jì)中,通過服務(wù)側(cè)omega的引入,saga協(xié)調(diào)器的職責(zé)更為單一(只需負(fù)責(zé)協(xié)調(diào)事務(wù)的完整性),與具體業(yè)務(wù)無關(guān),因此,開發(fā)人員可以聚焦在具體業(yè)務(wù)的開發(fā)。
Saga演進(jìn)后的架構(gòu),如下圖所示,主要包含兩個(gè)組件,即alpha和omega,其中:
- alpha充當(dāng)協(xié)調(diào)者的角色,主要負(fù)責(zé)對(duì)事務(wù)的事件進(jìn)行持久化存儲(chǔ)以及協(xié)調(diào)子事務(wù)的狀態(tài),使其最終得以與全局事務(wù)的狀態(tài)保持一致,即保證事務(wù)中的子事務(wù)要么全執(zhí)行,要么全不執(zhí)行。
- omega是微服務(wù)中內(nèi)嵌的一個(gè)agent,負(fù)責(zé)對(duì)網(wǎng)絡(luò)請(qǐng)求進(jìn)行攔截并向alpha上報(bào)事務(wù)事件,并在異常情況下根據(jù)alpha下發(fā)的指令執(zhí)行相應(yīng)的補(bǔ)償或重試操作。
omega內(nèi)部運(yùn)行機(jī)制
omega是微服務(wù)中內(nèi)嵌的一個(gè)agent,負(fù)責(zé)向alpha上報(bào)事務(wù)狀態(tài)并與其它omega直接傳遞事務(wù)上下文信息。其中,每個(gè)服務(wù)的事務(wù)上下文包括:
- 全局事務(wù)id(Global Tx Id):用于唯一標(biāo)識(shí)全局事務(wù),一般在全局事務(wù)入口生成,并在整個(gè)事務(wù)過程中傳遞。
- 本地事務(wù)id(Local Tx Id):用于唯一標(biāo)識(shí)本地事務(wù),一般由本地事務(wù)生成。
- 父事務(wù)id(Parent Tx Id):用于構(gòu)建子事務(wù)間的關(guān)系,可由請(qǐng)求上下文中構(gòu)建。
如下圖所示,分布式事務(wù)與用于分布式調(diào)用鏈追蹤的zipkin[5]的處理流程很類似,在服務(wù)提供方,omega會(huì)將請(qǐng)求攔截并從中提取請(qǐng)求信息中的全局事務(wù)id作為其自身的全局事務(wù)id(即Saga事件id),并將請(qǐng)求中的本地事務(wù)id作為其父事務(wù)id,且使用新生成的id作為本地事務(wù)id;在服務(wù)消費(fèi)方,omega會(huì)將請(qǐng)求攔截并往其中添加當(dāng)前的全局事務(wù)id和本地事務(wù)id。通過服務(wù)提供方和服務(wù)消費(fèi)方的這種協(xié)作處理,子事務(wù)能連接起來形成一個(gè)完整的全局事務(wù)。
omega在預(yù)處理階段會(huì)先向alpha發(fā)送事務(wù)開始的事件,在后處理階段會(huì)再向alpha發(fā)送事務(wù)結(jié)束的事件。alpha在收到事件后會(huì)進(jìn)行持久化的存儲(chǔ)。因此,每個(gè)成功的子事務(wù)都有一一對(duì)應(yīng)的開始及結(jié)束事件。
在omega啟動(dòng)時(shí)會(huì)向alpha注冊(cè),使得異常或者超時(shí)場(chǎng)景下,alpha能通過回調(diào)向omega發(fā)送重試或補(bǔ)償?shù)拿詈拖鄳?yīng)的調(diào)用參數(shù),從而確保全局事務(wù)的一致性。
具體處理流程
成功場(chǎng)景
全局事務(wù)開始前omega會(huì)先向alpha發(fā)送全局事務(wù)開始的事件,并在所有子事務(wù)完成時(shí)向alpha發(fā)送全局事務(wù)結(jié)束的事件。而每個(gè)子事務(wù)在執(zhí)行前也會(huì)向alpha發(fā)送事務(wù)開始的事件,在成功執(zhí)行后,會(huì)向alpha發(fā)送事務(wù)結(jié)束的事件。子事務(wù)間通過全局事務(wù)id連接在一起,但也因本地事務(wù)id而有所區(qū)分。因此,在成功場(chǎng)景下,每個(gè)開始的事件都會(huì)有對(duì)應(yīng)的結(jié)束事件。
異常場(chǎng)景
在子事務(wù)執(zhí)行期間拋出異常時(shí),omega會(huì)向alpha上報(bào)aborted事件,然后alpha會(huì)向該全局事務(wù)的其它已完成的子事務(wù)發(fā)送補(bǔ)償指令,確保最終同一全局事務(wù)下的所有子事務(wù)要么都成功,要么都回滾。由于事務(wù)中沒有明確指定全局事務(wù)中的參與者,因此,alpha的掃描器會(huì)定期查詢事件表并找出已完成所有補(bǔ)償子事務(wù)的全局事務(wù),然后對(duì)這些全局事務(wù)添加全局事務(wù)結(jié)束事件以保證事務(wù)的完整性。
超時(shí)場(chǎng)景
alpha的掃描器會(huì)定期掃描正在處理的事件狀態(tài),若發(fā)現(xiàn)事件超時(shí),則會(huì)記錄相應(yīng)的aborted事件,然后alpha會(huì)向該全局事務(wù)的其它已完成的子事務(wù)發(fā)送補(bǔ)償指令來恢復(fù)至事務(wù)開始前的狀態(tài)。
如何使用?
Saga的使用主要涵蓋兩方面,alpha的啟動(dòng)及omega的使用。
alpha的啟動(dòng)
alpha啟動(dòng)前需要先運(yùn)行數(shù)據(jù)庫(kù)PostgreSQL:
docker run -d -e "POSTGRES_DB=saga" -e "POSTGRES_USER=saga" -e "POSTGRES_PASSWORD=password" -p 5432:5432 postgres?
在確保數(shù)據(jù)庫(kù)正常啟動(dòng)后,即可運(yùn)行alpha:
docker run -d -p 8090:8090 \-e "JAVA_OPTS=-Dspring.profiles.active=prd" \-e "spring.datasource.url=jdbc:postgresql://{docker.host.address}:5432/saga?useSSL=false" \alpha-server:0.1.0?
omega的使用
omega的使用很簡(jiǎn)單,以一個(gè)簡(jiǎn)化的轉(zhuǎn)賬業(yè)務(wù)為例,同一筆轉(zhuǎn)賬要么轉(zhuǎn)入和轉(zhuǎn)出都成功,要么都失敗。在這樣一個(gè)業(yè)務(wù)中引入Saga,只需簡(jiǎn)單幾步即可:
?
Copy
2.2 在全局事務(wù)的起點(diǎn)添加?@SagaStart?的注解。
@SagaStart(timeout=10)public boolean transferMoney(String from, String to, int amount) {transferOut(from, amount);transferIn(to, amount);}?
2.3 在子事務(wù)處添加?@Compensable?的注解并指明其對(duì)應(yīng)的補(bǔ)償方法。其中,補(bǔ)償方法的形參列表需與子事務(wù)方法的形參列表保持一致。
@Compensable(timeout=5, compensationMethod="cancel")public boolean transferOut(String from, int amount) {repo.reduceBalanceByUsername(from, amount);}public boolean cancel(String from, int amount) {repo.addBalanceByUsername(from, amount);}?
2.4 對(duì)轉(zhuǎn)入服務(wù)重復(fù)第2.3步即可。
2.5 在每個(gè)服務(wù)的application.yaml中添加配置項(xiàng),指明服務(wù)信息和alpha的地址信息:
spring:application:name: {application.name}alpha:cluster:address: {alpha.cluster.addresses}?
目前Saga的實(shí)現(xiàn)還存在著很多有意思且有挑戰(zhàn)性的課題,如alpha的協(xié)調(diào)調(diào)度實(shí)現(xiàn)、冪等的實(shí)現(xiàn)及自動(dòng)補(bǔ)償?shù)膶?shí)現(xiàn)等,歡迎有志之士與我們攜手一起解決數(shù)據(jù)一致性的難題,共同為完善微服務(wù)生態(tài)貢獻(xiàn)自己的力量。
如何加入Apache ServiceComb 社區(qū):
http://servicecomb.incubator.apache.org/cn/docs/join_the_community/
?
參考文獻(xiàn)
[1] Apache ServiceComb 官網(wǎng),
http://servicecomb.incubator.apache.org/cn/
[2] 代碼參考項(xiàng)目地址? Apache ServiceComb(incubating) Saga,
https://github.com/apache/incubator-servicecomb-saga
[3] ServiceComb中的數(shù)據(jù)最終一致性方案,
http://servicecomb.incubator.apache.org/cn/docs/distributed_saga_1/
http://servicecomb.incubator.apache.org/cn/docs/distributed_saga_2/
http://servicecomb.incubator.apache.org/cn/docs/distributed_saga_3/
[4] Sagas, Hector Garcia-Molina & Kenneth Salem,?
https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf
[5] ACID, Wikipedia,?
https://en.wikipedia.org/wiki/ACID
[6] zipkin, zipkin,?
https://github.com/openzipkin/zipkin
[7] 碼云地址,
https://gitee.com/servicecomb
https://www.oschina.net/p/servicecomb
轉(zhuǎn)載于:https://my.oschina.net/u/3823482/blog/1798723
總結(jié)
以上是生活随笔為你收集整理的微服务Apache ServiceComb 数据一致性Saga演进介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Vue安装jquery插件
- 下一篇: UWP 剪贴板 Clipboard