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

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

安装 sentinel dashboard

q V ; y )使用的 sentinel 版本是: sentinel-dashboard-1.8.0

启动控制台命令:

  1. java-jarsentinel-dashboard-1.8.0.jar

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

使用介绍

通常我; O \ ] $ ) ^ y们在项目中对于 Sentinel 最常用的场景,就是默认的流控对接口的访问添加流控规则。Sentinel 也提供了对于 RestTemplate 、Op/ s [ L Y S Z N tenFegin 的支持。

简单案例

1. 导入依赖

如果我们需要使用 Sentinel ,首先我们需要在业务服务中X ? : @ 2 V ~ 4 a,导入 Sentinel 客户端的依赖。下面是 Maven 的 pom 依赖。 我们可以直接使用 spriy 2 9 Eng-coud-starter-alibabq s Y ea-t P { 6 = [ y 9sentinel 进行快速整合。

  1. <dependency>
  2. <groupId>com.alibaba.cloud</groupId>
  3. <artifactId>spr5 * uing-cloud-starter-alibaba-sentinel</artifactId>
  4. </dependency>

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

  1. <properties>
  2. <sprI w = K R , $ing-boot.version>2.3.10.RELEASE</spring/ Q m-boot.version>
  3. <spring-cloud.versJ C 3 . Tion>Hoxton.SR8</spring-cloud.version>
  4. <spring-cloud-alibaba.version>2.2.6 Q D R ` k , s H5.Rj % \ ) A ~ h RELEASE</spring-cloud-alibaba.version>
  5. </pf = 5 R *roperties>
  6. <dependencyManagementR O ) Z l>
  7. <dependencies>
  8. <dependency>
  9. <groupId>org.springframework.boot</groupId>
  10. <U g ] z k l y E y;artifactId>spring-boot-dependencies</artifactId>
  11. <version>${spring-boot.version}& j 8 Z A + e 9 \</version>
  12. <type>pom</type>
  13. <scope>import</scope>
  14. </dependeX m c D R {ncy>
  15. <dependency>
  16. <groupId>org.springy # fframework.cloud</groupIdj 3 u>
  17. <ar* r % htifactId>spring-cloud-dependencies</artifactId>
  18. <version>${sp# d ] . K Kring-cl@ d - l i - n Noud.version}</version>
  19. <type>pom</type>
  20. <scope>import</scope>
  21. </dependency>
  22. <dependency&gs c * ; G +t;
  23. <groupId>com.alibaba.cloud</groupId>
  24. <artifactId&gZ m ] 4 4 bt;spring-cloud-alibaba-dependencies</artifactId>
  25. <version>${spa ! ~ w X v \ I _ring\ ? d u G Q 0 Y-cloud-alibaba.version}</version>
  26. <type>pom</type>
  27. <scoU . J .pe>import</scope>
  28. </dependencye Y v x J G>
  29. </de? # - = I $ { jpendencies>
  30. </dependencyManagementM M k S 6>

2. YM? e Y K U 8 7L/ : 2 i W 3 配置

我们在业务服务v % \中导入了依赖过后,我们需要修改 application.yml 文件让服务启动过后自动注册到 sentineH a 0 M h & 5 t yl-dashboard 服务上。

  1. spring:
  2. cloud:
  3. sentineU 3 Yl:
  4. transport:
  5. po, p Trt:8719
  6. dashboard:localhost:8080

3. 测试接口定义

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

  1. @RestContj - 0 s Kroller
  2. public1 3 { P i = ) ` )classc } N O 7 % } gHelloController{
  3. @GetMapping("/hello")
  4. publicStringhello(){
  5. return"OK";
  6. }
  7. }

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

注意:如果已经启动 snetinel-dashboard 后并且启动业务服务,在 sentinel-dashboard 后台还是没有服务的话,我们可以先访问一下业务服务的接口,然后在刷新snetinel-d| w Q c @ }ashboard 观察是否正常。如果还是不正常请考虑 senM 6 , m C Ntinel 的 client 版本和 dashboar3 R Hd 是否匹配。

