SpringCloud Alibaba Sentinel 使用方式及限流规则持久化

目录

一、SpringCloud Alibaba Sentinel 概述及控制台的搭建

1、SpringCloud Alibaba Sentinel 概述

2、Sentinel 控制台的搭建

2.1、下载地址

2.2、启动sentinel

2.3、访问sentinel

3、 SpringCloud Alibaba Sentinel 控制台有哪些能力

4、常见的限流方案

5、流控规则高级说明

5.1、流控模式

5.2、流控效果

二、项目中使用sentinel的限流功能 

1、添加依赖

2、yml配置(spring:cloud下)

3、编写限流controller接口

4、编写自定义通用的限流处理逻辑

三、使用sentinel 保护 RestTemplate 服务间调用

1、配置RestTemplate 

1.1、yml配置文件配置

1.2、代码配置

2、配置服务异常降级之后的处理方法和限流后的处理方法

3、使用 Sentinel 保护 RestTemplate 服务间调用

四、使用sentinel 对 fegin 熔断降级支持

1、配置fegin

2、编写fegin client 

3、编写Sentinel 对 OpenFeign 接口的降级策略

4、编写controller测试使用fegin的熔断降级

五、使用sentinel 对 RestTemplate 熔断降级支持 

1、编写服务熔断降级后的策略(controller中fallback中的方法和类中的方法参数必须一致)

2、编写controller测试使用RestTemplate的熔断降级

五、Sentinel 结合 Nacos 实现限流规则持久化

1、SpringCloud Alibaba Sentinel 配置信息

2、 整合nacos实现限流规则持久化

2.1、添加依赖

2.2、编写限流接口

2.3、yml配置(spring:cloud下)

2.4、在nacos上编写指定限流接口的配置

3、 整合nacos实现熔断规则持久化

3.1、添加依赖

3.2、yml配置

3.3、在nacos上编写熔断规则。

3.4、熔断策略讲解

 3.5、编写fegin client 

3.6、编写Sentinel 对 OpenFeign 接口的降级策略

3.7、编写controller测试使用fegin的熔断降级

六、Gateway集成Sentinel实现网关限流(不论那种方式硬编码中的样板代码必须添加在Gateway)

1、引入依赖

2、编写配置文件(spring:cloud下)

3、硬编码方式实现

4、本地文件方式实现

4.1、编写路由规则

4.2、编写路由规则分组 

4.3、编写配置文件

5、nacos方式实现

 5.1、nacos上编写路由规则

5.2、nacos上编写路由规则分组 

5.3、编写yml配置文件


一、SpringCloud Alibaba Sentinel 概述及控制台的搭建

1、SpringCloud Alibaba Sentinel 概述

SpringCloud Alibaba Sentinel 使用方式及限流规则持久化_第1张图片

2、Sentinel 控制台的搭建

2.1、下载地址

        Releases · alibaba/Sentinel · GitHub

2.2、启动sentinel

java -Dserver.port=7777 -Dcsp.sentinel.dashboard.server=localhost:77
77 -Dproject.name=zhangkechen-sentinel-dashboard -jar sentinel-dashboard-1.8.6.jar

2.3、访问sentinel

地址:http://localhost:7777/

SpringCloud Alibaba Sentinel 使用方式及限流规则持久化_第2张图片

3、 SpringCloud Alibaba Sentinel 控制台有哪些能力

SpringCloud Alibaba Sentinel 使用方式及限流规则持久化_第3张图片

4、常见的限流方案

  • 静态窗口限流(每个自然秒中可接受的请求数量,0-1,1-2,不能解决突发的问题)
  • 动态窗口限流(滑动窗口,比如现在2.5秒,他计算的范围为1.5-2.5秒,不能解决突发的问题)
  • 漏桶限流(把请求放到桶(队列)里面,规定一秒钟消费多少个请求,桶有上线,超过容量全部拒绝)
  • 令牌桶限流(桶中放令牌,有上线,进:某个程序定时给桶中生成令牌,生成是会判断桶是否达到上限,请求进来后拿到令牌执行业务,否则失败。)
  • 令牌大闸:(开始时就初始化令牌个数,请求进来后拿到令牌执行业务,否则失败。)

