一, sentinel 的持久化配置
上一章中我们通过 Dashboard 来为 Sentinel 客户端设置各种各样的规则, 但是这些规则默认是存放在内存中, 极不稳定, 无法用于生成环境, 所以需要将其持久化.
DataSource 扩展常见的实现方式有:
拉模式: 客户端主动向某个规则管理中心定期轮询拉取规则, 这个规则中心可以是 RDBMS, 文件, 甚至是 VCS 等. 这样做的方式是简单, 缺点是无法及时获取变更;
推模式: 规则中心统一推送, 客户端通过注册监听器的方式时刻监听变化, 比如使用 Nacos https://github.com/alibaba/nacos ,Zookeeper 等配置中心. 这种方式有更好的实时性和一致性保证.
Sentinel 目前支持以下数据源扩展:
Pull-based: 文件, Consul
Push-based: ZooKeeper, Redis, Nacos, Apollo,
生产环境中一般常用的就是推模式. 这里我们使用 Nacos 存储规则. 推送模式的正确做法应该是 配置中心控制台 / Sentinel 控制台 → 配置中心 → Sentinel 数据源 → Sentinel.
1.1 sentinel 同步 nacos 配置
增加 sentinel 的依赖和 nacos 存储扩展依赖
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
- </dependency>
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-datasource-nacos</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
添加 nacos 相关配置
- spring:
- cloud:
- sentinel:
- datasource:
- # 名称随意
- javatrip:
- nacos:
- server-addr: 127.0.0.1:8848
- dataId: ${spring.application.name}-rules
- groupId: SENTINEL_GROUP
- # 规则类型, 取值见:
- # org.springframework.cloud.alibaba.sentinel.datasource.RuleType
- rule-type: flow
提供接口用于测试限流
- @RestController
- class test{
- @RequestMapping("/test")
- public String test(){
- return "Java 旅途";
- }
- }
nacos 中增加限流规则的配置
resource: 资源名, 即限流规则的作用对象
limitApp: 流控针对的调用来源, 若为 default 则不区分调用来源
grade: 限流阈值类型(QPS 或并发线程数);0 代表根据并发数量来限流, 1 代表根据 QPS 来进行流量控制
count: 限流阈值
strategy: 调用关系限流策略
controlBehavior: 流量控制效果(直接拒绝, Warm Up, 匀速排队)
clusterMode: 是否为集群模式
测试, 访问 test 接口, 发现 sentinel-dashboard 中出现了一条流控规则
1.2 sentinel-dashboard 中修改规则同步到 nacos
要想实现在 sentinel-dashboard 中修改规则并同步到 nacos, 我们就需要修改 sentinel 服务. 首先我们去官网 https://github.com/alibaba/Sentinel 下载 Sentinel.
修改 pom 文件
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-datasource-nacos</artifactId>
- <scope>test</scope>
- </dependency>
将 test 注释掉, 因为这个是作用与 test 目录下的.
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-datasource-nacos</artifactId>
- <!--<scope>test</scope>-->
- </dependency>
找到
sentinel-dashboard/src/test/java/com/alibaba/csp/sentinel/dashboard/rule/nacos
目录, 将整个目录拷贝到
- sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/
- .
找到
com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2
, 将默认动态规则修改为 nacos 动态规则.
- @Autowired
- @Qualifier("flowRuleDefaultProvider")
- private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
- @Autowired
- @Qualifier("flowRuleDefaultPublisher")
- private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
修改为:
- @Autowired
- @Qualifier("flowRuleNacosProvider")
- private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
- @Autowired
- @Qualifier("flowRuleNacosPublisher")
- private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
找到
sentinel-dashboard/src/main/webapp/resources/App/scripts/directives/sidebar/sidebar.html
将以下内容注释去掉
- <!--<li ui-sref-active="active" ng-if="entry.appType==0">-->
- <!--<a ui-sref="dashboard.flow({app: entry.app})">-->
- <!--<i class="glyphicon glyphicon-filter"></i> 流控规则 V1</a>-->
- <!--</li>-->
重新编译打包, 运行打包后的 sentinel-dashboard.jar.
测试, 我们删除 nacos 中的流量规则配置
在 sentinel-dashboard-->流量规则 V1 中新增一个规则.
刷新 nacos, 发现多了一个配置
在 nacos 中修改这个配置, 将阀值改为 1
刷新 sentinel-dashboard, 流量阀值修改为 1 了.
重启服务, 重启 sentinel-dashboard, 发现流控规则依然存在.
注意: 以上只是演示了流控规则的持久化, sentinel 还支持其他规则, 如果想实现哪种规则都可以采用相同的方式实现!
二, Gateway 网关限流
限流: 就是请求多了, 对请求进行定制的快速响应处理, 应用在服务提供者本身.
从 1.6.0 版本开始, Sentinel 提供了 Spring Cloud Gateway 的适配模块, 可以提供两种资源维度的限流:
route 维度: 即在 Spring 配置文件中配置的路由条目, 资源名为对应的 routeId
自定义 API 维度: 用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组
添加依赖
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
- <version>x.y.z</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-transport-simple-http</artifactId>
- </dependency>
注入对应的
SentinelGatewayFilter
实例以及
SentinelGatewayBlockExceptionHandler
实例.
- @Configuration
- public class GatewayConfiguration {
- private final List<ViewResolver> viewResolvers;
- private final ServerCodecConfigurer serverCodecConfigurer;
- public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
- ServerCodecConfigurer serverCodecConfigurer) {
- this.viewResolvers=viewResolversProvider.getIfAvailable(Collections::emptyList);
- this.serverCodecConfigurer = serverCodecConfigurer;
- }
- @Bean
- @Order(Ordered.HIGHEST_PRECEDENCE)
- public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
- // Register the block exception handler for Spring Cloud Gateway.
- return new MySentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);
- }
- @Bean
- @Order(Ordered.HIGHEST_PRECEDENCE)
- public GlobalFilter sentinelGatewayFilter() {
- return new SentinelGatewayFilter();
- }
- }
自定义异常处理
- public class MySentinelGatewayBlockExceptionHandler extends SentinelGatewayBlockExceptionHandler {
- private List<ViewResolver> viewResolvers;
- private List<HttpMessageWriter<?>> messageWriters;
- public MySentinelGatewayBlockExceptionHandler(List<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
- super(viewResolvers,serverCodecConfigurer);
- this.viewResolvers = viewResolvers;
- this.messageWriters = serverCodecConfigurer.getWriters();
- }
- @Override
- public Mono<Void> handle(ServerWebExchange serverWebExchange, Throwable throwable) {
- if(serverWebExchange.getResponse().isCommitted()){
- return Mono.error(throwable);
- }
- if(!BlockException.isBlockException(throwable)){
- return Mono.error(throwable);
- }
- return handleBlockedRequest(serverWebExchange, throwable).flatMap(response -> writeResponse(response, serverWebExchange));
- }
- private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
- return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
- }
- private final Supplier<ServerResponse.Context> contextSupplier = () -> new ServerResponse.Context() {
- @Override
- public List<HttpMessageWriter<?>> messageWriters() {
- return MySentinelGatewayBlockExceptionHandler.this.messageWriters;
- }
- @Override
- public List<ViewResolver> viewResolvers() {
- return MySentinelGatewayBlockExceptionHandler.this.viewResolvers;
- }
- };
- private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) {
- ServerHttpResponse resp = exchange.getResponse();
- resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
- String JSON = "{\"code\": -1, \"data\": null, \"msg\": \" 访问量过大, 请稍后再试 \"}";
- DataBuffer buffer = resp.bufferFactory().wrap(JSON.getBytes(StandardCharsets.UTF_8));
- return resp.writeWith(Mono.just(buffer));
- }
- }
配置路由
- server:
- port: 7003
- spring:
- application:
- name: alibaba-gateway
- cloud:
- nacos:
- discovery:
- server-addr: 127.0.0.1:8848
- gateway:
- enabled: true
- discovery:
- locator:
- enabled: true # 开启从注册中心动态创建路由的功能, 利用微服务名称进行路由
- routes:
- - id: sentinel-nacos # 路由 id, 建议配合服务名
- uri: lb://sentinel-nacos #匹配路由名
- predicates:
- - Path=/sentinel/** # 断言, 路径相匹配的进行路由
- filters:
- - StripPrefix=1
添加启动参数
-Dcsp.sentinel.App.type=1 -Dcsp.sentinel.dashboard.server=localhost:8081 -Dproject.name=alibaba-gateway
访问接口, 查看效果
三, feign 调用实现熔断降级
降级: 就是服务崩溃了, 所以降级逻辑应该应用在消费者 (调用者) 那里, 加在服务提供者本身是毫无意义的, 因为服务已经断开了.
我们根据实际需求在 sentinel-dashboard 中配置降级规则, 然后编写代码.
定义接口
- @RequestMapping("/test")
- public String test(){
- return "Java 旅途";
- }
定义远程服务调用接口
- @FeignClient(name = "nacos-sentinel",fallback = RmoteTestFallback.class)
- interface RemoteTest{
- @RequestMapping("/test")
- public String test();
- }
为了简写 fallback, 我们更倾向于用 fallbackFactory = RmoteTestFallbackFactory.class
- @FeignClient(name = "nacos-sentinel",fallbackFactory = RmoteTestFallbackFactory.class)
- interface RemoteTest{
- @RequestMapping("/test")
- public String test();
- }
服务降级处理 fallback
- @Component
- class RmoteTestFallback implements RemoteTest{
- @Override
- public String test() {
- return null;
- }
- }
服务降级处理 fallbackFactory
- @Component
- class RmoteTestFallbackFactory implements FallbackFactory<RemoteTest> {
- @Override
- public RemoteTest create(Throwable throwable) {
- return null;
- }
- }
来源: https://www.cnblogs.com/zhixie/p/13253166.html