当前位置: 首页 > news >正文

Spring Cloud全解析:熔断之Hystrix线程隔离导致的问题


文章目录

    • Hystrix线程隔离


Hystrix线程隔离

在微服务框架中,可能一个服务需要调用多个微服务,在tomcat中运行时,tomcat只是分配了100个线程,由于多个服务之间调用的时间消耗过长,可能会导致线程耗尽,而在Hystrix中存在线程隔离,对于每个微服务分配一个线程池,访问某个微服务时就从对应的线程池中取线程,如果对应线程池中的线程都用光了,那么就认为该服务不可用了,如果在需要请求该微服务,则直接返回

那么这个线程池是存在于哪里呢?

  • [ ]

既然Hystrix的Command都是在线程池中执行的,就会遇到当前的RequestContextHolder获取不到RequestAttributes,没办法,跨线程了呀(RequestContextHolder中使用了ThreadLocal),这怎么解决呢?Hystrix中提供了一个HystrixConcurrencyStrategy类,HystrixConcurrencyStrategy提供了一套默认的并发策略实现。我们可以根据我们自己不同需求通过装饰去扩展它。如每次执行HystrixCommand的时候都会去调用wrapCallable(Callable) 方法,这里我们就可以通过装饰Callable使它提供一些额外的功能(如ThreadLocal上下文传递)

