前言
虽然Netflix在多年之前,已经停止更新Hystrix,但是Hystrix在国内依然在广泛使用,Hystrix主要作用是实现服务隔离与保护,以及熔断与降级。
服务隔离
一般在使用tomcat容器时,http服务用共用一个线程池,当一个http服务访问后端出现响应慢异常时, 造成了服务响应延迟。当多个请求集中在这一个服务上时,这会导致该服务调用的所有线程被阻塞,直致线程池中线程都被耗尽,最终导致整个服务崩溃,这也是通常所说的雪崩效应。
使用服务隔离,就是对不同的服务分配不同的线程池,当一个服务出现异常时,不会对其它服务造成影响。

例如上图所示,假如线程池中有10个线程,我们提供两个http服务1和2,分别调用后端服务A和B,正常情况下,服务1和2在调用完A和B,之后,会释放资源进入线程池中;假如后端服务A出现异常 ,调用服务A的线程出现阻塞情况,并且恰好大量服务持续调用服务1,那调用服务2的线程在回收完之后,会立马被服务1占用,并且这十个线程都处理阻塞状态,线程池中的线程被 耗光殆尽。这时,我们再发请http请求时,不管是请求1还是请求2,由于线程池中没有可用线程,因为所有的调用服务都会失败,整个系统就处理瘫痪状态。

使用hystrix后,如上图所示,hystrix会为http服务1和2分别分配两个线程为5的线程池,在上述同样的情况下,假如服务A出现故障,http1服务受阻,那池程池1中的五个线程被耗尽;与此同时,线程池2中的线程,由于服务B一切正常 ,所以线程可以不断循环回收,以此来保证http服务2不受影响。
服务隔离一般分为两种方案,一是线程隔离,一是信号量隔离
线程池隔离使用场景 ,一般为第三方应用,并发量较大的情况下使用
信号量隔离使用场景,一般为内部调用,并发量较小的情况下使用
代码实现
1.首先引入maven依赖,本次演示使用1.5.18版本
<dependency><groupId>com.netflix.hystrix</groupId><artifactId>hystrix-metrics-event-stream</artifactId><version>1.5.18</version></dependency>
2.编写服务层代码,用于发送http请求
package hystrix.service;import java.io.IOException;import org.apache.http.HttpStatus;import org.apache.http.client.config.RequestConfig;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpPost;import org.apache.http.entity.StringEntity;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.util.EntityUtils;import org.springframework.stereotype.Service;@Servicepublic class TestHystrixService {public String service1(){return httpPost("http://localhost:8080/test","test");}public static String httpPost(String url, String strParam) {RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000).build();CloseableHttpClient httpClient = HttpClients.createDefault();String result = null;HttpPost httpPost = new HttpPost(url);httpPost.setConfig(requestConfig);try {if (null != strParam) {StringEntity entity = new StringEntity(strParam, "utf-8");entity.setContentEncoding("UTF-8");entity.setContentType("application/x-www-form-urlencoded");httpPost.setEntity(entity);}CloseableHttpResponse resp = httpClient.execute(httpPost);if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {try {result = EntityUtils.toString(resp.getEntity(), "utf-8");} catch (Exception e) {}}} catch (IOException e) {} finally {httpPost.releaseConnection();}return result;}}
3.编写handle继承HystrixCommand方法,并设置各种参数
package hystrix.handle;import org.springframework.beans.factory.annotation.Autowired;import com.netflix.hystrix.HystrixCommand;import com.netflix.hystrix.HystrixCommandGroupKey;import com.netflix.hystrix.HystrixCommandKey;import com.netflix.hystrix.HystrixCommandProperties;import com.netflix.hystrix.HystrixThreadPoolKey;import com.netflix.hystrix.HystrixThreadPoolProperties;import hystrix.service.TestHystrixService;public class TestHystrixHandle extends HystrixCommand<String>{@AutowiredTestHystrixService service;public TestHystrixHandle(TestHystrixService service) {super(setter());}@Overrideprotected String run() throws Exception {return service.service1();}private static Setter setter() {// 服务分组HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("http1s");// 服务标识HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey("svc1");// 线程池名称HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey("http1-pool");// 线程池配置HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter().withCoreSize(10).withKeepAliveTimeMinutes(15).withQueueSizeRejectionThreshold(100);HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter().withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD).withExecutionTimeoutEnabled(true);return HystrixCommand.Setter.withGroupKey(groupKey).andCommandKey(commandKey).andThreadPoolKey(threadPoolKey).andThreadPoolPropertiesDefaults(threadPoolProperties).andCommandPropertiesDefaults(commandProperties);}@Overrideprotected String getFallback() {return "系统错误!";}}
4.编写控制层代码
package hystrix.controller;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import hystrix.handle.TestHystrixHandle;import hystrix.service.TestHystrixService;public class TestController {@AutowiredTestHystrixService service;@RequestMapping("http1")public String process(){return (new TestHystrixHandle(service).execute());}}




