物联网长连接应采用事件驱动而非多进程模型;NioEventLoopGroup线程数默认设为2×CPU核心数,以平衡I/O等待与事件处理,避免CPU闲置。

因为长连接项目本质是I/O密集型,但“count进程数”设为CPU核心数,通常意味着你误用了进程模型去扛连接,而不是用事件驱动——这个配置本身就有问题,得先分清场景。
别把Netty的NioEventLoopGroup线程数和“count进程数”混为一谈
物联网长连接(如MQTT、CoAP、自定义TCP心跳)几乎全是I/O密集型:线程大部分时间在等网络数据到达,而非计算。这时候用多进程(比如用fork起多个worker进程)是低效的,尤其当连接数上万时,每个进程都带完整内存上下文,开销爆炸。
真正该关注的是:NioEventLoopGroup中eventLoop线程数,不是系统级进程数。它的默认值是2 * CPU核心数,原因很实在:
- 一个线程在等网络包时会阻塞在
epoll_wait或kqueue,此时CPU空闲 - 另一个线程正好可以处理已就绪的读写事件,避免CPU闲置
- 乘以2是经验值,平衡了等待与处理,不是拍脑袋定的
如果你真在用多进程(比如Go的goroutine + fork,或Python的multiprocessing)
那“设为CPU核心数”只在极少数情况下合理:
- 每个进程内部是单线程+阻塞IO(比如老式PHP-FPM模型),且连接数不高(
- 你在做CPU密集型预处理(如解密、协议解析)并希望每个进程独占一个物理核
- 你明确禁用了超线程,且确认每个进程绑定到独立物理核(用
taskset或sched_setaffinity)
否则,盲目设成CPU核心数只会导致:
- 连接数增长时,新连接排队等待accept,延迟飙升
- 进程间无法共享连接状态,心跳/重连逻辑变复杂
- 内存占用翻倍(每个进程都要加载TLS证书、协议栈、缓冲区)
真实项目里更常见的错误配置
很多团队看到“CPU核心数”就无脑套用,结果踩坑:
- 用Java写Netty服务,却把
NioEventLoopGroup(4)硬编码成Runtime.getRuntime().availableProcessors()——在16核机器上只跑4个eventLoop,吞吐直接砍掉60% - 用Node.js跑MQTT Broker,没调
UV_THREADPOOL_SIZE,大量fs.read或crypto.pbkdf2阻塞主线程,导致ping响应超时 - 在MTK安卓主板上启多个Java进程处理4G模块AT指令,结果串口资源被抢占,
IOException: Device or resource busy频发
关键不在“设多少”,而在“谁在等、等什么、能不能并发处理”。长连接的瓶颈从来不是CPU算力,而是内核socket队列长度、TIME_WAIT回收速度、以及应用层如何批量处理就绪事件——这些比纠结“进程数=核心数”重要得多。

















