作者:京東物流 劉達
一、Sentinel是什么?
Sentinel是從阿里技術(shù)體系內(nèi)誕生并由相關(guān)社區(qū)從微服務(wù)到云原生階段持續(xù)孵化的流量治理組件,在服務(wù)熔斷限流以及秒級/分鐘級監(jiān)控方面提供了開箱即用的解決方案,此外作為支持云原生的重要探索,還提供了GO語言實現(xiàn)。Sentinel目前擁有著活躍的開源社區(qū),從1.8.x版本開始,通過深度參與到SpringCloudAlibaba套件的支持,實現(xiàn)與Java主流開發(fā)框架SpringBoot及SpringCloud的兼容,進而成為了Java技術(shù)棧開源熔斷限流的事實標準。雖然其2.x版本持續(xù)難產(chǎn)(可能是適配OpenSergo規(guī)范的影響),不過好在1.8.x并沒停止迭代,今年以來已經(jīng)在1.8.7(JDK8)的基礎(chǔ)之上做了1.8.8(JDK17)的升級,完成了主流JDK版本的支持,基本能夠滿足Javaer的開發(fā)需求。
考慮到一般部署環(huán)境以JDK8居多,而且1.8.8除了JDK的升級外,沒有做實質(zhì)的功能改造,所以本篇文章主要基于1.8.7版本展開,即在JDK8的環(huán)境下對Sentinel的能力進行討論。
二、Sentinel能帶來什么?
就如前文所介紹的,Sentinel提供了完善的熔斷、限流以及秒級/分鐘級監(jiān)控方案。最核心的一點,就是它把應(yīng)用規(guī)則的目標統(tǒng)一抽象成了一個概念——資源。按照官方說明,資源可以是Java應(yīng)用程序中的任何內(nèi)容,比如服務(wù)、接口方法或者一段代碼。只要用Sentinel提供的資源創(chuàng)建及釋放API包裹起來,就可以稱之為一個資源。資源的抽象為Sentinel的使用提供了極大的靈活性,這讓開發(fā)者可以把代碼鏈路中的任何一個部分都做到流量治理規(guī)則中,當(dāng)然為了提高代碼的可讀性以及規(guī)范性,我們還是推薦以服務(wù)入口(HttpRPC)、接口或者接口的實現(xiàn)方法作為最小資源單元。
同時,Sentinel提供了豐富的控制規(guī)則:
?流量控制(FlowRule)
區(qū)分來源、限流類型(QPS/線程數(shù))、支持上下游鏈路、多種流控效果(拒絕、排隊、慢啟動)
熱點限流是對流量控制的補充,對Top-K的熱點參數(shù)進行限流處理
?系統(tǒng)負載限流(SystemRule)
可以理解為應(yīng)用級的流量控制策略,包含負載、單機平均RT,單機QPS等。不過,因為粒度較粗且部分指標的獲取在容器環(huán)境下存在適配問題,所以社區(qū)中大部分人對這個的理解是還有待完善,成熟的案例比較少。
?熔斷降級(DegradeRule)
在熔斷降級方面,則是直接對標的Hystrix框架,一是在實現(xiàn)機制上做了優(yōu)化,相對Hystrix基于線程池的隔離控制策略,通過并發(fā)控制機制減少了線程池的創(chuàng)建和占用。另外,在配置上也更加簡化,相信有過Hystrix使用經(jīng)驗,都會對其繁雜的注解配置項感到困惑,而當(dāng)引入Sentinel時則無需擔(dān)心這些。
如果僅僅是這些,Sentinel的定位也僅限于一個組件包,類似Hystrix一樣。那為何本文開篇說Sentinel是一套解決方案呢?因為它還做到了另外的三點,接下來繼續(xù)進行說明:
第一點:包容性
Sentinel通過對Adapter模塊組持續(xù)迭代,目前已經(jīng)兼容了主流的一系列調(diào)用協(xié)議及組件,比如dubbo2,dubbo3,httpclient,okhttp,grpc,sofa,quarkus,webflux,webmvc等。此外還完成了對Java開源網(wǎng)關(guān)的支持,包括zuul1,zuul2,springcloud-gateway。并且作為java應(yīng)用流量控制的標準框架,很多其他開源框架也在項目內(nèi)部做了相關(guān)的兼容。
第二點:界面化
Sentinel提供了方便易用的Dashboard,支持常用的一系列操作。比如應(yīng)用的注冊發(fā)現(xiàn),規(guī)則參數(shù)的配置、查看,接口簇點鏈路的自發(fā)現(xiàn)和樹狀展示,秒級的監(jiān)控視圖等等,雖然開源方案展示的數(shù)據(jù)以內(nèi)存或者對應(yīng)用節(jié)點信息的拉取為依托,但這已經(jīng)提供了非常強的指導(dǎo)性。其對應(yīng)的商業(yè)化版本AHAS已經(jīng)在阿里云中得到廣泛應(yīng)用。
第三點:擴展性
雖然core包提供的是基于應(yīng)用內(nèi)存的數(shù)據(jù)存取策略,但是sentinel同時對控制規(guī)則數(shù)據(jù)的拉取鏈路做了通用的抽象,并衍生出了一系列datasource包。包含apollo、consul、etcd、nacos、redis、zk等,他們具備的共同點就是客戶端能夠及時的獲取到配置數(shù)據(jù)變更事件,而Sentinel依賴的控制規(guī)則就是以配置數(shù)據(jù)的形式維護在這些中間件中,并實現(xiàn)對客戶端的分發(fā)。
前文介紹了這么多,那引入Sentinel能帶來什么改變呢?
我覺得,首先,限流策略更加豐富,能夠更好的應(yīng)對日趨復(fù)雜的限流需求;其次,對于資源的流量管理實現(xiàn)了統(tǒng)一,從單一入口維護應(yīng)用的所有流量控制規(guī)則,無需從網(wǎng)關(guān)、JSF等分別對應(yīng)用的入口進行配置;限流的維度更加細化,從入口級下沉到了應(yīng)用內(nèi)資源;在熔斷的支持上,除了JSF客戶端調(diào)用外,應(yīng)用內(nèi)部或作為客戶端對外部的任何協(xié)議調(diào)用都可以增加熔斷的管理,服務(wù)的穩(wěn)定性也會隨之提升。
三、Sentinel的重點實現(xiàn)
概念之后再來說說Sentinel中的關(guān)鍵實現(xiàn)。這一部分準備分三塊來說明。第一是它的核心規(guī)則控制鏈路,第二它的datasource實現(xiàn)結(jié)構(gòu),第三Dashboard與應(yīng)用的交互邏輯。此處主要是專注在架構(gòu)實現(xiàn)上,像業(yè)內(nèi)熟知的一些控制算法比如令牌桶等,不再贅述。
1、核心規(guī)則控制鏈路
為了更好的理解這條鏈路的結(jié)構(gòu),此處引入一下官方圖
??
上圖即Sentinel的默認ProcessorSlotChain所配置的鏈路結(jié)構(gòu),默認實現(xiàn)依托DefaultProcessorSlotChain。
??
從代碼上看是一個標準的鏈表結(jié)構(gòu),鏈表中裝配的節(jié)點對象類型為AbstractLinkedProcessorSlot,也就是圖中這些Slot的父類,我們或可以稱之為Slot模版類。通過代碼的查看,會發(fā)現(xiàn)它聲明了兩個方法,entry、exit分別作為Slot的入口和出口,并且在方法入?yún)⒅袛y帶了當(dāng)前調(diào)用鏈路的上下文信息。通過官方圖例能夠看出,請求在進入處理鏈條后,按先后順序會經(jīng)過三類Slot,前置的NodeSelectorSlot、ClusterBuilderSlot用于調(diào)用鏈路的提取,中間StatisticSlot是通用的滑動窗口計數(shù)功能,比如RT、通過數(shù)、拒絕數(shù)、異常數(shù)等,后置的ParamFlowSlot、SystemSlot等則為真正的規(guī)則驗證鏈條。如下圖所示,
??
在上圖中,會發(fā)現(xiàn)在模版類中有額外的兩個方法,fireEntry和fireExit,這兩個方法在AbstractLinkedProcessSlot中均有默認的實現(xiàn),主要是用于在當(dāng)前節(jié)點entry或exit方法執(zhí)行過程中觸發(fā)對next節(jié)點的調(diào)度,這就使得Slot鏈表觸發(fā)順序和完成順序并不一定相同。這樣的好處是在基礎(chǔ)鏈路上提供了充足的靈活性,上游Slot可以按需觸發(fā)下游Slot并獲取執(zhí)行結(jié)果。例如此處用于統(tǒng)計計數(shù)的StatisticSlot和用于規(guī)則驗證的一系列Slot列表之前的關(guān)系,正常通過和規(guī)則攔截的調(diào)用都能被StatisticSlot抓取到進行統(tǒng)計。
2、Datasource實現(xiàn)
作為配置文件的讀取來源,Sentinel提供了標準實現(xiàn)框架,并以此為基礎(chǔ),對主流的開源分布式配置中心也做了充分的適配,還是以類結(jié)構(gòu)圖作為切入點
??
可以看到,Sentinel提供的Datasource規(guī)范中,通過loadConfig,readSource,getProperty,close四個方法,覆蓋了數(shù)據(jù)源的讀取、加載、查詢和釋放整個流程。落地到具體實現(xiàn)方案,它提供了兩個大的方向,前者是支持熱更新,后者是不可變的配置來源,如jar包中的文件。
熱更新模式下,基于數(shù)據(jù)源的特性,又細分了兩種,我把它總結(jié)為輪詢模式和訂閱模式。像Eureka、本地文件這種,不支持數(shù)據(jù)變更事件的訂閱,Sentinel提供的方案是按照一定的時間間隔,定期的去拉取最新數(shù)據(jù)比對是否需要更新,這種就是前面講的輪詢模式。還有一種,依托于越來越成熟的各種開源分布式配置中間件,應(yīng)用通過SDK集成,能夠方便的訂閱指定的配置項,并實時接收數(shù)據(jù)變更事件進行處理邏輯,相對于輪詢模式配置生效的更加及時,是目前線上案例中最常用的模式。
對于不可變模式,Sentinel也僅提供了一種實現(xiàn),僅限于無配置變更需求的場景,支持一次性加載,好處是輕量依賴項少,但更新需要重啟。
3、Dashboard與應(yīng)用的交互
核心鏈路和數(shù)據(jù)來源之后,再來說說Sentinel關(guān)于控制面的實現(xiàn)。
首先,要說明的是,即便是到最新的版本,Sentinel Dashboard也不是必須的。尤其是在1.6.x以前,datasource和dashboard這些模塊都還未完善,項目引用Sentinel的方式主要是以硬編碼為主,控制規(guī)則是借助RuleManager的靜態(tài)方法進行初始化,調(diào)用鏈路中通過SphU或SphO實現(xiàn)資源的創(chuàng)建,使用Tracer去顯式的記錄異常(@SentinelResource是在1.8.x才趨于完善)?,F(xiàn)在,官方文檔在大部分基礎(chǔ)用例中也是以這些形式為主。那Dashboard的作用是什么?
Dashboard為我們提供了相對完整的控制面,基本涵蓋了Sentinel的所有功能,包含各種規(guī)則的查看和配置、節(jié)點的自動注冊發(fā)現(xiàn)以及健康狀態(tài)監(jiān)控、簇點鏈路的采集等,在可觀測方面提供了秒級的監(jiān)控視圖,而在后臺為這些功能的數(shù)據(jù)提供了基于內(nèi)存的實現(xiàn),為我們實現(xiàn)硬編碼到控制臺的轉(zhuǎn)變提供了明確的方向。接下來從三個角度說明Dashboard的重點實現(xiàn),分別是節(jié)點信息的發(fā)現(xiàn)、規(guī)則數(shù)據(jù)的維護、秒級監(jiān)控的采集。邏輯鏈路如下所示:
這張鏈路圖基本把Sentinel從客戶端到Dashboard服務(wù)端的交互過程做了明確的展示。
A. 首先,Sentinel控制臺對客戶端的發(fā)現(xiàn)機制并不依賴于其他中間件,是獨立的相對輕量的實現(xiàn)。邏輯上很簡單,即在控制臺暴露了一個MachineRegistryController,客戶端配置Dashboard地址后,定時的上報心跳數(shù)據(jù)。
B. Sentinel對應(yīng)用的Metrics數(shù)據(jù)采集是以定時拉取的方式,應(yīng)用SDK會暴露http入口,用于提供給Dashboard服務(wù)側(cè)進行調(diào)用。Dashboard中相關(guān)的規(guī)則配置也是以類似的方式進行,額外增加了數(shù)據(jù)的寫入動作用于更新規(guī)則。
C. sentinel-core本身對Dashboard側(cè)的交互沒有依賴,而是通過transport包中以集成Spiloader的方式追加相關(guān)的初始化動作,實現(xiàn)像注冊心跳、遠端控制等附加能力,即sentinel-core仍然是獨立可用的。
SlotChain、Dashboard和Datasource是一套組合拳,共同構(gòu)成了Sentinel的流控解決方案。SlotChain完成了核心的規(guī)則控制邏輯,而Datasource則是解決了配置數(shù)據(jù)怎么更新怎么同步的問題,最后Dashboard則是將配置數(shù)據(jù)的界面化維護以及運行時數(shù)據(jù)的展示入口提供給了開發(fā)者,讓線上的落地成為了可能。
?
四、Sentinel源碼包結(jié)構(gòu)
從工程結(jié)構(gòu)上看,Sentinel以sentinel-core為基礎(chǔ),衍生了一系列的模塊:
1、sentinel-dashboard:sentinel控制臺,提供簡易的登錄方式,功能上支持節(jié)點注冊展示,限流、熔斷等流控規(guī)則的查看與下發(fā),節(jié)點Metric信息的采集和聚合展示等。
2、sentinel-transport:內(nèi)部通信模塊,實現(xiàn)客戶端節(jié)點的心跳注冊以及消息接收功能。
3、sentinel-logging:sentinel為了和應(yīng)用日志做隔離,單獨指定的日志輸出問題,這個模塊提供了基于slf4j的默認實現(xiàn),同時可以作為參考實現(xiàn),以SPI的方式定制其他日志輸出通道。
4、sentinel-adapter:協(xié)議適配模塊,基本兼容了所有開源的協(xié)議,一是在資源生成時指定prefix,另外就是依賴調(diào)用鏈路中的FiIter做協(xié)議解析,以支持抽取流控規(guī)則依賴的參數(shù),比如origin等。
5、sentinel-extension:這個模塊組則是作為一版擴展實現(xiàn),不過大部分主要是依賴各種分布式配置型中間件實現(xiàn)的datasource模塊,實現(xiàn)規(guī)則數(shù)據(jù)的存取。
6、sentinel-cluster:主要是提供集群限流的部分簡易實現(xiàn),目前看這種基于token分發(fā)中心的集群限流方案在性能上損耗相對單機型還是要大一些。
?
五、Sentinel的落地問題及改造方案
在上文中,對Sentinel的邏輯架構(gòu)以及源碼已經(jīng)做了詳細介紹。如果在我們生產(chǎn)環(huán)境中落地,有哪些問題?
我們知道,Sentinel提供的默認實現(xiàn),數(shù)據(jù)的讀取以內(nèi)存為主要媒介。Dashboard基于節(jié)點上報的心跳信息做匯總,收集到AppManagement中,用于左側(cè)菜單欄的應(yīng)用展示,并開始根據(jù)心跳上傳時間判斷各應(yīng)用內(nèi)節(jié)點的在線離線狀態(tài),當(dāng)單個應(yīng)用內(nèi)所有節(jié)點都離線就對該應(yīng)用進行隱藏。規(guī)則數(shù)據(jù)的讀取以及Metric統(tǒng)計信息是通過遠程調(diào)用節(jié)點的通信入口進行。由此可以衍生出下面四個場景的落地方案:
1、規(guī)則數(shù)據(jù)的讀寫
在第三部分中也介紹到,Sentinel對于規(guī)則數(shù)據(jù)的同步機制,提供了一組datasource模塊,主要以各分布式配置中間件為中心,實現(xiàn)數(shù)據(jù)的寫入和變更監(jiān)聽,達到動態(tài)變更規(guī)則數(shù)據(jù)的目的。如果開發(fā)者并不想引入這些額外的中間件,那么就需要根據(jù)自己的需求來擴展datasource模塊。
接入新的配置源,首先從Dashboard開始,我們可以參考FlowControllerV2中提供的Nacos配置樣例,對應(yīng)于各個規(guī)則,實現(xiàn)基于appName的DynamicRuleProvider和DynamicRulePublisher的讀寫入口類,將規(guī)則數(shù)據(jù)以Json的形式寫入新的配置源中,當(dāng)然為了更大的擴展性和業(yè)務(wù)隔離性,我們可以在appName的參數(shù)基礎(chǔ)上,再追加類似Datacenter這種參數(shù),以區(qū)分不同的業(yè)務(wù)群,避免單個Dashboard中應(yīng)用過量造成處理壓力。
另外,就要考慮sentinel-datasource-{CustomizedDatasource}的開發(fā),基于sentinel-datasource-extension這個數(shù)據(jù)源監(jiān)聽模版,參考sentinel-datasource-nacos中NacosDataSource實現(xiàn)對應(yīng)的AbstractDataSource,到此為止只是實現(xiàn)了Datasource類的定義和實現(xiàn)。而真正打通Dashboard到節(jié)點側(cè)的數(shù)據(jù)鏈路,還需要對Datasource的調(diào)用和初始化流程。Sentinel包中的demo工程,有針對于各個datasource的初始化樣例。
而我們?nèi)绻胝嬲涞氐巾椖恐?,僅僅這些還是不夠的,而是需要把Datasource對各個規(guī)則的加載和監(jiān)聽封裝成獨立的Starter,這樣才能最大限度降低springboot集成的復(fù)雜度。對于這個想法,我們則需要轉(zhuǎn)向另一個開源項目:spring-cloud-alibaba-sentinel-datasource和spring-cloud-starter-alibaba-sentinel。
前者將不同Datasource和對應(yīng)的配置節(jié)點做了關(guān)聯(lián),如下
①DatasourceFactoryBean的聲明
public class NacosDataSourceFactoryBean implements FactoryBean
②Properties初始化參數(shù)中攜帶對應(yīng)的FactoryBean
public NacosDataSourceProperties() { super(NacosDataSourceFactoryBean.class.getName());}
后者,則是在初始化SentinelDataSourceHandler的過程中,根據(jù)SentinelProperties中各Datasource子節(jié)點配置與否決定是否初始化到Bean實例,如下
??
通過這幾部分的構(gòu)建,我們就可以實現(xiàn)自己的Sentinel-Starter,實現(xiàn)基于自定義數(shù)據(jù)源做規(guī)則數(shù)據(jù)的運維。
?
2、Metric統(tǒng)計數(shù)據(jù)及日志的托管
目前Metric信息是采用從Dashboard定時拉取再從應(yīng)用維度聚合的方式進行。節(jié)點中的Metrics信息是相對完整的,我們可以從兩方面來進行收集:
第一種方式,節(jié)點主動上報,收集至統(tǒng)一的存儲,再以Grafana的形式做數(shù)據(jù)展示。具體方式的話,可以選用直接上傳到定制的OAP服務(wù),也可以擴展sentinel-log模塊的實現(xiàn)做基于日志的上傳(因為sentinel的設(shè)計機制中,自身的狀態(tài)日志和業(yè)務(wù)日志是分離的)。不過,這會造成一定的性能損耗,落地到項目中需要進行詳細的壓測和評估。
第二種方式,由中控進行定時采樣,時間間隔可以自定義,也就是以拉的方式進行,采樣率可以在中控進行統(tǒng)一的動態(tài)控制,合理配置能夠更容易達到性能損耗和觀測性的平衡。
此處不再細說,方案比較多,見仁見智。
?
3、Dashboard的適配
Dashboard面向線上業(yè)務(wù)場景,需要解決的有以下三點:
①數(shù)據(jù)存儲問題:上文中規(guī)則數(shù)據(jù)的Datasource擴展不再討論,除此以外,Sentinel中節(jié)點、應(yīng)用、簇點鏈路都是基于內(nèi)存存儲的,這就有一個問題——重啟丟失。因為這些信息都是基于節(jié)點心跳的,數(shù)據(jù)丟失后意味著重新收集,那么之前在這些數(shù)據(jù)上做的規(guī)則配置就會丟失查看的入口。另外,應(yīng)用的展示是以應(yīng)用內(nèi)節(jié)點的在線狀態(tài)為準的,當(dāng)應(yīng)用內(nèi)所有節(jié)點都離線,也會造成應(yīng)用列表中缺失。所以解決方案就是需要將應(yīng)用、節(jié)點保存至持久化存儲中,例如Mysql,而簇點鏈路信息由于樹狀結(jié)構(gòu)的特殊性,可以直接放到Redis中存儲以及更新。
②權(quán)限問題:Dashboard通過輕量的自定義Filter實現(xiàn)的最簡單的登錄控制。落地的話就需要首先接入ERP統(tǒng)一登錄,另外還需要做應(yīng)用權(quán)限的管理,避免權(quán)限穿透和誤操作問題。
③業(yè)務(wù)劃分:需要按照業(yè)務(wù)進行應(yīng)用層面的劃分。實現(xiàn)多數(shù)據(jù)中心的支持,避免中心節(jié)點集成應(yīng)用過多。
?
4、協(xié)議的適配
相比前幾點,此處的改動是最輕量的。當(dāng)開發(fā)使用的調(diào)用協(xié)議不在Sentinel官方兼容,那么就需要對協(xié)議做適配性開發(fā)。按照sentinel-adapter中對其他協(xié)議的適配方式,我們需要改造的大體可以總結(jié)為兩點,第一,常規(guī)調(diào)用上下文參數(shù)的解析,比如調(diào)用來源等;第二,定義協(xié)議入口的資源前綴,與其他資源做區(qū)分。
六、小結(jié)
本文圍繞Sentinel展開,從其基本概念到核心實現(xiàn),再到探討開源方案的挑戰(zhàn)和如何在實際項目中應(yīng)用和改進Sentinel。Sentinel以其高度的靈活性和可擴展性贏得了廣大開發(fā)者的青睞,不論是新系統(tǒng)的開發(fā)還是現(xiàn)有系統(tǒng)的維護,Sentinel都能為我們提供極具價值的支持。
?
參考內(nèi)容:
【1】https://sentinelguard.io/zh-cn/?
審核編輯 黃宇
-
內(nèi)存
+關(guān)注
關(guān)注
8文章
3025瀏覽量
74047 -
開源
+關(guān)注
關(guān)注
3文章
3349瀏覽量
42500 -
JDK
+關(guān)注
關(guān)注
0文章
81瀏覽量
16596 -
Sentinel
+關(guān)注
關(guān)注
0文章
10瀏覽量
7152
發(fā)布評論請先 登錄
相關(guān)推薦
評論