文章目錄
安裝Sentinel
sentinel組件由兩個部分組成:
- 核心庫(Java客戶端),不依賴任何框架和庫,能夠運行於Java運行時環境,同時對SpringCloud等框架也有較好的支持。
- 控制檯(DashBoard)基於SpringBoot開發,打包後可以直接運行,不需要額外的Tomcat等應用容器
下載
https://github.com/alibaba/Sentinel/releases
運行命令
java -jar sentinel-dashboard-1.7.2.jar
注意:8080端口不能被佔用
訪問sentinel管理界面
http://localhost:8080
賬號密碼:sentinel
流控規則
基本介紹
- 資源名:唯一名稱,默認請求路徑
- 針對來源:Sentinel可以針對調用者進行限流,填寫微服務名,默認default(不區分來源)
- 閾值類型/單機閾值
- QPS(每秒請求數量):當調用該api的QPS達到閾值的時候,進行限流
- 線程數:當調用該api的線程數達到閾值的時候,進行限流
- 是否集羣:不需要集羣
- 流控模式:
- 直接:api達到限流條件時,直接限流
- 關聯:當關聯的資源達到閾值時,就限流自己
- 鏈路:只記錄指定鏈路上的流量(指定資源從入口資源進來的流量,如果達到閾值,就進行限流)
- 直接:api達到限流條件時,直接限流
- 流控效果
- 快速失敗:直接失敗。拋異常
- Warm up:根據coldfactor(冷加載因子,默認3)的值,從閾值/coldfactor,經過預熱時長,才達到設置的QPS閾值
如:秒殺系統在開啓瞬間,會有很多流量上來,很可能把系統打死,預熱方式就是爲了保護系統,可慢慢的把流量放進來,慢慢的把閾值增長到設置的閾值。 - 排隊等待:勻速排隊,讓請求以勻速通過,閾值類型必須設置爲QPS,否則無效
降級規則
RT
異常比例
異常數
熱點key限流
配置
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
@RequestParam(value = "p2",required = false) String p2)
{
//int age = 10/0;
return "------testHotKey";
}
返回異常不友好界面,blocked by sentinel
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
@RequestParam(value = "p2",required = false) String p2)
{
//int age = 10/0;
return "------testHotKey";
}
public String deal_testHotKey (String p1, String p2, BlockException exception)
{
return "------deal_testHotKey,o(╥﹏╥)o"; //sentinel系統默認的提示:Blocked by Sentinel (flow limiting)
}
自定義blockHandler,處理異常。
參數例外項
假如當p1的值等於5時,它的閾值可以達到200:
參數類型僅限於基本數據類型或者String
系統規則
系統配置管轄太寬泛,可能引起全局範圍內的問題,不使用,危險。
@SentinelResource
按照資源名稱+流控規則限流+後續處理
@GetMapping("/byResource")
@SentinelResource(value = "byResource",blockHandler = "handleException")
public CommonResult byResource()
{
return new CommonResult(200,"按資源名稱限流測試OK",new Payment(2020L,"serial001"));
}
public CommonResult handleException(BlockException exception)
{
return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服務不可用");
}
按照url+流控規則限流+後續處理
@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl")
public CommonResult byUrl()
{
return new CommonResult(200,"按url限流測試OK",new Payment(2020L,"serial002"));
}
現階段問題
- 系統默認,沒有體現特定的業務要求
- 自定義Handler與業務邏輯耦合
- 每個業務邏輯都需要獨自的兜底Handler,代碼膨脹
- 沒有全局統一的處理方法
自定義限流處理邏輯
- 自定義限流處理類
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
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class,
blockHandler = "handlerException2")
public CommonResult customerBlockHandler()
{
return new CommonResult(200,"按客戶自定義",new Payment(2020L,"serial003"));
}
服務熔斷
消費側Sentinel整合Ribbon+OpenFeign+FallBack
- pom
<!--SpringCloud openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--SpringCloud ailibaba sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
- yml
server:
port: 84
spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
#配置Sentinel dashboard地址
dashboard: localhost:8080
#默認8719端口,假如被佔用會自動從8719開始依次+1掃描,直至找到未被佔用的端口
port: 8719
#消費者將要去訪問的微服務名稱(註冊成功進nacos的微服務提供者)
service-url:
nacos-user-service: http://nacos-payment-provider
# 激活Sentinel對Feign的支持
feign:
sentinel:
enabled: true
Ribbon
- 配置RestTemplate
@Configuration
public class ApplicationContextConfig
{
@Bean
@LoadBalanced
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
}
- 業務邏輯
@RequestMapping("/consumer/fallback/{id}")
//fallback只負責業務異常
//blockHandler只負責sentinel控制檯配置違規
@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);
}
OpenFeign
- Service
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)
public interface PaymentService
{
@GetMapping(value = "/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
- FallBackService
@Component
public class PaymentFallbackService implements PaymentService
{
@Override
public CommonResult<Payment> paymentSQL(Long id)
{
return new CommonResult<>(44444,"服務降級返回,---PaymentFallbackService",new Payment(id,"errorSerial"));
}
}
- Controller
@Resource
private PaymentService paymentService;
@GetMapping(value = "/consumer/paymentSQL/{id}")
@SentinelResource(value = "fallback",blockHandler = "blockHandler")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
{
return paymentService.paymentSQL(id);
}
規則持久化
一旦重啓應用,sentinel規則消失,生產環境需要將配置規則進行持久化。
將限流規則持久進Nacos保存,只要刷新8401某個rest地址,sentinel控制檯的流控規則就能看得到,只要Nacos裏面的配置不刪除,針對8401上的流控規則持續有效
- 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>
- yaml
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848 #Nacos服務註冊中心地址
sentinel:
transport:
dashboard: localhost:8080 #配置Sentinel dashboard地址
port: 8719
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: cloudalibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
management:
endpoints:
web:
exposure:
include: '*'
feign:
sentinel:
enabled: true # 激活Sentinel對Feign的支持
- 添加Nacos業務規則配置