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

在前面一篇文章我已经对 Sentinel 做了一个简单的介绍,相信大家对 Senti. ? Qnel 有一个简单的了解,本~ u R z d ;次主要是讲 Sentinel 的使用。在 sentinel-dashboard 配置流控规则,以及使用 Sentinel 整合 RestTemplate、OpenFeign 进行流控使用(建& R 3 # )议网页版阅读% b * T % H t \)。

安装 sentinel dashboaB 3 P }rd

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

启动控制台命令:

  1. java-jarsentinel-dashboard-1.8.0.jar

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

使用介绍

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

简单案例

1. 导入依赖

如果我们需要使用 Sentin– ? telD $ 9 p P B 4 ,首先R q D ) ! 9 ] L K我们需要在业务服务中,导入 Sentinel 客户端的依赖。下面r 1 L 9是 Mav^ ! r 3 F ben 的 pom 依赖。 我们可O } P (以直接使用 spring-coud-starter-alibaba-sentinel 进行快速整: s k K F S 2 @合。

  1. <dependency>
  2. <groupId>com.alibaba.cloud</grQ q B 0 Y z t 1 $oupId>
  3. <artifactId>spring-cloud-z G i U B & ~ 9 Hstarter-alibaba-sentinel</arh j utifactId>
  4. <! } g [ \ +/dependency>

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

  1. <properties>
  2. <sprinY r ^ = 4 k C r ~g-boot.version>2.3.10.RELEASE<T z : h q F/spring-boot.version>
  3. &G g & f w A G D Llt= _ K n Z _ \;spring-cloud.version>Hoxton.SR8</spring-cloud.version&gO M q ? | , S Et;
  4. <spri_ Z : m . #ng-cloud-alibaba.ve& V irsion>2.2.5.RELEQ M + p DASE</spring-cloud-alibaba.vers3 6 ! } 0 dion&\ F h Lgt;
  5. </properties>
  6. <dependencyManagement>
  7. <dependencies>
  8. <dependency>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId&( R d q Hgt;spring-boot-dependenciN @ v P :es</artifactId>
  11. <version>${spring-boot.version}</version>
  12. <type>pom</type>
  13. <scope>import</scope- g k | 0&gD K M v 5 `t;
  14. </dependency>
  15. <O w g 0 4 q;dependency>
  16. <groupId>org.springframeworkv B y.cloud</groupId>
  17. <artifactId>spring-cloud-dependencies</artifactId&f { [ E 4 4gt;
  18. <versn @ P Bion>${springO ) c-cloud.version}</version>
  19. <type>l m Z O H hpom</type>
  20. <scope>import</scope>
  21. </dependency>
  22. <depl q xendency>
  23. <groupId>com.alibaba.cloud</groupId>
  24. &l` = % 3 p - G st;artifactId>spring-cloud-alibaba-depR r H H =endencies</artifac5 E qtId>
  25. <version>${spring-cloud-alibC M [ = eaba.version}</ve= u g :rsion>
  26. <type>pom</type>
  27. <scope>import</scope>
  28. </dependency>
  29. </dependencies>
  30. </dependencyManagement>

2. YML 配置

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

  1. spring:
  2. cloud:
  3. sentinel5 V 2 T G:
  4. transport:
  5. port:8719
  6. dashboard:lr ~ N D D k $ Nocalhost:8080

3. 测试接口定义

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

  1. @RestController
  2. publicclassHelloController{
  3. @GetMapping("/hello")
  4. publicString; ~ 7 n ) W + bhello(){
  5. return"OK";
  6. }
  7. }

4. 通c w ! d过控制台配置流控规则

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

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

我们可以配置, 我们选择【阀值类型】: ? E G 5 = %选择【QPS】,然后% 5 R # c 5 ( w (设置【单机阀X t N : l ) m N ;值】 填入 1 。表示该接口每秒钟只能接受一个 QPS ,如果超过阈值过后就会触发 【流控】默认 Sentinel 返回 Blocked by Sentinel (flow limiting)

5z # E H. 流控规则触发

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

  1. ~curlhttp://127.0.0.1:8066/hello
  2. OK%~curlhttp://127.0.0.1:8066/hello
  3. ~c| c % @ * xurlhttp://127.0.0.1:8066/hello
  4. BlockedbySentinel(flowlimiting)%

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

整合 Rj x l LestTemplate

1. YML 配置

Sentinel 整合 Res, ] –ttemplate 除了需要导入 spring-cloud-starter-alibaba-seE A W $ # entinel 开需要开启 Sentinel 对h J ) – # Resttemplate 的支持。

  1. resttemplate:
  2. sentinel:
  3. eD s Rnabled:truu f $e

2. 创建 RestTemplate

如果 RestTemplate 在使用的时候需要使用到 Sentinel 的流控规则,首先需要在创建 RestTemplate 的时候添加s ? T # S @Sen. 9 : 9 C 1tinelRestTemplate 注解。注意: SentinelExceptionHandler 中的方法都是 static 方法

  1. @C+ & ?onfiguration
  2. publicclass} c MRestTemplate^ t F r b @ m zConfig{
  3. @Bean
  4. @ConditionalOnMissingBean(RestTemplate.class)
  5. @LoadBaa 8 5 ~ % b N (lanced
  6. @SentinelRestTemplate(
  7. blockHandler="handlerExceptioS e ? s Un",blockHandlerClass=SentinelExceptionHandlT , , ` a rer.class,
  8. fallback="handleFallback",fallbackClass=SentiV u G ; a R 8nelExceptionHandler.class)
  9. publicRestTemplaterestTemplate(){
  10. returnnewRestTemplate();
  11. }
  12. }
  13. //异常处理类
  14. publicclassSentinelExceptioS z O . vnHandler{
  15. //限流熔断业务逻辑
  16. publicstat% { S 0icSentinelClientHttpRj , \ Z n u - eesponsehandlerException(HttpRequestrequest,byte[]body,ClientHttpRequesN d _ h W V -tExecutionexecution,BlockExceptione( R X T ? * h 8 Ax){
  17. Stringmessage=JSON.toJSONString(CommonResult.error(-100,"系统错误(限流熔断业务逻辑)"));
  18. reY h + j x ` ) kturnnewSentinelClientHttpResponse(message);u / ( k
  19. }
  20. //异常降级业务逻辑
  21. public9 2 ] + c ) Tstat{ l 0icSentinelClientHttK A ; I N ^pResponse# V [ (handleFallback(HttpRequestrequest,byte[]body,Clie} B KntHttpRequestExecutionexecution,BlockExceptionex){
  22. Stringmessage=JSON.toJSONString(CommonResult.error(-100,"系统错误(异常降级业务逻辑)"));
  23. returnnewSentinelClientHttpResponse(message);
  24. }
  25. }

