主备切换导致约30秒连接闪断,服务端主动关闭旧Primary的TCP连接;需配置心跳、空闲超时及副本集URI,并由应用层实现带状态校验的重试逻辑。

主备切换时长连接直接断开,不是“卡住”而是“被杀”
主备切换会触发一次约30秒的连接闪断——这不是网络抖动,而是MongoDB服务端主动关闭所有到旧Primary的TCP连接。应用层看到的现象通常是:MongoSocketReadException、Connection refused,或Java里抛出SocketTimeoutException(如果超时设置过长)。PHP里更典型:shell能连,但PHP-FPM进程里的连接一直失败,直到重启进程才恢复,本质是连接池里缓存的socket句柄已失效,但驱动没主动清理。
连接池不会自动驱逐失效连接,得靠配置+心跳
多数官方驱动(如Java的MongoDB Java Driver、Node.js的mongodb包)默认不开启连接有效性校验。切换后,连接池里大量“僵尸连接”仍被复用,导致后续请求持续失败。必须显式启用以下机制:
-
minHeartbeatFrequencyMS=5000:缩短心跳探测间隔,更快发现节点失联 -
heartbeatFrequencyMS=10000:确保心跳线程活跃,避免被GC或空闲回收误判 -
maxIdleTimeMS=60000:强制闲置连接在1分钟内释放,防止长期滞留失效连接 - Java场景下,还需确认
maxWaitTimeMS设为≤30000,否则线程会在失效连接上阻塞超时,拖垮Tomcat线程池
自动重连≠自动恢复业务,重试逻辑必须由应用控制
驱动的retryWrites=true只对单条写操作生效(如insertOne),且仅限于“写入前发现节点不可达”的场景;它不处理写入中途主备切换导致的WriteConcernException,也不覆盖读操作。真实业务中必须自己封装重试:
- 对非幂等操作(如
findAndModify),不能无脑重试,需结合业务状态校验 - 分页查询类接口,要捕获
CursorNotFound错误并重建游标,而非重放整个聚合管道 - Spring Data MongoDB 5.x用户注意:
serverSelectionTimeoutMS若未显式配置,可能沿用旧版默认值(30s),导致切换后30秒内无法选出新Primary
高可用连接地址不是可选项,是保命底线
硬编码mongodb://primary-host:27017等于把命交给单点。必须改用副本集URI:mongodb://node1:27017,node2:27017,node3:27017/?replicaSet=rs0。这个地址本身不指向某个固定节点,而是让驱动自行发现拓扑、监听isMaster响应变化。但要注意:
- URI里至少填两个节点地址,防止单个节点宕机导致initial connect失败
- 不要在URI里加
connectTimeoutMS=1000这种过短值,否则选举窗口期(通常5–15秒)内驱动可能反复放弃重连 - 云环境(如阿里云MongoDB)务必使用控制台提供的
ConnectionStringURI,它已内置DNS轮询和故障转移策略
catch块里写的那三行状态判断。

