public class FeignHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy
{private static final Logger log;private HystrixConcurrencyStrategy delegate;public FeignHystrixConcurrencyStrategy() {try {this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();if (this.delegate instanceof FeignHystrixConcurrencyStrategy) {return;}HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins.getInstance().getCommandExecutionHook();HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy();HystrixPlugins.reset();// 注册并发策略HystrixPlugins.getInstance().registerConcurrencyStrategy(this);HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);}catch (Exception e) {log.error("Failed to register Sleuth Hystrix Concurrency Strategy", e);}}// 这个时候还在主线程了,所以通过RequestContextHolder.getRequestAttributes()是能拿到上下文的拿到后hold住,等到run执行的时候再绑定即可public <T> Callable<T> wrapCallable( Callable<T> callable) {// 获取当前请求的requestAttributesRequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();return new WrappedCallable<T>(callable, requestAttributes);}public ThreadPoolExecutor getThreadPool( HystrixThreadPoolKey threadPoolKey,  HystrixProperty<Integer> corePoolSize,  HystrixProperty<Integer> maximumPoolSize,  HystrixProperty<Integer> keepAliveTime,  TimeUnit unit,  BlockingQueue<Runnable> workQueue) {return this.delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);}public ThreadPoolExecutor getThreadPool( HystrixThreadPoolKey threadPoolKey,  HystrixThreadPoolProperties threadPoolProperties) {return this.delegate.getThreadPool(threadPoolKey, threadPoolProperties);}public BlockingQueue<Runnable> getBlockingQueue( int maxQueueSize) {return this.delegate.getBlockingQueue(maxQueueSize);}public <T> HystrixRequestVariable<T> getRequestVariable( HystrixRequestVariableLifecycle<T> rv) {return this.delegate.getRequestVariable(rv);}class WrappedCallable<T> implements Callable<T>{private final Callable<T> target;private final RequestAttributes requestAttributes;public WrappedCallable( Callable<T> target,  RequestAttributes requestAttributes) {this.target = target;this.requestAttributes = requestAttributes;}@Overridepublic T call() throws Exception {try {// 执行之前绑定上下文,执行完成后释放RequestContextHolder.setRequestAttributes(this.requestAttributes);return this.target.call();}finally {RequestContextHolder.resetRequestAttributes();}}}
}

这时候大家就奇怪了,为什么在wrapCallable方法中可以获取到当前请求呢,来看源码是怎么调用HystrixConcurrencyStrategy的

public class HystrixContextRunnable implements Runnable {private final Callable<Void> actual;// 父线程的上下文private final HystrixRequestContext parentThreadState;public HystrixContextRunnable(Runnable actual) {this(HystrixPlugins.getInstance().getConcurrencyStrategy(), actual);}public HystrixContextRunnable(HystrixConcurrencyStrategy concurrencyStrategy, final Runnable actual) {// 实例化HystrixContextRunnable的时候去调用的concurrencyStrategy.wrapCallable,此时还没有切换线程呢this.actual = concurrencyStrategy.wrapCallable(new Callable<Void>() {@Overridepublic Void call() throws Exception {actual.run();return null;}});this.parentThreadState = HystrixRequestContext.getContextForCurrentThread();}@Overridepublic void run() {HystrixRequestContext existingState = HystrixRequestContext.getContextForCurrentThread();try {// set the state of this thread to that of its parentHystrixRequestContext.setContextOnCurrentThread(parentThreadState);// execute actual Callable with the state of the parenttry {actual.call();} catch (Exception e) {throw new RuntimeException(e);}} finally {// restore this thread back to its original stateHystrixRequestContext.setContextOnCurrentThread(existingState);}}}

参考文献

  • Hystrix线程隔离导致的问题

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • web群集--nginx配置文件location匹配符的优先级顺序详解及验证
  • 防蓝光护眼灯有用吗?五款防蓝光效果好的护眼台灯推荐
  • 《JavaEE进阶》----11.<SpringIOCDI【Spring容器+IOC详解+DI介绍】>
  • ArcGIS Pro SDK (十三)地图创作 4 设备
  • 基于鸿蒙API10的RTSP播放器(八:音量和亮度调节功能的整合)
  • LeetCode --- 414周赛
  • 深入理解Linux中的多路复用技术:select、poll与epoll
  • 玄机靶场初体验
  • 目标检测-小目标检测方法
  • 《ORANGE‘s 一个操作系统的实现》-- ubuntu14.04下bochs2.3.5的配置与使用
  • 【第34章】Spring Cloud之SkyWalking分布式日志
  • JVM四种垃圾回收算法以及G1垃圾回收器(面试)
  • 今日leetCode 242.有效的字母异位词
  • 云服务器部署DB-GPT项目
  • .Net 执行Linux下多行shell命令方法
  • 时间复杂度分析经典问题——最大子序列和
  • [笔记] php常见简单功能及函数
  • 《Javascript高级程序设计 (第三版)》第五章 引用类型
  • 〔开发系列〕一次关于小程序开发的深度总结
  • go语言学习初探(一)
  • Java多线程(4):使用线程池执行定时任务
  • Java应用性能调优
  • js正则,这点儿就够用了
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • ubuntu 下nginx安装 并支持https协议
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 搭建gitbook 和 访问权限认证
  • 记录一下第一次使用npm
  • 简单实现一个textarea自适应高度
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 前端面试题总结
  • 一道面试题引发的“血案”
  • 用jquery写贪吃蛇
  • 仓管云——企业云erp功能有哪些?
  • 新年再起“裁员潮”,“钢铁侠”马斯克要一举裁掉SpaceX 600余名员工 ...
  • # windows 运行框输入mrt提示错误:Windows 找不到文件‘mrt‘。请确定文件名是否正确后,再试一次
  • (3)选择元素——(17)练习(Exercises)
  • (C语言)fgets与fputs函数详解
  • (C语言)字符分类函数
  • (day18) leetcode 204.计数质数
  • (附源码)计算机毕业设计高校学生选课系统
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (四)Controller接口控制器详解(三)
  • (四十一)大数据实战——spark的yarn模式生产环境部署
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置
  • .babyk勒索病毒解析:恶意更新如何威胁您的数据安全
  • .net CHARTING图表控件下载地址
  • .NET Compact Framework 3.5 支持 WCF 的子集
  • .NET 程序如何获取图片的宽高(框架自带多种方法的不同性能)
  • .net 后台导出excel ,word
  • .NET 设计模式—简单工厂(Simple Factory Pattern)
  • .NET 实现 NTFS 文件系统的硬链接 mklink /J(Junction)
  • .NET开源的一个小而快并且功能强大的 Windows 动态桌面软件 - DreamScene2
  • @Autowired 和 @Resource 区别的补充说明与示例