今天来聊一聊微服务的隔离和熔断是怎么做的, 如果你的项目没有用微服务,不要走开,可以看看对一个问题的解决思路

假设Tomcat线程池有100个线程, 每次有新的用户请求过来,Tomcat就会从中找出一个空闲的线程去执行, 抛开那些琐碎的小细节,这些请求其实非常简单, 无非就是这么几件事:

1. 根据用户ID调用用户服务, 获取用户对象。

2. 获取该用户的推荐商品

3. 获取该用户的积分。

4. 把这些信息组合起来,返回给浏览器。

有意思的是前三件事情全是HTTP调用,需要调用某个地方的所谓“微服务”。

有一次,线程A去执行几个逻辑,等它调用“推荐服务”的时候,“推荐服务”迟迟没有返回,线程A也许很高兴, 终于可以休息了!

新的用户请求源源不断地到来,线程池中越来越多的线程都在等待推荐服务返回。

很快,100个线程全部用光,Tomcat只好挂出一个牌子: “系统繁忙,暂停营业。”

总之, 一个服务的出错竟然导致了整个Tomcat不可用,实在是难以忍受。

也许你会和运维商量一下,来个简单粗暴的办法: 给Tomcat线程池在增加100个线程兄弟, 可是这不能解决问题, 在高并发的情况下, 只要那些远程的微服务有一个阻塞,无论多少线程,很快就会被用光。

于是,你只好重启Tomcat,毁灭这个可爱的世界,但是重启后问题还是有可能发生。

隔离

怎么把一个微服务的故障给隔离起来呢?让他们互不影响呢?

Netflix的程序员们想了一个点子, 对每个微服务,都分配一个线程池,像这样:

比如说调用“推荐服务”的时候,就会从“推荐服务线程池” (假设有5个线程)中找到一个线程执行。如果这个HTTP系统调用迟迟没有返回,那这个线程就会一直等待,新的请求就需用使用池中别的线程。

如果5个线程都用光了,会发生什么情况?

这很简单, 可以简单地认为这个服务不可用了!马上返回,绝不等待。 

这些新的线程池,是一种隔离的手段, 一个微服务一旦出了问题,很快就会被识别出来。

熔断器

但是上面这种方案,还是有一定的问题,如果这个推荐服务已经不可用了,还不断地尝试去调用,那肯定是一种浪费。

所以Netflix的程序员又想了一个办法:使用熔断器(也叫断路器),注意:当这个熔断器关闭的时候,外面的请求可以直接调用,如果打开,就把外界的请求给阻断了。

具体的做法是:系统会检测请求失败的比率(失败数/总请求数), 一旦这个比率达到一个阈值的时候,熔断器就开启, 直接拒绝执行用户请求。然后休眠一段时间,尝试放过一部分流量(比如一个请求),如果调用成功,熔断器闭合,恢复到正常状态,否则继续进行休眠周期。

API

现在有了新的线程池,对程序员来讲,该如何使用呢? 原来是这么做的:

UserService service = ... 获得用户服务...
User user = service.getUser(userID);

现在,为了利用新的线程池, 需要做一层封装:

UserService service = ... 获得用户服务...
UserServiceCmd  cmd = new UserServiceCmd(service, userID);
User user = cmd.execute();

看到没有? UserService 被封装了一层, 放到了一个UserServiceCmd中去执行。

这个Command代码是这个样子的:

public class UserServiceCmd    extends HystrixCommand<User> {private UserService userService = null;private String userID = null;……public UserServiceCmd(UserService userService,String userID) {……this.userService = userService;this.userID = userID;}@Overrideprotected User run(){        return userService.getUser(userID);        }@Overrideprotected User getFallback() {        return annonymousUser;}
}

看起来非常简单吧, 可是背后的魔法是什么呢?

实际上,在这个UserServiceCmd执行的时候,会使用另外一个线程池的线程去调用那个run()方法。

(注:这是一种同步调用,实际上还可以异步调用)

线程池的维护是在HystrixCommand这个父类中(命令模式),不需要程序员处理,程序员只需要告诉它: 我需要几个线程,就可以了。

眼光敏锐的你也许已经猜到,这里还采用了设计模式模板方法

HystrixCommand它定义了一个抽象的方法: run(), 这个方法需要程序员去实现(例如前面的UserServiceCmd  ), 父类的的execute方法会调用程序员写的run()方法。

你也许还会注意到,还有一个叫做getFallback()的方法,这是干嘛用的?

其实前面的例子中我们只说道了线程池耗尽的时候,直接返回。 但是大部分情况下总得返回一点儿东西吧,比如UserServiceCmd,我们也许可以返回一个匿名的用户给调用方。

这就是所谓的撤退,退却(Fallback)逻辑

当然,这个逻辑也可以用在熔断器开启,调用失败,超时等情况下。

一个粗略的、大致的流程图是这样的:

Netflix把这些功能(当然,这里只是概要介绍,还有很多其他功能)给组装起来,形成了一个开源的库,叫做Hystrix,就是豪猪,浑身是刺,自我保护,还是挺贴切的。

后记

刚写完这个文章,就得到了一个”悲惨“的消息: Hystrix不再开发新功能,将进入维护模式。 考虑到Hystrix巨大的使用量,学习它还是非常有价值的。

