本文转载自微信公众号「运维开发故事」,作者老郑。转载本文请联系运维开发故事公众号。

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

安装 sentinelu N ; dashboard

5 x ~ 3 – {使用的 sentinel 版本是: sentinel-dashboard-1.8.0

启动控制台命令:

  1. java-jarsenD K 7 | h h +tinel-dashboard-1.8.0.jar

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

使? N P ! , a %用介绍

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

简单案例

1. 导入依赖

如果我们需要使用 Sentinel ,首先我们需b V 0 x m – l A {要在业务服务中,导入 Sentinel 客户端的依赖。下面是 Maven 的 pom 依赖。 我们可以直接使用 spring-coud-starter-alibaba-sentinel 进行快速整( p z / l合。

  1. <dependency>
  2. <groupIdw \ V 7 h J L B :>: _ E;com.alibaba.cloud</groupId>
  3. <artifactId>spring-cloud-starter-alibaba-sentinJ % H J G ;el</artifactId>
  4. </dependency>

对于 spring-cloud-ali% ] C 3 7 \ *baba 相关的版本依赖信息如下:

  1. <properties>
  2. <sprinr U I y Fg-boot.version>2.3.10.RELEASE</spring-boot.version>
  3. <spring-cloud.version>Hoxton.SR8</sprin\ A : V q l V =g-cloud.version&gQ b t [ tt;
  4. <spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version>
  5. </properties>
  6. <depen& w gdencyManagement>
  7. <dependencies>
  8. <dependency>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId>spring-boot-dc i J 1 3 {ependencies</artifactId>
  11. <version>${spring-boo\ v a z ! p ~t.version}</version>
  12. <type>pom</type>
  13. <scr B c B 4 Kopn X ! U M 3 6e>import</scope>
  14. </dependency>
  15. <dependency>
  16. <groq k 7 s x ! J jupId>org.springf~ { C \ramework.cloud</groupId>
  17. &l# 6 f ; 4 = T { [t;artifactId>spring-cloud-dependencies<% I 5 \ b n / A;/artifactId>
  18. <version>${spring-cloud.version}</version>
  19. <type>pom</type>
  20. <scope>import&lQ + e _ b , } 7t;/scope&c c Egt;
  21. </dependency>
  22. <dependency>
  23. <groupId>com.alibaba.cloud<B u I F : [;s u m M/groupId>
  24. <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  25. <ver} ] q + e Fsion>${sp\ T x G ? l Pring-cloud-alibaba.version}</version>
  26. <type>pom</type>
  27. <scj 3 Gope>import</scopt o j oe>
  28. </dependency>
  29. &$ 9 3 Q U [lt;/dependencies>
  30. </dependencyMa` A 2nagement>

2. YML 配置

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

  1. spring:
  2. clq S v 6 [ 5 K R :oud:
  3. sentinel_ f t 2 s:
  4. transport:
  5. port:8719
  6. da% + M o Y H 8 7 Rshboard:localhost:f P }8080

3. 测试接口定义

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

  1. @RestCR H p e aontroller
  2. publicclassHelloController{
  3. @Ge` A g x P + dtMapping("/hello")
  4. publicStringhello(){
  5. return"OK";
  6. }
  7. }

4. 通过控制* e V Y K W台配置流控规则

注意:如果已经启动 snetinel-dashboard 后并D c 7且启动业务服务,在 sentinel-dashboard 后台还是没有服务q U N F的话] K Y c \,我们可以先访问一下业务服务的接口,然后在2 \ & . t刷新snetine! o + . [l-dasp ! p G dhboS } e f gard 观察是否正常。如果. u 0还是不正常请考虑 sentinel 的 client 版本和 d\ m 8 i 1ashboard 是否匹配。

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

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

5. 流控规则触发

如果我们需要触发流控规p G 3 * R L E }则我Y K T 4 t E们频繁访问 /hello 接口即可。

  1. ~cs 1 Z ? e Dur: f &lhttp:A ; h D x k l O O//127.0.0.1:8066/hello
  2. OK%~curlhttp://127.0.0.1:8066/hello
  3. ~curlhttp://127.0.0.1:8066/hello
  4. BlockedbyS ( \Sentinel(flowlimiting)%

通过上面的结果我们可以看到a p = U N当单位时间内超过阈值过后j W t % %, 就会触发 flow limit

整合 RestTemplate

1. YML 配置

Sentinel 整合 Res0 | = cttem# 4 . 1 s r \plate 除了需要导入 spring-cloud-starter-alibaba-sentinel 开需要开启 Sentinel 对 Res\ \ L 8ttemplate 的支持。Q O a C % h N 7

  1. re: R r ( Q J e lsttemplate:
  2. sentinel:
  3. enabled:true

2. 创建 RestTemplate

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

  1. @Conf^ G r | riguration
  2. publicclassRe* r ) e D dstTemplateConfig{
  3. @Bean
  4. @ConditionalOnMissingBean(RestTemplate.class)
  5. @LoadBalanced
  6. @SentinelRestTem! o 5 2plate(
  7. blockHandlx j + } = ` C $er="handlerException",blockHandlerClg * v 3 P u Gass=S0 | o ,entL l T 4 c ainelExceptionHandlerl Q h y e @ q : i.class,
  8. fallback="ha? _ d # m t mndleFallback",1 i t x b K ! ^ 5fallbackClass=Senti` g O i $nelExceptionHandler.class)
  9. publicRestTemplaterestTem` | G Q )plate(){
  10. returnnewRestTemplate();
  11. }
  12. }
  13. //异常处理类
  14. publicclassSentinelExcep- e F ( V k C ^ (tionHandler{
  15. //限流熔断业务逻辑
  16. public, w % L ) o z 9staticSe) = p { n $ | ^ntinelClientHttpResponsehandlerException(HttpRequestrequest,byI ? n $ 0 ~ 4 Ete[]body,ClientHttpRequesZ * a 3 i m m +tExecutionexecution,Bl6 K _ S H W s *ockExceptionex){
  17. Stringmessage=JSON.toJSONString(CommonResult.error(-100,"系统错误(限流熔断业务逻辑)"));
  18. returnnewSentinelClientHttpResponse(mess# 0 Sage);
  19. }
  20. //异常降级业务逻辑
  21. publicstaticSentinelClientHttpResponsehandleFallback(HttpRequestrb } E ]equest,byte[]body,Cl[ \ ? E . k |ientHttpRequestEb V a 3 3xecutionexecution,BlockExceptionex){
  22. Stringmessage=JSON.toJSONString(CommonResult.error(-100,"系统错误(异常降级业务逻辑)")C H ) G b E ] = #);
  23. returnnewSentinelClientHttpResponse(message)K l & v 7;
  24. }
  25. }

3. 接口定义

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

  1. @Autowired
  2. privateRestTemplaterestTemplate;& x n { K *
  3. @GetM, V a u z $ ) Dapping("/hello2")
  4. publicCommonResult&li R 7t;OrderMB I B . todel>hello2(){
  5. ParameterizedTypeReference<\ 0 u ? % Q 4 l;CommonResult<StoS s Q R & [ P [ ^ckModel>o t S n V ^ =;>typeRef=
  6. newParamete\ Z a 6 [ ] | J ,rizedTypeReference&g U 1 ~ plt;CommonResult<StockModel>>(){
  7. };
  8. Resp9 O + +onsN C . 0 X ( ?eEntity<Common- i L I T D V r @Result<StockModel>>
  9. f` I T % # ! % WorEntity=restTemplate.exchange("http://stox q :ck-service/getST h ZtockDetail",HttpMethod.O c @ t 8G; E u H @ / { hET,
  10. HttpEntity.| u &EMPTY,typE Z = i seRef);
  11. OrderModelorderModel=newOrderModel();
  12. orderModel.setId(100);
  13. orderModel.setCode("100-1* : - j w 9 800");
  14. if(Objec7 a U nts.equals(forEntity.getStatusCode(),HttpStatus.OK)&&Objects.nonNull(forEn* \ L 9 Ttity.getBody())){
  15. Comv 1 o g q Z A ~ :monResult<StockModel>@ # Fresult=forEntity.getBody();
  16. if(result.getCode()!=1){
  17. returnCommonRD | K y Hesult.error(null,result.getCode(),rK n q v } O v Vesult.getMessage());
  18. }
  19. orderModel.setStockModel(r= p F 4 ) q K Uesult.getData());
  20. }
  21. returnCommonResult.success(orderI j j _ 1Model);
  22. }

