Spring中@Scheduled和HttpClient的连环坑
前言
本文主要给大家介绍了关于spring中@scheduled和httpclient的坑,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。
曾经踩过一个大坑:
由于业务特殊性,会定时跑很多定时任务,对业务数据进行补偿操作等。
在spring使用过程中,我们可以使用@scheduled注解可以方便的实现定时任务。
有一天早上突然发现,从前一天晚上某一时刻开始,所有的定时任务全部都卡死不再运行了。
@scheduled默认单线程
经排查后发现,我们使用@scheduled注解默认的配置的话,所有的任务都是单线程去跑的。写了一个测试的task让它sleep住,就很容易发现,其他所有的task在时间到的时候都没有触发。
如果需要开启多线程处理,则需要进行如下的配置,设置一下线程数:
@configuration public class scheduleconfig implements schedulingconfigurer { @override public void configuretasks(scheduledtaskregistrar taskregistrar) { taskregistrar.setscheduler(executors.newscheduledthreadpool(5)); } }
这样就解决了如果一个task卡住,会引起所有task全部卡住的问题。
但是为什么会有task卡住呢?
httpclient默认参数配置
原来,有些task会定时请求外部服务的restful接口,而httpclient的配置如下:
poolinghttpclientconnectionmanager connmanager = new poolinghttpclientconnectionmanager(); connmanager.setmaxtotal(maxconnection); httpclient = httpclients.custom() .setconnectionmanager(connmanager) .build();
在最开始使用httpclient的时候,根本没有想这么多,基本也都是用用默认配置。
追踪源码可以发现,在使用上述方式进行配置的时候,httpclient的timeout时间竟然全部都是-1,也就是说如果对方服务有问题,httpclient的请求会永不超时,一直等待。源码如下:
builder() { super(); this.staleconnectioncheckenabled = false; this.redirectsenabled = true; this.maxredirects = 50; this.relativeredirectsallowed = true; this.authenticationenabled = true; this.connectionrequesttimeout = -1; this.connecttimeout = -1; this.sockettimeout = -1; this.contentcompressionenabled = true; }
所以我们这时候必须手动指定timeout时间,问题就解决了。例如:
poolinghttpclientconnectionmanager connmanager = new poolinghttpclientconnectionmanager(); connmanager.setmaxtotal(maxconnection); requestconfig defaultrequestconfig = requestconfig.custom() .setsockettimeout(3000) .setconnecttimeout(3000) .setconnectionrequesttimeout(3000) .build(); httpclient = httpclients.custom() .setdefaultrequestconfig(defaultrequestconfig) .setconnectionmanager(connmanager) .build();
联想到另一个问题
其实httpclient的使用过程中也遇到过另外一个配置的问题,就是defaultmaxperroute这个参数。
最开始使用的时候也没有注意过这个参数,只是设置过连接池的最大连接数maxtotal。
defaultmaxperroute参数其实代表了每个路由的最大连接数。比如你的系统需要访问另外两个服务:google.com 和 bing.com。如果你的maxtotal设置了100,而defaultmaxperroute设置了50,那么你的每一个服务的最大请求数最大只能是50。
那么如果defaultmaxperroute没有设置呢,追踪源码:
public poolinghttpclientconnectionmanager( final httpclientconnectionoperator httpclientconnectionoperator, final httpconnectionfactory<httproute, managedhttpclientconnection> connfactory, final long timetolive, final timeunit tunit) { super(); this.configdata = new configdata(); //这里使用的cpool构造方法,第二个参数即为defaultmaxperroute,也就是默认为2。 this.pool = new cpool(new internalconnectionfactory( this.configdata, connfactory), 2, 20, timetolive, tunit); this.pool.setvalidateafterinactivity(2000); this.connectionoperator = args.notnull(httpclientconnectionoperator, "httpclientconnectionoperator"); this.isshutdown = new atomicboolean(false); }
这里发现,原来默认值竟然只有2。怪不得当时在高并发情况下总会出现超时,明明maxtotal已经设的很高。
所以如果你的服务访问很多不同的外部服务,并且并发量比较大,一定要好好配置maxtotal和defaultmaxperroute两个参数。
所以后来再使用任何新的东西,都有好好看下都什么配置,有疑问的一定要先查一下,不要网上copy一段代码直接就用。当时可能没问题,但是以后没准就被坑了。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
上一篇: AE怎么做出放大镜效果? AE放大镜动画的制作方法
下一篇: 网络推广有哪些方法?