Solon v2.7.5

九、更好的配置 server 线程数

</> markdown

以 http server 为例,讨论下 server 的几个线程数配置:

#服务 http 最小线程数(默认:0表示自动,支持固定值 2 或 内核倍数 x2)//一般不用配置
server.http.coreThreads: 0 
#服务 http 最大线程数(默认:0表示自动,支持固定值 32 或 内核倍数 x32) 
server.http.maxThreads: 0
#服务 http 闲置线程超时(0表示自动,单位毫秒) //v1.10.13 后支持
server.http.idleTimeout: 0
#服务 http 是否为IO密集型? //v1.12.2 后支持
server.http.ioBound: true

线程,不是越多越好(切换需要费时间),也不是越少越好(会不够用)。了解情况,作合适的配置为佳。

1、两个重要概念

  • Cpu 密集型

比如写一个 “hello world” 程序,不做任何处理直接返回字符串。它就算是 cpu 密集型了。事情只在内存与cpu里完成了。

这种情况,一般响应非常快。如果线程多了,切换线程的时间反而成了一种性能浪费。

  • Io 密集型

比如写 crud 的程序,一个数据保存到数据库里;或者上传文件,保存到磁盘里。事情“额外”涉及了网卡、磁盘等一些Io处理。

这种情况,一般响应会慢,有些可能还要10多秒。一次处理会占用一个线程,线程往往会不够用。

2、框架默认的配置

server.http.ioBound: true 时:

线程数例:2c4g 的线程数
coreThreads内核数的 2倍(一般是不用配置的)4
maxThreadscoreThreads 的32倍128

server.http.ioBound: false 时:

线程数例:2c4g 的线程数
coreThreads内核数的 2倍(一般是不用配置的)4
maxThreadscoreThreads 的8倍32

3、如何做简单的计算

  • 关于 qps

比如一次请求响应为 0.1 秒,那一个线程1秒内可以做10次响应,100个线程,可以做1000个响应。即 qps = 1000

  • 关于内存

一个线程最少会占用 1m - 2m的内存。100个线程,就算是 200m

一个请求包,如果是 200k,操作处理时可能会有多个副本(算它4个),那是 800k。qps 1000 时,每秒占用 800m/s 的内存,如果5s后才自动释放,那实际每秒占用为 4g/s

4、为什么 coreThreads 不需要配置

  • 对 bio 来说,coreThreads 太大,就不会收缩了。

  • 对 nio 来说,coreThreads 不能太大。nio 与 bio 一般做两段式线程池,coreThreads 即为它的第一段,maxThreads 则为第二段。

5、线程(即 maxThreads)不够时一般会怎么样

  • 可能会卡,但卡一会儿还能接收请求

这种情况,一般是提交线程池被拒后,改用主线程处理。所以主线程没法再接收请求了,需要等手上的活完成后才能再接收请求。

  • 直接是返回异常或者当前关闭链接(即拒绝服务)

通过协议直接返回异常,是为了让客户端马上知道结果,服务端吃不消了。如果直接关闭链接了,那是解析协议的线程也不够用了,没法按协议返回,就直接关链接了。

6、如何配置 maxThreads

一般默认即可。如果是单实例,流量大或请求慢。可以根据内存,把 maxThreads 配大些,比如这个服务能用1c2g标准的:

如果可以配成:x256 。即 512 个线程,每个线程按2m占用算,线程最大内存占用为 1024g。还有 1g 用于业务数据处理。可能有点吃紧,也可能内存会暴掉。