本文转载自微信公众号「运维开发故事」,作者老郑。转载本文请联系运维开发故事公众号。
在前面一篇文章我已经对 Sentinel 做了一个简单的介绍,相信大家对 Sentinell ^ I 有一个简单的了解,本次主要是讲 Sentiner ) R gl 的使用。在 sentinel-dashboard 配置流控规则,以及使用 Sentinel 整合 RestTemplate、OpenFeign 进行流控使用(建议网页版阅读)。
安装 sentinel dashboard
我q V ; y )使用的 sentinel 版本是: sentinel-dashboard-1.8.0
启动控制台命令:
- 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 进行快速整合。
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spr5 * uing-cloud-starter-alibaba-sentinel</artifactId>
- </dependency>
对于 spring-cloud-alibaba 相关的版本依赖信息如下:
- <properties>
- <sprI w = K R , $ing-boot.version>2.3.10.RELEASE</spring/ Q m-boot.version>
- <spring-cloud.versJ C 3 . Tion>Hoxton.SR8</spring-cloud.version>
- <spring-cloud-alibaba.version>2.2.6 Q D R ` k , s H5.Rj % \ ) A ~ h RELEASE</spring-cloud-alibaba.version>
- </pf = 5 R *roperties>
- <dependencyManagementR O ) Z l>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <U g ] z k l y E y;artifactId>spring-boot-dependencies</artifactId>
- <version>${spring-boot.version}& j 8 Z A + e 9 \</version>
- <type>pom</type>
- <scope>import</scope>
- </dependeX m c D R {ncy>
- <dependency>
- <groupId>org.springy # fframework.cloud</groupIdj 3 u>
- <ar* r % htifactId>spring-cloud-dependencies</artifactId>
- <version>${sp# d ] . K Kring-cl@ d - l i - n Noud.version}</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- <dependency&gs c * ; G +t;
- <groupId>com.alibaba.cloud</groupId>
- <artifactId&gZ m ] 4 4 bt;spring-cloud-alibaba-dependencies</artifactId>
- <version>${spa ! ~ w X v \ I _ring\ ? d u G Q 0 Y-cloud-alibaba.version}</version>
- <type>pom</type>
- <scoU . J .pe>import</scope>
- </dependencye Y v x J G>
- </de? # - = I $ { jpendencies>
- </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 服务上。
- spring:
- cloud:
- sentineU 3 Yl:
- transport:
- po, p Trt:8719
- dashboard:localhost:8080
3. 测试接口定义
首先我们需要定义对外开放的接口。
- @RestContj - 0 s Kroller
- public1 3 { P i = ) ` )classc } N O 7 % } gHelloController{
- @GetMapping("/hello")
- publicStringhello(){
- return"OK";
- }
- }
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 接口即可。
- ~c= y Lurlhttp://127.0.0.1:8066/hello
- OK%~curlhttp://127.0.0.1:8066/hello
- ~curlhttp://127.0.0.1:8066/hello
- 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 的支持。
- resttemplate:
- sB C B L $entinel:
- enabled:true
2. 创建 RestTemplate
如果 RestTemplate 在使用的时候需要使用到 Sentinel 的流控规则,首先需要在创建 RestTemplate 的时候添加 @SentinelRestTemplate 注解。注意: SentiW A o @ anelExceptionHandler 中的方法都是 static 方法
- @C) ( Eonfigurat[ P eion
- publicclassRestTemplao ` 5 : xte* H H i l w v &Config{
- @Bean
- @ConditionalOnMissingBean(RestTemplate.class)
- @LoadBalanced
- @SentinelRestTe= S b k i 0 | cmplate(
- blockHandlZ a _ / 3 ( b 7 4er="handlerExceptiK G ) Pon",blockHandl| a p R CerClass=SentinelExceptionHandler.class,
- fallback="handleb x pFallback",fallbackClass=SentinelExceptionHandler.p 0 R `class)
- publicRestTemplaterestTemplate(){
- returnnewRer Z w [ J e } FstTs # ? K B }emplate();
- }
- }
- //异常处理类
- publicclassSen? 3 5 o ~ a m dtinelExceptionHandler{
- //限流熔断业务逻辑
- publicstaticSentinelClientHttpResponsehandlerException(HttpReques3 r $ $ O $ A 2trequest,byte[]body,ClientHttpRequesr { 7 D [ 3 1 PtExecutionexecution,BlockExceptionex){P W A + T ^ R u G
- Stringmessage=JSON.toJSONString(CommonR? x 6 ~ ? Kesult.error(-100,"系统错误(限流熔断业务逻辑)"));
- returnnewSentinelClientHttpResponse(message);
- }
- //异常降级业务逻辑
- publicstati, i X \ 0cSentinelClientHttpResponsehandleFallback(HttpRequestrequest,byte[]body,ClientHttpRequq K ( O [ $ OestExecutionexecution,BlockExceptionex){
- Stringmessage=JSON, [ 1 \ l w 4.toJSONString(CommonResult.errt U Yor(-100,"系统错误(异常降级业务逻辑)"));
- returnnewSentinelClientHttpe ] ) H \ h (Response(message);
- }
- }
3. 接口定义
下面就是我们使用的代码,可能写得稍微有点复杂,我来解释一下。首先我是通过 ReU ! [ \stTemplate 访问 stock-service 服务的 /getStockDetail 接口然后将接口M s + h k * J ! U的返回数据解析,通过CommonResult 实例对象进行接收, 如果失败就返回错误信息。
- @Autow* 8 lired
- privateRestTemplaterestTemplate;
- @GetMapping("/hello2")
- pv h c e W & ` UubliZ ^ IcCommonResult<OrderMu w 6 *odel>hello2(){
- ParameterizedTypeReference<CommonResult<StockModel>>typeRef=
- newParameterizedTypeReference<CommonResult<StockModel>>(){
- };
- ResponseEntity<CommonResult<StockModel>>
- forEntity=restTemplate.exchanX y W Mge("http://stock-k U z = / 3service/getStockDetail",HttpMethod.GET,
- HttpEntity.EMPTY,typeRef);
- OrderModelorderModel=newOrderModel();
- orderModel.setId(100);
- orderModel.setCode(, K n h 3"100-100");
- if(Objects.equals(forEntity.getStatum W j O E O $ ZsCode(),HttpStatus.OK)&&Objects.nonNull(forE! } c t 8 \ ; $ntity.getB+ \ ~ B lody())){
- CommonResult<StockModel>result=forEnK e \tity.getBody();
- if(result.getCode()!=1){
- returnCommonResult.error(null,result.get\ } qCode(),result.getMessab & ^ge());
- }
- ordex ~ y y ? \ brModel.setStockModel(result.getDj d ] v - j l Qata());
- }
- returnCommonResult.success(order9 G - / / &Model);
- }
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
- <dependency>
- <groupId>org.springframework.cloud&k ) & { d C Blt;/groupId>
- <artifactId>spring-cloud-starter-openfeign</artifactId>
- </dependenc0 t x r A g Ky>
2. YML 配置
Sentinel 整合 Openfeign 需要5 | # | a 4 m开启对 fe/ E 3 b U {ign 的支持,配置如下:
- feign:
- sentinel:
- 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根方法。
- @FeignClient(name="s\ S = % : Etock2 , + k x f , `-se? v ~ T R ? h Qrvice",fallbackFactory=StockFeignFallbackFactory. u ^ + B.class)
- publicinterfaceStockFeign{
- @GetMapping(i M Z Q ) u"/getStockDetail")
- CommonResult&B h = t F 2 Clt;Stocn S ZkModel>getStockDetait [ - Ul();
- }
StockFeignFallbackFactory 类是服务降级的处理。
- @Component
- publicclassStockFeignFallb6 R \ ~ ^ ]ackFactoryimplementsFallbackFactory<StockFeign>{
- privateLoggerlog=Loggerk % = )Factory.getLogger(StoQ 2 ; E vckFeignFallbackFactor, 0 Jy.class);
- @Overrie D y p # V z Ede
- publicSto} M 4 j J V {ckFeigncreate(Throwablethrowable){
- returnnewStockFeign(){
- @Override
- publicCommonResult<StockModel>getStoc* ; 5 I gkDetaiR ( )l(){
- log.error("调用查询库存详情降级",throwable);
- returnCommonResult.error(null,n 7 O 8 2 f % S K-100,"调用查询库存详情降级");
- }
- };
- }
- }
Controller 调用代码
- @Autowired
- privateStockFeignstockFeign;
- @GetMapping("/hello1")
- publicCommonResult<OrderModel>hello(){
- CommonResult<` % e U D;StockModel>result=stockFeign.getStockDetail();
- if(result.getCode()!=1){
- returnCommonResult.error(null,result.getCode(),result.getMessage());
- }
- StockModelstockDetail=result.getData();
- OrderModelorderModel=newOrderModel();
- orp P _ 5 N O S }derModel.setStockModel(stockDetail);
- returnCommonResult.success(orderModel);
- }
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