為了保證最終一致性, 在錯(cuò)誤發(fā)生時(shí), 沿著整個(gè)錯(cuò)誤的傳遞路徑進(jìn)行undo操作. 對于復(fù)雜的工作流來說, 盡可能保證相互依賴的流程上數(shù)據(jù)語義的最終一致性.
問題
在分布式環(huán)境中, 大量的數(shù)據(jù)在節(jié)點(diǎn)間不斷的傳輸和被修改. 為了保證整個(gè)系統(tǒng)的性能, 任何一個(gè)節(jié)點(diǎn)往往都是要求最終一致性, 而不是全局強(qiáng)一致性. 在最終一致性的模式下, 分布式環(huán)境中的每個(gè)點(diǎn)維護(hù)自己的狀態(tài)機(jī), 從全局來看, 整個(gè)系統(tǒng)處于不一致的狀態(tài). 但所有的節(jié)點(diǎn)在執(zhí)行完規(guī)定操作后, 整個(gè)系統(tǒng)可以最終達(dá)到一致的狀態(tài)(沒有新數(shù)據(jù)進(jìn)來的情況下)
這種設(shè)計(jì)帶來的問題就是當(dāng)一個(gè)操作在某個(gè)環(huán)節(jié)出問題了, 希望對數(shù)據(jù)進(jìn)行回滾, 但是這個(gè)操作很可能無法成功. 因?yàn)樯嫌蔚姆?wù)可能已經(jīng)使用了錯(cuò)誤的數(shù)據(jù), 而下游服務(wù)可能還沒有把錯(cuò)誤數(shù)據(jù)寫入. 回滾過程就不是簡單的達(dá)到一個(gè)正確的一致性狀態(tài), 而是達(dá)到一個(gè)業(yè)務(wù)可以容忍的一致性狀態(tài)
因此我們需要根據(jù)業(yè)務(wù)執(zhí)行一定的補(bǔ)償策略, 盡可能的回滾受到影響的數(shù)據(jù), 及時(shí)終止錯(cuò)誤數(shù)據(jù)的傳播, 并對已經(jīng)出錯(cuò)無法恢復(fù)的業(yè)務(wù)執(zhí)行一定的補(bǔ)償操作, 如根據(jù)日志進(jìn)行非常重的重算, 或者等待新的正確數(shù)據(jù)覆蓋舊數(shù)據(jù)等.
解決
這種設(shè)計(jì)模式是和業(yè)務(wù)緊耦合的, 一般來說, 是通過維護(hù)一個(gè)業(yè)務(wù)流.系統(tǒng)會對整個(gè)業(yè)務(wù)流進(jìn)行狀態(tài)記錄, 當(dāng)回滾時(shí), 針對workflow的狀態(tài)機(jī)進(jìn)行回滾. 由于狀態(tài)機(jī)是維護(hù)在各個(gè)節(jié)點(diǎn)上的, 所以回滾過程可以并發(fā)進(jìn)行.
從這個(gè)描述, 我們知道, 能夠執(zhí)行這種操作的業(yè)務(wù)必須是能夠接受最終一致性,所有操作必須是冪等的
決策
錯(cuò)誤判斷 一個(gè)業(yè)務(wù)是否失敗了往往是難以判斷的, 一種情況是服務(wù)端的exception則可以判斷為立即失敗. 另外一種, 如一個(gè)預(yù)約系統(tǒng), 預(yù)約醫(yī)生后醫(yī)生因急事無法赴約, 這種業(yè)務(wù)端的失敗很難被捕捉到
補(bǔ)償機(jī)制難以被確定 如何回滾狀態(tài)機(jī), 回滾過程失敗如何挽救等等都難以進(jìn)行邏輯編程
非冪等操作 非冪等的操作無法回滾很容易理解, 如何把冪等操作轉(zhuǎn)化成冪等操作是一個(gè)非常大的挑戰(zhàn)
操作序列的影響 在回滾時(shí)可能又改變了很多狀態(tài), 能夠單獨(dú)回撤一個(gè)狀態(tài), 還是一起回滾, 回撤時(shí)的順序是否有影響?
示例
我們假設(shè)有這樣的一個(gè)業(yè)務(wù)場景是某旅游服務(wù)提供商, 客戶依次進(jìn)行如下操作
- 訂Flight 1航班, 從北京到上海
- 訂Flight 2航班, 從上海到杭州
- 訂Flight 3航班, 從杭州回北京
- 在上海H1酒店訂一個(gè)房間
- 在杭州H2酒店訂一個(gè)房間
這一系列操作在業(yè)務(wù)上是相互關(guān)聯(lián)的, 但每個(gè)操作本身對于數(shù)據(jù)庫來說是原子的. 由于業(yè)務(wù)的異步性和延時(shí)性, 很可能客戶的所有航班和杭州的H2旅館反饋正常使用, 但上海H1旅館因?yàn)榉N種原因在2小時(shí)后返回失敗信息, 或者更進(jìn)一步的, 返回信息表示取消之前成功的操作.
一個(gè)服務(wù)非常好的公司, 會注意到這個(gè)操作鏈, 通知用戶, 并根據(jù)用戶的意愿對關(guān)聯(lián)環(huán)節(jié)進(jìn)行"回滾". 這里的"回滾"往往是基于策略的補(bǔ)償式的. 如發(fā)現(xiàn)用戶的航班購買成功, 但旅館失敗,則補(bǔ)償更高級別的同區(qū)域旅館, 旅館成功但航班失敗則補(bǔ)償票價(jià)并自動取消旅館的訂房.
類似這樣的業(yè)務(wù)操作, 需要能夠理解用戶意圖, 并把多個(gè)原子操作合并成相互關(guān)聯(lián)的一個(gè)大操作來面對.
同時(shí)再業(yè)務(wù)層對回滾進(jìn)行策略編程, 形成基于業(yè)務(wù)的回滾機(jī)制