微服务框架下,一个服务依赖于很多服务。在高并发访问下,系统所依赖的服务的稳定性对系统的影响非常大,依赖有很多不可控的因素,比如网络连接变慢,资源突然繁忙,暂时不可用,服务脱机等,一个被调用服务出问题可能导致调用者不能正常调用其他服务。我们要构建稳定、可靠的分布式系统,就必须要有一套容错方法来应对这些情况。

Hystrix是Netflix开源的一款容错框架,包含常用的容错方法:线程池隔离、信号量隔离、熔断(Circuit Breaker)、降级回退(Fallback),还支持请求缓存(Request Caching)、请求合并(Request Collapsing)等。应用场景如网关服务调用订单服务、商品服务、用户服务。

Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable.

1 基本概念

Dependency
指的是在当前服务中所调用的服务,如若当前服务为网关服务,则其所调用的订单服务是其一个Dependency。
 
HystrixCommand、HystrixObservableCommand
Hystrix中用命令模式来包装对所依赖的服务的调用,如将对订单服务的调用包装成一个commond,示例:

public class GetOrderCommand extends HystrixCommand<List> {

    OrderService orderService;

    public GetOrderCommand(String name){
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ThreadPoolTestGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("testCommandKey"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(name))
.andCommandPropertiesDefaults(
HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(5000)
)
.andThreadPoolPropertiesDefaults(
HystrixThreadPoolProperties.Setter()
.withMaxQueueSize(10) //配置队列大小
.withCoreSize(2) // 配置线程池里的线程数
)
);
} @Override
protected List run() throws Exception {
return orderService.getOrderList();
} public static class UnitTest {
@Test
public void testGetOrder(){
// new GetOrderCommand("hystrix-order").execute();
Future<List> future =new GetOrderCommand("hystrix-order").queue();
} }
}

每个服务对应的commond都有单独的线程池来负责执行。这样当调用者调用多个服务时,某个服务发生异常不会影响调用者对其他服务的调用。

Commond可同步或异步执行:execute()、queue()、observe()、toObservable()

2 内部执行流程

3 容错技术

3.1 依赖隔离(Dependency Isolation)

依赖隔离是指采用某种处理方式使得对一个依赖的调用阻塞时不影响调用方对其他依赖的调用。

显然,最简单的方式是每次调用都起一个新线程执行调用处理,这理论上是可行的,但实际上不会被采用,因为很耗费资源(频繁创建线程、可创建线程数有限等)。解决:仍采用多线程,但需要进一步改造——限制可创建的线程数,有线程池、信号量方式。

3.1.1 线程池隔离

每个依赖的服务的Client(如订单服务的OrderClient)都被包装成HystrixCommand或HystrixObservableCommand。

commond相当于是目标服务的Client的代理,每个服务对应一个commond,每个common内部有个线程池,用来负责执行对目标服务的调用。这样的优点之一是:在调用者方面,一个服务调用阻塞(如超时)时不会影响对其他服务的调用,将影响范围限制在了一个服务内;通过线程池大小控制并发能力。

the isolation provided by thread pools allows for the always-changing and dynamic combination of client libraries and subsystem performance characteristics to be handled gracefully without causing outages.

示意图:

线程池技术本质上与数据库等的连接池类似,一方面用于复用线程/连接以免重复创建线程/连接、另一方面用于限制对服务端的并发访问数。这里的线程池隔离与数据库连接池的区别在于:前者由于要对接多个后端服务而后者专为一个后端服务(数据库),故前者需要为每个服务对应一个线程池而后者只需要一个连接池,两者本质上是一样的。(其实很多技术本质上是一样的,透过现象看本质!)

3.1.2 信号量隔离

此模式使用的场景是被调用的依赖是不耗时的操作时(如从当前进出内存取数据等而非进行RPC)。该模式下每次调用commond时直接用当前线程来执行对目标服务的调用,因此实际上是做不到依赖隔离的——当前服务同时调用多个服务时一个服务的阻塞会影响对其他服务的调用。其主要作用是控制对一个依赖的并发调用个数,所以称counter更贴切。

