1 背景
业务定时器利用中午常常会触发熔断异样的告警邮件
依据邮件提醒的类找到演绎以下表格
编号 | 报错办法 | 接口所属利用 | 所属定时工作类 |
---|---|---|---|
A | VipTradeReportFeignService#getShopTradeReportByDate | pinka-mod-stats | ShopOrderSturctureTask |
B | VipMemberStatsFeignService#statMemberRecord | pinka-mod-stats | MemberStatTask |
C | VipPartnerWalletFeignService.handlePartnerWithdraw | pinka-mod-customer | PartnerWithdrawCheckTask |
D | VipWeixinBabyActivityFeignService.getBabyActivityNoticePage | pinka-mod-weixin | VipWeixinBabyNoticeTask |
以上 A~D 都是在一个分布式定时器事件处理利用 (pinka-mod-scheduler) 中对外的 feign 微服务调用产生的,相当于 4 类工作,每类都会调 1 次或屡次内部 feign 微服务接口,而其中的 A~D 接口产生了问题
其中 A 和 B 都是如下模式的异样
com.netflix.hystrix.exception.HystrixTimeoutException
at com.netflix.hystrix.AbstractCommand$HystrixObservableTimeoutOperator$1$1.run(AbstractCommand.java:1154)
at com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable$1.call(HystrixContextRunnable.java:45)
at com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable$1.call(HystrixContextRunnable.java:41)
...
而 C 和 D 都是如下模式的异样
feign.RetryableException: 10.13.32.111:56000 failed to respond executing POST http://pinka-mod-customer/vip/partner/wallet/handlePartnerWithdraw
at feign.FeignException.errorExecuting(FeignException.java:67)
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:104)
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76)
at feign.hystrix.HystrixInvocationHandler$1.run(HystrixInvocationHandler.java:114)
...
Caused by: org.apache.http.NoHttpResponseException: 10.13.32.111:56000 failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
...
2 追究
2.1 HystrixTimeoutException 超时异样
A 与 B 的异样简直每天都产生,且提醒很显著,是 Hystrix 中设置了超时工夫(目前为 10s),并且执行超时导致的。为何会超时?去接口实现发现是有 for 循环场景的耗时逻辑
通过 Kibana 日志零碎查历史执行耗时,也能够发现都根本 >13s,所以这类异样根本确因
2.1.1 解决与思考
这其实是一个很典型场景,定时器工作执行并且解决逻辑是在另外一个微服务中,而解决逻辑属于简单耗时,怎么办?
A. 减少超时工夫,这是个粗犷的思路,因为设长了可能导致更大的问题,因为超时原本就是为了 fastfail,设 20s 那之后可能还会遇到要 30s 甚至更久的场景。所以这个计划不能用在所有调用的公共默认超时工夫上;
然而能够思考用在某些接口上,比方 VipTradeReportFeignService#getShopTradeReportByDate 接口评估失常耗时就是要 15s 以上,那就独自为其设置。相干配置形式:
# 默认公共超时
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=10000
#独自为某个 feign 接口设置超时
hystrix.command."FeignService#sayHello(String)".execution.isolation.thread.timeoutInMilliseconds=15000
B. 优化接口提供方的逻辑执行工夫。比方上述 VipTradeReportFeignService#getShopTradeReportByDate 中的 for 循环,是否移到接口调用方,相当于接口提供方每次只执行 for 循环的 1 次操作。说白了就是确保接口返回要在超时工夫内,这也合乎微服务接口的设计准则。
C. 还有种思路是接口解决异步化,即接口提供方立即返回,本人再用异步线程去解决最终逻辑。然而单纯这样会导致工作执行不牢靠,即接口返回胜利不代表实在肯定执行胜利了,如果此时接口提供方重启或异样导致耗时的异步逻辑执行一半就中断了,反而无奈利用分布式定时任务调度的机制去重试执行等。所以应用此思路时,接口立即返回但不能立即将工作也作为胜利执行结束,须要配合一些异步告诉机制,即接口提供方实在胜利完结耗时操作,告诉给接口调用方,接口调用方再将工作作为胜利返回上报。
2.2 feign.RetryableException failed to respond executing 异样
这是 C 和 D 的异样,是随机低频告警。看字面意思是接口申请无响应,再联合邮件中的“熔断”字眼就天然揣测是接口提供利用的问题了(预先证实被“熔断”字眼坑了)。所以去追究接口所属利用 pinka-mod-customer 在告警前后的监控指标,发现 tcp 连贯、CPU、内存、网络流量体现都没什么异样情况。另外如果是熔断,那此接口必然得是调用失败屡次呀,而每次定时工作对该接口调用却只有一次。
这时候查看接口提供方 Controller 层日志,发现告警时刻的确提供方没进入 controller 解决。
由此揣测,提供方利用自身并无问题。而查看调用方利用日志和性能指标,在那个时刻也无异常情况,还在一直向其余利用调用产生日志。再联合这个异样日志,揣测起因是 因为调用方与提供方某次调用的网络闪断导致的(所以是随机低频)。
但为何会开启“熔断”,这个还无法解释。此时去追究邮件告警的代码源头,告警实质是通过重写了 openfeign 官网的 HystrixCommand 创立逻辑中的 getFallback 办法实现的,即进入 fallback 逻辑就会发邮件
此时水落石出了,其实只是进了 fallback 降级,并不代表开启熔断,比方在 HystrixCommand 的 run 中抛出异样会进 fallback,run 执行超时会进 fallback,熔断也会进 fallback。即 A~D 这些异样,尽管邮件写的是熔断,但其实都没开启熔断,而只是进了 fallback 降级!
所以 feign.RetryableException failed to respond executing 这个其实只是一次偶尔的调用失败进了 fallback 而已,并没之前猜测的那么简单。
2.2.1 解决与思考
邮件告警逻辑天然是要批改,辨别熔断和降级。如果要判断熔断,能够用如下办法
protected Object getFallback() {if (this.isCircuitBreakerOpen()) {
// 熔断告警形式
sendExceptionEmail(...);
}else{
// 非熔断降级告警,如果无需告警也可不写
sendExceptionEmail(...);
}
....
}
“架构人生,迭代生命”——高深老夏,搜寻 summer_deep 微信公众号可获取更多帮忙