3. 接口定义

下面就是我们使用的代码,可能写得稍微有点复杂,我来解释一下。首先我是通过 RestTemplate 访问 ste 6 ) 6 n 6ock-service 服b * s d ~ . | c务的 /getStockDetail 接口然后将接口J { y D c的返回数据解析,通过CommonResult 实例对象进行接收, 如果失败就返回错误信息。

  1. @Autowired
  2. privateRestTemplaterestTemplate;
  3. @GetMapping("/hello2")
  4. publicCommonResultZ . e H ~ X<OrderModel>hello2(){
  5. ParameterizedTypeR, A Neference<} T :;CommonResu. r D i a (lt<StockModel>>typeRef=
  6. newParameJ F T RterizedTypeReference&l_ a W d ? p `t;CommonResult<StockModel>: - l z 0 q = ~ %;>(){
  7. };
  8. ResponseEntity<CommonResult<StockModel>>
  9. forEntityK \ 3 D b=restTemplate.exchange("http://stoc= @ q \ _ s r g [k-service/getStockDetail",HttpMethod.GET,
  10. HttpEntity.EMPTY,tS R B # v D IypeRef);
  11. OrderModelorderModel=newOrderModel();
  12. orderModel.setId(100);
  13. orderModel.setCode("100-100");
  14. ifW j d O Q ( T(O; C 7 ?bjecc # Pts.equals(forEntity.getStatu6 u \ }sCode(),HttpStatus.OK)&&Objects.nonNull(forEy ^ + 0ntity.getBody())){
  15. CommonResult<StockModel>result=forEnt/ & ` uity.getBody();
  16. if(result.getCode()d s 1 f [ , \!=1){
  17. retuZ R ,rnCommonResultC l & K L.error(null,re\ F k D Asult.getCode(),result.getMessage());J s R n
  18. }
  19. orderModel.setStockModel(rA 0 ^ qeh f M O V t [ y hsult.getData());
  20. }
  21. returnCommonResult.^ - L X H g & a hsuccess(orderModel);
  22. }

4. 流控触发

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

~ 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,”co5 w 7 M Lde”:”STOCK==>1000″}}}

