服務保護的基本概念
服務限流
服務限流目的是為了更好的保護我們的服務,在高并發的情況下,如果用戶端請求的數量達到一定極限(背景可以配置門檻值),請求的數量超出了設定的門檻值,開啟自我的保護,直接調用我們的服務降級的方法,不會執行業務邏輯操作,直接走本地 falback 的方法,傳回一個友好的提示。
服務降級
在高并發的情況下, 防止使用者一直等待,采用限流/熔斷方法,使用服務降級的方式傳回一個友好的提示給用戶端,不會執行業務邏輯請求,直接走本地的falback的方法。
提示語:目前排隊人數過多,稍後重試~
服務雪崩
預設的情況下,Tomcat或者是Jetty伺服器隻有一個線程池去處理用戶端的請求,這樣的話就是在高并發的情況下,如果用戶端所有的請求都堆積到同一個服務接口上, 那麼就會産生tomcat伺服器所有的線程都在處理該接口,可能會導緻其他的接口無法通路。
假設我們的tomcat線程最大的線程數量是為20,這時候用戶端如果同時發送100個請求會導緻有80個請求暫時無法通路,就會轉圈。
服務雪崩的解決方案:服務隔離機制:線程池隔離或者信号量隔離機制
- 線程池隔離機制:每個服務接口都有自己獨立的線程池,互不影響,缺點就是占用cpu資源非常大。
- 信号量隔離機制:最多隻有一定的門檻值線程數處理我們的請求,超過該門檻值會拒絕請求。
Sentinel
前哨以流量為切入點,從流量控制,熔斷降級,系統負載保護等多個次元保護服務的穩定性。
前哨具有以下特征:
- 豐富的應用場景:前哨兵承接了阿裡巴巴近10年的雙十一大促流的核心場景,例如秒殺(即突然流量控制在系統容量可以承受的範圍),消息削峰填谷,傳遞流量控制,實時熔斷下遊不可用應用等。
- 完備的實時監控:Sentinel同時提供實時的監控功能。您可以在控制台中看到接收應用的單台機器秒級資料,甚至500台以下規模的整合的彙總運作情況。
- 廣泛的開源生态:Sentinel提供開箱即用的與其他開源架構/庫的內建子產品,例如與Spring Cloud,Dubbo,gRPC的整合。您隻需要另外的依賴并進行簡單的配置即可快速地接入Sentinel。
- 完善的SPI擴充點:Sentinel提供簡單易用,完善的SPI擴充接口。您可以通過實作擴充接口來快速地定制邏輯。例如定制規則管理,适應動态資料源等。
Sentinel中文文檔介紹:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
Sentinel 與hytrix差別
重點差別:熔斷降級政策、限流、流量整形、系統保護支援、控制台、Sentinel 支援的架構多。
限流配置
官方文檔:https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8
手動使用代碼配置 純代碼或者注解的形式配置
這種方式不需要 sentinel 儀表盤項目。
maven依賴的引入
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel</artifactId>
<version>0.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
第一種方式: java代碼
private static final String GETORDER_KEY = "getOrder";
@RequestMapping("/initFlowQpsRule")
public String initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<FlowRule>();
FlowRule rule1 = new FlowRule();
rule1.setResource(GETORDER_KEY);
// QPS控制在2以内
rule1.setCount(1);
// QPS限流
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setLimitApp("default");
rules.add(rule1);
FlowRuleManager.loadRules(rules);
return "....限流配置初始化成功..";
}
@RequestMapping("/getOrder")
public String getOrders() {
Entry entry = null;
try {
entry = SphU.entry(GETORDER_KEY);
// 執行我們服務需要保護的業務邏輯
return "getOrder接口";
} catch (Exception e) {
e.printStackTrace();
return "該服務接口已經達到上線!";
} finally {
// SphU.entry(xxx) 需要與 entry.exit() 成對出現,否則會導緻調用鍊記錄異常
if (entry != null) {
entry.exit();
}
}
}
第二種方式: 手動放入到項目啟動自動加載
@Component
@Slf4j
public class SentinelApplicationRunner implements ApplicationRunner {
private static final String GETORDER_KEY = "getOrder";
@Override
public void run(ApplicationArguments args) throws Exception {
List<FlowRule> rules = new ArrayList<FlowRule>();
FlowRule rule1 = new FlowRule();
rule1.setResource(GETORDER_KEY);
// QPS控制在2以内
rule1.setCount(1);
// QPS限流
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setLimitApp("default");
rules.add(rule1);
FlowRuleManager.loadRules(rules);
log.info(">>>限流服務接口配置加載成功>>>");
}
}
第三種方式: 注解形式配置管理Api限流
@SentinelResource value參數:流量規則資源名稱、
blockHandler 限流/熔斷出現異常執行的方法
Fallback 服務的降級執行的方法
注解屬性:
- value:資源名稱,必需項,由于須要經過resource name找到對應的規則,這個是必須配置的。code
-
entryType:entry 類型,可選項,
有IN和OUT兩個選項,預設為 EntryType.OUT。xml
- blockHandler:blockHandler 對應處理 BlockException 的函數名稱,可選項。blockHandler 函數通路範圍須要是 public,傳回類型須要與原方法相比對,參數類型須要和原方法相比對而且最後加一個額外的參數,類型為 BlockException。對象
- blockHandlerClass:blockHandler 函數預設須要和原方法在同一個類中,若是但願使用其餘類的函數,則須要指定 blockHandlerClass 為對應的類的 Class 對象,注意對應的函數必需為 static 函數,不然沒法解析。
- fallback:fallback 函數名稱,可選項,用于在抛出異常的時候提供 fallback 處理邏輯。fallback 函數能夠針對全部類型的異常(除了 exceptionsToIgnore 裡面排除掉的異常類型)進行處理。資源
-
fallbackClass:fallbackClass的應用和blockHandlerClass相似,fallback 函數預設須要和原方法在同一個類中。
若但願使用其餘類的函數,則能夠指定 fallbackClass 為對應的類的 Class 對象,注意對應的函數必需為 static 函數,不然沒法解析。
- defaultFallback(since 1.6.0):若是沒有配置defaultFallback方法,預設都會走到這裡來。預設的 fallback 函數名稱,可選項,一般用于通用的 fallback 邏輯。預設 fallback 函數能夠針對全部類型的異常(除了 exceptionsToIgnore 裡面排除掉的異常類型)進行處理。若同時配置了 fallback 和 defaultFallback,則隻有 fallback 會生效。
- exceptionsToIgnore(since 1.6.0):用于指定哪些異常被排除掉,不會計入異常統計中,也不會進入 fallback 邏輯中,而是會原樣抛出。
@SentinelResource(value = GETORDER_KEY, blockHandler = "getOrderQpsException")
@RequestMapping("/getOrderAnnotation")
public String getOrderAnnotation() {
return "getOrder接口";
}
/**
* 被限流後傳回的提示
*
* @param e
* @return
*/
public String getOrderQpsException(BlockException e) {
e.printStackTrace();
return "該接口已經被限流啦!";
}
Sentinel 控制台形式配置
下載下傳對應Sentinel-Dashboard 下載下傳位址。
運作執行下面指令
java -Dserver.port=8718 -Dcsp.sentinel.dashboard.server=localhost:8718 -Dproject.name=sentinel-dashboard -Dcsp.sentinel.api.port=8719 -jar jar包名稱
安裝好之後請求路徑:http://localhost:8718/
登入頁面
控制台頁面
springboot項目整合 sentinel控制台
在上面的基礎上增加 yml 配置
spring:
application:
name: kaico-sentinel-demo
cloud:
#sentinel儀表盤連接配接資訊
sentinel:
transport:
dashboard: 127.0.0.1:8718
eager: true
啟動項目後,可以在控制台看見服務名稱,這是限流規則可以實時修改并且生效。
接口上沒有加注解的話,資源名稱預設為@RequestMapping注解的value的值(注意:是全部value的值。包括
/
),預設sentinel 會有自己的限流傳回資訊。
在控制台添加限流規則
資源名稱:如果被限流的方法上有注解
@SentinelResource
,則使用注解中指定的名稱,沒有的話使用使用
@RequestMapping、@GetMapping等注解
的value的值
QPS:表示一秒鐘處理多少個請求
線程數:就是信号量隔離,同一時刻最多隻有多少個線程處理請求。