Spring Cloud Alibaba Sentinel 实现熔断与限流

140 阅读3分钟

蒲公英追逐旳不只是天空,还有一份自由。

核心组件Sentinel

Sentinel简介

随着微服务的流行,服务和服务之间的稳定性变得越来越重要;Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

Sentinel特性

(1)丰富的应用场景:承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀,可以实时熔断下游不可用应用; (2)完备的实时监控:同时提供实时的监控功能。可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况; (3)广泛的开源生态:提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合; (4)完善的 SPI 扩展点:提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。

Sentinel安装

官网下载 Sentinel文档

执行命令启动Sentinel控制台

默认端口8080,登录账号密码均为sentinel

	java -jar sentinel-dashboard-1.8.5.jar --server.port=8080

Sentinel应用

	<dependency>
		<groupId>com.alibaba.cloud</groupId>
		<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
	</dependency>

bootstrap.yml

server:
  port: 9401
spring:
  application:
    name: btks-authorization
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 #Nacos地址
      config:
        server-addr: 127.0.0.1:8848 #Nacos地址
        file-extension: yaml #这里我们获取的yaml格式的配置
    sentinel:
      transport:
        dashboard: localhost:8080

流控规则

	@SentinelResource(value = "/oauth/token",blockHandler = "handleException")

我们可以根据@SentinelResource注解中定义的value(资源名称|路径)来进行限流操作,但是需要指定限流处理逻辑。Sentinel采用的懒加载规则,需要我们先访问下接口,Sentinel控制台中才会有对应服务信息,我们先访问下该接口:http://localhost:9101/authorization/oauth/token。

1、设置阈值类型QPS单机阈值(单机阈值必须大于等于0)0,再次访问http://localhost:9101/authorization/oauth/token时, Blocked by Sentinel (flow limiting) 直接被流量限制访问。

自定义处理逻辑

@Configuration
public class CustomBlockHandler implements BlockExceptionHandler {

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException blockException) throws IOException {
        httpServletResponse.setStatus(HttpStatus.OK.value());
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setContentType("application/json;charset=utf-8");
        httpServletResponse.setHeader("Content-Type","application/json;charset=utf-8");
        if (blockException instanceof FlowException) {
            new ObjectMapper().writeValue(httpServletResponse.getWriter(),BtJsonResult.build(BtJsonResult.SUCCESS,"接口限流啦!",blockException));
        } else if (blockException instanceof DegradeException) {
            new ObjectMapper().writeValue(httpServletResponse.getWriter(),BtJsonResult.build(BtJsonResult.SUCCESS,"服务降级啦!",blockException));
        } else if (blockException instanceof ParamFlowException) {
            new ObjectMapper().writeValue(httpServletResponse.getWriter(),BtJsonResult.build(BtJsonResult.SUCCESS,"热点参数限流啦!",blockException));
        } else if (blockException instanceof SystemBlockException) {
            new ObjectMapper().writeValue(httpServletResponse.getWriter(),BtJsonResult.build(BtJsonResult.SUCCESS,"系统规则(负载/...不满足要求)!",blockException));
        } else if (blockException instanceof AuthorityException) {
            new ObjectMapper().writeValue(httpServletResponse.getWriter(),BtJsonResult.build(BtJsonResult.SUCCESS,"授权规则不通过!",blockException));
        }else{
            new ObjectMapper().writeValue(httpServletResponse.getWriter(),BtJsonResult.build(BtJsonResult.SUCCESS,"未知异常!",blockException));
        }
    }
}

blockHandlerClass

@SentinelResource(value = "/oauth/token",blockHandler = "handleException",blockHandlerClass = CustomBlockHandler.class)

1、设置阈值类型QPS单机阈值(单机阈值必须大于等于0)0,再次访问http://localhost:9101/authorization/oauth/token时,

{
	"status": "200",
	"msg": "接口限流啦!",
	"data": {
		"cause": null,
		"stackTrace": [],
		"rule": {
			"resource": "/oauth/token",
			"limitApp": "default",
			"grade": 1,
			"count": 0,
			"strategy": 0,
			"refResource": null,
			"controlBehavior": 0,
			"warmUpPeriodSec": 10,
			"maxQueueingTimeMs": 500,
			"clusterMode": false,
			"clusterConfig": {
				"flowId": null,
				"thresholdType": 0,
				"fallbackToLocalWhenFail": true,
				"strategy": 0,
				"sampleCount": 10,
				"windowIntervalMs": 1000
			}
		},
		"ruleLimitApp": "default",
		"localizedMessage": null,
		"message": null,
		"suppressed": []
	}
}

Sentinel熔断降级与Feign整合

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

在application.yml中打开Sentinel对Feign的支持:

feign:
  sentinel:
    enabled: true #打开sentinel对feign的支持

声明降级逻辑:

@Component
public class BtAccountApFallbackService implements BtAccountApiService {
	......
}

指定降级逻辑:

@FeignClient(name = AccountConstant.SERVICE_NAME,url = "${FeignClient.btks-account}",fallback = BtAccountApFallbackService.class)

测试发现Sentinel熔断降级生效。

常见问题

Sentinel 限流规则持久化

pom.xml 添加相关依赖

<dependency>
   <groupId>com.alibaba.csp</groupId>
   <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

Nacos 配置限流规则

image.png

application.yml 数据源配置

image.png

重启应用,测试发现流控规则中已经有该配置了,并且修改Nocos中的配置发布,实时同步。

image.png