sentinel 是什么
Sentinel 是面向分布式服務(wù)架構(gòu)的輕量級流量控制框架错敢,主要以流量為切入點,從流量控制缕粹、熔斷降級稚茅、系統(tǒng)負載保護等多個維度來幫助您保護服務(wù)的穩(wěn)定性。
sentinel 基本概念
資源
資源是 Sentinel 的關(guān)鍵概念平斩。它可以是 Java 應(yīng)用程序中的任何內(nèi)容亚享,例如,由應(yīng)用程序提供的服務(wù)双戳,或由應(yīng)用程序調(diào)用的其它應(yīng)用提供的服務(wù)虹蒋,甚至可以是一段代碼
規(guī)則
圍繞資源的實時狀態(tài)設(shè)定的規(guī)則,可以包括流量控制規(guī)則飒货、熔斷降級規(guī)則以及系統(tǒng)保護規(guī)則。
sentinel 功能和設(shè)計理念
流量控制
對系統(tǒng)來說峭竣,任意時間到來的請求往往是隨機不可控的塘辅,而系統(tǒng)的處理能力是有限的。我們需要根據(jù)系統(tǒng)的處理能力對流量進行控制皆撩。
sentinel 流量控制有一下幾個角度:
- 資源的調(diào)用關(guān)系扣墩,例如資源的調(diào)用鏈路哲银,資源和資源之間的關(guān)系;
- 運行指標呻惕,例如 QPS荆责、線程池、系統(tǒng)負載等亚脆;
- 控制的效果做院,例如直接限流、冷啟動濒持、排隊等键耕。
熔斷降級
在微服務(wù)中,由于調(diào)用關(guān)系的復(fù)雜性柑营,如果調(diào)用鏈路中的某個資源出現(xiàn)了不穩(wěn)定屈雄,比如服務(wù)超時,會導(dǎo)致請求發(fā)生堆積官套,長時間占用系統(tǒng)資源酒奶,最終會導(dǎo)致其他正常服務(wù)也不可用,導(dǎo)致整個系統(tǒng)的雪崩奶赔。熔斷降級就是當調(diào)用鏈路中某個資源出現(xiàn)不穩(wěn)定讥蟆,例如,表現(xiàn)為 timeout纺阔,異常比例升高的時候瘸彤,則對這個資源的調(diào)用進行限制,并讓請求快速失敗笛钝。
sentinel 熔斷的兩種方式:
- 通過并發(fā)線程數(shù)進行限制
和資源池隔離的方法不同质况,Sentinel 通過限制資源并發(fā)線程的數(shù)量,來減少不穩(wěn)定資源對其它資源的影響玻靡。這樣不但沒有線程切換的損耗结榄,也不需要您預(yù)先分配線程池的大小。當某個資源出現(xiàn)不穩(wěn)定的情況下囤捻,例如響應(yīng)時間變長臼朗,對資源的直接影響就是會造成線程數(shù)的逐步堆積。當線程數(shù)在特定資源上堆積到一定的數(shù)量之后蝎土,對該資源的新請求就會被拒絕视哑。堆積的線程完成任務(wù)后才開始繼續(xù)接收請求。 - 通過響應(yīng)時間對資源進行降級
除了對并發(fā)線程數(shù)進行控制以外誊涯,Sentinel 還可以通過響應(yīng)時間來快速降級不穩(wěn)定的資源挡毅。當依賴的資源出現(xiàn)響應(yīng)時間過長后,所有對該資源的訪問都會被直接拒絕暴构,直到過了指定的時間窗口之后才重新恢復(fù)跪呈。
系統(tǒng)負載保護
Sentinel 同時對系統(tǒng)的維度提供保護段磨。防止雪崩,是系統(tǒng)防護中重要的一環(huán)耗绿。當系統(tǒng)負載較高的時候苹支,如果還持續(xù)讓請求進入,可能會導(dǎo)致系統(tǒng)崩潰误阻,無法響應(yīng)债蜜。在集群環(huán)境下,網(wǎng)絡(luò)負載均衡會把本應(yīng)這臺機器承載的流量轉(zhuǎn)發(fā)到其它的機器上去堕绩。如果這個時候其它的機器也處在一個邊緣狀態(tài)的時候策幼,這個增加的流量就會導(dǎo)致這臺機器也崩潰,最后導(dǎo)致整個集群不可用奴紧。
針對這個情況特姐,Sentinel 提供了對應(yīng)的保護機制,讓系統(tǒng)的入口流量和系統(tǒng)的負載達到一個平衡黍氮,保證系統(tǒng)在能力范圍之內(nèi)處理最多的請求唐含。
sentinel 的使用
使用 Sentinel 來進行資源保護,主要分為兩個步驟:
1.定義資源
2.定義規(guī)則
定義資源
拋出異常的方式定義資源
Entry entry = null;
// 務(wù)必保證finally會被執(zhí)行
try {
// 資源名可使用任意有業(yè)務(wù)語義的字符串
entry = SphU.entry("自定義資源名");
/**
* 被保護的業(yè)務(wù)邏輯
*/
} catch (BlockException e1) {
// 資源訪問阻止沫浆,被限流或被降級
// 進行相應(yīng)的處理操作
} finally {
if (entry != null) {
entry.exit();
}
}
返回布爾值方式定義資源
// 資源名可使用任意有業(yè)務(wù)語義的字符串
if (SphO.entry("自定義資源名")) {
// 務(wù)必保證finally會被執(zhí)行
try {
/**
* 被保護的業(yè)務(wù)邏輯
*/
} finally {
SphO.exit();
}
} else {
// 資源訪問阻止捷枯,被限流或被降級
// 進行相應(yīng)的處理操作
}
注解方式定義資源
Sentinel 支持通過 @SentinelResource 注解定義資源并配置 blockHandler 和 fallback 函數(shù)。
規(guī)則定義
Sentinel 支持以下幾種規(guī)則:流量控制規(guī)則专执、熔斷降級規(guī)則淮捆、系統(tǒng)保護規(guī)則 以及 授權(quán)規(guī)則。
流量規(guī)則的定義
屬性 | 說明 | 默認值 |
---|---|---|
resource | 資源名本股,資源名是限流規(guī)則的作用對象 | |
count | 限流閾值 | |
grade | 限流閾值類型攀痊,是按照 QPS 還是線程數(shù) | QPS 模式 |
limitApp | 是否根據(jù)調(diào)用者來限流 | 否 |
strategy | 判斷的根據(jù)是資源自身,還是根據(jù)其它資源 (refResource)拄显,還是根據(jù)鏈路入口 (refResource) | 根據(jù)資源本身 |
controlBehavior | 發(fā)生攔截后的流量整形和控制策略(直接拒絕 / 排隊等待 / 慢啟動模式) | 直接拒絕 |
硬編碼的方式定義流量控制規(guī)則實例:
private static void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule1 = new FlowRule();
rule1.setResource(KEY);
// set limit qps to 20
rule1.setCount(20);
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setLimitApp("default");
rules.add(rule1);
FlowRuleManager.loadRules(rules);
}
熔斷降級規(guī)則 (DegradeRule)
屬性 | 說明 | 默認值 |
---|---|---|
resource | 資源名苟径,資源名是限流規(guī)則的作用對象 | |
count | 熔斷閾值 | |
grade | 降級模式,根據(jù) RT 降級還是根據(jù)異常比例降級 | RT |
timeWindow | 降級的時間 |
硬編碼的方式定義流量控制規(guī)則實例:
private static void initDegradeRule() {
List<DegradeRule> rules = new ArrayList<>();
DegradeRule rule = new DegradeRule();
rule.setResource(KEY);
// set threshold rt, 10 ms
rule.setCount(10);
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
rule.setTimeWindow(10);
rules.add(rule);
DegradeRuleManager.loadRules(rules);
}
系統(tǒng)保護規(guī)則 (SystemRule)
屬性 | 說明 | 默認值 |
---|---|---|
highestSystemLoad | 最大的 load1躬审,參考值 | -1 (不生效) |
avgRt | 所有入口流量的平均響應(yīng)時間 | -1 (不生效) |
grade | 降級模式棘街,根據(jù) RT 降級還是根據(jù)異常比例降級 | RT |
maxThread | 入口流量的最大并發(fā)數(shù) | -1 (不生效) |
用硬編碼的方式定義流量控制規(guī)則的實例:
private void initSystemProtectionRule() {
List<SystemRule> rules = new ArrayList<>();
SystemRule rule = new SystemRule();
rule.setHighestSystemLoad(10);
rules.add(rule);
SystemRuleManager.loadRules(rules);
}