5、流控规则高级说明

5.1、流控模式

  • 直接:默认,指的是直接对当前资源做限流。
  • 关联:对目标的限流是有条件的,需要关联的资源限流时,目标才会限流。两个接口的关联是实时的,当关联的资源限流时,目标资源同步开启限流。
  • 链路:当入口资源为配置的资源名称进来的请求,才会开始目标资源的限流。需要在配置文件配置Sping.cloud.sentinel.web-context-unify=false。流控模式时链路时必须关闭这个开关,默认是true,为true时可以在控制台-簇点链路界面看到所有请求都在一个链路下面。

5.2、流控效果

  • 快速失败-》表示达到单机阈值的话直接拒绝请求。
  • Warm Up-》预热,规则是coldFactor为3,即请求QPS从(闽值 /3)开始,经多少预热时长才逐渐升至设定的QPS闽值,假设单机阈值为100,预热时长为10,则表示从33开始经过十秒上升到100。
  • 排队等待-》编写等待时长,单位毫秒。假设单机阈值为10,等待时长为500,当进来100个请求是,90个是等待状态,这些请求等待500毫秒,在500毫秒内如果满足单机阀值的要求(单机阀值小于10),就可以执行,否则拒绝。

二、项目中使用sentinel的限流功能 

1、添加依赖

        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-sentinel
        

2、yml配置(spring:cloud下)

    sentinel:
      # 配置 sentinel dashboard 地址
      transport:
        dashboard: 127.0.0.1:7777
        port: 8719 # 会在应用对应的机器上启动一个 Http Server, 该 Server 会与 Sentinel 控制台做交互
      # 服务启动直接建立心跳连接
      eager: true
      datasource:

3、编写限流controller接口

/**
 * 

基于 Sentinel 控制台配置流控规则

* Sentinel 是懒加载的, 先去访问一下, 就可以在 Sentinel Dashboard 看到了 * */ @Slf4j @RestController @RequestMapping("/dashboard") public class RateLimitController { /** *

在 dashboard 中 "流控规则" 中按照资源名称新增流控规则

* */ @GetMapping("/by-resource") @SentinelResource( value = "byResource", blockHandler = "qinyiHandleBlockException", blockHandlerClass = QinyiBlockHandler.class ) public CommonResponse byResource() { log.info("coming in rate limit controller by resource"); return new CommonResponse<>(0, "", "byResource"); } /** *

在 "簇点链路" 中给 url 添加流控规则

* */ @GetMapping("/by-url") @SentinelResource(value = "byUrl") public CommonResponse byUrl() { log.info("coming in rate limit controller by url"); return new CommonResponse<>(0, "", "byUrl"); } }

4、编写自定义通用的限流处理逻辑

/**
 * 

自定义通用的限流处理逻辑

* */ @Slf4j public class QinyiBlockHandler { /** *

通用限流处理方法

* 这个方法必须是 static 的 * */ public static CommonResponse qinyiHandleBlockException(BlockException exception) { log.error("trigger qinyi block handler: [{}], [{}]", JSON.toJSONString(exception.getRule()), exception.getRuleLimitApp()); return new CommonResponse<>( -1, "flow rule trigger block exception", null ); } }

三、使用sentinel 保护 RestTemplate 服务间调用

1、配置RestTemplate 

1.1、yml配置文件配置

# 开启或关闭 @SentinelRestTemplate 注解
resttemplate:
  sentinel:
    enabled: true

1.2、代码配置