~ curl http://127.0.0.1:8066/helt ) n ?lo2

{“code”:-100,”message”:”系统错误 (限流熔断业务逻辑)”,”data”:nulR y h \ w =l}

整合 OpenFegin

1. 导入 openfeign 依赖

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

  1. <dependency>
  2. <groupId>org.springframework.cloud&d i y ; h 9 Wlt;/gU H 1 s ? : qroupId>
  3. <artifactId>spring-cloud-starter-openfeign</artifacu A U { ; \tId>
  4. </dependency>

2. YML 配置

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

  1. feign:
  2. sentinel:
  3. enabled:tM ; * w = ) V S @rue

注意:启动类上要增加 @EnableFeignClients 来配置 OpF 1 u f 7 J {enfeS ) & ) | : gign 的启用

3. 调用代码

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

  1. @FeignClient(name="stock-service",fallbackFactory=StockFeignFallbackFactory.class)
  2. publica a qinterfaceStockFeign{
  3. @GetMapping("/go v v Z 3etStockDe 2 6 P o = Z M }etail")
  4. CommonResult<StockModel>getStock2 O } [ o U \ ] `Detail();
  5. }d I - X Q ?

StockFeignFallbackFactory 类是服务降级的处理。

  1. @Component
  2. publiccE 4 q mlassStockFeigT Q ; T [ QnFallbackFactoryimplementsFallbackFactory<StockFeign>{
  3. privateLoggerlog=LoggerFactory.getLogger(StockFeignFallbackFactory.c% v Plass);
  4. @Override
  5. publicStockFeigncreate9 d T m i B(Throwablethrowable)( _ b 1 o ) c _{
  6. retuN D j D @ ! ( 2rnnewStockFeign(){
  7. @Override
  8. pu. } u @ ] VblicC1 A ~ ] - s EommonResult&L M 1 3lt;StockModel>getStockDetail(){
  9. log.error("调用查询库存详情降级",throwable);
  10. returnCommont } V C f q NResult.erro& l g G : rr(null,-100,( / A O ^ ]"2 } [ 5调用查询库存详情降级S \ F _ 7 h A");
  11. }
  12. };
  13. }
  14. }

Controller 调用代码

  1. @AutoG T ~ ! 2 9 R 5 Bwired
  2. privateStockFeignstockFeign;
  3. @G$ 9 0 \ W x g xetMapping("/hello1")
  4. publK g u a h $icCommonResult<k T s ; ! % h |;OrderModel>( F v I a A T y;hello(){
  5. CommonResult<StockModel>rQ E [ ^ Wesult=stockFeign.getStockDetail(R G m ^);
  6. if(result.getCode()!=1){
  7. returnCommop H 9 1 x AnResult.error(null,result.getCode(),result.getMessage());
  8. }
  9. StockModelstockDetail=result.getData();
  10. OrderModelorderModel=newOrderMY { = L ~ H ? Hodel();
  11. orderM[ P _odel.setStockModel(stockDetail);
  12. returnCommonResult.success(orderModel);
  13. }

4. 业务执行

如果我们多次访问,G U g CSentinel 就会触发降级策略。然后执行 Stoq { 6 EckFeignFallbackFactory 的本地存根方法返回

源码地址

ge Q W # q $ Jitee: https://gitee.com/zhengsh/excavator

参考

httz 3 Fps://sprink 8 \ D G 1g-cloud-alibaba-group.github.io/github-pages/hoxton/en-us/index.html#_spring_cloud_alJ { L ? V %ibaba_se1 u U % j 2 f Sntinel

https://segmentfault.com/a/1190000019070557

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注