服务雪崩效应
一种因服务提供者的不可用导致服务调用者的不可用,并将不可用逐渐放大的过程.
分布式系统中经常会出现某个基础服务不可用造成整个系统不可用的情况, 这种现象就是服务雪崩. 为了应对它, 一种常见的做法就是手动服务降级. 而Hystrix的出现,给我们提供了另一种选择.
服务雪崩效应可能的原因
服务提供者不可用
服务调用者不可用
说明:服务不可用的原因可能是硬件故障、程序Bug、缓存击穿、用户大量请求
为什么需要熔断器
当项目被划分为多个独立的服务,服务和服务之间需要远程调用,在这个过程中,不可避免的会遇到网络故障、被调用的服务本身造成服务调用延迟、调用失败等问题.可能会造成链式反应,从而影响这个应用的正常运行.这个时候,就需要使用熔断器Hystrix,它负责监控服务之间的调用情况,必要的时候就会进行熔断,从而实现对应用的保护.Hystrix常用于解决分布式系统交互时超时处理和容错等问题,阻止联动故障的发生,从而提升系统的可用性、容错性和弹性.
Hystrix设计思想
断路器是一种保护措施,比如当同时使用多种大功率电器的时候,电表箱就会跳闸,因为担心会过载所以在达到某一个阙值时就会跳闸,跳闸后就会完全切断电路,对整体电路起到保护的作用.Hystrix也正是基于这种思想.在 Hystrix 中调用某个依赖多次失败或者超时后,断路器就会处于打开状态.当断路器打开后再想要调用该依赖时 Hystrix 就不会允许了.
Hystrix-Fallback
Hystrix有一个非常重要的保护方法Fallback,当调用的服务出现故障时,就可以触发Fallback 方法.Hystrix 间隔一段时间会再次检查故障的服务,如果故障服务恢复了,将再次启用该服务.具体表现在,当Hystrix判定请求出现故障,会立马对请求做出响应动作,不会再继续执行正常请求逻辑,当然,请求线程也不会处于阻塞状态,从而有效防止雪崩效应.
Hystrix保护机制
1) 通过hystrixCommand或者HystrixObservableCommand来封装对外部依赖的访问请求,这个访问请求一般会运行在独立的线程中.
2) 对于超出我们设定的阈(yu)值的服务调用,直接进行超时返回,不允许它长时间的阻塞.
3) 对每一个依赖服务进行资源隔离.通过线程池或者是semaphore这两种方式.
4) 对依赖服务被调用的成功次数、失败次数、拒绝次数、超时次数进行统计(健康度).
5) 如果对某一个依赖服务的调用失败次数超过了一定的阈值,Hystrix自动进行熔断,并在一段时间内对该服务的调用直接进行降级,一段时间后再自动尝试恢复.
6) 当对一个服务调用出现失败、被拒绝、超时、短路等异常情况时,自动触发fallback.
Hystrix实践
Ribbon中使用熔断器
在 pom.xml 中增加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
在 springboot 入口中增加 @EnableHystrix 注解
@EnableDiscoveryClient //注册服务,以实现服务发现
@SpringBootApplication
@EnableHystrix //开启熔断模式
public class WebAdminRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(WebAdminRibbonApplication.class,args);
}
}
在 Ribbon 调用方法上增加 @HystrixCommand 注解并指定 fallbackMethod 熔断方法
/**
* 负载均衡式远程调用
*/
@Service
public class AdminService {
@Autowired
private RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "hiError")
public String sayHi(String message) {
//根据服务应用名进行远程调用(实现了负载均衡)
return restTemplate.getForObject("http://hello-spring-cloud-service-admin/hi?message=" + message, String.class);
}
public String hiError(String message) {
return String.format("hi your message is: %s ,but there is something error...",message);
}
}
测试熔断器
此时我们关闭服务提供者,再次请求 http://localhost:8888/hi?message=haha
浏览器会显示:
hi your message is: haha,but there is something error...
Feign 中使用熔断器
Feign 是自带熔断器的,但默认是关闭的.需要在配置文件中配置打开它,在配置文件增加以下代码:
feign:
hystrix:
enabled: true
在接口上指定熔断实现类
@FeignClient(value = "hello-spring-cloud-service-admin",fallback = AdminServiceHystrix.class) //对应远程调用服务的名称,同时指定熔断类
public interface AdminService {
@RequestMapping(value = "hi", method = RequestMethod.GET) //对应远程调用的具体服务项
String sayHi(@RequestParam(value = "message") String message); //对应远程调用的请求参数名
}
创建熔断器类并实现对应的 Feign 接口
/**
* 熔断实现类
*/
@Component
public class AdminServiceHystrix implements AdminService {
@Override
public String sayHi(String message) {
return String.format("hi your message is : %s ,but there is something error...",message);
}
}
测试熔断器
此时我们关闭服务提供者,再次请求 http://localhost:9999/hi?message=haha
浏览器会显示:
hi your message is: haha,but there is something error...