九、更好的配置 server 线程数
以 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 |
maxThreads | coreThreads 的32倍 | 128 |
当 server.http.ioBound: false
时:
线程数 | 例:2c4g 的线程数 | |
---|---|---|
coreThreads | 内核数的 2倍(一般是不用配置的) | 4 |
maxThreads | coreThreads 的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 用于业务数据处理。可能有点吃紧,也可能内存会暴掉。