面试连环问之微服务高可用

196 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

1、前言

    在笔者刚从事程序猿工作的时候,记得有次面试,面试官问了这么一个问题:如果现在有个接口,需要去调用第三方服务,但是现在有时候总会超时,针对这种情况怎么去优化?当时回答的很浅显,就说设置好超时时间,进行熔断,避免服务雪崩。面试官接着问还有没有更好的解决方法。抓耳挠腮思索了一番,也没什么好方法。现在会想起,一是当时回答的太笼统、简单,二是面试官想听一整套解决方案,不是某个解决方法。其实,本质上这是一个如何去保证服务高可用的问题。那么知道了面试官到底想问什么,接下来就好说了。本次,就结合Hystrix为大家介绍下如何保证服务高可用。

2、Hystrix基本介绍

    在微服务系统中,有时候一个服务可能依赖多个服务,比如说:订单服务依赖于商品服务,A服务依赖于B服务,B服务又依赖于C服务这样,形成了一条依赖链。那么,如果说C服务因为网络原因或者其他故障,不能对外响应,进而造成请求堵塞堆积,tomcat线程资源耗尽,就可能会造成B服务不可用,进而A服务不可用,最后导致服务雪崩。这个时候我们就需要一套容错机制,对依赖服务进行资源隔离。Hystrix就可以来帮我们解决这些问题。

    Hystrix是网飞公司开源的一套高可用性保障框架。它可以:1)对依赖服务调用时出现的调用延迟和调用失败进行控制和容错保护,防止服务雪崩;2)具有快速失败和快速恢复机制;3)支持服务降级;4)还支持近实时的监控、报警等;

3、基于timeout机制,解决接口超时问题

1、pom文件引入Hystrix依赖

<!--熔断器-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.3.5.RELEASE</version>
</dependency>
<!--应对没有HystrixCommand注解-->
<dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-javanica</artifactId>
</dependency>

2、修改配置文件

#开启hystrix支持
feign:
  hystrix:
    enabled: true 
hystrix:
  command:
    default:
      circuitBreaker:
        #触发断路器时,服务休眠时间
        sleepWindowInMilliseconds: 5000
        #触发断路器时,最小错误比率
        errorThresholdPercentage: 50
        #在一个时间窗口内(10s)触发断路器的最小请求量
        requestVolumeThreshold: 20
      execution:
        isolation:
          thread:
            #请求等待超时时间
            timeoutInMilliseconds: 3000
        timeout:
          # false则熔断器不进行超时
          enabled: true 
  threadpool:
    default:
      #并发执行的最大线程数,默认10
      coreSize: 200 
      #BlockingQueue的最大队列数,默认值-1
      maxQueueSize: 1000 
      #即使maxQueueSize没有达到,达到queueSizeRejectionThreshold该值后,请求也会被拒绝,默认值5
      queueSizeRejectionThreshold: 800 
 

上面的配置,是整个服务用的默认配置,那么如果调用的三方接口是个无关紧要的功能,优先保证主流程。我们就需要将超时时间设置的更短一些。下面就为大家介绍下,基于@HystrixCommand注解来实现。

@Component
public class SfHttpComponent {
 
    /**
     * 请求三方系统获取Banner等信息
     * @param url
     * @param params
     * @return
     * @throws UnsupportedEncodingException
     */
    @HystrixCommand(commandKey = "sfQueryHttp", fallbackMethod = "getSfQueryInfoFallBack", commandProperties = {
            //设置超时时间,默认1000(ms)
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "500"),
            //启用fallback方法回退
            @HystrixProperty(name = "fallback.enabled", value = "true"),
            //启用断路器
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
            //该属性用来设置在滚动时间窗中,断路器熔断的最小请求数。例如,默认该值为20的时候,
            //如果滚动时间窗(默认10秒)内仅收到了19个请求,即使这19个请求都失败了, 断路器也不会打开。
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
            // 该属性用来设置在熔动时间窗中表示在滚动时间窗中,在请求数量超过
            // circuitBreaker.requestVolumeThreshold 的情况下,如果错误请求数的百分比超过50,
            //就把断路器设置为“打开”状态,否则就设置为“关闭”状态。
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
            //熔断器打开后,所有请求都会快速失败,然后过一段时间,Hystrix会放行一个请求,进行测试是否恢复,如果恢复则关闭熔断器。
            // 这个属性就是用于指定熔断器开启后过多久会进行一次尝试,默认是5000毫秒
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000")
    }, groupKey = "SfHttpRequest")
    public String getSfQueryInfo(String url, Map<String, Object> params) throws UnsupportedEncodingException {
        Map<String, Object> header = new HashMap<>();
        header.put("Content-Type", "application/json");
        header.put("project-name", "default");
        if (CollectionUtils.isEmpty(params)) {
            return StringUtils.EMPTY;
        }
        params.put("log_id", UUID.randomUUID());
        logger.info("请求三方接口,请求地址:{},header:{},参数:{}", url, header, params);
        return HttpRequestPoolUtil.httpPostRawJsonRequest(url, header, params);
    }

    public String getSfQueryInfoFallBack(String url, Map<String, Object> params, Throwable throwable){
        logger.error("请求三方信息触发熔断策略,请求地址:{},请求参数:{},错误信息:{}", url, params, throwable.getMessage(), throwable);
        return StringUtils.EMPTY;
    }

}

好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