多外部下游服务线程隔离

一、问题背景        

        我们的系统中有一个微服务(以下简称A服务)需要调用多个部署在各省(市)的外部服务(简称B服务,一共有30多个B服务),不同省(市)网络、硬件性能不同,所以省市系统的处理数据能力有很大差异,平均响应时间超过5秒,部分省系统平均响应时间超过10秒,A服务调用所有B服务超时时间设置为30秒。

二、问题现象

        恰逢其会,某日某省网络不知什么原因出现问题,A服务调用该省B服务推送数据大量超时,因为,因为超时时间较长,导致A的上游服务请求积压,A服务的连接池被沾满,导致A服务不能继续接收请求,导致业务终端几个小时,也就是一个外部服务的错误导致全国所有省市的用户都不能使用系统服务。

三、解决思路

        计划使用Hystrix的线程隔离功能,实现A服务调用各省B服务时的线程隔离,从而因各种原因导致的某省B服务响应能力不佳时,其他省市用户仍能正常使用业务。

        使用Hystrix命令来实现线程隔离时,有三个关键的Key:groupKey、commandKey和threadPoolKey,groupKey缺省为@HystrixCommand标注的类名,commandKey缺省是@HystrixCommand标注的方法名,threadPoolKey缺省与groupKey相同,这三个键均可以通过注解来修改。Hystrix根据threadPoolKey进行隔离,不同的threadPoolKey对应不同的线程池。根据系统实际情况,应该把各省(市)B服务的URL作为threadPoolKey。如果采用注解的方式来配置线程隔离,因为threadPool是需要提前配置的,所以就需要用HystrixCommand进行30多处注解,在分发用户的请求时,如果不使用反射,那么就意味着有一个30多个分支的switch-case,实在是丑陋之极,所以决定使用继承HystrixCommand类的方法。

四、代码片段

class MyCommand extends HystrixCommand {
    private String url; //省B服务的地址
    private String msg; //发送到省的数据

    public MyCommand(String url, String msg){
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory
                .asKey("Send2ProvinceCommandGroup"))
                .andCommandKey(HystrixCommandKey.Factory.asKey("Send2ProvinceCommand"))
                .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(url))
                .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                        .withExecutionTimeoutInMilliseconds(10000)));
        this.url = url;
        this.msg = msg;
    }
    @Override
    protected BaseRes run(){
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate.getForObject(url, BaseRes.class);
    }
    @Override
    protected BaseRes getFallback(){
         return BaseRes.getInstance(ErrorCodeEnum.FORWARD_PROVINCE_AUTH_FAILURE);
     }
}

你可能感兴趣的:(spring,boot,spring,cloud)