Hystrix实现服务隔离和降级

背景

在分布式环境下,服务之间有大量的依赖,单个依赖故障时的容灾是个很重要的话题。

伴随着业务复杂性的提高,系统的不断拆分,一个面向用户端的API,其内部的RPC调用层层嵌套,调用链条可能会非常长。这会造成以下问题:API接口可用性降低。

引用Hystrix官方例子,如果一个服务依赖30个子服务,子服务都是99.99%的可用性,那么该服务可用性为99.99%的30次方 = 99.7%,即0.3%的失败率。从请求数量上讲,一亿次请求中如果有0.3%的失败,失败次数是300万。从时间上讲,上述服务相当于每个月有2个小时的不可用时间。

名称解释

服务熔断

类似现实世界中的“保险丝”,当某个异常条件被触发,直接熔断整个服务,而不是一直等到此服务超时。 熔断的触发条件可以依据不同的场景有所不同,比如统计一个时间窗口内失败的调用次数。

保证每个服务互不影响,使用信号量和线程池方式

服务降级

一般是从整体负荷考虑。就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值。 这样做虽然服务水平下降,但好歹可用,比直接挂掉要强,当然这也要看适合的业务场景。

当服务不可用的时候,不会被等待,直接返回一个友好的提示

服务隔离

每个服务接口互不影响,服务隔离有两种实现方式线程池方式、计数器。当服务产生堆积的时候,对服务实现保护功能。

当服务器达到最大的承受能的之后,直接拒绝访问服务,最会调用服务降级方法,返回友好提示。目的是保证服务不被宕机掉

Hystrix是什么

介绍

Hystrix 是有 Netflix 开源的一个针对分布式系统容错处理的开源组件。Hystrix单词意为"豪猪”,浑身有刺来保护自己,Hystrix 就是这样一个用来捍卫应用程序健康的利器。

Hystrix 是一个延迟和容错库,旨在隔离远程系统、服务和第三方库,阻止级联故障,在复杂的分布式系统中实现恢复能力。

设计目标

  1. 通过客户端库对延迟和故障进行保护和控制。
  2. 在一个复杂的分布式系统中停止级联故障。
  3. 快速失败和迅速恢复。
  4. 在合理的情况下回退和优雅地降级。
  5. 开启近实时监控、告警和操作控制。

做了什么事

  • 资源隔离:包括线程池隔离和信号量隔离,避免某个依赖出现问题会影响到其他依赖。
  • 断路器:当请求失败率达到一定的阈值时,会打开断路器开关,直接拒绝后续的请求,并且具有弹性机制,在后端服务恢复后,会自动关闭断路器开关。
  • 降级回退:当断路器开关被打开,服务调用超时/异常,或者资源不足(线程、信号量)会进入指定的fallback降级方法。
  • 请求结果缓存:hystrix实现了一个内部缓存机制,可以将请求结果进行缓存,那么对于相同的请求则会直接走缓存而不用请求后端服务。
  • 请求合并:可以实现将一段时间内的请求合并,然后只对后端服务发送一次请求。

核心概念

资源隔离

Hystrix的资源隔离策略有两种,分别为:线程池信号量

线程池隔离:为每一个依赖创建一个线程池来处理来自该依赖的请求,不同的依赖线程池相互隔离,就算依赖A出故障,导致线程池资源被耗尽,也不会影响其他依赖的线程池资源。

优点:支持排队和超时,支持异步调用。

缺点:线程的创建一个调度会造成一定的性能开销。

信号量隔离:初始化信号量currentCount=0,每进来一个请求需要先将currentCount自增,再判断currentCount的值是否小于系统最大信号量,小于则继续执行,大于则直接返回,拒绝请求。

优点:轻量,无额外的开销,只是一个简单的计数器。

缺点:不支持任务排队和主动超时,不支持异步调用。

隔离方式是否支持超时是否支持熔断隔离原理是否异步调用资源消耗适用场景
线程池隔离支持,可直接返回支持,当线程池到达maxSize后,再请求会触发fallback接口进行熔断每个服务单独用线程池,请求线程与转发处理线程不是同一个可以是异步,也可以是同步。看调用的方法大,大量线程的上下文切换,容易造成机器负载高适合耗时较长的接口场景,因为线程池模式的请求线程与实际转发线程不是同一个,所以可以保证容器有足够的线程来处理新的请求。比如接口处理逻辑复杂,且与第三方中间件有交互。
信号量隔离不支持,如果阻塞,只能通过调用协议(如:socket超时才能返回)支持,当信号量达到maxConcurrentRequests后。再请求会触发fallback通过信号量的计数器,请求线程与转发处理线程是同一个同步调用,不支持异步小,只是个计数器适合能快速响应的接口场景,不适合一些耗时较长的接口场景,因为信号量模式下的请求线程与转发处理线程是同一个,如果接口耗时过长有可能会占满容器的线程数。

断路器

断路器工作原理如图:

 

Hystrix是基于滚筒式来处理,每一秒会产生一个buckets,每产生一个新的buckets就会移除一个最老的buckets,默认是10秒一个窗口。buckets在内存中就是一种数据结构,每个buckets会记录Metrics的相关数据,比如成功、失败、超时、拒绝。

当一个HystrixCommand进来后,会先通过allowRequest()方法判断是否允许通过该次请求,allowRequest()方法会通过isOpen判断断路器是否打开。断路器关闭,则允许通过该次请求;断路器打开,则会判断是否过了睡眠周期。没有过睡眠周期则返回false,拒绝通过该次请求,过了睡眠周期则会尝试放行。

isOpen()方法会按照(failure) / (success+failure)公式计算出失败率,如果失败率大于阈值,则会触发熔断。公式中的成功、失败的数据就来源于每10秒中一个窗口的滚筒数据。

对于一个依赖调用,要么调用成功,要么调用失败(包括异常、超时、拒绝),这些调用结果都会记录到buckets中。对于调用成功结果来说,还会判断断路器开关是否打开,如果是打开状态的话,则会关闭断路器并重置相关的计数器。

降级回退

降级,通常指事务高峰期,为了保证核心服务正常运行,需要停掉一些不太重要的业务,或者某些服务不可用时,执行备用逻辑从故障服务中快速失败或快速返回,以保障主体业务不受影响。

Hystrix提供的降级主要是为了容错,保证当前服务不受依赖服务故障的影响,从而提高服务的健壮性。

进入降级逻辑的情况

  • 断路器打开
  • 线程池/信号量资源不足
  • 执行依赖调用超时
  • 执行依赖调用异常

请求结果缓存

实际应用场景很少,不做介绍,如图:

请求合并

实际应用场景很少,不做介绍,如图:

 

快速开始

引入相关依赖

引入Hystrix包,如下所示:

<dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

启用断路器模式

开启断路器注解,在启动类添加@EnableHystrix注解。

@SpringBootApplication
@EnableHystrix
@EnableDiscoveryClient
public class ClientApplication {
    public static void main(String[] args) {
         SpringApplication.run(ClientApplication.class, args);
    }
}

增加@HystrixCommand和降级fallback

在业务代码中增加@HystrixCommand和降级fallback

@HystrixCommand(fallbackMethod="defaultUser")
public String getUser(String username) throws Exception {
     if(username.equals("spring")) {
           return "This is real user";
     }else {
           throw new Exception();
     }
}

/**
* 出错则调用该方法返回友好错误
*/
public String defaultUser(String username) {
     return "The user does not exist in this system";
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值