BASE 理論是由 Dan Pritchett 在 ACM 上發表的一篇論文中提出的理論。是在 CAP 理論基礎上提出的一種更實際的理論指導,和 PACELC 理論是有些相近的地方的。
BASE 是指 基本可用(Basically Available)、軟狀態( Soft State)、最終一致性( Eventual Consistency)。
對於目前的網際網路應用,基本上都不會是單機系統,而是多機分散式系統,所以 CAP 中的 P 是一定要的特性。剩下的 C P 根據實際場景取捨。BASE 就是一種取捨方案的指導。
假設我們微服務系統結構是:
假設我們系統有如下幾個業務需求:
- 查詢賬戶餘額(涉及賬戶微服務)
- 商品下單(涉及賬戶微服務,訂單微服務,商品微服務)
- 商品剩餘庫存(涉及商品微服務)
- 檢視使用者訂單(涉及訂單微服務,商品微服務)
1. 基本可用(Basically Available)
基本可用主要包括三點:
- 目前系統能承受的壓力範圍內的請求是正常處理的,超過範圍的可能處理不正常,但是不能因為這些請求影響正常的請求。
- 響應時間正常,在壓力大的時候,響應時間可能增長,但是不能超過一定時間
- 可以忍受一定的功能損失,在某些系統出問題的時候,其他系統應該保證本身業務介面正常的執行。
1.1. 目前系統能承受的壓力範圍內的請求是正常處理的
在雙 11 的時候,使用者量會突然增高,並且這個量很難預測,尤其是商品下單的業務壓力會增大很多,可能超過系統的極限。在超過系統極限的時候,可能會導致整個系統都不可用(例如超過超時極限導致很多請求在佇列排隊導致後續請求也排隊從而雪崩),這是不可取的。
所以,一般會考慮動態擴容,根據業務壓力,進行相應的系統微服務的擴容。並且由於動態擴容一般具有滯後性,還需要加上限流器,對某些敏感業務請求根據微服務數量進行動態限制,防止雪崩的出現。
1.2. 響應時間正常
在閒時,使用者請求下單可能是毫秒級返回,在系統壓力大的時候,這個響應時間可以適當加大,例如 3s 返回。但是這個響應超時時間不要設定太長,第一影響使用者體驗,第二會導致更多請求排隊。
對於不同的業務介面最好設定不同的響應超時時間,例如查詢賬戶餘額超時時間短一些,檢視使用者訂單可以稍微長一些。
可以根據系統介面的平均響應時間,請求的個數,制定系統擴容策略
1.3. 可以忍受一定的功能損失
這個主要在於微服務的拆分,以及服務降級策略
比如現在商品微服務因為壓力過大掛了,或者重啟,這時候的業務:
- 查詢賬戶餘額(涉及賬戶微服務),這個由於微服務隔離不受影響
- 查詢商品剩餘庫存(涉及商品微服務),這個系統掛了,需要服務降級,例如返回商品庫存載入中(前端定時查詢),或者商品庫存為 0.
- 商品下單,目前不可用
- 檢視使用者的訂單,可能裡面的商品資訊顯示不出來(服務降級),但是訂單列表,以及其中的訂單金額、交易時間資訊等等應該可以展示,而不是整個介面報異常。
2. 軟狀態(Soft State)
指的是允許系統中的資料存在中間狀態,並認為該狀態不影響系統的整體可用性,即允許系統在多個不同節點的資料副本存在資料延時。
例如下單,訂單可以有 初始化 -> 已凍結金額 -> 已扣庫存 -> 已扣款 -> 下單成功 這幾個狀態,如果扣庫存失敗則變為 待解凍金額 -> 下單失敗 狀態,分別對應下單的幾個中間邏輯。除了下單成功與下單失敗以外,其他的都是軟狀態,並不是最終狀態。基本上所有的軟狀態都需要對應的補償任務。有了這些中間狀態,即使系統重啟,也可以通過這些中間狀態補償重試將下單邏輯走下去。
查詢訂單的時候,在已凍結金額狀態之後的訂單就可以展示給使用者看了,在下單成功之前,都可以顯示為處理中。在扣庫存失敗之後,可以顯示為退款中。
3. 最終一致性(Eventually Consistent)
上面提到的軟狀態,並不會一直保持在這個軟狀態,而是最終通過系統正常邏輯或者補償邏輯走向最終狀態,各個節點也會同步這個最終狀態,這就是最終一致性。
Werner Vogels針對這個最終一致性,總結了五種實現最終一致性的不同場景方案,分別是:
- Causal consistency(因果一致性)
- Read-your-writes consistency(讀你所寫一致性)
- Session consistency(會話級別一致性)
- Monotonic read consistency(單調讀一致性)
- Monotonic write consistency(單調寫一致性)
在實際的實踐中,這 5 種設計方案往往會互相結合使用,以構建一個具有最終一致性的分散式系統。
3.1. Causal consistency(因果一致性)
因果關係的意思是程式 A 的修改會通知程式 B,沒有因果一致性的就是程式 A 的修改不會通知程式 C。對於有因果關係的程式,他們訪問的資料應該是強一致性的,沒有這個關係的走的是最終一致性。
舉一個例子,使用者檢視商品庫存的請求是非常巨大的,並且能接受一點時間內的不一致。假設為了應對這麼大的請求,這個庫存在商品微服務例項本地也快取了一份,並且會隨著收到下單請求就會將快取失效重新獲取扣庫存後最新的庫存量,同時這個快取 5s 後一定會過期(真正扣庫存不會使用這個快取,這個僅僅展示用)。那麼下單請求通過訂單微服務 RPC 請求的商品微服務例項上面的庫存就是最新的庫存,其他例項的庫存可能有點滯後性。
3.2. Read-your-writes consistency(讀你所寫一致性)
程式 A 在更新了資料項之後,總是訪問更新的值,永遠不會看到舊的值。這是因果一致性模型的一個特例。
3.3. Session consistency(會話級別一致性)
在同一個會話內的修改,是可以立刻讀取到最終修改的。在其他會話可能不會立刻讀取到。
例如資料庫的主從同步,請求在這個會話內寫入主資料庫,那麼主資料庫會話能立刻讀取到這個修改,根據資料庫的雙 1 同步配置,預設情況下,只有同步完成後才能讀取到這個修改。
3.4. Monotonic read consistency(單調讀一致性)
如果一個節點從系統中讀取出一個資料項的某個值後,那麼系統對於該節點後續的任何資料訪問都不應該返回更舊版本的值。
3.5. Monotonic write consistency(單調寫一致性)
系統要保證同一個節點的寫操作是順序執行的。
微信搜尋“我的程式設計喵”關注公眾號,每日一刷,輕鬆提升技術,斬獲各種offer: