前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 Sentinel 实现接口限流

使用 Sentinel 实现接口限流

作者头像
没有故事的陈师傅
发布2021-05-17 17:05:07
2.5K0
发布2021-05-17 17:05:07
举报
文章被收录于专栏:运维开发故事

在前面一篇文章我已经对 Sentinel 做了一个简单的介绍,相信大家对 Sentinel 有一个简单的了解,本次主要是讲 Sentinel 的使用。在 sentinel-dashboard 配置流控规则,以及使用 Sentinel 整合 RestTemplate、OpenFeign 进行流控使用(建议网页版阅读)。

安装 sentinel dashboard

我使用的 sentinel 版本是: sentinel-dashboard-1.8.0

启动控制台命令:

代码语言:javascript
复制
java -jar sentinel-dashboard-1.8.0.jar

默认启动的是 8080 端口, 登录账号和密码默认都是: sentinel。 如果需要修改启动端口可以在启动命令前面加 -Dserver.port=9999 进行修改。

使用介绍

通常我们在项目中对于 Sentinel 最常用的场景,就是默认的流控对接口的访问添加流控规则。Sentinel 也提供了对于 RestTemplate 、OpenFegin 的支持。

简单案例

1. 导入依赖

如果我们需要使用 Sentinel ,首先我们需要在业务服务中,导入 Sentinel 客户端的依赖。下面是 Maven 的 pom 依赖。 我们可以直接使用 spring-coud-starter-alibaba-sentinel 进行快速整合。

代码语言:javascript
复制
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
代码语言:javascript
复制

对于 spring-cloud-alibaba 相关的版本依赖信息如下:

