语境
- 微服务架构下,各服务之间的依赖层级关系复杂,甚至成网状
- 依赖:A调用B,称为A依赖B,也可称A有一个对B对依赖
- Client:依赖的形式基本上是A使用B提供的client来调用B,也可以是A使用HttpClient这样的通用client来调用B
能做什么?
- 避免因一个节点的超时,导致下游节点级联式的请求堆积,崩溃整个系统
- 避免对一个故障节点发出请求,节省网络资源
- 快速失败
- 相对快速的恢复:侦测节点,恢复通信
- 熔断时的降级
- 一些报警,监控,运行时控制的功能
- hystrix不仅仅局限于网络通信,用在其他地方也是可以的
设计原则
- 防止单个依赖用尽容器(如Tomcat)的所有线程
- 使用减载和快速失败,而不是排队
- 提供fallback
- 使用隔离技术(隔离舱,泳道,熔断器模式)限制单个依赖所能产生的影响
- 防止整个客户端的执行失败,而不只是网络流量
- 支持运行时修改配置
架构
- 对外部系统调用的包装:HystrixCommand、HystrixObservableCommand
- 超时阈值:建议稍微低于99.5%线
- 每个依赖有一个小线程池或者信号量:线程池满了的话则直接拒绝
- 指标:成功数、失败数(客户端异常数)、超时数、线程拒绝数
- 熔断:错误数超过比例自动熔断,也可手动熔断
- fallback(降级):请求失败时、超时时、拒绝时、熔断时
- 近实时修改:监控指标和配置变更
断路器
三个状态:OPEN、CLOSED、HALF-OPEN
OPEN
意思:断开,请求被直接短路 触发条件:
- 当断路器流量达到基础值
- failure比例到达设定阈值
维持时间:通过参数控制,比如1秒
CLOSED
意思:闭合,请求可以通过
HALF-OPEN
意思:半开,如果下一个请求成功则闭合,否则断开 触发条件:在OPEN之后过了一段时间变成半开状态,时间可设置 状态迁移:
- 在HALF-OPEN之后第一个请求成功 -> CLOSED
- 失败 -> OPEN
隔离机制
线程池
- 为单个Client提供一个线程池(5-20个线程)
- 将Caller线程(如Tomcat线程)和实际工作线程解耦
- 不会阻塞Caller线程
- 开销:任务排队、调度、上下文切换
信号量
- 为单个Client提供一个Semaphore
- caller线程和实际工作线程同一个
- 会阻塞Caller线程
- 开销:比线程池模式小多了
请求折叠
- 在一段时间里对同一个依赖的请求折叠起来,变成一个请求,降低对依赖的实际并发数,比如把get 100个id的动作合并成一个
- 怎么折叠要用户自己实现
- 代价:会增加一定的延迟,因为要等待一批请求折叠起来
请求缓存
- 把在同一请求上下文内的重复请求去重,比如在同一请求内,调用了两次getById(1)
- 在代码复杂的时候,你很难避免重复调用的代码路径存在
评论