写在前面

用XMind画了一张导图记录Spring Cloud Alibaba的学习笔记(源文件对部分节点有详细备注和参考资料,由于太大就没展示全部,欢迎关注我的公众号:阿风的架构笔记 后台发送【导图】拿下载链接, 已经完善更新):

前言

思考这个问题:

Sentinel的降级熔断的配置,生产环境使用的时候,一般会在控制台管理,持久化到Nacos;微服务监听Nacos的配置变化,从而实现服务调用的降级熔断策略。

现在就会遇到这样的问题,如果有很多Feign接口,如上图服务A、服务B都有一些Feign接口的远程调用,都需要我们进行一一配置。而且配置的一些参数绝大多数都一样的。如:

1、对Feign远程调用的慢响应策略的配置降级策略

2、对Feign远程调用的异常数的配置降级策略

3、对Feign远程调用的异常比例数的配置降级策略

针对上面的配置1-2个服务方法还好;但是现在公司的生产环境都有100~200个微服务,服务之间的调用方法就更多了;那针对普通标准的降级熔断的配置都需要人工一个个配置,那是不是太麻烦了。

本文就来解决这个问题,跟着继续往下看。

源码分析

我们先来看看Sentinel是怎么设置熔断策略的,在上图中我们知道是通过Sentinel控制台进行配置,然后微服务都可以订阅这些配置;我们看一下源码。

这个是监听nacos配置的相关的代码

上图代码核心就是发现配置有变化,就updateValue规则;我们继续跟踪代码发现一个DegradeRuleManager降级规则的管理类,里面有2个核心的变量ruleMap、circuitBreakers;我们可以猜出就是降级规则集合以及熔断规则集合。

在继续往下看,我们发现有个RulePropertyListener中reloadFrom方法****,即重新加载规则;方法里面有个buildCircuitBreakers方法,一看方法名就知道是构建熔断策略。

在看一下buildCircuitBreakers方法,我们看到本质就是遍历DegradeRule集合,然后在初始化熔断对象CircuitBreaker。

这里我们知道熔断是怎么产生的了;本质就是通过DegradeRule产生的。

解决方案

上面我们知道了一些熔断对象产生的原理,我们只要可以自定义DegradeRule对象就可以产生。我们在学习Sentinel的时候,他有个Api方式去定义降级规则,大家可以去看一下之前的文章,详细介绍了Api定义规则的方式。我们看一下案例

我们可以看到DegradeRule对象的定义,以及DegradeRuleManager对象;上面的代码就能给资源名api定义了慢响应的降级策略了

讲到这里聪明的小伙伴们有没有想到一些思路呢?往下看。

方案思路

先给出整体的解决思路

上图中介绍的流程

1、启动服务时扫描jar,获取@FeignClient注解的接口(技术难点一:扫描哪些jar包)
2、获得Feign接口中的调用方法
3、服务本地创建DegradeRule对象。(技术难点二:Sentinel的资源名支持动态配置)
4、把设置的默认的降级熔断规则同步到Nacos

根据上面的流程,我们就可以看到,一旦微服务启动了,就会自动把Feign接口配置默认的降级熔断规则,以及同步到Nacos中;再结合之前文章中介绍的Sentinel控制台改造,就立刻在控制台显示这些降级规则了,而不需要认为配置了。

注意:上面只是介绍了整体流程,在编写代码的时候,我们需要考虑到很多场景,如:

一)服务第二次启动的时候,nacos中已经有了相关的配置,是否还要修改nacos的配置。

二)以及有些特殊业务在Sentinel控制台进行了降级配置,那默认的全局配置如何兼容人工的配置。

这些就不在这里讲了,本文只介绍核心方案思路,核心代码

其他的有兴趣的小伙伴们,可以跟要源码

技术难点

难点一

我们扫码jar包,而且是要扫码包含@FeignClient注解接口的jar。我们知道在使用Feign功能的时候,需要在SpringBootApplication启动类中加上@EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ApplicationA {
public static void main(String[] args) {
SpringApplication.run(ApplicationA.class, args);
}
}

有的时候Feign包会用第三方jar的形式存在,那代码就有会变成

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = {"com.rainbow.demo1.feign","com.rainbow.demo2.feign"})
public class ApplicationA {
public static void main(String[] args) {
SpringApplication.run(ApplicationA.class, args);
}
}

里面的@EnableFeignClients注解的属性basePackages中显式的指向了Feign包的位置了,这个比较好弄,直接用用ClassScan工具类扫就行了。

