ReadPreference 是控制 MongoDB 读请求路由的参数,必须显式设置才能实现读写分离;仅配置 replicaSet 参数无法让客户端读取从节点,默认始终读主节点。

Read Preference 是什么,为什么不能只靠 replicaSet 参数
PyMongo 的 replicaSet 参数只是让客户端能发现副本集节点,并不决定读请求发给谁。真正控制读流量走向的是 read_preference——它必须显式设置,否则默认走 Primary(主节点),根本不会读从节点,更谈不上读写分离。
常见误解是“配了 replicaSet 就自动读从库”,实际连 Secondary 都不会碰一下。读写分离的前提,是把读操作的偏好明确设为非 Primary 的选项。
如何在连接时设置 read_preference 为 Secondary
最常用也最直接的方式是在 MongoClient 初始化时传入 read_preference 参数:
from pymongo import MongoClient, ReadPreference
client = MongoClient(
"mongodb://node1:27017,node2:27017,node3:27017/",
replicaSet="rs0",
read_preference=ReadPreference.SECONDARY
)
注意几点:
-
ReadPreference.SECONDARY表示只向从节点发读请求,主节点完全不参与读 - 所有数据库、集合、查询默认继承该配置,无需每处重复设置
- 如果某个查询必须读主(比如刚写完立刻查),可用
.with_options(read_preference=ReadPreference.PRIMARY)覆盖 - 连接字符串里不能指定
read_preference,必须用 Python 对象传参
SecondaryPreferred 和 Nearest 的区别与适用场景
SECONDARY_PREFERRED 和 NEAREST 看似都“尽量读从库”,但行为差异很大,容易误用:
-
ReadPreference.SECONDARY_PREFERRED:优先发给从节点;如果当前没有可用从节点,降级到主节点读 —— 适合对一致性容忍度稍高、但不能接受读失败的业务 -
ReadPreference.NEAREST:按网络延迟选最近节点(主或从都可能),不区分角色 —— 适合地理分布广、读延迟敏感、且能接受主从混合读的场景(如全球 CDN 后的服务) - 不要用
NEAREST替代读写分离目标,它不保证读从库,可能全打到主上 -
SECONDARY和SECONDARY_PREFERRED要求副本集至少有一个健康从节点,否则读会报ServerSelectionTimeoutError
聚合管道和事务中 read_preference 的限制
读偏好不是万能的,两个关键边界必须注意:
- 事务内所有操作强制使用
PRIMARY,设置read_preference无效。即使你在事务里调用.find(),PyMongo 也会忽略你配的SECONDARY,强制走主节点 - 带
$lookup或分片聚合的管道,若涉及跨分片或跨副本集,read_preference可能被忽略或部分生效;建议先确认explain("executionStats")中的serverInfo.host是否符合预期 - 使用
collection.find().hint(...).max_time_ms(...)这类链式调用时,read_preference必须在find()时就确定,后续方法无法修改
读写分离不是开关一开就完事,得盯住事务、聚合、故障降级这些真实压测里才暴露的点。特别是 SECONDARY_PREFERRED 在从节点全部宕机时静默切主,可能掩盖底层高可用问题。

















