一次线程池队列参数所引发的血案

业务背景

        京东,支付宝等支付机构会有在线上快捷给用户开二类三类卡,这些卡用户购买理财等产品,在开卡后会进行签约以及签约结果回查


业务架构

        业务组(即本次遇性能瓶颈处):负责提供签约业务相关服务(最终签约解约查询等还是调中台操作)

        中台:负责最底层的签约 以及 用户签约信息查询

业务组服务器相关配置:

        4个数据库库,每个库4个实例(2c4g),即16台机器[因异地问题实际可用8台]

        业务网关:4台虚机 2c2g

前置 与 业务中间还有一个 业务网关,主要负责业务分发,结构如下

一次线程池队列参数所引发的血案_第1张图片

第一版

        因预估此签约类型的流量会越来越少,并且考虑到用户体验,所以选择的是随机多活(即任意一个库挂了之后,将此业务发送到其他库---不用担心重复签约问题,底层幂等)

        随机多活带来的问题:不确定当时签约业务在哪个分库,所以网关在做签约回查时只能并发扫描所有分库数据

血案背景

        web服务器[非tomcat]设置的线程池队列为SynchronousQueue,仅仅在线上配置了最大线程数为200

        业务线程池配置:核心5线程最大100线程、队列为ArrayBlockingQueue(size 100)、默认拒绝策略

        查询请求进来后会占用 web服务器一个线程,然后使用业务线程池去并发查询所有分库数据[会创建4个任务并行跑],web线程阻塞等待结果

血案现场

        当时是在压测,大量的请求进来后,在业务阻塞队列中阻塞,因只有4个核心线程,故当时现场表现为:所有请求响应都特别慢被注册中心频繁下线且一会后上线来回循环,网关服务器CPU100%

       原因:当时整体压测tps为800多,平均到单台网关是200左右,正好打满web线程池,但是业务线程池始终只会有4个核心线程在执行查询任务,故请求任务都在阻塞队列中等待调度(业务线程池队列大小为1000,而最大任务数为:200web线程 * 4并发请求 = 800任务)

        注:线程池基本原理:先用核心线程,然后放入阻塞队列,如队列满了则创建工作线程


第二版

        虽然临时调整web线程池大小 或 业务线程池队列大小 可以解决这个问题,但是我们还是想直接把这个性能问题(坑)根除掉

优化

        修复线程池所引发的缺陷后的优化讨论:

                采用用户尾号进行分库:即按照用户尾号00-99将数据均分到其中一个库,问题是:如其中一个库发生故障,会导致一段时间内损失四分之一的业务

                进一步优化:采用之前oracle互为主备架构思想优化:4个库,分成2组,逻辑上互为主备(根据配置指定)

        eg:                

                1库:用户尾号00-24、2库:25-49、3库:50-74、4库:75-99

                1、3库互为主备,2、4互为主备[意味着某个库出现问题,业务网关会将请求 路由到对应备库的实例上]         

                正常情况:每次签约 以及签约回查 只会调用一次

                异常情况:01库挂了将业务分发到03库,当签约业务回查时:先去根据配置去01库查询,若数据不存在则再去备库03库,那么在数据库异常情况下,回查时至多会调用两个库


结语

        上述web线程池与业务线程池配置冲突问题 以及 优化方案希望对你有帮助

你可能感兴趣的:(java,tomcat,线程池)