详解sentinel:分布式系统的流量防卫兵
目錄
sentinel是什么
sentinel具有以下特征
豐富的應用場景
完備的實時監控
廣泛的開源生態
完善的SPI擴展點
sentinel的主要特性
?下載安裝
控制臺
應用接入
pom文件
application.yml
sentinel的功能
流控規則
直接-快速失敗
?默認錯誤
?關聯-快速失敗
預熱-Warm Up
?排隊等待
降級規則
RT(平均響應時間)
異常比例
異常數
熱點規則-熱點key限流
?自定義異常信息
?熱點規則?
參數例外項
系統規則(總控-所有的uri的控制)
自定義兜底方法(錯誤信息)
?@SentinelResource注解
ribbon、nacos、sentinel一起使用
異常忽略
?feign
sentinel、Hystrix、resilience4j的對比
持久化
sentinel是什么
隨著微服務的流行,服務和服務之間的穩定性變得越來越重要。Sentinel以流量為切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性。
其實sentinel就是histrix的阿里版本!有一套單獨的web管理界面,可以給我們進行更加細粒度化的配置流控、速率控制、服務熔斷、服務降級等等。
sentinel具有以下特征
豐富的應用場景
sentinel承接了阿里巴巴近10年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的范圍)、消息削峰填谷、集群流量控制、實時熔斷下游不可用應用等。
完備的實時監控
sentinel同時提供實時的監控功能。您可以在控制臺中看到接入應用的單臺機器秒級數據,甚至500臺以下規模的集群的匯總運行情況。
廣泛的開源生態
sentinel提供開箱即用的與其它開源框架/庫的整合模塊,例如與spring cloud、dubbo、gRPC的整合。您只需要引入相應的依賴并進行簡單的配置即可快速地接入sentinel。
完善的SPI擴展點
sentinel提供簡單易用、完善的SPI擴展接口。您可以通過實現擴展接口來快速地定制邏輯。例如定制規則管理、適配動態數據源等。
sentinel的主要特性
?下載安裝
控制臺
sentinel分為兩個部分:
1.核心庫(java客戶端)不依賴任何框架/庫,能夠運行于所有java運行時環境,同時對dubbo/spring cloud等框架也有較好的支持。
2.?控制臺(dashboard)基于spring?boot開發,打包后可以直接運行,不需要額外的tomcat等應用容器。
sentinel使用的是8080端口!
啟動命令:java -jar sentinel-dashboard-1.7.0.jar
用戶名密碼:sentinel/sentinel
localhost:8080訪問(懶加載)
?
應用接入
pom文件
<!--SpringCloud ailibaba nacos --> <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--SpringCloud ailibaba sentinel-datasource-nacos 后續做持久化用到--> <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId> </dependency> <!--SpringCloud ailibaba sentinel --> <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>application.yml
server:port: 8401spring:application:name: cloudalibaba-sentinel-servicecloud:nacos:discovery:server-addr: localhost:8848 #Nacos服務注冊中心地址sentinel:transport:dashboard: localhost:8080 #配置Sentinel dashboard地址port: 8719 #默認8719端口,假如被占用會自動從8719開始依次+1掃描,直至找到未被占用的端口datasource:ds1:nacos:server-addr: localhost:8848dataId: cloudalibaba-sentinel-servicegroupId: DEFAULT_GROUPdata-type: jsonrule-type: flowmanagement:endpoints:web:exposure:include: '*'feign:sentinel:enabled: true # 激活Sentinel對Feign的支持sentinel的功能
流控規則
1.資源名:唯一名稱,默認請求路徑。
2.針對來源:Sentinel可以針對調用者進行限流,填寫微服務名,默認default(不區分來源)。
3.閾值類型/單機閾值:
? ? QPS(每秒鐘的請求數量):當調用該api的QPS達到閾值的時候,進行限流。
? ? 線程數:當調用該api的線程數達到閾值的時候,進行限流。
4.是否集群:不需要集群。
5.流控模式:
? ? 直接:api達到限流條件時,直接限流。
? ? 關聯:當關聯的資源達到閾值時,就限流自己。(當與A關聯的資源B達到閾值后,就限流A自己)
? ? 鏈路:只記錄指定鏈路上的流量(指定資源從入口資源進來的流量,如果達到閾值,就進行限流)【api級別的針對來源】
6.流控效果:
? ? 快速失敗:直接失敗,拋出異常。
? ? Warm?Up(預熱):根據codeFactor(冷加載因子,默認3)的值,從閾值/codeFactor,經過預熱時長,才達到設置的QPS閾值。
? ? 排隊等待:勻速等待,讓請求以勻速的速度通過,閾值類型必須設置為QPS,否則無效。
直接-快速失敗
以下配置表示:1秒鐘內只可以查詢一次,若超過次數1,就直接-快速失敗,報默認錯誤。
?默認錯誤
sentinel有自帶默認的錯誤
源碼:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
直接:快速失敗(默認的流控處理)。
?關聯-快速失敗
以下配置表示:當關聯資源/testB的qps閾值超過1時,就限流/testA的Rest訪問地址,當關聯資源到閾值后限制配置好的資源名。
預熱-Warm Up
Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即預熱/冷啟動方式。當系統長期處于低水位的情況下,當流量突然增加時,直接把系統拉升到高水位可能瞬間把系統壓垮。通過“冷啟動”,讓通過的流量緩慢增加,在一定時間內逐漸增加到閾值上限,給冷系統一個預熱的時間,避免冷系統被壓垮。
通常冷啟動的過程系統允許通過的QPS曲線如下圖所示:
?Warm Up配置
默認coldFactor為3,即請求QPS從(threshold /?3)開始,經多少預熱時長才逐漸升至設定的QPS閾值。
案例:閾值為10+預熱時長設置5秒。
系統初始化的閾值為10 / 3約等于3,即閾值剛開始為3;然后過了5秒后閾值才慢慢升高恢復到10。
?排隊等待
勻速排隊,讓請求以均勻的速度通過,閾值類型必須設成QPS,否則無效。
設置含義:/testA每秒1次請求,超過的話就排隊等待,等待的超時時間為20000毫秒。
?勻速排隊(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式會嚴格控制請求通過的間隔時間,也即是讓請求以均勻的速度通過,對應的是漏桶算法。
該方式的作用如下圖所示:
?這種方式主要用于處理間隔性突發的流量,例如消息隊列。想象一下這樣的場景,在某一秒有大量的請求到來,而接下來的幾秒則處于空閑狀態,我們希望系統能夠在接下來的空閑期間逐漸處理這些請求,而不是在第一秒直接拒絕多余的請求。
降級規則
?
RT(平均響應時間,秒級):
? ? 平均響應時間?超出閾值?且?在時間窗口內通過的請求>=5,兩個條件同時滿足后觸發降級。
? ? 窗口期過后關閉斷路器。
? ? RT最大4900(更大的需要通過-Dcsp.sentinel.statistic.max.rt=xxxx才能生效)
異常比例(秒級):
? ? QPS>=5且異常比例(秒級統計)超過閾值時,觸發降級;時間窗口結束后,關閉降級。
異常數(分鐘級):
? ? 異常數(分鐘統計)超過閾值時,觸發降級;時間窗口結束后,關閉降級。
?? ?Sentinel熔斷降級會在調用鏈路中某個資源出現不穩定狀態時(例如調用超時或異常比例升高),對這個資源的調用進行限制,讓請求快速失敗,避免影響到其它的資源而導致級聯錯誤。
?? ?當資源被降級后,在接下來的降級時間窗口之內,對該資源的調用都自動熔斷(默認行為是拋出DegradeException)。
?? ?Sentinel是沒有半開狀態的!半開狀態系統自動去檢測是否請求有異常,沒有異常就關閉斷路器恢復使用,有異常則繼續打開斷路器不可用。具體可以參考Hystrix。
RT(平均響應時間)
?
?
?
?按照上述配置,永遠一秒鐘打進來10個線程(大于5個了)調用testD,我們希望200毫秒處理完本次任務,如果超過200毫秒還沒處理完,在未來1秒鐘的時間窗口內,斷路器打開(保險絲跳閘)微服務不可用,保險絲跳閘斷電了。
后續我們停止jmeter,沒有這么大的訪問量了,斷路器關閉(保險絲恢復),微服務繼續使用。
異常比例
異常比例(DEGRADA_GRADE_EXCEPTION_RATIO):當資源的每秒請求量>=5,并且每秒異常總數占通過量的比值超過閾值(DegradeRule中的count)之后,資源進入降級狀態,即在接下來的時間窗口(DeradeRule中的timeWindow,以s為單位)之內,對這個方法的調用都會自動地返回。異常比率的閾值范圍是[0.0, 1.0],代表0% - 100%。
?
?
?
?按照上述配置,單獨訪問一次,必然會報錯一次(int age = 10/0),調用一次報錯一次。
開啟jmeter后,直接高并發發送請求,后臺持續報錯,斷路器開啟,微服務不可用了。
異常數
異常數(DEGRADE_GRADE_EXCEPTION_COUNT):當資源近1分鐘的異常數目超過閾值之后會進行熔斷。注意由于統計時間窗口是分鐘級別的,若timeWindow小于60s,則結束熔斷狀態后仍可能再進入熔斷狀態。
時間窗口一定要大于等于60秒。
?
?
?http://localhost:8080/testE,第一次訪問報錯,我們看到error窗口,但是達到5次報錯后,進入熔斷后降級。
熱點規則-熱點key限流
源碼:com.alibaba.csp.sentinel.slots.block.BlockException
?自定義異常信息
?熱點規則
?方法testHotKey里面的第一個參數(參數索引設置為0)主要QPS超過每秒1次,馬上降級處理,會調用deal_testHotKey。
也就是說:
訪問http://localhost:8080/testHotKey?p1=abc? 熱點規則生效
訪問http://localhost:8080/testHotKey?p1=abc&p2=123? 熱點規則生效
訪問http://localhost:8080/testHotKey?p2=abc? 熱點規則不生效
參數例外項
?
?
場景:
1.普通場景:超過1秒鐘一個后,達到閾值1后馬上限流。
2.特例:我們希望p1參數當它是某個特殊值時,它的限流值和平時不一樣(加入當p1的值等于5時,它的閾值可以達到200)。
方法中報錯,該報異常報異常,它只處理自己的異常:
?@SentinelResource處理的是Sentinel控制臺配置的違規情況,有blockHandler方法配置的兜底處理。
RuntimeException:int age = 10/0,這個是java運行時報出的運行時異常,@SentinelResource不管。
總結:@SentinelResource主管配置出錯,運行出錯走正常的異常處理邏輯。
系統規則(總控-所有的uri的控制)
?系統保護規則是從應用級別的入口流量進行控制,從單臺及其的load、CPU使用率、平均RT、入口QPS和并發線程數等幾個維度監控應用指標,讓系統盡可能跑在最大吞吐量的同時保證系統整體的穩定性。
系統保護規則是應用整體維度的,而不是資源維度的,并且僅對入口流量生效。入口流量指的是進入應用的流量(EntryType.IN),比如Web服務或Dubbo服務端接收的請求,都屬于入口流量。
系統規則支持以下的模式:
· Load自適應(僅對Linux/Unix-like機器生效):系統的load1作為啟發指標,進行自適應系統保護。當系統load1超過設定的啟發值,且系統當前的并發線程數超過估算的系統容量時才會觸發系統保護(BBR階段)。系統容量由系統的maxQps * minRt估算得出。設定參考值一般是CPU cores * 2.5。
· CPU usage(1.5.0+版本):當系統CPU使用率超過閾值即觸發系統保護(取值范圍0.0 - 1.0),比較靈敏。
· 平均RT:當單臺機器上所有入口流量的平均RT達到閾值即觸發系統保護,單位是毫秒。
· 并發線程數:當單臺機器上所有入口流量的并發線程數達到閾值即觸發系統保護。
· 入口QPS:當單臺機器上所有入口流量的QPS達到閾值即觸發系統保護。
自定義兜底方法(錯誤信息)
@GetMapping("/rateLimit/customerBlockHandler") @SentinelResource(value = "customerBlockHandler",blockHandlerClass = CustomerBlockHandler.class,blockHandler = "handlerException2") public CommonResult customerBlockHandler() {return new CommonResult(200,"按客戶自定義",new Payment(2020L,"serial003")); }public class CustomerBlockHandler {public static CommonResult handlerException(BlockException exception){return new CommonResult(4444,"按客戶自定義,global handlerException----1");}public static CommonResult handlerException2(BlockException exception){return new CommonResult(4444,"按客戶自定義,global handlerException----2");} }?@SentinelResource注解
注意:注解方式埋點不支持private方法。
?@SentinelResource用于定義資源,并提供可選的異常處理和fallback配置項。?@SentinelResource注解包含以下屬性:
· value:資源名稱、必需項(不能為空)。
· entryType:entry類型,可選項(默認為EntryType.OUT)。
· blockHandler / blockHandlerClass:blockHandler對應處理BlockException的函數名稱,可選項。blockHandler函數訪問范圍需要是public,返回類型需要與原方法相匹配,參數類型需要和原方法相匹配并且最后加一個額外的參數,類型為BlockException。blockHandler函數默認需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定blockHandlerClass為對應的類的Class對象,注意對應的函數必需為static函數,否則無法解析。
· fallback:fallback函數名稱,可選項,用于在拋出異常的時候提供fallback處理邏輯。fallback函數可以針對所有類型的異常(除了exceptionToIgnore里面排除掉的異常類型)進行處理。fallback函數簽名和位置要求:
① 返回值類型必須與原函數返回值類型一致。
② 方法參數列表需要和原函數一致,或者可以額外多一個Throwable類型的參數用于接收對應的異常。
③ 方法參數列表需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定fallbackClass為對應的類的Class對象,注意對應的函數必需為static函數,否則無法解析。
· defaultFallback(since1.6.0):默認的fallback函數名稱,可選項,通常用于通用的fallback邏輯(即可以用于很多服務或方法)。默認fallback函數可以針對所有類型的異常(除了exceptionsToIgnore里面排除掉的異常類型)進行處理。若同時配置了fallback和defaultFallback,則只有fallback會生效。defaultFallback函數簽名要求:
① 返回值類型必須與原函數返回值類型一致。
② 方法參數列表需要為空,或者可以額外多一個Throwable類型的參數用于接收對應的異常。
ribbon、nacos、sentinel一起使用
@RequestMapping("/consumer/fallback/{id}") //@SentinelResource(value = "fallback") //沒有配置 //@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只負責業務異常 //@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只負責sentinel控制臺配置違規 //若blockHandler和fallback都進行了配置,則被限流降級而拋出BlockException時只會進入blockHandler處理邏輯。 @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler",exceptionsToIgnore = {IllegalArgumentException.class}) public CommonResult<Payment> fallback(@PathVariable Long id) {CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);if (id == 4) {throw new IllegalArgumentException ("IllegalArgumentException,非法參數異常....");}else if (result.getData() == null) {throw new NullPointerException ("NullPointerException,該ID沒有對應記錄,空指針異常");}return result; } //本例是fallback public CommonResult handlerFallback(@PathVariable Long id,Throwable e) {Payment payment = new Payment(id,"null");return new CommonResult<>(444,"兜底異常handlerFallback,exception內容 "+e.getMessage(),payment); } //本例是blockHandler public CommonResult blockHandler(@PathVariable Long id,BlockException blockException) {Payment payment = new Payment(id,"null");return new CommonResult<>(445,"blockHandler-sentinel限流,無此流水: blockException "+blockException.getMessage(),payment); }異常忽略
?feign
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class) public interface PaymentService {@GetMapping(value = "/paymentSQL/{id}")public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id); }@Component public class PaymentFallbackService implements PaymentService {@Overridepublic CommonResult<Payment> paymentSQL(Long id){return new CommonResult<>(44444,"服務降級返回,---PaymentFallbackService",new Payment(id,"errorSerial"));} }@GetMapping(value = "/consumer/paymentSQL/{id}") public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {return paymentService.paymentSQL(id); } # 激活Sentinel對Feign的支持 feign:sentinel:enabled: truesentinel、Hystrix、resilience4j的對比
| sentinel | Hystrix | resilience4j | |
| 隔離策略 | 信號量隔離(并發線程數限流) | 線程池隔離/信號量隔離 | 信號量隔離 |
| 熔斷降級策略 | 基于響應時間、異常比率、異常數 | 基于異常比率 | 基于異常比率、響應時間 |
| 實時統計實現 | 滑動窗口(LeapArray) | 滑動窗口(基于RxJava) | Ring Bit Buffer |
| 動態規則配置 | 支持多種數據源 | 支持多種數據源 | 有限支持 |
| 擴展性 | 多個擴展點 | 插件的形式 | 接口的形式 |
| 基于注解的支持 | 支持 | 支持 | 支持 |
| 限流 | 基于QPS,支持基于調用關系的限流 | 有限的支持 | Rate Limiter |
持久化
服務重啟后,sentinel在管理端的配置就會重置,所以需要持久化。
使用nacos做sentinel的持久化
<!--SpringCloud ailibaba sentinel-datasource-nacos 后續做持久化用到--> <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId> </dependency> spring:application:name: cloudalibaba-sentinel-servicecloud:nacos:discovery:server-addr: localhost:8848 #Nacos服務注冊中心地址sentinel:transport:dashboard: localhost:8080 #配置Sentinel dashboard地址port: 8719datasource:ds1:nacos:server-addr: localhost:8848dataId: cloudalibaba-sentinel-servicegroupId: DEFAULT_GROUPdata-type: jsonrule-type: flow?
resource:資源名稱。
limitApp:來源應用。
grade:閾值類型,0表示線程數,1表示QPS。
count:單機閾值。
strategy:流控模式,0表示直接,1表示關聯,2表示鏈路。
controlBehavior:流控效果,0表示快速失敗,1表示Warm Up,2表示排隊等待。
clusterMode:是否集群。
?
?
總結
以上是生活随笔為你收集整理的详解sentinel:分布式系统的流量防卫兵的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot启动流程,手把手打断
- 下一篇: Myeclipse2017下使用Mave