使用Hystrix实现服务隔离

前言

虽然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());
 }
	
}

------------------------------------------------------------

欢迎关注我的公众号,获取更多信息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值