线程池隔离与信号量隔离的区别:

  • THREAD — it executes on a separate thread and concurrent requests are limited by the number of threads in the thread-pool。(HystrixCommand推荐用此)
  • SEMAPHORE — it executes on the calling thread and concurrent requests are limited by the semaphore count。(HystrixOvservableCommand推荐用此)

3.2 断路器(Circuit Breaker)

6个核心参数:

1、circuitBreaker.enabled

是否启用熔断器,默认是TURE。

2、circuitBreaker.forceOpen

熔断器强制打开,始终保持打开状态。默认值FLASE。

3、circuitBreaker.forceClosed

熔断器强制关闭,始终保持关闭状态。默认值FLASE。

4、circuitBreaker.errorThresholdPercentage

设定错误百分比,默认值50%,例如一段时间(10s)内有100个请求,其中有55个超时或者异常返回了,那么这段时间内的错误百分比是55%,大于了默认值50%,这种情况下触发熔断器-打开。

5、circuitBreaker.requestVolumeThreshold

默认值20。意思是至少有20个请求才进行errorThresholdPercentage错误百分比计算。比如一段时间(10s)内有19个请求全部失败了。错误百分比是100%,但熔断器不会打开,因为requestVolumeThreshold的值是20.。

6、circuitBreaker.sleepWindowInMilliseconds

半开试探休眠时间,默认值5000ms。当熔断器开启一段时间之后比如5000ms,会尝试放过去一部分流量进行试探,确定依赖服务是否恢复。

3.3 降级回退(Fallback)

即指定在调用目标服务失败时进行怎样的处理,通常是返回个默认值。

3.4 请求合并(Request Collapsing)

3.5 请求缓存(Request Caching)

4 弊端

牛逼吹了一堆,实际使用时发现的弊端。

关于熔断功能:熔断有connectionTimeout、readTimeout,前者为建立连接过程的超时时间、后者为连接成功后发起请求到收到调用结果的超时时长。启用熔断后,发起服务调用时,若达到了任一个超时时间则调用方会认为服务不可用,然而若达到了readTimeout,实际上可能被调用服务已经在执行,而调用方却认为服务不可用了,这就会造成不同服务间的数据不一致,除非调用方在认为服务不可用时对被调用服务进行回滚(分布式事务等)。因此readTimeout是个很重要的参数,定太短了会导致不同服务上的数据不一致,然而这个参数通常不好定,特别是服务调用链很长时更难以确定该设什么值。

5 参考资料

https://github.com/Netflix/Hystrix/wiki/How-it-Works?spm=a2c4e.11153940.blogcont183592.6.4ec85c9dkbFMeW

https://www.jianshu.com/p/3e11ac385c73

