05服務冪等設計
冪等定義
請求層面冪等
保證請求重復執(zhí)行和執(zhí)行一次的結果一致
業(yè)務層面冪等
- 同一用戶不重復下單
- 商品不超賣
- MQ消費端去重
冪等目的
交易、轉賬等操作在重試的時候不會出錯。如果每個請求失敗之后直接返回給用戶,則不用考慮冪等。
數據訪問層冪等
- Create操作禁止使用auto increment id,使用業(yè)務相關的唯一ID可以保證操作冪等
- Read操作本身冪等
- Update操作分為兩種,絕對值更新是冪等的,相對值更新不是冪等的
- Delete操作分為兩種,絕對值刪除是冪等的,相對值刪除不實冪等的
冪等案例
QQ離線消息的已讀狀態(tài)(請求層面冪等)
天然冪等操作
計數增加操作
增加Where操作,先查出當前值,再更新。但這種做法在高并發(fā)情況下性能不好。
電商平臺購買商品
整個購買流程(整個請求)的冪等性由分布式事務來保證。即轉換成分布式事務問題。
業(yè)務層面冪等
冗余部署多個進程,當MQ上游重復添加消息時,保證下游不重復消費。本質上是分布式鎖問題。
06分布式鎖設計
定義
分布式環(huán)境下鎖定全局唯一資源(解決業(yè)務層面的冪等問題,解決消息的重復消費)
- 請求處理串行化
- 實際表現為互斥鎖
****為什么不能解決消息的重復發(fā)送?
當沒有收到ACK的時候,無法確定消息是否發(fā)送成功,只能重新發(fā)送
基于Redis分布式鎖
實現方式
Set nx (SET if Not eXists)
存在的問題
- 鎖的時間不可控:
- 難以確定過期時間
- 無法續(xù)租
- 單點問題:
- 單例情況下,進程一旦死掉,會徹底阻塞業(yè)務流程
- 主從方式,主從同步異步,當主從切換時會導致兩個線程獲取鎖。
能不能用Redis實現分布式鎖區(qū)別與業(yè)務場景:
- 交易場景要求絕對一致,不能使用
- 如果是社交或其他不極端要求嚴格的場景,可以使用
Redis主從復制半同步,本質上是AP模型,分布式鎖是CP模型
Redis官方簡歷使用RedLock,類似自己實現Raft算法。實現上復雜性高。
高可用分布式鎖設計目標
- 強一致性
- 服務高可用
- 鎖自動續(xù)約及其自動釋放
- 代碼高度抽象,業(yè)務接入極間
- 可視化管理后臺,監(jiān)控和管理
存儲層產品對比