/**
 * 

开启服务间的调用保护, 需要给 RestTemplate 做一些包装

* */ @Slf4j @Configuration public class SentinelConfig { /** *

包装 RestTemplate

* */ @Bean @SentinelRestTemplate( fallback = "handleFallback", fallbackClass = RestTemplateExceptionUtil.class, blockHandler = "handleBlock", blockHandlerClass = RestTemplateExceptionUtil.class ) public RestTemplate restTemplate() { return new RestTemplate(); // 可以对其做一些业务相关的配置 } }

2、配置服务异常降级之后的处理方法和限流后的处理方法

/**
 * 

RestTemplate 在限流或异常时的兜底方法

* */ @Slf4j public class RestTemplateExceptionUtil { /** *

限流后的处理方法

* */ public static SentinelClientHttpResponse handleBlock(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException ex) { log.error("Handle RestTemplate Block Exception: [{}], [{}]", request.getURI().getPath(), ex.getClass().getCanonicalName()); return new SentinelClientHttpResponse( JSON.toJSONString(new JwtToken("qinyi-imooc-block")) ); } /** *

异常降级之后的处理方法

* */ public static SentinelClientHttpResponse handleFallback(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException ex) { log.error("Handle RestTemplate Fallback Exception: [{}], [{}]", request.getURI().getPath(), ex.getClass().getCanonicalName()); return new SentinelClientHttpResponse( JSON.toJSONString(new JwtToken("qinyi-imooc-block")) ); } }

3、使用 Sentinel 保护 RestTemplate 服务间调用

/**
 * 

使用 Sentinel 保护 RestTemplate 服务间调用

* */ @Slf4j @RestController @RequestMapping("/sentinel-rest-template") public class SentinelRestTemplateController { private final RestTemplate restTemplate; public SentinelRestTemplateController(RestTemplate restTemplate) { this.restTemplate = restTemplate; } /** *

从授权服务中获取 JwtToken

* 1. 流控降级: * 是针对于簇点链路中的 http://127.0.0.1:7000/ecommerce-authority-center/authority/token * 2. 容错降级: 对于服务不可用时不能生效 * */ @PostMapping("/get-token") public JwtToken getTokenFromAuthorityService( @RequestBody UsernameAndPassword usernameAndPassword) { String requestUrl = "http://127.0.0.1:7000/ecommerce-authority-center/authority/token"; log.info("RestTemplate request url and body: [{}], [{}]", requestUrl, JSON.toJSONString(usernameAndPassword)); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return restTemplate.postForObject( requestUrl, new HttpEntity<>(JSON.toJSONString(usernameAndPassword), headers), JwtToken.class ); } }

四、使用sentinel 对 fegin 熔断降级支持

1、配置fegin

# 打开 Sentinel 对 Feign 的支持
feign:
  sentinel:
    enabled: true
spring:
  cloud:
    openfeign:
      lazy-attributes-resolution: true

2、编写fegin client 

/**
 * 

通过 Sentinel 对 OpenFeign 实现熔断降级

* */ @FeignClient( value = "e-commerce-imooc", fallback = SentinelFeignClientFallback.class ) public interface SentinelFeignClient { @RequestMapping(value = "qinyi", method = RequestMethod.GET) CommonResponse getResultByFeign(@RequestParam Integer code); }

3、编写Sentinel 对 OpenFeign 接口的降级策略


/**
 * 

Sentinel 对 OpenFeign 接口的降级策略

* */ @Slf4j @Component public class SentinelFeignClientFallback implements SentinelFeignClient { @Override public CommonResponse getResultByFeign(Integer code) { log.error("request supply for test has some error: [{}]", code); return new CommonResponse<>( -1, "sentinel feign fallback", "input code: "+ code ); } }

4、编写controller测试使用fegin的熔断降级

/**
 * 

OpenFeign 集成 Sentinel 实现熔断降级

* */ @Slf4j @RestController @RequestMapping("/sentinel-feign") public class SentinelFeignController { private final SentinelFeignClient sentinelFeignClient; public SentinelFeignController(SentinelFeignClient sentinelFeignClient) { this.sentinelFeignClient = sentinelFeignClient; } /** *

通过 Feign 接口去获取结果

* */ @GetMapping("/result-by-feign") public CommonResponse getResultByFeign(@RequestParam Integer code) { log.info("coming in get result by feign: [{}]", code); return sentinelFeignClient.getResultByFeign(code); } }

五、使用sentinel 对 RestTemplate 熔断降级支持 

1、编写服务熔断降级后的策略(controller中fallback中的方法和类中的方法参数必须一致)

/**
 * 

Sentinel 回退降级的兜底策略

* 都需要是静态方法 fallback中的方法和类中的方法参数必须一致 * */ @Slf4j public class QinyiFallbackHandler { /** *

getTokenFromAuthorityService 方法的 fallback

* */ public static JwtToken getTokenFromAuthorityServiceFallback( UsernameAndPassword usernameAndPassword ) { log.error("get token from authority service fallback: [{}]", JSON.toJSONString(usernameAndPassword)); return new JwtToken("imooc-qinyi-fallback"); } /** *

ignoreException 方法的 fallback

* */ public static JwtToken ignoreExceptionFallback(Integer code) { log.error("ignore exception input code: [{}] has trigger exception", code); return new JwtToken("imooc-qinyi-fallback"); } }

2、编写controller测试使用RestTemplate的熔断降级

package com.imooc.ecommerce.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.fastjson.JSON;
import com.imooc.ecommerce.fallback_handler.QinyiFallbackHandler;
import com.imooc.ecommerce.vo.JwtToken;
import com.imooc.ecommerce.vo.UsernameAndPassword;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

/**
 * 

Sentinel 提供容错降级的功能 服务未启动(容错了)

* */ @SuppressWarnings("all") @Slf4j @RestController @RequestMapping("/sentinel-fallback") public class SentinelFallbackController { /** 注入没有增强的 RestTemplate */ private final RestTemplate restTemplate; public SentinelFallbackController(RestTemplate restTemplate) { this.restTemplate = restTemplate; } @PostMapping("/get-token") @SentinelResource( value = "getTokenFromAuthorityService", fallback = "getTokenFromAuthorityServiceFallback", fallbackClass = { QinyiFallbackHandler.class } ) public JwtToken getTokenFromAuthorityService( @RequestBody UsernameAndPassword usernameAndPassword) { String requestUrl = "http://127.0.0.1:7000/ecommerce-authority-center/authority/token"; log.info("RestTemplate request url and body: [{}], [{}]", requestUrl, JSON.toJSONString(usernameAndPassword)); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return restTemplate.postForObject( requestUrl, new HttpEntity<>(JSON.toJSONString(usernameAndPassword), headers), JwtToken.class ); } /** *

让 Sentinel 忽略一些异常

* */ @GetMapping("/ignore-exception") @SentinelResource( value = "ignoreException", fallback = "ignoreExceptionFallback", fallbackClass = { QinyiFallbackHandler.class }, exceptionsToIgnore = { NullPointerException.class } ) public JwtToken ignoreException(@RequestParam Integer code) { if (code % 2 == 0) { throw new NullPointerException("yout input code is: " + code); } return new JwtToken("qinyi-imooc"); } }

五、Sentinel 结合 Nacos 实现限流规则持久化

1、SpringCloud Alibaba Sentinel 配置信息

SpringCloud Alibaba Sentinel 使用方式及限流规则持久化_第4张图片

2、 整合nacos实现限流规则持久化

2.1、添加依赖

        
        
            com.alibaba.csp
            sentinel-datasource-nacos
        

2.2、编写限流接口

    /**
     * 

在 dashboard 中 "流控规则" 中按照资源名称新增流控规则

* */ @GetMapping("/by-resource") @SentinelResource( value = "byResource", blockHandler = "qinyiHandleBlockException", blockHandlerClass = QinyiBlockHandler.class ) public CommonResponse byResource() { log.info("coming in rate limit controller by resource"); return new CommonResponse<>(0, "", "byResource"); }

2.3、yml配置(spring:cloud下)

    sentinel:
      # 配置 sentinel dashboard 地址
      transport:
        dashboard: 127.0.0.1:7777
        port: 8719 # 会在应用对应的机器上启动一个 Http Server, 该 Server 会与 Sentinel 控制台做交互
      # 服务启动直接建立心跳连接
      eager: true
      datasource:
        # 名称任意, 代表数据源
        ds:
          nacos:
            # NacosDataSourceProperties.java 中定义
            server-addr: ${spring.cloud.nacos.discovery.server-addr}
            dataId: ${spring.application.name}-sentinel
            namespace: ${spring.cloud.nacos.discovery.namespace}
            groupId: DEFAULT_GROUP
            data-type: json
            # 规则类型: com.alibaba.cloud.sentinel.datasource.RuleType
            # FlowRule 就是限流规则
            rule-type: flow

2.4、在nacos上编写指定限流接口的配置

[
  {
    "resource": "byresource",
    "limitApp": "default",
    "grade": 1,
    "count": 1,
    "strategy": 0,
    "controlBehavior": 0,
    "clusterMode": false
  }
]
  • resource:资源名称。
  •  limitApp:针对来源,可以编写成服务名称,默认为default。
  • grade:阈值类型,QPS(1)、并发线程数(0)。
  • count:单机阈值。
  • strategy:流控模式,直接(0)、关联(1)、链路(2)。
  • controlBehavior:流控效果,快速失败(0)、Warm Up(1)、排队等待(2)。
  • clusterMode:是否集群,是(true)、否(false)。
  • warmUpPeriodSec:预热时长,单位秒。
  • maxQueueingTimeMs:超时时间,单位毫秒。
  • refResource:关联资源名称

3、 整合nacos实现熔断规则持久化

3.1、添加依赖


        
        
            com.alibaba.csp
            sentinel-datasource-nacos
        

3.2、yml配置

feign:
  sentinel:
    enabled: true
spring:
  cloud:
    openfeign:
      lazy-attributes-resolution: true
    sentinel:
      datasource:
        degrade:
          nacos:
            dataId: sentinel-batch-degrade
            groupId: DEFAULT_GROUP
            namespace: train
            ruleType: degrade
            serverAddr: 127.0.0.1:8848
      transport:
        dashboard: localhost:18080
        port: 8719

3.3、在nacos上编写熔断规则。

[{
"resource":"GET:http://business/hello",
"grade":0,
"count": 201,
"timeWindow":11,
"minRequestAmount":6,
"statIntervalMs":1000,
"slowRatioThreshold":0.3
}]
  • resource:资源名称。
  • grade:熔断策略,慢比例调用(0)、异常比例(1)、异常数(2)。
  • count:最大响应时间(最大TR),单位毫秒。
  • timeWindow:熔断时长,单位秒。
  • minRequestAmount:最小请求数。
  • statIntervalMs:统计时长,单位毫秒。
  • slowRatioThreshold:比例阀值。
[{
"resource":"GET:http://business/hello",
"grade":1,
"count": 0.3,
"timeWindow":11,
"minRequestAmount":6,
"statIntervalMs":1000
}]
  • resource:资源名称。
  • grade:熔断策略,慢比例调用(0)、异常比例(1)、异常数(2)。
  • count:比例阀值。
  • timeWindow:熔断时长,单位秒。
  • minRequestAmount:最小请求数。
  • statIntervalMs:统计时长,单位毫秒。
[{
"resource":"GET:http://business/hello",
"grade":2,
"count":3,
"timeWindow":11,
"minRequestAmount":6,
"statIntervalMs":1000
}]
  • resource:资源名称。
  • grade:熔断策略,慢比例调用(0)、异常比例(1)、异常数(2)。
  • count:异常数。
  • timeWindow:熔断时长,单位秒。
  • minRequestAmount:最小请求数。
  • statIntervalMs:统计时长,单位毫秒。

3.4、熔断策略讲解

  1. 慢比例调用:当最大RT=201,比例阀值=0.3,熔断时长=11,最小请求数=6,统计时间=1000,表示当请求资源时,当满足在一秒钟内,请求数超过6个,并且30%的请求时间超过201毫秒这个条件时,接口熔断11秒。
  2. 异常比例:当比例阀值=0.3,熔断时长=3,最小请求数=6,统计时间=1000,表示当请求资源时,当满足在一秒钟内,请求数超过6个,并且异常比例达到30%这个条件时,接口熔断3秒。
  3. 异常数:当异常数=3,熔断时长=3,最小请求数=6,统计时间=1000,表示当请求资源时,当满足在一秒钟内,请求数超过6个,并且异常数超过3个这个条件时,接口熔断3秒。

3.5、编写fegin client 

/**
 * 

通过 Sentinel 对 OpenFeign 实现熔断降级

* */ @FeignClient( value = "e-commerce-imooc", fallback = SentinelFeignClientFallback.class ) public interface SentinelFeignClient { @RequestMapping(value = "qinyi", method = RequestMethod.GET) CommonResponse getResultByFeign(@RequestParam Integer code); }

3.6、编写Sentinel 对 OpenFeign 接口的降级策略


/**
 * 

Sentinel 对 OpenFeign 接口的降级策略

* */ @Slf4j @Component public class SentinelFeignClientFallback implements SentinelFeignClient { @Override public CommonResponse getResultByFeign(Integer code) { log.error("request supply for test has some error: [{}]", code); return new CommonResponse<>( -1, "sentinel feign fallback", "input code: "+ code ); } }

3.7、编写controller测试使用fegin的熔断降级

/**
 * 

OpenFeign 集成 Sentinel 实现熔断降级

* */ @Slf4j @RestController @RequestMapping("/sentinel-feign") public class SentinelFeignController { private final SentinelFeignClient sentinelFeignClient; public SentinelFeignController(SentinelFeignClient sentinelFeignClient) { this.sentinelFeignClient = sentinelFeignClient; } /** *

通过 Feign 接口去获取结果

* */ @GetMapping("/result-by-feign") public CommonResponse getResultByFeign(@RequestParam Integer code) { log.info("coming in get result by feign: [{}]", code); return sentinelFeignClient.getResultByFeign(code); } }

六、Gateway集成Sentinel实现网关限流(不论那种方式硬编码中的样板代码必须添加在Gateway)

1、引入依赖

        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-sentinel
        
        
            com.alibaba.cloud
            spring-cloud-alibaba-sentinel-gateway
        
        
        
            com.alibaba.csp
            sentinel-datasource-nacos
        

2、编写配置文件(spring:cloud下)

    sentinel:
      # 配置 sentinel dashboard 地址
      transport:
        dashboard: 127.0.0.1:7777
        port: 8719 # 会在应用对应的机器上启动一个 Http Server, 该 Server 会与 Sentinel 控制台做交互
      # 服务启动直接建立心跳连接
      eager: true

3、硬编码方式实现

package com.imooc.ecommerce.config;

import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * 

Gateway 集成 Sentinel 实现限流

* */ @Slf4j @Configuration public class SentinelGatewayConfiguration { //=====================================================样板间式代码开始===================================================== /** 视图解析器 */ private final List viewResolvers; /** HTTP 请求和响应数据的编解码配置 */ private final ServerCodecConfigurer serverCodecConfigurer; /** *

构造方法

* */ public SentinelGatewayConfiguration( ObjectProvider> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer ) { this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList); this.serverCodecConfigurer = serverCodecConfigurer; } /** *

限流异常处理器, 限流异常出现时, 执行到这个 handler

* */ @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() { // 默认会返回错误 message, code 429 return new SentinelGatewayBlockExceptionHandler( this.viewResolvers, this.serverCodecConfigurer ); } /** *

限流过滤器, 是 Gateway 全局过滤器, 优先级定义为最高

* */ @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public GlobalFilter sentinelGatewayFilter() { return new SentinelGatewayFilter(); } /** * 自定义限流异常返回 */ @PostConstruct public void initBlockHandlers() { BlockRequestHandler blockRequestHandler = new BlockRequestHandler() { public Mono handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) { Map result = new HashMap(); result.put("code","500016"); result.put("msg","接口被限流了"); return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromObject(result)); } }; GatewayCallbackManager.setBlockHandler(blockRequestHandler); } //=====================================================样板间式代码结束===================================================== //=====================================================硬编码方式实现限流规则============================================// /** *

初始化限流规则

* */ // @PostConstruct public void doInit() { log.info("---------------------------------------------------"); // 加载网关限流规则 log.info("load sentinel gateway rules (code define)"); initGatewayRules(); // 加载自定义限流异常处理器 initBlockHandler(); log.info("---------------------------------------------------"); } /** *

硬编码网关限流规则

* */ private void initGatewayRules() { Set rules = new HashSet<>(); GatewayFlowRule rule = new GatewayFlowRule(); // 指定限流模式, 根据 route_id 做限流, 默认的模式 rule.setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_ROUTE_ID); // 指定 route_id -> service id rule.setResource("e-commerce-nacos-client"); // 按照 QPS 限流 rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 统计窗口和限流阈值 rule.setIntervalSec(60); rule.setCount(3); // rules.add(rule); // 限流分组, Sentinel 先去找规则定义, 再去找规则中定义的分组 rules.add( new GatewayFlowRule("nacos-client-api-1") .setCount(3).setIntervalSec(60) ); rules.add( new GatewayFlowRule("nacos-client-api-2") .setCount(1).setIntervalSec(60) ); // 加载到网关中 GatewayRuleManager.loadRules(rules); // 加载限流分组 initCustomizedApis(); } /** *

自定义限流异常处理器

* */ private void initBlockHandler() { // 自定义 BlockRequestHandler BlockRequestHandler blockRequestHandler = new BlockRequestHandler() { @Override public Mono handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) { log.error("------------- trigger gateway sentinel rule -------------"); Map result = new HashMap<>(); result.put("code", String.valueOf(HttpStatus.TOO_MANY_REQUESTS.value())); result.put("message", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase()); result.put("route", "e-commerce-nacos-client"); return ServerResponse .status(HttpStatus.TOO_MANY_REQUESTS) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(result)); } }; // 设置自定义限流异常处理器 GatewayCallbackManager.setBlockHandler(blockRequestHandler); } /** *

硬编码网关限流分组

* 1. 最大限制 - 演示 * 2. 具体的分组 * */ private void initCustomizedApis() { Set definitions = new HashSet<>(); // nacos-client-api 组, 最大的限制 ApiDefinition api = new ApiDefinition("nacos-client-api") .setPredicateItems(new HashSet() {{ // 模糊匹配 /imooc/ecommerce-nacos-client/ 及其子路径的所有请求 add(new ApiPathPredicateItem() .setPattern("/imooc/ecommerce-nacos-client/**") // 根据前缀匹配 .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX)); }}); // nacos-client-api-1 分组 ApiDefinition api1 = new ApiDefinition("nacos-client-api-1") .setPredicateItems(new HashSet() {{ add(new ApiPathPredicateItem() // 精确匹配 /imooc/ecommerce-nacos-client/nacos-client/service-instance .setPattern("/imooc/ecommerce-nacos-client" + "/nacos-client/service-instance")); }}); // nacos-client-api-2 分组 ApiDefinition api2 = new ApiDefinition("nacos-client-api-2") .setPredicateItems(new HashSet() {{ add(new ApiPathPredicateItem() // 精确匹配 /imooc/ecommerce-nacos-client/nacos-client/project-config .setPattern("/imooc/ecommerce-nacos-client" + "/nacos-client/project-config")); }}); definitions.add(api1); definitions.add(api2); // 加载限流分组 GatewayApiDefinitionManager.loadApiDefinitions(definitions); } }

4、本地文件方式实现

4.1、编写路由规则

gateway-flow-rule-sentinel.json(路由规则,resource可以为接口名称、微服务名称、分组名称,resourceMode=1,resourceMode=0表示分组)

[
  {
    "resource": "e-commerce-nacos-client",
    "resourceMode": 0,
    "count": 3,
    "intervalSec": 60
  },
  {
    "resource": "nacos-client-api",
    "resourceMode": 1,
    "count": 1,
    "intervalSec": 60
  }
]

4.2、编写路由规则分组 

gateway-flow-rule-api-sentinel.json(路由规则分组,表示resource中是apiname时,该分组中的接口路径都按照resource中的限流规则)

[
  {
    "apiName": "nacos-client-api",
    "predicateItems": [
      {
        "pattern": "/imooc/ecommerce-nacos-client/nacos-client/project-config"
      },
      {
        "pattern": "/imooc/ecommerce-nacos-client/**",
        "matchStrategy": 1
      }
    ]
  }
]

4.3、编写配置文件

    sentinel:
      eager: true
      transport:
        client-ip: 8720
        dashboard: 127.0.0.1:7777
      datasource:
        dsl.file:
          file: classpath:gateway-flow-rule-sentinel.json
          ruleType: gw-flow
        ds2.file:
          file: classpath:gateway-flow-rule-api-sentinel.json
          ruleType: gw-api-group

5、nacos方式实现

 5.1、nacos上编写路由规则

gateway-flow-rule-sentinel.json(路由规则,resource可以为接口名称、微服务名称、分组名称,resourceMode=0为roteId,resourceMode=1表示api分组)

[
  {
    "resource": "e-commerce-nacos-client",
    "resourceMode": 0,
    "count": 3,
    "intervalSec": 60
  },
  {
    "resource": "nacos-client-api",
    "resourceMode": 1,
    "count": 1,
    "intervalSec": 60
  }
]

5.2、nacos上编写路由规则分组 

gateway-flow-rule-api-sentinel.json(路由规则分组,表示resource中是apiname时,改分组中的接口路径都按照resource中的限流规则,matchStrategy=1表示为模糊匹配,默认为精确匹配)

[
  {
    "apiName": "nacos-client-api",
    "predicateItems": [
      {
        "pattern": "/imooc/ecommerce-nacos-client/nacos-client/project-config"
      },
      {
        "pattern": "/imooc/ecommerce-nacos-client/**",
        "matchStrategy": 1
      }
    ]
  }
]

5.3、编写yml配置文件

    sentinel:
      eager: true
      transport:
        client-ip: 8720
        dashboard: 127.0.0.1:7777
      datasource:
        # 名称任意, 代表数据源
        ds1:
          nacos:
            # NacosDataSourceProperties.java 中定义
            server-addr: ${spring.cloud.nacos.discovery.server-addr}
            dataId: gateway-flow-rule-sentinel
            namespace: ${spring.cloud.nacos.discovery.namespace}
            groupId: DEFAULT_GROUP
            data-type: json
            # 规则类型: com.alibaba.cloud.sentinel.datasource.RuleType
            # FlowRule 就是限流规则
            rule-type: gw_flow
        # 名称任意, 代表数据源
        ds2:
          nacos:
            # NacosDataSourceProperties.java 中定义
            server-addr: ${spring.cloud.nacos.discovery.server-addr}
            dataId: gateway-flow-rule-api-sentinel
            namespace: ${spring.cloud.nacos.discovery.namespace}
            groupId: DEFAULT_GROUP
            data-type: json
            # 规则类型: com.alibaba.cloud.sentinel.datasource.RuleType
            # FlowRule 就是限流规则
            rule-type: gw_api_group



你可能感兴趣的:(gateway,spring,cloud,sentinel,java)