容错框架之Hystrix小记的更多相关文章

  1. Dubbo服务容错(整合hystrix)

    简介:Hystrix旨在通过控制那些访问远程系统.服务和第三方库的节点从而对延迟和故障提供更强大的容错能力,Hystrix具备拥有回退机制和断路器功能的线程和信号隔离.请求缓存和请求打包以及监控和配置 ...

  2. SpringCloud初体验:三、Feign 服务间调用(FeignClient)、负载均衡(Ribbon)、容错/降级处理(Hystrix)

    FeignOpenFeign Feign是一种声明式.模板化的HTTP客户端. 看了解释过后,可以理解为他是一种 客户端 配置实现的策略,它实现 服务间调用(FeignClient).负载均衡(Rib ...

  3. SpringCloud系列之服务容错保护Netflix Hystrix

    1. 什么是雪崩效应? 微服务环境,各服务之间是经常相互依赖的,如果某个不可用,很容易引起连锁效应,造成整个系统的不可用,这种现象称为服务雪崩效应. 如图,引用国外网站的图例:https://www. ...

  4. SpringCloud之Hystrix:集群容错框架

    分布式环境中,可能会有一些被依赖的服务会失效,影响系统的稳定运行.Hystrix通过添加延迟阈值以及容错的逻辑,以控制分布式系统间组件的交互.Hystrix通过隔离服务间的访问点.停止它们之间的级联故 ...

  5. 微服务容错限流Hystrix入门

    为什么需要容错限流 复杂分布式系统通常有很多依赖,如果一个应用不能对来自依赖 故障进行隔离,那么应用本身就处在被拖垮的风险中.在一个高流量的网站中,某个单一后端一旦发生延迟,将会在数秒内导致 所有应用 ...

  6. 遗传算法框架GAFT优化小记

    前言 前段时间一直在用自己写的遗传算法框架测试算法在优化力场参数的效果,但是跑起来效率很慢,因为适应度函数需要调用多次力场程序计算能量,但是还是比我预想中的慢我也没有及时对程序进行profiling和 ...

  7. 【Spring Cloud】服务容错保护:Hystrix(四)

    一.雪崩效应 在微服务架构中,由于服务和服务之间可以互相调用,一项工作的完成可能会依赖调用多个微服务模块,但由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就 ...

  8. 2.4容错保护:Hystrix

    在ribbon使用断路器 改造serice-ribbon 工程的代码,首先在pox.xml文件中加入spring-cloud-starter-hystrix的起步依赖: 引入 <dependen ...

  9. Spring Cloud组件使用/配置小记

    仅使用,无多少技术含量,权记于此以备忘. 微服务架构下的主要组件 服务注册组件:Consul.Etcd等 网关:Zuul.Spring Cloud Gateway等 容错框架:Hystrix 负载均衡 ...

随机推荐

  1. matplotlib动态绘图

    目录 package Process 解决中文乱码问题 simple_plot() scatter_plot() three_dimension_scatter() Jupyter notebook ...

  2. LeetCode 739:每日温度 Daily Temperatures

    题目: 根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数.如果之后都不会升高,请在该位置用 0 来代替. 例如,给定一个列表 temperature ...

  3. mysql float类型详解

    mysql float类型详解float类型长度必须设置3以上 不然会报错 out of range如果设置3 就只是 整数+小数的长度 比方说3.23 3.2等等 3.333就不行了 4位了

  4. 2019.11.21 做OJ题的反思

    1.利用二分法查找数组元素(适用于有序数组) #include<stdio.h> int BinarySearch(int a[],int n,int key); ]; int main( ...

  5. mysql百万级数据分页查询缓慢优化-实战

    作为后端攻城狮,在接到分页list需求的时候,内心是这样的 画面是这样的 代码大概是这样的 select count(id) from …       查出总数 select * from …. li ...

  6. C++:class

    class 类是C++的一个重要概念,也是面向对象的一个重要内容.类的行为类似结构体,但功能比结构体的更强大.类是定义该类对象的一个模板,它告诉我们,一个类应该具有什么内容. 声明.定义 类用关键字c ...

  7. conda opencv cv2.imshow无法使用

    error: -------src-dir-------/opencv-2.4.10/modules/highgui/src/window.cpp:501: error: (-2) The funct ...

  8. C# SmtpClient 发邮件

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  9. C# winform 获取鼠标点击位置

    说明:该篇随笔的代码内容并非出自本人,是在其他网站搜寻的,出处已经不记得了,本次随笔只为记录,目的帮助自己,帮助他人. 实现的原理也不做多的赘述,直接上代码. 第一个类是需要用到的Windows AP ...

  10. NIO你真正了解多少?

    解释一下java.io.Serializable接口 类通过实现 Java.io.Serializable 接口以启用其序列化功能.未实现此接口的类将无法使其任何状态序列化或反序列化. IO操作最佳实 ...