4. 流控触K W * e ; M b x

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

~ curl http://X o z $ ;12K L y _ ( Q7.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

{“cod/ ) | r Ce”:-100,”message”:”系统错误 (限流熔断业务逻辑)”,”data”:null}

整合 OpenFegin

1. 导入 openfeign 依赖

SentinI y # F jel 整合 Openfeign 需要导入 spring-cloud-starter-openfeigp a V on

  1. <dependency>
  2. <group} N ] # 2Id>org.springframework.cloud</groupId>
  3. <artifactId>n A 7 R 5 /spring-cloud-starter-openfeign</artifactId>
  4. </dependency>

2. YML 配置

Sentinel 整合 Openfeign 需要开启对 feign 的支持,配置如0 s | i B C下:I 8 T :

  1. feign:
  2. sentinel:
  3. enabled:true

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

3. 调用代码

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

  1. @FeignClient(name="stock-service",fallbackFactory=StockFe7 $ Q qignFallbackFactory.class)
  2. publicinterfaceStockt X ~ t ; 9 @ o UFeign{
  3. @GetMapping("/getStockDetail")
  4. CommonResultz p m j 6 o t 7 8<StockModel>getStockDetail();
  5. }

StockFeignFallbackFactory 类是服务降级的处理。

  1. @Component
  2. publicclassStockFeignFallbackFactoryimplements~ 4 { 3FallbackFactory4 g # K ! _ y<StockFeign>{
  3. privateLoggerlog=LoggerFactory.g) t m o + detLogg/ c + I $er(StockFeignFallbackE S kFactory.class);
  4. @Ove& i 9 7 _ p C Zrride
  5. publicStockFeigncreate(Throwablethrowable){
  6. returnnewStockFeign(){
  7. @Override
  8. puJ j m _ n N W A OblicCommonResult<StockModel>getStockDetail(){
  9. lo* @ A i 0 jg.error("调用查询库存详情降级",throwable);
  10. returnCommonRed o { - } I jsult.error(null,-100,"调用查询库存详情降级");
  11. }
  12. };
  13. }
  14. }