Tair也可用來做分布式鎖的存儲
Tair是淘寶開源的一個分布式key/value結構數據庫。參考:深入理解Tair
美團點評內部開發(fā)的分布式鎖Cerberus,使用了多種引擎實現(Tair、ZK),支持使用方自主選擇一種或多種引擎。這樣可以結合引擎的特點,選擇符合實際業(yè)務需求和系統架構的方式。
選型(ETCD)
07分布式事務設計
數據不一致的原因
單獨的數據庫,可以依賴于數據的事務操作保證數據的一致性。在分布式系統中,數據的不一致性原因包括:
- 多個DB
- DB和緩存
舉例
在一個業(yè)務流程中,比如:下單->減庫存->支付
三個操作分布在不同的服務和不同的數據庫上。此時無法使用本地事務保證數據的一致性。只能采用分布式事務來解決。
實際問題
在實際系統中,當系統中使用MQ的話,會進一步增加事務的復雜性。比如當消息發(fā)送者需要執(zhí)行事務的回滾操作。
相關概念
剛性分布式事務
- 強一致性
- XA模型(實現了事務的ACID特性)。XA規(guī)范由AP(Application Program,應用程序)、RM(Resource Manager,資源管理器)、TM(Transaction Manager,事務管理器)組成。2PC
- CAP模型中實現CP
柔性分布式事務
- 最終一致性
- CAP、BASE理論,實現CAP中的AP。典型實現:TCC模型,Saga模型
BASE (Basically Availabe, Soft state, Eventual consistency)
柔性分布式事務場景
異步場景:基于MQ消息驅動的分布式事務
這個場景解決的問題是,本地操作和發(fā)送消息兩個行為的事務問題。
在消息消費端:
- 消息冪等通過分布式鎖來實現
- 執(zhí)行失敗,一般通過報警、日志、人工干預來解決。
方案一
MQ提供類似XA的分布式事務功能,通過MQ事務消息,等達到分布事務事務的最終一致。(RocketMQ)
缺點:業(yè)務方需要給MQ提供回查接口(對業(yè)務入侵大),發(fā)送消息非冪等(消費端需要處理冪等)
方案二
本地事務表。本質上是將本地操作和發(fā)消息轉化成本地事務問題。通過本地事務操作表和本地事務消息表,兩個表通過本地事務保證。
同步場景:基于異步補償分布
同步場景描述的是在服務聚合處,串行執(zhí)行下單、減庫存、支付三個操作。
由業(yè)務網邏輯層驅動的同步場景。
如果下單執(zhí)行成功,減庫存執(zhí)行失敗,如果回滾下單操作?
可能地方案是在減庫存執(zhí)行失敗時,服務聚合節(jié)點調用下單服務的回滾接口。理論上可以通過XA、TCC等來結局。但這里沒講。
08服務降級設計
目的
- 流量高峰期
- 短時請求量大
如果沒有服務降級,可能導致:服務宕機、系統雪崩等。
手段
拒絕部分老請求
確?!靶隆闭埱笳?響應,因為老請求可能在前端以及等待超時了。
實現方式可以通過RPC隊列:請求入隊、出隊時間,對于在隊列中停留超過閾值的直接丟棄。
優(yōu)先級請求
丟棄非核心請求,保證主要業(yè)務
隨機拒絕
隨機處理一定比例的請求,網站一會可用,一會不可用。
Integer.valueOf("1.23")的實現
方案
集中式:僅僅在網關層執(zhí)行降級不靠譜,因為網關層無法確定應該過濾多少流量。只有底層才知道自己能處理多少個請求。
自治式:各個層都由自己的降級方案。
一般不需要對DB層進行降級,但新浪微博對于明星時間的突發(fā)流量,通過將瞬時數據寫入緩存,然后在慢慢回放給數據庫保證服務的可用性。
Log4j是阻塞的寫日志,如果阻塞大量日志需要寫的話,也會把主機資源用完。
09服務限流/熔斷設計
目的
屏蔽性能下降時的非關鍵服務,防止導致雪崩。
平臺化熔斷系統需求分析
- 大部分熔斷返回默認值
- 進入熔斷時打印日志同時返回業(yè)務定制的Exception
- 通過服務治理平臺能夠對熔斷進行查看、管理
- 可以報警
- 接口粒度
基于RPC客戶端來實現熔斷,升級時只需要升級RPC客戶端就可以。
通過動態(tài)代理實現是否熔斷。
業(yè)界方案
Hystrix、Resilience4J
10服務灰度發(fā)布設計
定義
一種發(fā)布規(guī)則,讓一部分用戶用新系統,另一部分仍用舊系統
金絲雀發(fā)布,A/B Test
目的
讓一小部分用戶來進行線上測試,如果發(fā)現問題可以快速回滾。
實現方案
通過配置中心對系統進行配置,包括:指定灰度服務器、灰度流量占比、是否允許灰度。
協議設計
數據協議:
確定Header中的灰度發(fā)布以來字段,比如:udi,Token,IP,網關中打Tag等。
灰度發(fā)布策略:僅根據uid/token/IP的單策略,基于上下文的灰度策略。
案例
- 多層服務進行灰度,通過nginx層打tag實現
- 涉及到數據的灰度服務分三步:部分灰度(數據全量復制、雙寫);全部灰度(雙寫);灰度完成(去除雙寫)
業(yè)界產品
Spring Cloud灰度發(fā)布神器:Nepxion Discovery,是服務注冊和負載均和的增強中間件,包含了灰度發(fā)布功能。
11服務全鏈路壓測設計
基于線上真實環(huán)境,模擬海量用戶,對整個鏈路進行壓測。
工具:
JMeter、TCPCopy(流量復制)、Apache ab
標準:
CPU、網卡、請求超時量、QPS