報告老闆,微服務高可用神器已祭出,您花巨資營銷的高流量來了沒

一、從阿里雙11的高併發高流量開始

正如眾所周知,每年的雙11除了是購物狂歡節,同樣也成了科技的大考和狂歡,讓我們得以看到那麼多高端的充滿想象力的黑技術。在整個雙11高併發高流量的過程中,Sentinel 承接了核心場景,完美地保障了阿里巴巴歷年雙十一的穩定性。

隨著微服務的流行,服務和服務之間的穩定性變得越來越重要。Sentinel以流量為切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性。

報告老闆,微服務高可用神器已祭出,您花巨資營銷的高流量來了沒

通過Sentinel可以應對或支撐以下場景:

  1. 持續峰值:限流、慢調用降級
  2. 秒殺(也可稱之為脈衝流量):限流、慢調用降級
  3. 削峰填谷:消費端可能會出現大批量的消息同時到達,若瞬時請求所有消息會導致系統負載過高。Sentinel利用勻速器模式將消息均攤到一段時間內,讓系統負載保持在處理能力水位的同時儘可能地處理更多消息,從而起到“削峰填谷”的效果。
  4. 冷啟動:當流量突然增大的時候,我們希望系統從空閒狀態到繁忙狀態的切換的時間長一些,即如果系統在此之前長期處於空閒的狀態,我們希望處理請求的速率緩慢增加,經過預期的時間以後,到達系統處理請求速率的設定值;
  5. 熱點商品自動探測、防護:自動統計訪問頻次最高的熱點參數並進行流量控制;
  6. 集群流量不均勻:通過集群限流來解決集群各個機器的流量不均導致整體限流效果不精確的問題;
  7. 完備的實時監控:Sentinel 同時提供實時的監控功能。可以在控制檯中看到接入應用的單臺機器秒級數據,甚至 500 臺以下規模的集群的彙總運行情況。

作為一個功能完備的高可用流量控制框架,核心的 sentinel-core 打包後只有 286KB(最新的1.7.2版本),非常輕量級,可以放心地引入 sentinel-core 而不需擔心依賴問題(打臉,沒有坑是不可能的)。根據官方提供的數據,引入 Sentinel 帶來的性能損耗非常小,單機 QPS 不太大的時候損耗幾乎可以忽略不計(單機 4.3W QPS 的損耗約為 2.36%)

二、核心功能及原理說明

2.1 模塊說明

報告老闆,微服務高可用神器已祭出,您花巨資營銷的高流量來了沒

  • sentinel-core 核心模塊,限流、降級、系統保護等都在這裡實現
  • sentinel-dashboard 控制檯模塊,可以對連接上的sentinel客戶端實現可視化的管理
  • sentinel-transport 傳輸模塊,提供了基本的監控服務端和客戶端的API接口,以及一些基於不同庫的實現
  • sentinel-extension 擴展模塊,主要對DataSource進行了部分擴展實現
  • sentinel-adapter 適配器模塊,主要實現了對一些常見框架的適配
  • sentinel-demo 樣例模塊,可參考怎麼使用sentinel進行限流、降級等
  • sentinel-benchmark 基準測試模塊,對核心代碼的精確性提供基準測試
  • sentinel-logging 日誌模塊,可將sentinel的日誌通過slf4j集成到項目中
  • sentinel-cluster 集群,1.4版本中提供了集群流控的功能

從使用上來看,主要分為兩大部分:核心庫(Java 客戶端):不依賴任何框架/庫,能夠運行於 Java 7 及以上的版本的運行時環境,同時對 Dubbo / Spring Cloud 等框架也有較好的支持(見 主流框架適配)。

控制檯(Dashboard):Dashboard 主要負責管理推送規則、監控、管理機器信息等。

2.2 總體框架

報告老闆,微服務高可用神器已祭出,您花巨資營銷的高流量來了沒

sentinel主要是基於7種不同的Slot形成了一個鏈表,每個Slot都各司其職,自己做完分內的事之後,會把請求傳遞給下一個Slot,直到在某一個Slot中命中規則後拋出BlockException而終止。前三個Slot負責做統計,後面的Slot負責根據統計的結果結合配置的規則進行具體的控制,是Block該請求還是放行。

  • NodeSelectorSlot 負責收集資源的路徑,並將這些資源的調用路徑,以樹狀結構存儲起來,用於根據調用路徑來限流降級;
  • ClusterBuilderSlot 則用於存儲資源的統計信息以及調用者信息,例如該資源的 RT, QPS, thread count 等等,這些信息將用作為多維度限流,降級的依據;
  • StatisticSlot 則用於記錄、統計不同緯度的 runtime 指標監控信息;
  • FlowSlot 則用於根據預設的限流規則以及前面 slot 統計的狀態,來進行流量控制;
  • AuthoritySlot 則根據配置的黑白名單和調用來源信息,來做黑白名單控制;
  • DegradeSlot 則通過統計信息以及預設的規則,來做熔斷降級;
  • SystemSlot 則通過系統的狀態,例如 load1 等,來控制總的入口流量;
    Sentinel 還提供簡單易用、完善的 SPI 擴展接口。讓開發人員可以通過實現擴展接口來快速地定製邏輯。例如定製規則管理、適配動態數據源等。

