本文转载自微信公众号「运维开发故事」,作者老郑。转载本文请联系运维开发故事公众号。
在前面一篇文章我已经对 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
启动控制台命令:
- 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合。
- <dependency>
- <groupIdw \ V 7 h J L B :>: _ E;com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-sentinJ % H J G ;el</artifactId>
- </dependency>
对于 spring-cloud-ali% ] C 3 7 \ *baba 相关的版本依赖信息如下:
- <properties>
- <sprinr U I y Fg-boot.version>2.3.10.RELEASE</spring-boot.version>
- <spring-cloud.version>Hoxton.SR8</sprin\ A : V q l V =g-cloud.version&gQ b t [ tt;
- <spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version>
- </properties>
- <depen& w gdencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-dc i J 1 3 {ependencies</artifactId>
- <version>${spring-boo\ v a z ! p ~t.version}</version>
- <type>pom</type>
- <scr B c B 4 Kopn X ! U M 3 6e>import</scope>
- </dependency>
- <dependency>
- <groq k 7 s x ! J jupId>org.springf~ { C \ramework.cloud</groupId>
- &l# 6 f ; 4 = T { [t;artifactId>spring-cloud-dependencies<% I 5 \ b n / A;/artifactId>
- <version>${spring-cloud.version}</version>
- <type>pom</type>
- <scope>import&lQ + e _ b , } 7t;/scope&c c Egt;
- </dependency>
- <dependency>
- <groupId>com.alibaba.cloud<B u I F : [;s u m M/groupId>
- <artifactId>spring-cloud-alibaba-dependencies</artifactId>
- <ver} ] q + e Fsion>${sp\ T x G ? l Pring-cloud-alibaba.version}</version>
- <type>pom</type>
- <scj 3 Gope>import</scopt o j oe>
- </dependency>
- &$ 9 3 Q U [lt;/dependencies>
- </dependencyMa` A 2nagement>
2. YML 配置
我们在业务服务中导入了依赖过后,我们需要修改 application.yml 文件让服务启动过后自动注册到 sentinel-dashboard 服务上。
- spring:
- clq S v 6 [ 5 K R :oud:
- sentinel_ f t 2 s:
- transport:
- port:8719
- da% + M o Y H 8 7 Rshboard:localhost:f P }8080
3. 测试接口定义
首先我们需要定义对外开放的接口。
- @RestCR H p e aontroller
- publicclassHelloController{
- @Ge` A g x P + dtMapping("/hello")
- publicStringhello(){
- return"OK";
- }
- }
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 接口即可。
- ~cs 1 Z ? e Dur: f &lhttp:A ; h D x k l O O//127.0.0.1:8066/hello
- OK%~curlhttp://127.0.0.1:8066/hello
- ~curlhttp://127.0.0.1:8066/hello
- 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
- re: R r ( Q J e lsttemplate:
- sentinel:
- enabled:true
2. 创建 RestTemplate
如果 RestTemplate 在使用的时候需要使用到e [ : a Sentinel 的流控规则,首先需要在创建 RestTemplate 的时候添加 @SentinelRestTemplatW j 3 Ie 注解。注意: SentinelExceptionHandler 中的方法都是 static 方法
- @Conf^ G r | riguration
- publicclassRe* r ) e D dstTemplateConfig{
- @Bean
- @ConditionalOnMissingBean(RestTemplate.class)
- @LoadBalanced
- @SentinelRestTem! o 5 2plate(
- 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,
- fallback="ha? _ d # m t mndleFallback",1 i t x b K ! ^ 5fallbackClass=Senti` g O i $nelExceptionHandler.class)
- publicRestTemplaterestTem` | G Q )plate(){
- returnnewRestTemplate();
- }
- }
- //异常处理类
- publicclassSentinelExcep- e F ( V k C ^ (tionHandler{
- //限流熔断业务逻辑
- 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){
- Stringmessage=JSON.toJSONString(CommonResult.error(-100,"系统错误(限流熔断业务逻辑)"));
- returnnewSentinelClientHttpResponse(mess# 0 Sage);
- }
- //异常降级业务逻辑
- publicstaticSentinelClientHttpResponsehandleFallback(HttpRequestrb } E ]equest,byte[]body,Cl[ \ ? E . k |ientHttpRequestEb V a 3 3xecutionexecution,BlockExceptionex){
- Stringmessage=JSON.toJSONString(CommonResult.error(-100,"系统错误(异常降级业务逻辑)")C H ) G b E ] = #);
- returnnewSentinelClientHttpResponse(message)K l & v 7;
- }
- }
3. 接口定义
下面就是我们使用的代码,可能写得稍微有点复杂,我来解释一下。首先我是通过 RestTemplate 访问 stock-service 服务的 /getStockDetail 接口然后将接口的返回数据解析,通过CommonResult 实例对象进行接收, 如果失败就返回错误信息。
- @Autowired
- privateRestTemplaterestTemplate;& x n { K *
- @GetM, V a u z $ ) Dapping("/hello2")
- publicCommonResult&li R 7t;OrderMB I B . todel>hello2(){
- ParameterizedTypeReference<\ 0 u ? % Q 4 l;CommonResult<StoS s Q R & [ P [ ^ckModel>o t S n V ^ =;>typeRef=
- newParamete\ Z a 6 [ ] | J ,rizedTypeReference&g U 1 ~ plt;CommonResult<StockModel>>(){
- };
- Resp9 O + +onsN C . 0 X ( ?eEntity<Common- i L I T D V r @Result<StockModel>>
- f` I T % # ! % WorEntity=restTemplate.exchange("http://stox q :ck-service/getST h ZtockDetail",HttpMethod.O c @ t 8G; E u H @ / { hET,
- HttpEntity.| u &EMPTY,typE Z = i seRef);
- OrderModelorderModel=newOrderModel();
- orderModel.setId(100);
- orderModel.setCode("100-1* : - j w 9 800");
- if(Objec7 a U nts.equals(forEntity.getStatusCode(),HttpStatus.OK)&&Objects.nonNull(forEn* \ L 9 Ttity.getBody())){
- Comv 1 o g q Z A ~ :monResult<StockModel>@ # Fresult=forEntity.getBody();
- if(result.getCode()!=1){
- returnCommonRD | K y Hesult.error(null,result.getCode(),rK n q v } O v Vesult.getMessage());
- }
- orderModel.setStockModel(r= p F 4 ) q K Uesult.getData());
- }
- returnCommonResult.success(orderI j j _ 1Model);
- }
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
- <dependency>
- <group} N ] # 2Id>org.springframework.cloud</groupId>
- <artifactId>n A 7 R 5 /spring-cloud-starter-openfeign</artifactId>
- </dependency>
2. YML 配置
Sentinel 整合 Openfeign 需要开启对 feign 的支持,配置如0 s | i B C下:I 8 T :
- feign:
- sentinel:
- enabled:true
注意:启动类上要增加 @EnableFeignClients 来配置 Openfeign 的启用
3. 调用代码
Feign 接口调服务 stock-service 的 /getStockDetail 接口,如果触发流控规则就会执行 FallbackFactory 中返回 StockFeign 的本地存根方法。
- @FeignClient(name="stock-service",fallbackFactory=StockFe7 $ Q qignFallbackFactory.class)
- publicinterfaceStockt X ~ t ; 9 @ o UFeign{
- @GetMapping("/getStockDetail")
- CommonResultz p m j 6 o t 7 8<StockModel>getStockDetail();
- }
StockFeignFallbackFactory 类是服务降级的处理。
- @Component
- publicclassStockFeignFallbackFactoryimplements~ 4 { 3FallbackFactory4 g # K ! _ y<StockFeign>{
- privateLoggerlog=LoggerFactory.g) t m o + detLogg/ c + I $er(StockFeignFallbackE S kFactory.class);
- @Ove& i 9 7 _ p C Zrride
- publicStockFeigncreate(Throwablethrowable){
- returnnewStockFeign(){
- @Override
- puJ j m _ n N W A OblicCommonResult<StockModel>getStockDetail(){
- lo* @ A i 0 jg.error("调用查询库存详情降级",throwable);
- returnCommonRed o { - } I jsult.error(null,-100,"调用查询库存详情降级");
- }
- };
- }
- }
Controller 调用代码
- @Autowired
- privateStockFeignstockFeign;
- @GetMapping(6 b f & F V"/hello1")
- publj Y @ FicCommonResult&a $ J ol| r w P f A Dt;OrderModel>hello(){
- CommonResult<StockModel>result=stockFeign.getStockDetail();
- if(result.getCode()!=1){
- returnCY W J v ! Z `ommonResult.error(null,result0 A P @ -.getCode(),resC % v g h Z Sult.getMessage());
- }
- StockModelss ^ s ttockDetail=result.getData();
- OrderModelorde6 & q $ ^rModel=t ; a K *newOrderModel(y ^ C s);
- orderModel.setStockModel(stockDetail);
- returnCommonResult.success(orderModel);
- }
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