前言
虽然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;
@Service
public 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>{
@Autowired
TestHystrixService service;
public TestHystrixHandle(TestHystrixService service) {
super(setter());
}
@Override
protected 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);
}
@Override
protected 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 {
@Autowired
TestHystrixService service;
@RequestMapping("http1")
public String process()
{
return (new TestHystrixHandle(service).execute());
}
}
------------------------------------------------------------
欢迎关注我的公众号,获取更多信息