在分布式环境中,许多服务依赖项中的一些必然会失败。Hystrix是一个库,通过添加延迟容忍和容错逻辑,帮助你控制这些分布式服务之间的交互。Hystrix通过隔离服务之间的访问点、停止级联失败和提供回退选项来实现这一点,所有这些都可以提高系统的整体弹性。
线程隔离的意思是服务A调用服务B、服务C、服务D的时候,如果服务D出了问题,那么服务A之前调用服务D的线程就全都阻塞了,随着不断有新的服务A进来,服务A的web容器中的线程就会不断增加,然后不断阻塞,随后把CPU撑爆。
所以我们需要线程隔离技术把服务A和服务D的执行线程隔离开来,hystrix提供了两种线程隔离技术,分别是线程池隔离和信号量隔离。
线程池隔离是指服务A调用服务D的时候,Hystrix另外搞一个新的线程池,从中取线程来执行服务D的调用,这个线程池跟服务A的web容器线程池是独立的,这样服务D的调用就不会服务A的web容器线程池。
信号量隔离是指服务A调用服务D的时候,Hystrix限制服务A调用服务D的web容器线程数,比如只允许10个线程可以调用服务D,这样就算服务D挂了,服务A的web容器线程数也只有10个不能用,不影响其它线程。
线程池隔离适用于有网络延迟的RPC调用,信号量隔离适用于无网络延迟的本地调用。
所谓服务熔断是一个整体的概念,它是说如果服务A调用服务B,服务B挂了,那么就把服务B熔断掉,以免影响服务A的运行。把服务B熔断掉,其实就是开启断路器,也就是服务降级。
服务熔断的方式有两种,分别是直接使用Hystrix的注解@HystrixCommand,和使用spring cloud 的feign组件。
服务降级的意思,就是服务在熔断之后,进入降级的方法,返回其它的结果,比如,返回一些友好的访问失败信息等。
服务降级的的时机包括如下几种:
服务降级之后,会走参数fallbackMethod里面的配置的方法。如果fallbackMethod的方法也需要调用其它的微服务,那这个方法也需要加注解@HystrixCommand,避免这个降级服务也就访问挂了。
断路器,英文名也circuitBreaker,就是加在服务调用之前的一套拦截器,它包括三种状态,分别是开启、关闭、半开,三种状态之间的切换时机如下:
默认关闭——>开启:requestVolumeThreshold以及errorThresholdPercentage同时超出设置的阀值,就开启断路器;
开启——>半开:断路器开启之后,可以通过sleepWindowInMiliseconds设置一个休眠期,默认是5秒。这5秒之内,断路器是开启状态,一旦5秒时间一到,就会暂时进入半开状态,这时候,断路器会尝试发送一个命令,看看当前请求是否还是超过上面的两个阀值。
半开——>开启:如果上面半开状态下,断路器发送命令之后,发现服务还是访问失败,那么继续进入开启状态,等待下次5秒后再进入半开状态。
半开——>关闭:如果上面半开状态下,断路器发送命令之后,发现服务访问OK了,也不超过那两个阀值了,那说明服务状态良好,就把断路器关了。
服务的请求缓存,是hystrix提供一种web服务本地缓存机制,在开启Hystrix的请求缓存之后,如果同一个微服务调用请求且参数相同时,并直接通过本地缓存返回结果,不用再调用微服务。
@CacheResult加在需要本地缓存的方法上面;
@CacheRemove加在需要清除本地缓存的方法上面,通过key配置需要清除的缓存key
注意,hystrix请求缓存本质上是一个filter,所以需要再写一个Filter类初始化Hystrix的请求缓存Filter。
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
package com.mazong.serverblogarticle;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class ServerBlogArticleApplication {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ServerBlogArticleApplication.class, args);
}
}
/**
* 降级函数getArticle
* @param id
* @return
*/
public Object fallGetArticle(Integer id) {
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("fallGetArticle", "服务熔断了!!!");
System.out.println(resultMap);
return resultMap;
}
@RequestMapping(value = "/getArticle")
@ResponseBody
@HystrixCommand(fallbackMethod = "fallGetArticle")
public Object getArticle(@RequestParam("id") Integer id) {
// ... 省略
return null;
}
配置使用的步骤:
(1)引入依赖
(2)启动类中激活
(3)配置熔断触发逻辑
(4)在需要保护的接口上使用@HystrixCommand
public Object defaultCallback() {
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("fallGetArticle", "统一级别服务降级了!!!");
System.out.println(resultMap);
return resultMap;
}
注意:统一函数不能有参数。返回值要保持一致。
@Controller
@RequestMapping("/")
@DefaultProperties(defaultFallback = "defaultCallback")
public class ArticleController {
// ... 省略
}
@RequestMapping(value = "/getArticle")
@ResponseBody
@HystrixCommand
public Object getArticle(@RequestParam("id") Integer id) {
// ... 省略
}
参考文档: