线程池是个既靠谱但又陌生的家伙, 像管家一样, 会踏踏实实的把你交代的任务完成, 但很死板, 没有自动安排人的能力, 需要你给它配好人手(线程实例)和承载容量(队列大小), 这些参数关系是否能够有效发挥出机器硬件的性能, 所以在日常工作根据业务情况进行自定义配置很重要.
完全核数决定, 通常核心线程数是核数或核数*2, 最大线程数为核数*2或核数*4, 队列直接使用阻塞队列, 长度呢? 粗暴设置大点, 核数*64或128, 这种设置方式尤其是队列的设置过大会导致很难让非核心线程发挥作用, 且线程数设置的没必要过多, 本文阐述一种基于业务QPS的设置线程数和队列长度的实践思路.
线程池相关的参数, 具体来说包含: 核心线程数、最大线程数、队列类型、队列大小。
要想配的好, 先了解下线程池的作用原理, 以及这些参数对线程池的影响.
任务被创建好后提交到线程池中, 可能会先后经过四个处理步骤: 核心线程 -> 队列缓存-> 非核心线程-> 拒绝策略, 不同步骤中的调度策略也不相同.
整个线程池的处理流程可类比餐馆: 有固定的正式员工, 通常数量会比较少, 因为常驻员工要交五险一金、要发工资, 成本较高, 临时工通常是天结, 干完就走, 但也不是无限招, 那数量怎么确定呢?另外客人来了可能会排队, 但也不能无限排, 实在处理不过来就忍痛拒绝客人用餐, 避免餐馆过载,影响正常客人的用餐.
线程数的确定与餐馆招多少员工、正式占比多少、预留多少临时工思路是一样的, 看总客人数和单个服务员一天所能服务的人数, 单人服务数由单个客人的用餐时长决定, 时长越长, 要求的员工数越多才能支持足够的订单量. 但客人的时长波动, 若按平均时长决定的员工数比较小, 但能够满足日常的客人用餐需求了; 最大时长决定的也是最大员工数, 该数量肯定会富裕, 不过可以应对节假日这种高峰期场景了. 所以根据avg确定核心线程数, 根据tp999或max决定最大线程数.
另外是队列长度, 就是容纳等待任务的数量, 对于流量稳定的服务来说, 其等候区可以设置小些, 为了提升用户体验, 不要让客人等, 多召些临时工就行, 来一个就赶紧招待了, 不让客人等太久, 若临时工招满了也招待不过来, 那就拒绝吧, 免得浪费客人时间, 因为流量稳定, 意味着当前客人到来的速率是稳定大于餐馆的最大处理能力, 若设置等待区, 等待区一直爆满, 队列积压, 导致每个任务都会等一段时间才能被处理, 拉高整体耗时, 此时应该做的是扩容而非等待, 这是同步队列的应用场景,.
另外一种阻塞队列, 适用于高低峰错位的流量不均的情况, 高峰时请求来了, 先在队列中等下, 等待线程依次处理, 高峰处理不过来, 但低峰就会慢慢消化掉, 就是耗时会长点, 若队列满了, 赶紧加临时线程, 避免请求处理失败了. 队列多长合适呢? 建议是核心线程数的3倍, 一个经验值. 过大就导致占据更多资源且整体耗时上涨, 需要及时加人手处理.