bigywater.tech
MongoDB · 86

连接数与线程模型

连接数多了会怎样?mongod 是一个连接一个线程吗?maxConns 到了会发生什么、客户端看到什么?这篇用真实的 mongod 数线程、数内存。

1072
1000 个连接时 mongod 的线程数(基线 73)
16
--maxConns 50 时被拒绝的连接数
7.4×
每次新建连接相对复用连接的耗时

一个连接一个线程

实测 · 本机执行输出
  基线(只有我自己)                   connections.current =     4,线程数 =    73,RSS =  100.3 MB
  再加到 100 个连接                 connections.current =   104,线程数 =   173,RSS =  118.8 MB
  再加到 500 个连接                 connections.current =   503,线程数 =   572,RSS =  143.4 MB
  再加到 1000 个连接                connections.current =  1003,线程数 =  1072,RSS =  173.3 MB
  建立 1,000 个连接(含各一次 hello)共 1.78 秒

连接从 4 加到 1003,线程数从 73 加到 1072,RSS 每个连接增加约 73 KB。

关闭之后

实测 · 本机执行输出
  关闭后约 0.3 秒                  connections.current =     3,线程数 =    72,RSS =  142.4 MB
  关闭后约 2 秒                    connections.current =     3,线程数 =    72,RSS =  142.6 MB
  关闭后约 5 秒                    connections.current =     3,线程数 =    71,RSS =  142.6 MB

连接关闭后线程数很快回落,RSS 却停在 142 MB 左右没有还给系统。

maxConns

实测 · 本机执行输出
  serverStatus.connections: {'current': 6, 'available': 44, 'totalCreated': 8, 'rejected': 0, 'active': 4, 'queuedForEstablishment': 0, 'establishmentRateLimit': {'rejected': 0, 'exempted': 0, 'interruptedDueToClientDisconnect': 0}, 'threaded': 6, 'exhaustIsMaster': 0, 'exhaustHello': 0, 'awaitingTopologyChanges': 3, 'loadBalanced': 0, 'priority': 0}
  依次建立 60 个连接并各发 hello:成功 44 个,失败 16 个
  失败的情况: ['ConnectionError:服务器关闭了连接(recv 返回空)', 'ConnectionResetError:[Errno 54] Connection reset by peer']
  服务器端: {'current': 50, 'available': 0, 'totalCreated': 52, 'rejected': 16, 'active': 4, 'queuedForEstablishment': 0, 'establishmentRateLimit': {'rejected': 0, 'exempted': 0, 'interruptedDueToClientDisconnect': 0}, 'threaded': 50, 'exhaustIsMaster': 0, 'exhaustHello': 0, 'awaitingTopologyChanges': 3, 'loadBalanced': 0, 'priority': 0}
  日志里含 "too many" / maxConns 的条目数 = 16;最后一条: {"s": "I", "c": "NETWORK", "id": 22942, "msg": "Connection refused because there are too many open connections"} attr = {"remote": "127.0.0.1:57579", "isLoadBalanced": false, "isProxyUnixSock": false, "isPriority": false, "uuid": {"uuid": {"$uuid": "efffb404-79f6-4da0-b

--maxConns 50 时第 45 个起的连接被拒,客户端看到连接被关闭或重置,服务端 connections.rejected 增加并打日志。

available

实测 · 本机执行输出
  默认:current = 6,available = 209709,current + available = 209715
  --maxConns 1000:current = 6,available = 994,current + available = 1000

current + available 等于 --maxConns;默认是 209,715。

新建连接的代价

实测 · 本机执行输出
  复用一个连接:1,000 次 find 共 42 ms(每次 42 μs);每次新建连接:共 309 ms(每次 309 μs)
  新建连接方式是复用的 7.4 倍

每次新建连接的 find 是复用连接的 7.4 倍(309 μs 对 42 μs)。

current / active / threaded

实测 · 本机执行输出
  200 个空闲原始连接 + 8 个已 ping 过的客户端,什么都没跑:current = 228,active = 10,threaded = 228,awaitingTopologyChanges = 9
  8 个慢查询正在跑:current = 228,active = 18,threaded = 228,awaitingTopologyChanges = 9
  慢查询结束后:current = 228,active = 10,threaded = 228,awaitingTopologyChanges = 9

threaded 等于 current;active 随正在执行的操作增减。

分步演示

连接数与线程模型
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / MongoDB 9.0.2(Homebrew 的 mongod、mongos)/ mongosh 2.12.0 / pymongo 4.18.3;每个实验在临时目录里起全新的 mongod(独立 dbpath,端口 9900 以上,只监听 127.0.0.1,WiredTiger 缓存 0.25 GB),需要副本集或分片集群时在本机起多个进程;命令输出来自真实的 mongosh,批量写入、计时与多线程用 pymongo;计时用 time.perf_counter,数字每次运行会有小幅抖动,ObjectId、时间戳等每次运行都不同。单机 mongod,原始 TCP 连接加手写 OP_MSG hello;线程数用 ps -M,RSS 用 ps -o rss
    • 没有验证:Linux 上线程栈大小与 ulimit -u 对连接上限的影响;maxConns 之外的 ulimit -n(文件描述符)限制;连接风暴下的 establishmentRateLimit;有 TLS 时每个连接的开销;mongos 的连接模型(connPoolMaxShardedConnsPerHost 等);默认 209,715 这个值的来源(没有查源码);RSS 不回落是否因分配器缓存,没有进一步验证
    京ICP备2026067502号-1京公网安备11010502063487号