记录一次由于线程使用不当引发的血案
背景
最近给第三方做了一个接口,接口的作用是接收数据对数据进行验证之后通过kafka
推送到模型进行数据处理,最终通过kafka
接收模型的数据,开始只做了一个异步的接口,由于对方业务原因需要一个同步的接口传输数据,但是每当运行一段时间之后程序就会进入假死状态,接口无法正常调用;
同步接口
同步接口的实现是使用阻塞Map,当对方发送请求时,对数据进行验证,然后推送到模型,等待结果返回之后将处理好的数据推送到对方接口,此时这次请求给调用方返回相应信息;
思路
开始认为是由于用户量过大导致内存不足引发的程序假死,使用JMeter
进行压力测试异步接口模拟10000个请求同时调用接口,程序如丝滑般运行,没有丝毫问题,所有请求都正常返回(这里由于在家里通过VPN连接的公司开发服务器,网络不稳定,所以就拿少量测试用例为例);
然后开始怀疑是不是同步接口出了问题,刚开始模拟少量请求,因为当时是在开发环境进行测试,模型并没有放上去,所以没有返回信息,一直在等待模型的返回结果,也是没有问题的,这时候调用异步接口也没有任何问题;
思考:所有资源都是阻塞状态,因为没有处理结果,一直没有释放进程,当数据过大时会不会造成服务器资源耗尽,导致程序假死?
当再次加大同步接口的调用次数的时候,再去尝试请求异步接口,发现异步接口也没有了返回信息,这时遍确认了问题所在;
线程全部在阻塞状态,当太多资源没有释放掉时,服务器资源耗尽,导致程序无法正常运行;
解决
找到问题之后就是要解决问题,去掉同步接口是不可能的,所以要给阻塞的线程设置一个超时时间,当长时间没有等到模型的处理数据时,主动放弃监听,释放掉占用的资源,从而保证服务器资源充足;
思考
虽然问题解决了,但是模型的数据产出最长达10秒钟,当并发量过大时还是会出现这种问题,在不动模型的情况下如何解决这种问题?如何一直保证服务器资源充足?
参考资料
阻塞Map的实现:https://songsong.iteye.com/blog/802881
压力测试简介和JMeter的简单实用:https://www.cnblogs.com/TankXiao/p/4059378.html