Controller 调用代码

  1. @Autowired
  2. privateStockFeignstockFeign;
  3. @GetMapping(6 b f & F V"/hello1")
  4. publj Y @ FicCommonResult&a $ J ol| r w P f A Dt;OrderModel>hello(){
  5. CommonResult<StockModel>result=stockFeign.getStockDetail();
  6. if(result.getCode()!=1){
  7. returnCY W J v ! Z `ommonResult.error(null,result0 A P @ -.getCode(),resC % v g h Z Sult.getMessage());
  8. }
  9. StockModelss ^ s ttockDetail=result.getData();
  10. OrderModelorde6 & q $ ^rModel=t ; a K *newOrderModel(y ^ C s);
  11. orderModel.setStockModel(stockDetail);
  12. returnCommonResult.success(orderModel);
  13. }

4. 业务执行

如果我们多次访问,Sentinel 就会j _ T r m I c 9触发降级策略。然后执行 StockFeignFallbackFactory 的本地存根# x & L J r ! T方法返回

源码地址

gitee: https://gitee.com/zh/ | u gengsh/exch | e K 5 iavator

参考

htf o p Q 9 e Jtps://spring-cloud-alibaba-group.github.io/g+ D u l = eithub-pages/hoxton/en-us/index.html#_spring_cloud_alibaba_sentinel

https://segmentfault.com/a/1190000019070557