Spring Cloud - 熔断
2021-04-02 22:25
标签:集成 信息 服务 调用 数据 and src 网络 影响 小齐同学最近正在学Spring Cloud,最近学到熔断这块的知识点,不是很理解,于是请教了公司的大佬老张。 小齐趁空闲时间找到老张:“张哥,我最近在学习Spring Cloud,看到所有书上都说熔断是微服务必须的,可我不用熔断,系统好像也能正常工作。那为什么说它是必须的呢?” “正常工作是没问题,那发生异常了呢?某个服务挂了或者网络不通的时候会发生什么?”老张反问小齐。 “让我思考一下,如果一个微服务不可用了,那调用它的微服务这个服务就会抛异常,一直到最上层。可这跟熔断又有什么关系?”小齐心中还是有一些疑惑。 老张笑了笑,解释道:“可不只是抛异常怎么简单。在Java中,每一个HTTP请求都会开启一个新线程。而下游服务挂了或者网络不可达,通常线程会阻塞住,直到Timeout。你想想看,如果并发量多一点,这些阻塞的线程就会占用大量的资源,很有可能把自己本身这个微服务所在的机器资源耗尽,导致自己也挂掉。” 小齐有些明白了,追问道:“那是不是最终所有上游微服务都有可能挂掉?” “是的,这也是称为‘雪崩效应’。最开始是一个微服务挂掉了。随着时间的推移,可能会导致整个系统都不可用。”老张一边回答,一边快速地在电脑上搜出了下面这个图: “那熔断具体是怎么解决这个问题的?”小齐点点头,然后继续追问。 老张见小齐似乎有些明悟,但知识点还没有串联起来,便一步一步地引导他:“那你知道Spring Cloud断路器的三种状态吗?” 似乎终于到了小齐自己比较熟悉的知识点,自信地说到:“这个我知道,Spring Cloud一般使用Hystrix来做断路器。就跟电路上的闸差不多。它有三种状态:关闭,开启和半开。最开始是关闭状态的,这个时候所有请求都可以通过;如果错误请求达到一定的阈值,就会变成开启状态,就会让所有请求短路,直接返回失败的响应;一段时间后,断路器会变成半开状态,如果下一个请求成功了,就关闭断路器,反之就开启断路器。” “那这个阈值具体是什么?” “这里主要就要用到三个属性了:”小齐快速答道 ? “非常正确!你知道Hystrix的底层原理吗?” 于是小齐祭出了官方的图: “Hystrix主要使用的是RxJava来做异步请求,RxJava是一个异步框架,是对观察者模式的一个应用。Hystrix会把对每个微服务的请求放到线程池里面,具体分配到哪个线程池可以使用HystrixThreadPoolKey来指定”: 老张继续问:“那你知道为什么要有这个key吗?它是用来干嘛的?”小齐摇了摇头,表示自己还不知道。 “你看源码就知道了,Hystrix使用了一个ConcurrentHashMap来保存线程池。” 小齐心中出现了一个新的问题:那为什么我们需要多个线程池呢? 此时老张继续说道:“这个其实叫资源隔离。应用程序会被完全保护起来,即使依赖的一个服务出问题了,也不会影响到应用程序的其他部分。使用多个线程池就是一种资源隔离方式,也是默认的隔离方式。而且Hystrix底层是使用的RxJava,使用线程池可以让你很方便地实现异步操作。” “那除了线程池隔离,还有其它隔离方式吗?” “有的,Hystrix提供了两种隔离方式:线程池隔离和信号量(Semaphore)隔离。” 小齐说到:“参考了RedSpider技术社区的这篇文章,我知道Semaphore在多线程编程中经常发挥的是限制线程数量的作用,那它在这里相当于一个限流的作用?” “是的,你可以参考这篇文章,信号量主要起一个限流的作用。如果信号量耗尽了,它就直接走「fallback流程」所以也能防止雪崩。但大多数情况,我们更倾向于使用线程池。” “刚刚你提到了一个词叫‘fallback流程’?” “是的,fallback翻译过来是‘回退’的意思,有时候我们也会称它‘「服务降级」’。” “那什么时候会触发fallback呢?” “其实你应该已经可以总结出来了,主要这五种情况会触发fallback:” “那触发fallback后会发生什么?” 老张熟练的打开源码,并快速敲下了一个Demo。“这个你得看HystrixCommand这个类的源码和使用方式。” “我们在使用Hystrix的时候,一般是继承HystrixCommand这个类,重写run和getFallback这两个方法。正常情况它是走run方法的。如果发生了fallback,它就会调用getFallback方法。” 小齐看着这段代码,问到:“这看起来有点麻烦,在Spring Cloud中,有更简单的使用方式吗?” “当然。「在Spring Cloud中,Hystrix可以和OpenFeign无缝集成」。OpenFeign接口上的每个方法都会被Hystrix断路器包裹(这也是一种典型的AOP实现)。你可以在注解上配置fallback方法:” “同时,你在@FeignClient这个注解里面可以看到两个属性:fallback和fallbackFactory,前者是指定一个类,通常这个类是继承当前接口的;后者是指定一个工厂类。具体示例代码如下:” “使用fallbackFactory的好处是可以得到异常信息,以便于自己做日志记录或者进一步的逻辑处理。” 感觉熔断这一块的知识点差不多理通了,小齐认真道谢,回到自己的位置继续撸代码…… 关于作者 推荐阅读 Yasin x Spring Cloud - 熔断 标签:集成 信息 服务 调用 数据 and src 网络 影响 原文地址:https://blog.51cto.com/14890694/2518855熔断
雪崩效应
(1)hystrix.command.default.circuitBreaker.requestVolumeThreshold(当在配置时间窗口内达到此数量的失败后,进行短路。默认20个)
简言之,10s内请求失败数量达到20个,断路器就会变成打开状态。
(2)hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds(短路多久以后开始尝试是否恢复,默认5s)
(3)hystrix.command.default.circuitBreaker.errorThresholdPercentage(出错百分比阈值,当达到此阈值后,开始短路。默认50%)
?资源隔离
Hystrix原理@HystrixCommand(threadPoolKey = "user-hello")
String getUserHello();
ConcurrentHashMap
fallback
class AuthCommand extends HystrixCommand
@HystrixCommand(fallbackMethod = "getByIdFallback")
public String getById(String id) {...}
private String getByIdFallback(String id) {...}
// Feign接口
@FeignClient(value = "service-user", fallback = UserClientImpl.class)
public interface UserClient {
@GetMapping("hello")
String getUserHello();
}
// 实现类
@Component
public class UserClientImpl implements UserClient {
@Override
public String getUserHello() {
return "default user";
}
}
// Feign接口
@FeignClient(value = "service-user", fallbackFactory = UserFallbackFactory.class)
public interface UserClient {
@GetMapping("hello")
String getUserHello();
}
// 工厂类
@Component
public class UserFallbackFactory implements FallbackFactory
微信公众号:编了个程(blgcheng)
个人网站:https://yasinshaw.com
你知道,这个公众号经常分享原创技术干货,关注了肯定不会后悔;
你知道,这个作者是个有趣的人,加个星标可以经常看到他写的文章;
你知道,转发并点击在看这篇文章的人都升职加薪了!
钟意作者