一次生产中 使用 list.parallelStream() 血的教训

项目背景

最近在完成一项历史数据的清洗工作,主要就是把以前的 垃圾数据调用第三方渠道来完成一次认证,迫于监管的淫威吧。

但是第三方的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消耗很低,除非有大量运算,基本全部是内存型应用。

坚定自己想法,抽丝剥茧~~~~~

你可能感兴趣的:(一次生产中 使用 list.parallelStream() 血的教训)