Netflix推荐大家转向Resilience4j,看来又有新的玩具可以研究下了,兴奋!

这是个相对新的项目,影响力和使用量现在还不能和Hystrix相比。

Resilience4j全面拥抱了Java 8和函数式编程, 他的核心功能包括:断路器,限速,隔离(不再支持线程池),自动重试,响应的缓存, 看,核心的功能还是类似的, resilience4j能发展到什么程度,我们拭目以待吧。

聊聊微服务的隔离和熔断相关推荐

  1. 微服务的隔离和熔断机制

    1.微服务故障背景 假设Tomcat线程池有100个线程, 每次有新的用户请求过来,Tomcat就会从中找出一个空闲的线程去执行, 抛开那些琐碎的小细节,这些请求其实非常简单, 无非就是这么几件事: ...

  2. 「微服务系列 13」熔断限流隔离降级

    我们知道微服务分布式依赖关系错综复杂,比方说前端的请求转化为后端调用的服务请求,一个前端请求会转为成很多个后端调用的服务请求,那么这个时候后台的服务出现不稳定或者延迟,如果没有好的限流熔断措施,可能会 ...

  3. 聊聊微服务架构及分布式事务解决方案

    转载自   聊聊微服务架构及分布式事务解决方案 分布式事务场景如何设计系统架构及解决数据一致性问题,个人理解最终方案把握以下原则就可以了,那就是:大事务=小事务(原子事务)+异步(消息通知),解决分布 ...

  4. 微服务架构下的熔断框架:hystrix-go

    伴随着微服务架构被宣传得如火如茶,一些概念也被推到了我们的面前.一提到微服务,就离不开这几个字:高内聚低耦合:微服务的架构设计最终目的也就是实现这几个字.在微服务架构中,微服务就是完成一个单一的业务功 ...

  5. 微服务之Hystrix降级熔断

    前言 分布式系统面临的问题-----服务雪崩 多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的"扇出".如果扇出的链 ...

  6. 扫盲帖:聊聊微服务与分布式系统

    今天和大家聊一聊分布式系统的相关概念及其常见分布式组件和设计思想(不涉及计算机科学中分布式系统的技术理论之类的东西),之前为了准备这次的面试我是把市面上的很多分布式组件都看了一遍,我们公司所用的分布式 ...

  7. c3p0 服务启动获取连接超时_微服务架构中的熔断、降级

    微服务架构中熔断和降级是保证服务高可用的一项重要功能点,微服务区别于一体化项目的最大区别也再于熔断和降级,很多微服务项目的开发人员对熔断的理解就是当服务不可用的时候,为了让整体服务可以正常运行,需要让 ...

  8. 使用 KubeSphere 轻松实现微服务灰度发布与熔断

    KubeSphere®️ 是在目前主流容器调度平台 Kubernetes 之上构建的企业级分布式多租户容器管理平台,提供简单易用的操作界面以及向导式操作方式,在降低用户使用容器调度平台学习成本的同时, ...

  9. 技术分享|“单身”还是“入微”?一起聊聊微服务的二三事

    云原生技术分享系列内容第三篇之--微服务架构篇. 感兴趣的朋友也可以去看行云创新关于云原生技术介绍的其它文章: <关于容器最通俗的解释,人人都能三分钟搞懂> <技术分享|关于K8S的 ...

最新文章

  1. R语言使用ggplot2包使用geom_boxplot函数绘制基础分组箱图(不同分组配置不同的箱体填充色+Brewer调色板)实战
  2. aix解压tgz_AIX 上压缩与解压缩 各种文件格式原理说明
  3. 手把手实现YOLOv3(一)
  4. 基于角色的访问控制'的权限管理的数据库的设计实现
  5. 关于request.getRequestDispatcher()的两个方法
  6. UI展示样机素材|让作品看起来毫无痕迹,还原场景!
  7. java连接mysql数据库 R_Java连接Mysql数据库详细代码实例
  8. 普罗米修斯 感染组合表
  9. Web端高保真动态交互Axure元件库
  10. 离线下载Express 2015 for Windows 10
  11. 资源共享的两阶段交叉效率DEA模型及matlab应用:地区科技投入产出效率案例分析,文后有网盘链接
  12. 怎么用计算机算一元三次方程,一元三次方程计算器求解(附使用方法)
  13. 英语数字转换器(POJ NO.1123)
  14. 如何通过关键字和搜索结果分析用户需求
  15. oracle付权,oracle权限总结
  16. 【2016.5.27】再见,软件工程,你好,软件工程。
  17. 聚类分析详细解读python
  18. python由大到小排序_Python选择从小到大的排序,python
  19. 这是我所收集的一些工具网站
  20. WINCE读取系统数据或系统配置信息

热门文章

  1. 在php的yii2框架中整合hbase库
  2. a标签中href=javacript:; href=javacript:void(0); href=#区别
  3. OEL上使用yum install oracle-validated 简化主机配置工作
  4. Spring学习笔记八--Bean生命周期和后置处理器
  5. Nginx使用webbench进行压力测试
  6. 应用程序虚拟化部署笔记二
  7. simulink中使用memory模块实现变量的累加和(离散积分器)
  8. ffmpeg拿AVPacket做缓冲队列时注意
  9. DCOM 示例:演示如何远程调用 COM 对象
  10. 论文笔记:MobileNet v2