You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot连接MongoDB副本集异常:主节点宕机后服务报错

问题分析与解决方案

先拆解下你遇到的核心问题:从错误日志能看出两个关键问题——一是你明明配置了secondary读偏好,但实际请求仍在尝试用primary读偏好选节点,主节点宕机后直接找不到可用节点;二是你的从节点被标记为被动节点(日志里passives=[secondIp:27017]),这类节点没法参与主节点选举,主节点挂了之后整个副本集就没了可用主节点,而写操作必须在主节点执行,这就是服务返回500的根本原因。

第一步:修复副本集节点角色,启用自动故障转移

你的从节点现在是被动节点,无法被选举为主,先把它改成普通secondary节点:

  1. 登录到可用的从节点(secondIp:27017)的Mongo Shell:
    mongo -u localadmin -p test123 --authenticationDatabase mydb
    
  2. 查看当前副本集状态,确认节点属性:
    rs.status()
    
    找到你的从节点,会看到它的passive字段为true,priority为0(被动节点优先级为0,不能参与选举)。
  3. 修改副本集配置:
    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});
    
  4. 等待10-30秒,再次执行rs.status(),确认从节点的stateStr变为SECONDARY,且passive属性消失。

第二步:确保Spring Boot的读偏好配置完全生效

你的配置类里重复设置了读偏好(URI和MongoClientOptions都加了),虽然不冲突,但要确保所有操作都能正确应用:

  1. 给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;
        }
    }
    
  2. 如果用Spring Data MongoDB的Repository,还可以在接口上单独指定读偏好:
    @Repository
    @ReadPreference(ReadPreference.SECONDARY_PREFERRED)
    public interface MyRepository extends MongoRepository<MyEntity, String> {
        // 自定义查询方法
    }
    

第三步:验证故障转移流程

  1. 重启主节点,等待副本集同步完成(执行rs.status()看主节点的syncingTo字段为空,状态正常)。
  2. 停止主节点,等待30秒左右,在从节点执行rs.status(),确认它的stateStr变为PRIMARY。
  3. 测试Spring Boot服务:
    • 读操作应该能正常返回数据
    • 写操作也能正常执行(此时已经有新的主节点了)

额外建议

副本集最佳实践是至少3个节点(主、从、仲裁),这样能避免脑裂问题,提升高可用性。如果条件允许,建议添加一个仲裁节点(不需要存储数据,只参与选举)。

内容的提问来源于stack exchange,提问作者Ragu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:43:00