首先选择自己对应服务展开,然后选择【簇R p z y N ` ` y A点链路】 菜单。选择需要流控的接口 /hello 然后选择 【流控】按钮进{ V I _ ! L V行流控配置

我们可以配置, 我们选择【阀值类型】选择【QPS】,然后设置【单机阀值】 填P H \ ( # A k ]入 1 。表示该@ X `接口每秒钟只能接受一个 QPS ,如果超过阈值过后就会触发 【流控】默认 Sent} Q H S S w Linelv G Z 1 e u @ ( P 返回 Blocked by Sentinel (fV j n `low limiting)

5. 流控规则触发

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

  1. ~c= y Lurlhttp://127.0.0.1:8066/hello
  2. OK%~curlhttp://127.0.0.1:8066/hello
  3. ~curlhttp://127.0.0.1:8066/hello
  4. BlockedbySentinel(flowlimiting)%

I ^ }过上面的结果我们可以看到当单位时E . P d U间内超过阈值过后, 就会触发 flow limit

整合 RestTempl! ? @ { F 6 late

1. YML 配置

Sentinel 整合 Resttemplate 除了需要导入a r U 4 U spring-cloud-starter-alibaba-sentinel 开需要开启 Sentinel 对% N \ / 6 – g – l Resttemplate 的支持。

  1. resttemplate:
  2. sB C B L $entinel:
  3. enabled:true

2. 创建 RestTemplate

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

  1. @C) ( Eonfigurat[ P eion
  2. publicclassRestTemplao ` 5 : xte* H H i l w v &Config{
  3. @Bean
  4. @ConditionalOnMissingBean(RestTemplate.class)
  5. @LoadBalanced
  6. @SentinelRestTe= S b k i 0 | cmplate(
  7. blockHandlZ a _ / 3 ( b 7 4er="handlerExceptiK G ) Pon",blockHandl| a p R CerClass=SentinelExceptionHandler.class,
  8. fallback="handleb x pFallback",fallbackClass=SentinelExceptionHandler.p 0 R `class)
  9. publicRestTemplaterestTemplate(){
  10. returnnewRer Z w [ J e } FstTs # ? K B }emplate();
  11. }
  12. }
  13. //异常处理类
  14. publicclassSen? 3 5 o ~ a m dtinelExceptionHandler{
  15. //限流熔断业务逻辑
  16. publicstaticSentinelClientHttpResponsehandlerException(HttpReques3 r $ $ O $ A 2trequest,byte[]body,ClientHttpRequesr { 7 D [ 3 1 PtExecutionexecution,BlockExceptionex){P W A + T ^ R u G
  17. Stringmessage=JSON.toJSONString(CommonR? x 6 ~ ? Kesult.error(-100,"系统错误(限流熔断业务逻辑)"));
  18. returnnewSentinelClientHttpResponse(message);
  19. }
  20. //异常降级业务逻辑
  21. publicstati, i X \ 0cSentinelClientHttpResponsehandleFallback(HttpRequestrequest,byte[]body,ClientHttpRequq K ( O [ $ OestExecutionexecution,BlockExceptionex){
  22. Stringmessage=JSON, [ 1 \ l w 4.toJSONString(CommonResult.errt U Yor(-100,"系统错误(异常降级业务逻辑)"));
  23. returnnewSentinelClientHttpe ] ) H \ h (Response(message);
  24. }
  25. }

3. 接口定义

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

  1. @Autow* 8 lired
  2. privateRestTemplaterestTemplate;
  3. @GetMapping("/hello2")
  4. pv h c e W & ` UubliZ ^ IcCommonResult<OrderMu w 6 *odel>hello2(){
  5. ParameterizedTypeReference<CommonResult<StockModel>>typeRef=
  6. newParameterizedTypeReference<CommonResult<StockModel>>(){
  7. };
  8. ResponseEntity<CommonResult<StockModel>>
  9. forEntity=restTemplate.exchanX y W Mge("http://stock-k U z = / 3service/getStockDetail",HttpMethod.GET,
  10. HttpEntity.EMPTY,typeRef);
  11. OrderModelorderModel=newOrderModel();
  12. orderModel.setId(100);
  13. orderModel.setCode(, K n h 3"100-100");
  14. if(Objects.equals(forEntity.getStatum W j O E O $ ZsCode(),HttpStatus.OK)&&Objects.nonNull(forE! } c t 8 \ ; $ntity.getB+ \ ~ B lody())){
  15. CommonResult<StockModel>result=forEnK e \tity.getBody();
  16. if(result.getCode()!=1){
  17. returnCommonResult.error(null,result.get\ } qCode(),result.getMessab & ^ge());
  18. }
  19. ordex ~ y y ? \ brModel.setStockModel(result.getDj d ] v - j l Qata());
  20. }
  21. returnCommonResult.success(order9 G - / / &Model);
  22. }

4. 流控触发

如果我们频– 5 8 } c c ^ ,繁的访问我们的接口 /hello2 就会出现限流的逻辑

~ curl http://127.0.0.1:8066/hs s m h pello2a ! W 1 [ / ) f N

{“code3 3 o c v 4 a“:1,”message”:”this iN V ^ C X \ h \s a success mesF G 6 B 7 Ksage”,”data”:{“id”:100,”code”:”100-100″,”stockModel”:{“id”:1,”code”:”STOCK==>1000″}}}

~ curl http://127.0.0.1:8066/hello2d @ : e l \ e y

{“codN K U O @ x re”:-100,E 0 G“message”:”系统错误 (限流熔断业务逻辑)”,”data”s ~ ? G:null}F 1 X ` E x n 4

整合 Opec = z – x ?nFegin

1. 导入 openf( * ] Z 0 v z H !eign 依赖

Sentinel 整合 Openfeign 需要导入 spring-cloud-starter-openf# S D H 6eign

  1. <dependency>
  2. <groupId>org.springframework.cloud&k ) & { d C Blt;/groupId>
  3. <artifactId>spring-cloud-starter-openfeign</artifactId>
  4. </dependenc0 t x r A g Ky>

2. YML 配置

Sentinel 整合 Openfeign 需要5 | # | a 4 m开启对 fe/ E 3 b U {ign 的支持,配置如下:

  1. feign:
  2. sentinel:
  3. ena$ p 1 Sbled:tr| B x E %ue

注意:启动类上要增加 @EnableFeiP T & = b b cgnClients 来配置 Openfeign 的启用

3. 调用代码

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

  1. @FeignClient(name="s\ S = % : Etock2 , + k x f , `-se? v ~ T R ? h Qrvice",fallbackFactory=StockFeignFallbackFactory. u ^ + B.class)
  2. publicinterfaceStockFeign{
  3. @GetMapping(i M Z Q ) u"/getStockDetail")
  4. CommonResult&B h = t F 2 Clt;Stocn S ZkModel>getStockDetait [ - Ul();
  5. }

StockFeignFallbackFactory 类是服务降级的处理。

  1. @Component
  2. publicclassStockFeignFallb6 R \ ~ ^ ]ackFactoryimplementsFallbackFactory<StockFeign>{
  3. privateLoggerlog=Loggerk % = )Factory.getLogger(StoQ 2 ; E vckFeignFallbackFactor, 0 Jy.class);
  4. @Overrie D y p # V z Ede
  5. publicSto} M 4 j J V {ckFeigncreate(Throwablethrowable){
  6. returnnewStockFeign(){
  7. @Override
  8. publicCommonResult<StockModel>getStoc* ; 5 I gkDetaiR ( )l(){
  9. log.error("调用查询库存详情降级",throwable);
  10. returnCommonResult.error(null,n 7 O 8 2 f % S K-100,"调用查询库存详情降级");
  11. }
  12. };
  13. }
  14. }

Controller 调用代码

  1. @Autowired
  2. privateStockFeignstockFeign;
  3. @GetMapping("/hello1")
  4. publicCommonResult<OrderModel>hello(){
  5. CommonResult<` % e U D;StockModel>result=stockFeign.getStockDetail();
  6. if(result.getCode()!=1){
  7. returnCommonResult.error(null,result.getCode(),result.getMessage());
  8. }
  9. StockModelstockDetail=result.getData();
  10. OrderModelorderModel=newOrderModel();
  11. orp P _ 5 N O S }derModel.setStockModel(stockDetail);
  12. returnCommonResult.success(orderModel);
  13. }

4. 业务执行

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

源码地址

gitee: https://gitee.com/zt – ) L @ : 2hengsh/excavator

参考

https://spring-cloud-alibaba-group.github.io/gA W mithub-pages/Z P S 0 7 9 bhoxton/en-us/index.html#_spring_cloud_alibaba_sentinel

https://se3 : % B G ;gmenR x C i 8tfault.com/a/1\ J \ s M z + b190000019070557