2.3 核心概念:Resource/Entry/Context/Node

報告老闆,微服務高可用神器已祭出,您花巨資營銷的高流量來了沒

  • Resource在Sentinel中把所有要保護的東西都稱之為資源,它可以是服務,服務裡的方法,甚至是一段代碼。只要通過 Sentinel API 定義的代碼,就是資源,能夠被 Sentinel 保護起來。大部分情況下,可以使用方法簽名,URL,甚至服務名稱作為資源名來標示資源。
  • ContextContext是一個用來保存調用鏈當前狀態的元數據的類,每次進入一個資源時,就會創建一個Context,相同的資源名可能會創建多個Context。一個Context中包含了三個核心的對象:1)當前調用鏈的根節點:EntranceNode2)當前的入口:Entry3)當前入口所關聯的節點:NodeContext中只會保存一個當前正在處理的入口Entry,另外還會保存調用鏈的根節點。需要注意的是,每次進入一個新的資源時,都會創建一個新的Context。
  • Entry每次調用 SphU#entry() 都會生成一個Entry入口,該入口中會保存了以下數據:入口的創建時間,當前入口所關聯的節點,當前入口所關聯的調用源對應的節點。Entry是一個抽象類,他只有一個實現類,在CtSph中的一個靜態類:CtEntry
  • Node節點是用來保存某個資源的各種實時統計信息的,他是一個接口,通過訪問節點,就可以獲取到對應資源的實時狀態,以此為依據進行限流和降級操作。

2.4 簡單上手及dashboard一覽

官方有比較完善的演示代碼:

<code> 

private

static

void

initFlowRules

(

)

{ List rules =

new

ArrayList<>(); FlowRule rule =

new

FlowRule(); rule.setResource(

"HelloWorld"

); rule.setGrade(RuleConstant.FLOW_GRADE_QPS); rule.setCount(

20

); rules.

add

(rule); FlowRuleManager.loadRules(rules); }

public

static

void

main

(

String[] args

)

{ initFlowRules();

while

(

true

) {

try

(Entry entry = SphU.entry(

"HelloWorld"

)) { System.

out

.println(

"hello world"

); }

catch

(BlockException ex) { System.

out

.println(

"blocked!"

); } } } /<code>

如果是SpringCloud項目,可參考https://github.com/sentinel-group/sentinel-guides/tree/master/sentinel-guide-spring-cloud

報告老闆,微服務高可用神器已祭出,您花巨資營銷的高流量來了沒

整個dashboard的功能體驗下來,就是不停的 “我,這功能也有。我,還能這麼玩啊”,網上案例比較多,這裡就不多描述了。

三、生產環境下使用的一些思考

3.1 流量控制規則管理及推送

在前面已經提到了,Sentinel支持實時動態地配置規則,而不是預先在代碼裡定義好就無法改變了。實際情況下流量是動態的,比如某一個促銷活動可能導致流量大增,甚至可能有一些不在預期內的流量。為了達到最好的防護效果,動態的規則可以將即將掛掉的應用從掛掉的邊緣拉回來。但默認情況下,在dashboard設定規則後是通過API 將規則推送至客戶端並直接更新到內存中,擴展寫數據源(WritableDataSource),這樣的方法簡單,無任何依賴 ,但缺點也同樣很明顯:不保證一致性;規則保存在內存中,重啟即消失。所以產線建議採用Push模式

報告老闆,微服務高可用神器已祭出,您花巨資營銷的高流量來了沒

如上圖所示,整個流程:配置中心控制檯/Sentinel 控制檯 → 配置中心 → Sentinel 數據源 → Sentinel。Sentinel目前已經支持了ZooKeeper、攜程的 Apollo, 阿里自身的Nacos 等的動態數據源。接下來以Nacos為例:

1、在Spring Cloud應用中引入Sentinel模塊和Nacos存儲擴展:

<code>

implementation

(

'com.alibaba.cloud:spring-cloud-starter-alibaba-sentinel:2.1.2.RELEASE'

){

exclude

group:

'com.alibaba'

,module:

'fastjson'

} implementation

'com.alibaba.csp:sentinel-datasource-nacos:1.7.2.RELEASE'

/<code>

2、在應用中添加配置信息

<code>

spring:

cloud:

sentinel:

transport:

dashboard:

localhost:8080

datasource:

ds:

nacos:

server-addr:

localhost:8848

dataId:

madashu-test-sentinel

groupId:

DEFAULT_GROUP

rule-type:

flow

/<code>

3、在Nacos中設置相應的規則

<code>

JSON:

[

{

"resource":

"/madashu/hello"

,

"limitApp":

"default"

,

"grade":

1

,

"count":

5

,

"strategy":

0

,

"controlBehavior":

0

,

"clusterMode":

false

}

]

