服务熔断降级简介
背景 在微服务中,当一切正常时,请求流看起来是这样的: 当其中有一个服务(例如服务I)有延迟时,它可能阻塞整个用户请求: 在高流量的情况下,一个依赖服务的延迟可能导致服务器上的所有资源在数秒内饱和,这也意味着后续再有请求将无法立即提供服务:解决方案 当使用熔断降级框架时,框架会包装每个依赖项,原有架构会发生变化,每个依赖项相互隔离,当延迟发生时,它会被限制在资源中,并包含回...
背景
很多网站背后都是一个庞大的分布式系统,多个子系统之间的调用大多是远程调用,要么HTTP要么RPC,这种远程调用其实是不可控的,当调用链越长,风险也就越大。
在微服务中,当一切正常时,请求流看起来是这样的:
当其中有一个服务(例如服务I)有延迟时,它可能阻塞整个用户请求:
在高流量的情况下,一个依赖服务的延迟可能导致服务器上的所有资源在数秒内饱和,这也意味着后续再有请求将无法立即提供服务:
解决方案
当使用熔断降级框架时,框架会包装每个依赖项,原有架构会发生变化,每个依赖项相互隔离,当延迟发生时,它会被限制在资源中,并包含回退逻辑,以决定在依赖项中发生故障时应作出何种响应:
基础概念
服务雪崩
当微服务A调用微服务B,B调用C和其他微服务,当调用链上某个服务不可用或响应时间过长,网关路由到A上的请求就会占用越来越多的系统资源,导致系统崩溃,这种现象称作雪崩效应。
在分布式系统中,为了保证服务的可用性,我们一般会加入重试机制,在有些情况下,重试确实能解决问题,比如网络抖动等。但是有些情况下,重试只会加剧问题的严重性,会给下游服务造成极大的资源压力。
重试不行,不重试也不靠谱,那我们怎么预防服务雪崩呢?答案是熔断器模式
熔断器模式
熔断器模式(Circuit Breaker Pattern)是一种现代软件开发的设计模式,用来侦测错误,避免不断的触发相同错误导致的灾难性后果。一个完善的熔断器一般有三种状态:
- 关闭
- 默认情况是关闭的,熔断器本身自带计数器的功能,每当错误发生一次,计数器会累加,当达到一定条件时,熔断器就会自动跳到开启状态。
- 开启
- 在开启状态下,任何请求都会直接被拒绝,并且抛出异常信息。
- 半开启
- 在此状态下,断路器会允许部分请求通过,当通过的请求全部成功响应时,断路器会自动关闭。
- 在此状态下,断路器会允许部分请求通过,当通过的请求全部成功响应时,断路器会自动关闭。
如果在微服务中引入断路器模式,那么整个分布式系统将天然具备快速失败和无缝恢复的功能。
服务熔断
一般是某个服务故障或者是异常引起的,类似于“保险丝”,当某个异常条件被触发,为了防止服务雪崩,直接熔断服务,而不是一直等到此服务超时。
典型的熔断场景:例如过载保护,当请求线程数过多时被限流,
服务降级
当服务器压力剧增时,根据当前业务情况及流量,对一些非核心服务进行有策略的停服,缓解服务器资源压力,以保证核心业务的正常运行。
- 自动降级:超时、失败次数过多、故障
- 响应时间超过配置的超时时间(异步机制探测回复情况)
- 不稳的API调用次数达到一定数量(异步机制探测回复情况)
- 调用的服务出现故障(HTTP状态码、网络故障、RPC服务异常)
- 人工降级:秒杀、双十一大促,非核心服务停服
熔断和降级异同
- 相同点
- 从可用性和可靠性触发,为了防止系统崩溃
- 最终让用户体验到的是某些功能暂时不能用
- 不同点
- 服务熔断一般是下游服务故障导致的
- 服务降级一般是从整体系统负荷考虑,由调用方控制
Hystrix
配置
circuitBreaker.requestVolumeThreshold // 滑动窗口的大小,默认为20
circuitBreaker.sleepWindowInMilliseconds // 过多长时间,熔断器再次检测是否开启,默认为5000,即5s
circuitBreaker.errorThresholdPercentage // 错误率,默认50%
这几个参数所表达的意思是:每当20个请求中,有50%失败时,断路器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。5s之后,重新检测该触发条件,判断是否把断路器关闭。
断路器打开之后,这种错误情况不可能直接传给用户,所以需要准备一个本地的fallback
回调函数,返回一个缺省值。
熔断降级代码示例
@GetMapping("/user/{id}")
@HystrixCommand(fallbackMethod ="hystrix_GET")
public User findById(@PathVariable("id") Integer id) {
User user = userService.findById(id);
if (null == user) {
throw new RuntimeException("user not found");
}
return user;
}
// 回调函数
public User hystrix_GET(@PathVariable("id") Integer id) {
log.info("in fallbackMethod ..");
return null;
}
启动类上加
@EnableCircuitBreaker
注解,开启服务熔断机制
Feign代码示例
@Component
public class UserClientFallback implements FallbackFactory<UserService> {
@Override
public UserService create(Throwable throwable) {
return new UserService() {
@Override
public User findById(Integer id) {
log.info("停服...");
return null;
}
@Override
public List<User> findAll() {
log.info("停服...");
return null;
}
};
}
}
@FeignClient(value = "user-client",fallbackFactory = UserClientFallback.class)
public interface UserClient {
@GetMapping("/user/{id}")
public User findById(@PathVariable("id") Integer id);
@GetMapping("/user")
public List<User> findAll();
}
feign: # 开启feign熔断降级功能
hystrix:
enabled: true
Sentinel
熔断降级代码示例
@Service
public class TestService {
@SentinelResource(value = "sayHello", blockHandler = "sayHelloBlockHandler")
public String sayHello(String name) {
return "Hello, " + name;
}
public Object sayHelloBlockHandler(String name, BlockException ex) {
log.warn("Sentinel fallback", ex);
return "Service down";
}
}
@RestController
public class TestController {
@Autowired
private TestService service;
@GetMapping(value = "/hello/{name}")
public String apiHello(@PathVariable String name) {
return service.sayHello(name);
}
}
Feign代码示例
@FeignClient(name = "service", fallback = ServiceFallback.class, configuration = FeignConfig.class)
public interface Service {
@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
String echo(@PathVariable("str") String str);
}
class FeignConfig {
@Bean
public ServiceFallback serviceFallback() {
return new ServiceFallback();
}
}
class ServiceFallback implements Service {
@Override
public String echo(@PathVariable("str") String str) {
return "echo fallback";
}
}
熔断降级框架比较
Sentinel | Hystrix | resilience4j | |
---|---|---|---|
隔离策略 | 信号量隔离(并发线程数限流) | 线程池隔离/信号量隔离 | 信号量隔离 |
熔断降级策略 | 基于响应时间、异常比率、异常数 | 基于异常比率 | 基于异常比率、响应时间 |
实时统计实现 | 滑动窗口(LeapArray) | 滑动窗口(RxJava) | Ring Bit Buffer |
动态规则配置 | 支持多种数据源 | 支持多种数据源 | 有限支持 |
扩展性 | 多个扩展点 | 插件的形式 | 接口的形式 |
基于注解的支持 | 支持 | 支持 | 支持 |
限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 | Rate Limiter |
流量整形 | 支持预热模式、匀速器模式、预热排队模式 | 不支持 | 简单的 Rate Limiter 模式 |
系统自适应保护 | 支持 | 不支持 | 不支持 |
控制台 | 提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等 | 简单的监控查看 | 不提供控制台,可对接其它监控系统 |
Hystrix官网,Hystrix已停止维护,Netflix官方推荐使用resilience4j,它更轻量,支持函数式接口和lambda表达式等使用方式,更加优雅。
Sentinel官网
更多推荐
所有评论(0)