Spring Boot连接MongoDB副本集异常:主节点宕机后服务报错
问题分析与解决方案
先拆解下你遇到的核心问题:从错误日志能看出两个关键问题——一是你明明配置了secondary读偏好,但实际请求仍在尝试用primary读偏好选节点,主节点宕机后直接找不到可用节点;二是你的从节点被标记为被动节点(日志里passives=[secondIp:27017]),这类节点没法参与主节点选举,主节点挂了之后整个副本集就没了可用主节点,而写操作必须在主节点执行,这就是服务返回500的根本原因。
第一步:修复副本集节点角色,启用自动故障转移
你的从节点现在是被动节点,无法被选举为主,先把它改成普通secondary节点:
- 登录到可用的从节点(
secondIp:27017)的Mongo Shell:mongo -u localadmin -p test123 --authenticationDatabase mydb - 查看当前副本集状态,确认节点属性:
找到你的从节点,会看到它的rs.status()passive字段为true,priority为0(被动节点优先级为0,不能参与选举)。 - 修改副本集配置:
var cfg = rs.conf(); // 遍历节点找到目标从节点,修改属性 cfg.members.forEach(member => { if (member.host === "secondIp:27017") { delete member.passive; // 移除被动节点标记 member.priority = 1; // 设置优先级为1,允许参与主节点选举 } }); // 强制应用新配置(主节点宕机时需要加force参数) rs.reconfig(cfg, {force: true}); - 等待10-30秒,再次执行
rs.status(),确认从节点的stateStr变为SECONDARY,且passive属性消失。
第二步:确保Spring Boot的读偏好配置完全生效
你的配置类里重复设置了读偏好(URI和MongoClientOptions都加了),虽然不冲突,但要确保所有操作都能正确应用:
- 给
MongoTemplate显式设置读偏好,覆盖全局默认:@Configuration @EnableMongoRepositories public class SampleMongoConfig extends AbstractMongoConfiguration { @Value("${app.mongo.uri}") private String mongoUri; @Override @Bean public Mongo mongo() throws Exception { // 改用secondaryPreferred:有主节点时优先读主,主节点挂了自动切到从节点 MongoClientURI uri = new MongoClientURI(mongoUri, MongoClientOptions.builder().readPreference(ReadPreference.secondaryPreferred()) ); return new MongoClient(uri); } @Override protected String getDatabaseName() { return "mydb"; } // 新增MongoTemplate配置,确保读偏好全局生效 @Bean public MongoTemplate mongoTemplate() throws Exception { MongoTemplate template = new MongoTemplate(mongo(), getDatabaseName()); template.setReadPreference(ReadPreference.secondaryPreferred()); return template; } } - 如果用Spring Data MongoDB的Repository,还可以在接口上单独指定读偏好:
@Repository @ReadPreference(ReadPreference.SECONDARY_PREFERRED) public interface MyRepository extends MongoRepository<MyEntity, String> { // 自定义查询方法 }
第三步:验证故障转移流程
- 重启主节点,等待副本集同步完成(执行
rs.status()看主节点的syncingTo字段为空,状态正常)。 - 停止主节点,等待30秒左右,在从节点执行
rs.status(),确认它的stateStr变为PRIMARY。 - 测试Spring Boot服务:
- 读操作应该能正常返回数据
- 写操作也能正常执行(此时已经有新的主节点了)
额外建议
副本集最佳实践是至少3个节点(主、从、仲裁),这样能避免脑裂问题,提升高可用性。如果条件允许,建议添加一个仲裁节点(不需要存储数据,只参与选举)。
内容的提问来源于stack exchange,提问作者Ragu
相关产品推荐
相关产品推荐