代码语言:javascript
复制
代码语言:javascript
复制
<properties>
  <spring-boot.version>2.3.10.RELEASE</spring-boot.version>
  <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
  <spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>${spring-boot.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>${spring-cloud.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-alibaba-dependencies</artifactId>
      <version>${spring-cloud-alibaba.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
代码语言:javascript
复制

2. YML 配置

我们在业务服务中导入了依赖过后,我们需要修改 application.yml 文件让服务启动过后自动注册到 sentinel-dashboard 服务上。

代码语言:javascript
复制
spring:
  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8080
代码语言:javascript
复制

3. 测试接口定义

首先我们需要定义对外开放的接口。

代码语言:javascript
复制
@RestController
public class HelloController {
    
    @GetMapping("/hello")
    public String hello () {
        return "OK";
    }
}
代码语言:javascript
复制

4. 通过控制台配置流控规则

注意:如果已经启动 snetinel-dashboard 后并且启动业务服务,在 sentinel-dashboard 后台还是没有服务的话,我们可以先访问一下业务服务的接口,然后在刷新snetinel-dashboard 观察是否正常。如果还是不正常请考虑 sentinel 的 client 版本和 dashboard 是否匹配。

首先选择自己对应服务展开,然后选择【簇点链路】 菜单。选择需要流控的接口 /hello 然后选择 【流控】按钮进行流控配置

我们可以配置, 我们选择【阀值类型】选择【QPS】,然后设置【单机阀值】 填入 1 。表示该接口每秒钟只能接受一个 QPS ,如果超过阈值过后就会触发 【流控】默认 Sentinel 返回 Blocked by Sentinel (flow limiting)

5. 流控规则触发

如果我们需要触发流控规则我们频繁访问 /hello 接口即可。

代码语言:javascript
复制
~ curl http://127.0.0.1:8066/hello
OK%                                                                                                                                                   ~ curl http://127.0.0.1:8066/hello
~ curl http://127.0.0.1:8066/hello
Blocked by Sentinel (flow limiting)%

通过上面的结果我们可以看到当单位时间内超过阈值过后, 就会触发 flow limit

整合 RestTemplate

1. YML 配置

Sentinel 整合 Resttemplate 除了需要导入 spring-cloud-starter-alibaba-sentinel 开需要开启 Sentinel 对 Resttemplate 的支持。

代码语言:javascript
复制
resttemplate:
  sentinel:
    enabled: true
代码语言:javascript
复制

2. 创建 RestTemplate

如果 RestTemplate 在使用的时候需要使用到 Sentinel 的流控规则,首先需要在创建 RestTemplate 的时候添加 @SentinelRestTemplate 注解。注意: SentinelExceptionHandler 中的方法都是 static 方法

代码语言:javascript
复制
代码语言:javascript
复制
@Configuration
public class RestTemplateConfig {
    @Bean
    @ConditionalOnMissingBean(RestTemplate.class)
    @LoadBalanced
    @SentinelRestTemplate(
            blockHandler = "handlerException", blockHandlerClass = SentinelExceptionHandler.class,
            fallback = "handleFallback", fallbackClass = SentinelExceptionHandler.class)
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
// 异常处理类
public class SentinelExceptionHandler {
    
    //限流熔断业务逻辑
    public static SentinelClientHttpResponse handlerException(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
        String message = JSON.toJSONString(CommonResult.error(-100,"系统错误 (限流熔断业务逻辑)"));
        return new SentinelClientHttpResponse(message);
    }
    //异常降级业务逻辑
    public static SentinelClientHttpResponse handleFallback(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
        String message = JSON.toJSONString(CommonResult.error(-100,"系统错误 (异常降级业务逻辑)"));
        return new SentinelClientHttpResponse(message);
    }
}
代码语言:javascript
复制

3. 接口定义

下面就是我们使用的代码,可能写得稍微有点复杂,我来解释一下。首先我是通过 RestTemplate 访问 stock-service 服务的 /getStockDetail 接口然后将接口的返回数据解析,通过CommonResult<StockModel> 实例对象进行接收, 如果失败就返回错误信息。

代码语言:javascript
复制
@Autowired
private RestTemplate restTemplate;
@GetMapping("/hello2")
public CommonResult<OrderModel> hello2() {
  ParameterizedTypeReference<CommonResult<StockModel>> typeRef =
    new ParameterizedTypeReference<CommonResult<StockModel>>() {
  };
  ResponseEntity<CommonResult<StockModel>>
    forEntity = restTemplate.exchange("http://stock-service/getStockDetail", HttpMethod.GET,
                                      HttpEntity.EMPTY, typeRef);
  OrderModel orderModel = new OrderModel();
  orderModel.setId(100);
  orderModel.setCode("100-100");
  if (Objects.equals(forEntity.getStatusCode(), HttpStatus.OK) && Objects.nonNull(forEntity.getBody())) {
    CommonResult<StockModel> result = forEntity.getBody();
    if (result.getCode() != 1) {
      return CommonResult.error(null, result.getCode(), result.getMessage());
    }
    orderModel.setStockModel(result.getData());
  }
  return CommonResult.success(orderModel);
}
代码语言:javascript
复制

4. 流控触发

如果我们频繁的访问我们的接口 /hello2 就会出现限流的逻辑

代码语言:javascript
复制
~ curl http://127.0.0.1:8066/hello2
{"code":1,"message":"this is a success message","data":{"id":100,"code":"100-100","stockModel":{"id":1,"code":"STOCK==>1000"}}}
~ curl http://127.0.0.1:8066/hello2
{"code":-100,"message":"系统错误 (限流熔断业务逻辑)","data":null}

整合 OpenFegin

1. 导入 openfeign 依赖

Sentinel 整合 Openfeign 需要导入 spring-cloud-starter-openfeign

代码语言:javascript
复制
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2. YML 配置

Sentinel 整合 Openfeign 需要开启对 feign 的支持,配置如下:

代码语言:javascript
复制
代码语言:javascript
复制
feign:
  sentinel:
    enabled: true

注意:启动类上要增加 @EnableFeignClients 来配置 Openfeign 的启用

3. 调用代码

Feign 接口调服务 stock-service/getStockDetail 接口,如果触发流控规则就会执行 FallbackFactory 中返回 StockFeign 的本地存根方法。

代码语言:javascript
复制
代码语言:javascript
复制
@FeignClient(name = "stock-service", fallbackFactory = StockFeignFallbackFactory.class)
public interface StockFeign {
    @GetMapping("/getStockDetail")
    CommonResult<StockModel> getStockDetail();
}
代码语言:javascript
复制

StockFeignFallbackFactory 类是服务降级的处理。

代码语言:javascript
复制
代码语言:javascript
复制
@Component
public class StockFeignFallbackFactory implements FallbackFactory<StockFeign> {
    private Logger log = LoggerFactory.getLogger(StockFeignFallbackFactory.class);
    @Override
    public StockFeign create(Throwable throwable) {
        return new StockFeign() {
            @Override
            public CommonResult<StockModel> getStockDetail() {
                log.error("调用查询库存详情降级", throwable);
                return CommonResult.error(null, -100, "调用查询库存详情降级");
            }
        };
    }
}

Controller 调用代码

代码语言:javascript
复制
@Autowired
private StockFeign stockFeign;
@GetMapping("/hello1")
public CommonResult<OrderModel> hello() {
  CommonResult<StockModel> result = stockFeign.getStockDetail();
  if (result.getCode() != 1) {
    return CommonResult.error(null, result.getCode(), result.getMessage());
  }
  StockModel stockDetail = result.getData();
  OrderModel orderModel = new OrderModel();
  orderModel.setStockModel(stockDetail);
  return CommonResult.success(orderModel);
}
代码语言:javascript
复制

4. 业务执行

如果我们多次访问,Sentinel 就会触发降级策略。然后执行 StockFeignFallbackFactory 的本地存根方法返回

代码语言:javascript
复制
~ curl http://127.0.0.1:8066/hello1
{"code":1,"message":"this is a success message","data":{"id":null,"code":null,"stockModel":{"id":1,"code":"STOCK==>1000"}}}
~ curl http://127.0.0.1:8066/hello1
{"code":-100,"message":"调用查询库存详情降级","data":null}%

源码地址

gitee: https://gitee.com/zhengsh/excavator

参考

https://spring-cloud-alibaba-group.github.io/github-pages/hoxton/en-us/index.html#_spring_cloud_alibaba_sentinel

https://segmentfault.com/a/1190000019070557

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-05-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 运维开发故事 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 安装 sentinel dashboard
  • 使用介绍
    • 简单案例
      • 1. 导入依赖
      • 2. YML 配置
      • 3. 测试接口定义
      • 4. 通过控制台配置流控规则
      • 5. 流控规则触发
    • 整合 RestTemplate
      • 1. YML 配置
      • 2. 创建 RestTemplate
      • 3. 接口定义
      • 4. 流控触发
    • 整合 OpenFegin
      • 1. 导入 openfeign 依赖
      • 2. YML 配置
      • 3. 调用代码
      • 4. 业务执行
  • 源码地址
  • 参考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档