ClassScan工具类是支持子包扫描的

那没有显式的定义basePackages,那怎么获取到jar包路径呢?

我们可以参考SpringCloud的源码实现的方法,看代码。

上面是根据启动服务时,堆栈信息获取main方法的启动类对象。

根据启动类对象,获取到EnableFeignClients对象,如果没有basePackages,那就是以启动类的包为扫描的入口。

这样我们就解决了扫描jar入口的问题。

难点二

常规方式

资源名的获取,举个例子

@FeignClient(name = "service-provider")
public interface ProviderServiceFeign {
@GetMapping("/transferHeaders")
public BaseRestResponse<String> transferHeaders();
}

根据微服务的Sentinel资源名定义,@FeignClient(name = "service-provider"),微服务名是service-provider;那针对transferHeaders()方法的降级策略资源名即为

lb://service-provider/transferHeaders

这个实现比较简单就是获取@FeignClient的name的值,以及方法@GetMapping里面的值就可以拼接出资源名。

指定Url地址

@FeignClient(name = "service-provider",url = "http://xxxxx")
public interface ProviderServiceFeign {
@GetMapping("/transferHeaders")
public BaseRestResponse<String> transferHeaders();
}

指定url的目的其实就是指定请求的方式,这种情况的Sentinel的资源名即为

http://xxxxx/transferHeaders

这个技术实现也比较简单,只需要考虑到这个场景,就可以了。

动态配置Url

还有一种情况即对接第三方平台时,我们一般不会写死Url,而是通过配置的方式,如

@FeignClient(name = "service-provider",url = "${reqUrl}")
public interface ProviderServiceFeign {
@GetMapping("/transferHeaders")
public BaseRestResponse<String> transferHeaders();
}

上面的${reqUrl}是通过配置的,那Sentinel的资源名是什么样的呢?本质上面资源名也是Url+具体的请求地址,即

http://${reqUrl}/transferHeaders

但是这样设置资源名肯定是不正确的,需要把具体的配置值拿过来拼接。那我们就需要在程序中获取${reqUrl}的值,讲到这里小伙伴们知道怎么实现了吗?其实就是用到

Environment environment ;//环境变量对象
this.environment.resolvePlaceholders(url);//获取变量的值

核心代码

上面的技术难点解决掉之后,我们就放开双手撸代码了,这里贴上核心的代码;小伙伴们。

public class DegradeRuleInitializer implements ApplicationRunner, EnvironmentAware

实现ApplicationRunner, EnvironmentAware就能够实现启动时,去扫描了,入口就在ApplicationRunner中的run方法。

扫描类

扫描FeignClient

初始化默认规则

设置了默认降级规则,把配置信息发布到nacos

效果

一旦微服务启动了,nacos配置就有了

我们会把默认的值发布到nacos里面,小伙伴们可以具体看一些资源名,里面就会有很多降级规则。

我们再来看看Sentinel控制台,里面就显示了降级规则列表;设计的是针对同一个资源名做异常数、异常比例、慢响应三种类型的降级熔断策略。

全局默认的值,到底是多少阀值,是可以通过配置的方式的,这些就不介绍了。比较简单。

到这里就全部实现了微服务中Feign接口的降级熔断策略的默认化配置,不需要人工去添加了;当然是支持人工去修改的,如果需要修改阀值,可以人工修改。

总结

本文介绍了Sentinel的全局Feign默认熔断的技术实现方案,整体思路原理不是太复杂,就是利用其本身的功能,做了一些扩展;这样更方便用户的使用。

看完三件事️



如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:

  1. 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  2. 关注公众号 『 阿风的架构笔记 』,不定期分享原创知识。
  3. 同时可以期待后续文章ing
  4. 关注后回复【666】扫码即可获取架构进阶学习资料包

