先来说下线程池调优,就拿 SpringBoot 内置的 Tomcat 来说,确实是支持线程池参数配置的,但不是 accept-count 参数,可以通过 threads.max 和 threads.minSpare 来配置线程池最大线程数和核心线程数。
如果没有设置,则会使用默认值
threads.max: 200threads.minSpare: 10
Tomcat 底层用到的 ThreadPoolExecutor 也不是 JUC 原生的线程池,而是自定义的,做了一些调整来支持 IO 密集型场景使用,Tomcat 自定义线程池的执行流程及原理,然后可以接入动态线程池框架 DynamicTp,将 Tomcat 线程池交由 DynamicTp 管理,使之能享受到动态调参、监控告警的功能。
在配置中心配置 tomcat 线程池核心参数
spring: dynamic: tp: tomcatTp: corePoolSize: 100 maximumPoolSize: 400 keepAliveTime: 60
Tomcat 线程池调优主要思想就是动态化线程池参数,上线前通过压测初步确定一套较优的参数值,上线后通过监控、告警实时感知线程池负载情况,动态调整参数适应流量的变化。
线程池调优就说这些吧,下面主要介绍下 Tcp backlog 及半连接、全连接队列相关内容。
threads.max 和 threads.minSpare 是用来配置 Tomcat 的工作线程池大小的,是线程池维度的参数
accept-count 和 max-connections 是 TCP 维度的配置参数
Client 端和 Server 端基于 TCP 协议进行通信时,首先需要经过三次握手建连的,通信结束时需要通过四次挥手断连的。注意所谓的连接其实是个逻辑上的概念,并不存在真实连接的,那 TCP 是怎么面向连接传输的呢?
TCP 定义了个复杂的有限状态机模型,通信双方通过维护一个连接状态,来达到看起来像有一条连接的效果。如下是 TCP 状态机状态流转图,这个图非常重要,建议大家一定要掌握。
图上半部分描述了三次握手建立连接过程中状态的变化
图下半部分描述了四次挥手断开连接过程中状态的变化

图 2 是通过三次握手建立连接的过程,老八股文了,建议结合图 1 状态机变化图看

图 3 是通过四次挥手断开连接的过程,建议结合图 1 状态机变化图看

服务端程序调用 listen() 函数后,TCP 状态机从 CLOSED 转变为 LISTEN,并且 linux 内核会创建维护两个队列。一个是半连接队列(Syn queue),另一个是全连接队列(Accept queue)。
建连主要流程如下:
客户端向服务端发送 SYN 包请求建立连接,发送后客户端进入 SYN_SENT 状态
服务端收到客户端的 SYN 请求,将该连接存放到半连接队列(Syn queue)中,并向客户端回复 SYN + ACK,随后服务端进入 SYN_RECV 状态
客户端收到服务端的 SYN + ACK 后,回复服务端 ACK 并进入 ESTABLISHED 状态
服务端收到客户端的 ACK 后,从半连接队列中取出连接放到全连接队列(Accept queue)中,服务端进入 ESTABLISHED 状态
服务端程序调用 accept() 方法,从全连接队列中取出连接进行处理请求
上述提到了半连接队列、全连接队列,这两队列都有大小限制的,超过的连接会被丢掉或者返回 RST 包。
半连接队列大小主要受:listen backlog、somaxconn、tcp_max_syn_backlog 这三参数影响
全连接队列大小主要受:listen backlog 和