项目背景
最近在完成一项历史数据的清洗工作,主要就是把以前的 垃圾数据调用第三方渠道来完成一次认证,迫于监管的淫威吧。
但是第三方的qps又没有多高,政府机关的接口你懂得。
于是,代码随心的写了起来。
项目上线
由于项目紧急,也没有压测,自觉也不会有什么问题,项目部署上线,部署了四个实例,对方 qps 实测 1s内完成 3~4次请求。
最后TPS 在20 上下,即使增加实例,起色不大。
排查原因
为什么呢这是?难道要堆机器嘛?不应该啊,单台实例 也不止这个 TPS 啊,
何况我是并发处理?
list.parallelStream().forEach(...)
明明已经并发了啊?怎么回事了?
再次review 代码发现:该api 其实开启的线程数 根据操作系统内核。
并且现在微服务部署都是 docker 部署。所以你懂得导致其实系统一直是单线程在跑,难怪 TPS 上不去。
解决方案之一
采用了一种解决方案就是,自己构造线程池来解决。
private ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("user-pool-%d")
.build();
private ThreadPoolExecutor pool = new ThreadPoolExecutor(10, 10, 10L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1024), namedThreadFactory, new ThreadPoolExecutor.CallerRunsPolicy());
这个 参数也是生产上跑数据用到的,其中尤其注意 队列满时的处理策略。
刚开始用的 直接丢弃肯定不行,后来换成CallerRunsPolicy,提交任务的线程来执行,这提交任务的线程就阻塞住,不会继续往线程池提交任务了。
总结:
一定深刻理解 CallerRunsPolicy 这种线程池的策略使用!~
其实中间过程一直感觉很奇怪,按道理来说单个实例都可以达到几百TPS,虽然中间有两次与数据库的交互。
也怀疑过是不是 CPU 核数不够啊?其实我们现在程序大多对CPU消耗很低,除非有大量运算,基本全部是内存型应用。
坚定自己想法,抽丝剥茧~~~~~