持续创作,加速成长!这是我参与「掘金日新计划 · 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;
}
}
好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