Sentinel全局Feign默认熔断设计实现的更多相关文章

  1. Spring Cloud Alibaba Sentinel 整合 Feign 的设计实现

    作者 | Spring Cloud Alibaba 高级开发工程师洛夜 来自公众号阿里巴巴中间件投稿 前段时间 Hystrix 宣布不再维护之后(Hystrix 停止开发...Spring Cloud ...

  2. Spring Cloud Alibaba Sentinel对Feign的支持

    Spring Cloud Alibaba Sentinel 除了对 RestTemplate 做了支持,同样对于 Feign 也做了支持,如果我们要从 Hystrix 切换到 Sentinel 是非常 ...

  3. SpringCloud Gateway高阶之Sentinel限流、熔断

    前言 为什么需要服务熔断和降级?微服务是当前业界的一大趋势,原理就是将单一职责的功能模块独立化为子服务,降低服务间的耦合,服务间互相调用.但是这样也会出现一些问题: 上图中大量微服务互相调用,存在大量 ...

  4. Sentinel流控与熔断

    参考: https://thinkwon.blog.csdn.net/article/details/103770879 项目结构 com.guo     ├── guo-sentinel       ...

  5. 全局axios默认值 和 自定义实例默认值

    首先说了一下情况, 登录后成功返回token 然后在带着token去继续下面的请求, 奇怪的是都是当前页面起作用,刷新和跳转之后就token 就消失了. 查了 axios文档发现 被自己坑了 我设置了 ...

  6. 一个名叫Sentinel-Rules-SDK的组件,使得Sentinel的流控&熔断规则的配置更加方便

    原文链接:一个名叫Sentinel-Rules-SDK的组件,使得Sentinel的流控&熔断规则的配置更加方便 1 Sentinel 是什么? 随着微服务的流行,服务和服务之间的稳定性变得越 ...

  7. SpringCloud:feign默认jackson解析'yyyy-MM-ddTHH:mm:ssZ'时间格式报错

    Feign默认的使用jackson解析,所以时间传值时会报错,时间格式错误 解决办法: 修改feign解析方式为fastjson方式: @Configuration public class CxfC ...

  8. Spring Cloud中Hystrix、Ribbon及Feign的熔断关系是什么?

    导读 今天和大家聊一聊在Spring Cloud微服务框架实践中,比较核心但是又很容易把人搞得稀里糊涂的一个问题,那就是在Spring Cloud中Hystrix.Ribbon以及Feign它们三者之 ...

  9. Sentinel与OpenFeign 服务熔断那些事

    点赞再看,养成习惯,微信搜索[牧小农]关注我获取更多资讯,风里雨里,小农等你,很高兴能够成为你的朋友. 项目源码地址:公众号回复 sentinel,即可免费获取源码 在上一篇中,我们讲解了 Senti ...

随机推荐

  1. Learn-JavaScript-with-MDN 系列文章: 01. var & let & const 对比

    Learn-JavaScript-with-MDN 系列文章: 01. var & let & const 对比 var & let & const 区别 https: ...

  2. FileReader, readAsText

    readastext filereader FileReader.readAsText() https://developer.mozilla.org/zh-CN/docs/Web/API/FileR ...

  3. WEB 用视频替换GIF动画

    原文 download ffmpeg gif to video 转化后文件大小大大降低 $ ffmpeg -i my-animation.gif -b:v 0 -crf 25 -f mp4 -vcod ...

  4. Flutter 区分开发环境和生产环境

    Uri _baseUrl; final isProd = const bool.fromEnvironment('dart.vm.product'); if (isProd) { _baseUrl = ...

  5. NGK数字增益平台中如何分配代币产出

    最近很多朋友听说NGK公链的主网和数字增益平台即将上线以后都纷纷表示非常感兴趣,已经基本了解了NGK代币的产出方式,但还是对代币产出分配的问题不是很明确.今天小编就给大家科普一下,NGK代币在NGK数 ...

  6. DBA 的效率加速器——CloudQuery v1.3.2 上线!

    嘿,兄弟,我们好久不见,你在哪里 嘿,朋友,如果真的是你,请打声招呼 我说好久不见,你去哪里 你却对我说,我去江湖 我去看 CloudQuery v1.3.2,看看新增了哪些好用的小功能! 一.自动/ ...

  7. Guava - LoadingCache实现Java本地缓存

    前言 Guava是Google开源出来的一套工具库.其中提供的cache模块非常方便,是一种与ConcurrentMap相似的缓存Map. 官方地址:https://github.com/google ...

  8. Python分类模型构建

    分离训练集测试集 from sklearn.model_selection import train_test_split eg: X_train, X_test, y_train, y_test = ...

  9. void指针及指针的多次赋值的理解

    1.void指针的类型转换 int A::functionCommamd(const DWORD _from,const DWORD _to,const DWORD Event_type,void * ...

  10. wxWidgets源码分析(9) - wxString

    目录 wxString wxString的中文字符支持 Windows Linux Unicode Linux UTF-8 总结 wxString与通用字符串的转换 wxString对象的创建 将wx ...