现象
订单服务的几个流程推动接口,出现了大量异常。持续20分钟。
排查
初步查看日志,发现这段时间有大量异常抛出,全部都是
java.lang.IllegalStateException: No instances available for travel-push。如图:
比较奇怪的是push全都是异步调用的。按理说不能影响到主流程才对。
查代码发现,用的异步调用,是用的org.springframework.web.client.AsyncRestTemplate
AsyncRestTemplate这个还是标注成废弃的
AsyncRestTemplate处理异步层面比较靠近调用,所以当被调用服务不可达的时候,这里会抛出异常,还是挺危险的。
并且这种方式不能传递traceId。
结论
可以自己写异步替代AsyncRestTemplate,利用CompletableFuture显式处理成功和失败。
同时可以指定executor来传递traceId。详见 异步线程带上traceId
我们在做异步处理的时候。用logger打日志以及http跨模块调用时,traceId都会因为线程改变而丢失原来的跟踪信息。在排查问题看日志时很不方便。
traceId其实是腾讯tsf基于spring cloud sleuth搞的,是trace和span中trace的id。
在其官方文档中,提供了几种异步传递trace/span的机制。
举个例子,
我们比较常用的是通过executor去创建一个异步线程,可以用LazyTraceExecutor去包装这个executor即可。
首先根据需要的场景,指定线程数等参数配置一个executor的bean。
@Bean(name = "myExecutorService")
public Executor getMyExecutorService() {
BasicThreadFactory threadFactory = new BasicThreadFactory.Builder()
.namingPattern("shunfeng-pool-%d")
.daemon(true)
.build();
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(threadPoolConfig.getCorePoolSize(),
threadPoolConfig.getMaxPoolSize(),
threadPoolConfig.getKeepAliveSeconds(),
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1024),
threadFactory,
new ThreadPoolExecutor.AbortPolicy());
return new LazyTraceExecutor(beanFactory, threadPoolExecutor);
}
在需要的地方注入,然后按原来的方式使用即可。
@Autowired
@Qualifier("myExecutorService")
Executor executor;
private void asyncDoSomething1() {
log.info("async.");
CompletableFuture.runAsync(() -> doSomething(), executor);
}
private void asyncDoSomething2() {
log.info("async.");
executor.execute(() -> doSomething());
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/71382.html