PyMongo超时需分层诊断:ConnectionTimeoutError是TCP未连通,socket.timeout是已连接但响应慢;应合理设置connectTimeoutMS、socketTimeoutMS和serverSelectionTimeoutMS三个参数,并注意游标和事务的生命周期限制。

PyMongo连接MongoDB频繁超时,不是代码写错了,而是连接链路中某一层卡住了——常见于网络延迟、DNS解析慢、TLS握手失败、副本集选主耗时过长,或游标/事务空闲超时被服务端主动清理。
ConnectionTimeoutError 和 socket.timeout 怎么区分
前者是 TCP 层连不上(ConnectionTimeoutError: timed out),说明 PyMongo 根本没发出去 SYN 包,或没收到 SYN-ACK;后者是连上了但读响应卡住(socket.timeout: The read operation timed out),说明 TCP 已建立,但服务端迟迟不发数据。
-
ConnectionTimeoutError:优先查ping、telnet your-host 27017或nc -zv your-host 27017,确认基础网络通不通 -
socket.timeout:说明连接已建好,问题在 DNS、TLS、认证或服务端负载上,比如 Atlas 白名单没加对、云防火墙放行了 27017 但没放通 SRV 查询端口(UDP 53) - 本地能连、Docker 或 K8s 里连不上?大概率是容器网络没配 host 网络,或 Pod CIDR 被安全组拦截
URI 里 timeoutMS 参数怎么设才有效
PyMongo 的超时参数必须显式传进 URI 或构造函数,靠默认值扛不住生产环境。关键是分清三个超时的作用域:
-
connectTimeoutMS:控制“发起 TCP 连接”最大等待时间,建议设为5000(5 秒),太小会误判慢网,太大拖慢故障发现 -
socketTimeoutMS:控制“一次请求读响应”的超时,影响单次查询,别盲目调大(比如设成 60000),否则慢查询会占满连接池 -
serverSelectionTimeoutMS:副本集场景下选主节点的总耗时,默认 30 秒,常被忽略,建议设为10000
正确写法:mongodb://host:27017/?connectTimeoutMS=5000&socketTimeoutMS=10000&serverSelectionTimeoutMS=10000
游标遍历中途报 CursorNotFound 怎么办
PyMongo 默认每批拉 100 条,如果 parse_data(row) 单次耗时 > 6 秒,100 次就超 MongoDB 默认 10 分钟游标有效期,第 101 条 fetch 时服务端已销毁游标。
- 最稳妥:用
.batch_size(10)主动减小每批数量,把单批处理时间压到 5 分钟内 - 避免内存爆炸:别用
list(collection.find())全量加载,尤其数据量大时 - 真要全量处理且不能改逻辑?加
no_cursor_timeout=True,但务必配合手动cursor.close(),否则服务端游标堆积会拖垮 mongod
事务 commit 失败报 ConnectionFailure 是不是超时设置错了
不是。PyMongo 事务 commit 报 ConnectionFailure 或 InvalidOperation,大概率是服务端已因空闲超时(transactionLifetimeLimitSeconds 默认 60 秒)终止了事务,客户端再发 commit 请求时上下文已不存在。
-
max_commit_time_ms只作用于 commit 阶段本身,单位毫秒,必须作为关键字参数传给session.commit_transaction(max_commit_time_ms=5000) - 它不能延长事务生命周期,只是防止 commit 因锁竞争卡死;事务整体存活时间仍由服务端管控
- 如果
socketTimeoutMS(默认 30000)比max_commit_time_ms小,TCP 层先超时,根本发不出 commit 请求
真正要治本,得缩短事务内操作耗时,或拆成多个短事务——游标超时、事务超时、连接超时,本质都是“操作耗时 > 服务端容忍窗口”,别只盯着 client 端调参。

