/<code>
  • resource:資源名
  • limitApp:流控針對的調用來源,default不區分來源
  • grade:限流閾值類型(0-根據併發數量來限流 1-根據QPS來進行流量控制)
  • count:限流閾值
  • strategy:調用關係限流策略
  • controlBehavior:流量控制效果(直接拒絕、WarmUP、勻速排隊)
  • clusterMode:是否集群模式

這裡官方社區提供了限流規則保存和訂閱的Demo,如果需要設置熔斷降級、系統保護、網關限流等,參考配置即可。基本方式:Dashboard將xxRuleEntityVO模型序列化到保存到nacos,應用從nacos訂閱後發序列成xxRule領域模型。

3.2 單機限流的閾值如何配置

這個千萬不能照搬網上的配置或者拍腦袋,否則將會導致產線大規模的誤殺或者癱瘓,一定要根據容量規劃和水位設定來配置。具體可以參考單機容量規劃的思路,在軟負載中調整某個節點的流量權重和比例直到逼近極限為止。記錄下極限狀態的QPS,按照單機房70%的水位設定標準,這樣就可以推算出該資源的單機限流閾值了。

四、從 Hystrix 遷移到 Sentinel

之前的微服務項目中基本上都是用Hystrix,從Hystrix遷移到Sentinel並不是一行配置一行代碼的事,不要受網上一些教程的誤導,需要具體評估自己的項目中使用到了Hystrix的場景。

4.1 為什麼Sentinel不支持線程池隔離

比如相對於Hystrix,Sentinel 沒有提供線程池隔離這樣比較重的隔離方式,而是提供了信號量隔離這種比較輕量級的隔離方式。線程池隔離的好處是隔離度比較高,可以針對某個資源的線程池去進行處理而不影響其它資源,但是代價就是線程數目比較多,線程上下文切換的 overhead 比較大,特別是對低延時的調用有比較大的影響。另外,託管的線程切換可能會導致基於 ThreadLocal 的上下文傳遞丟失的問題(如 Spring 事務管理)。

4.2. 遷移方案

報告老闆,微服務高可用神器已祭出,您花巨資營銷的高流量來了沒

五、實戰踩坑:Jar包兼容的那些坑

5.1 fastjson序列化異常

之前有一個Spring Cloud項目,在某個AOP中使用fastjson打印出入參,功能運行的很完美。後來引入了sentinel,添加了jar包spring-cloud-starter-alibaba-sentinel:2.1.2.RELEASE,然後很悲劇地發現fastjson序列化竟然異常了!

<code>java.lang.NoSuchMethodError: 
com.alibaba.fastjson.serializer.JavaBeanSerializer.processValue
(Lcom/alibaba/fastjson/serializer/JSONSerializer;
Lcom/alibaba/fastjson/serializer/BeanContext;Ljava/lang/

Object

; Ljava/lang/

String

;Ljava/lang/

Object

;) Ljava/lang/

Object

;Ljava/lang/Integer; at com.alibaba.fastjson.serializer.ASMSerializer_12_XXX.writeNormal(Unknown Source) ~[?:?] /<code>

經過排查發現,sentinel這個jar包依賴了fastjson1.2.62,而這個版本中是有bug的,具體參見,https://github.com/alibaba/fastjson/issues/2790。

解決方案:排除掉依賴的jar包即可,fastjson1.2.60中是不存在該問題的。最新的1.2.68中是否修復了該問題沒有驗證,有興趣的小夥伴可以驗一下。

<code>

implementation

(

'com.alibaba.cloud:spring-cloud-starter-alibaba-sentinel:2.1.2.RELEASE'

){

exclude

group:

'com.alibaba'

,module:

'fastjson'

} /<code>

5.2. Sleuth和Sentinel,我們決鬥吧

在微服務中,一個請求往往經過多個業務模塊,比如用戶發起支付,可能經過了會員服務、交易服務、支付服務、賬戶服務等,此時一旦某個服務發生了問題,定位時將會非常的困難。在Spring Cloud項目上,一般會引入鏈路調用跟蹤框架Spring Cloud Sleuth+zipkin,此時務必要注意:如果在項目中使用了Feign,熔斷可能已經失效了

。因為Sleuth為了傳遞鏈路調用跟蹤的信息對Feign進行了擴展,而Sentinel為了實現熔斷限流也對Feign進行了擴展,也就導致了兩個本互不相干的框架竟然產生了衝突。

解決方案:方案1:二選一,做個決斷吧,哈哈。Sleuth是支持Hystrix的,而Hystrix已停止了維護,Sentinel正火,說不定很快Sleuth也會支持Sentinel。方案2:換成其他的鏈路調用跟蹤框架,這個網上有很多開源的產品,筆者之前的公司時也曾研發並開源了這樣一套系統。方案3:最近剛發現網上有一位大佬提供了修改源碼的方案,實現還是很簡單的,將Sentinel融入到Sleuth中

報告老闆,微服務高可用神器已祭出,您花巨資營銷的高流量來了沒

詳細可參見:https://www.cnblogs.com/yinjihuan/p/12730654.html

以上只是對Sentinel一些粗淺的體驗,在Sentinel中有很多優秀的設計思想、先進的算法、值得拜讀的代碼等,後續再慢慢品味。


分享到:


相關文章: