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

Spring Mongo连接多个MongoDB出现连接超时问题求助

多MongoDB连接服务频繁出现超时错误

问题概述

微服务需连接Mongo Cloud Atlas同一集群中的4个云数据库,部署到GCP Cloud Run后,每几小时就频繁触发各类网络超时错误,但同一环境下仅连接单数据库的Spring服务无此问题。所有服务通过VPC与Mongo Atlas建立对等连接。

错误信息

MongoSocketReadTimeoutException: Timeout while receiving message
MongoSocketReadException: Exception receiving message
MongoSocketOpenException: Exception opening socket
MongoSocketWriteException: Exception sending message
MongoSocketException: cluster0-shard-00-00-pri.xxxxxx.mongodb.net: Temporary failure in name resolution

单库连接服务配置(无异常)

@Configuration
public class MongoConfiguration {

    @Value("${spring.data.mongodb.host}")
    private String connectionString;

    @Bean
    public MongoClient mongoClient() {
        CodecRegistry pojoCodecRegistry = fromProviders(PojoCodecProvider.builder().automatic(true).build());
        CodecRegistry codecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), pojoCodecRegistry);
        return MongoClients.create(MongoClientSettings.builder()
                .applyConnectionString(new ConnectionString(connectionString))
                .uuidRepresentation(UuidRepresentation.STANDARD)
                .codecRegistry(codecRegistry)
                .build());
    }

    @Bean
    public MongoClientSettings mongoClientSettings() {
        return MongoClientSettings.builder()
                .retryWrites(true)
                .applyToClusterSettings(builder ->
                        builder.serverSelectionTimeout(5000, TimeUnit.MILLISECONDS))
                .applyToConnectionPoolSettings((ConnectionPoolSettings.Builder builder) -> builder.maxSize(300) //connections count
                        .minSize(100)
                        .maxConnectionLifeTime(1000, TimeUnit.MILLISECONDS)
                        .maintenanceFrequency(5000, TimeUnit.MILLISECONDS)
                        .maxConnectionIdleTime(1000, TimeUnit.MILLISECONDS)
                        .maxWaitTime(150, TimeUnit.MILLISECONDS))
                .applyToSocketSettings(builder -> builder.connectTimeout(10, TimeUnit.SECONDS)
                        .readTimeout(15, TimeUnit.SECONDS))
                .applicationName("ProfileServiceApplication")
                .retryWrites(true)
                .build();
    }

    @Bean
    public MongoCustomConversions mongoCustomConversions() {
        return new MongoCustomConversions(Arrays.asList(
                new BigDecimalDecimal128Converter(),
                new Decimal128BigDecimalConverter()
        ));

    }

    @WritingConverter
    private static class BigDecimalDecimal128Converter implements Converter<BigDecimal, Decimal128> {

        @Override
        public Decimal128 convert(@NonNull BigDecimal source) {
            return new Decimal128(source);
        }
    }

    @ReadingConverter
    private static class Decimal128BigDecimalConverter implements Converter<Decimal128, BigDecimal> {

        @Override
        public BigDecimal convert(@NonNull Decimal128 source) {
            return source.bigDecimalValue();
        }

    }
}

多库连接服务配置(存在异常)

主Mongo Client配置

@Configuration
public class TorchMongoConfig {
    @Autowired
    private Environment env;

    @Primary
    @Bean(name = "TorchMongoDBFactory")
    public MongoDatabaseFactory torchFactory(@Qualifier("TORCH_CLIENT") MongoClient mongoClient) {
        return new SimpleMongoClientDatabaseFactory(mongoClient, "Torch");
    }

    @Primary
    @Bean
    public MongoTemplate torchMongoTemplate(@Qualifier("TORCH_CLIENT") MongoClient client) {
        return new MongoTemplate(torchFactory(client));
    }

    @Bean("TORCH_CLIENT")
    @Primary
    public MongoClient mongoClient() {
        CodecRegistry pojoCodecRegistry = fromProviders(PojoCodecProvider.builder().automatic(true).build());
        CodecRegistry codecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), pojoCodecRegistry);
        return MongoClients.create(MongoClientSettings.builder()
                .applyConnectionString(new ConnectionString(env.getProperty("spring.data.mongo.torchdb.uri")))
                .uuidRepresentation(UuidRepresentation.STANDARD)
                .codecRegistry(codecRegistry)
                .applyToConnectionPoolSettings(builder -> {
                    builder.maxConnectionLifeTime(1000, TimeUnit.MILLISECONDS)
                            .maintenanceFrequency(5000, TimeUnit.MILLISECONDS)
                            .maxConnectionIdleTime(1000, TimeUnit.MILLISECONDS)
                            .maxWaitTime(150, TimeUnit.MILLISECONDS);
                })
                .applyToClusterSettings(builder -> {
                    builder.serverSelectionTimeout(5000, TimeUnit.MILLISECONDS);
                })
                .build());
        }
        
    @Bean
    public MongoClientSettingsBuilderCustomizer mongoDBDefaultSettings() {
        return builder -> {
            builder.applyToSocketSettings(builderSettings -> {
                builderSettings.connectTimeout(10, TimeUnit.SECONDS)
                        .readTimeout(15, TimeUnit.SECONDS);
            });

            builder.applyToClusterSettings(builderSettings -> {
                builderSettings
                        .serverSelectionTimeout(5000, TimeUnit.MILLISECONDS);
            });

            builder.applyToConnectionPoolSettings(builderSettings -> {
                builderSettings.maxSize(300) //connections count
                        .minSize(100)
                        .maxConnectionLifeTime(1000, TimeUnit.MILLISECONDS)
                        .maintenanceFrequency(5000, TimeUnit.MILLISECONDS)
                        .maxConnectionIdleTime(1000, TimeUnit.MILLISECONDS)
                        .maxWaitTime(150, TimeUnit.MILLISECONDS);
            });
            // Apply other settings to the builder.
        };
    }

    @Bean
    public MongoCustomConversions mongoCustomConversions() {
        return new MongoCustomConversions(Arrays.asList(
                new BigDecimalDecimal128Converter(),
                new Decimal128BigDecimalConverter()
        ));
    }

    @WritingConverter
    private static class BigDecimalDecimal128Converter implements Converter<BigDecimal, Decimal128> {

        @Override
        public Decimal128 convert(@NonNull BigDecimal source) {
            return new Decimal128(source);
        }
    }

    @ReadingConverter
    private static class Decimal128BigDecimalConverter implements Converter<Decimal128, BigDecimal> {

        @Override
        public BigDecimal convert(@NonNull Decimal128 source) {
            return source.bigDecimalValue();
        }

    }
}

次要Mongo Client配置

@Configuration
public class ProjectInformationMongoConfig {
    @Autowired
    private Environment env;

    @Bean(name = "ProjectInformationMongoDBFactory")
    public MongoDatabaseFactory userProjectMongoDatabaseFactory(@Qualifier("ProjectInformation") MongoClient mongoClient) {
        return new SimpleMongoClientDatabaseFactory(mongoClient, "ProjectInformation");
    }

    @Bean(name = "projectInformationMongoTemplate")
    public MongoTemplate userProjectMongoTemplate(@Qualifier("ProjectInformationMongoDBFactory") MongoDatabaseFactory mongoDatabaseFactory) {
        return new MongoTemplate(mongoDatabaseFactory);
    }

    @Bean("ProjectInformation")
    public MongoClient mongoClient() {
        CodecRegistry pojoCodecRegistry = fromProviders(PojoCodecProvider.builder().automatic(true).build());
        CodecRegistry codecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), pojoCodecRegistry);
        return MongoClients.create(MongoClientSettings.builder()
                .applyConnectionString(new ConnectionString(env.getProperty("spring.data.mongo.projectinformation.uri")))
                .uuidRepresentation(UuidRepresentation.STANDARD)
                .codecRegistry(codecRegistry)
                .applyToConnectionPoolSettings(builder -> {
                    builder.maxConnectionLifeTime(30, TimeUnit.MINUTES)
                            .maintenanceFrequency(5000, TimeUnit.MILLISECONDS)
                            .maxConnectionIdleTime(1000, TimeUnit.MILLISECONDS)
                            .maxWaitTime(150, TimeUnit.MILLISECONDS);
                })
                .applyToClusterSettings(builder -> {
                    builder.serverSelectionTimeout(5000, TimeUnit.MILLISECONDS);
                })
                .build());
    }
}

第三和第四个连接配置与上述次要Client一致,不再重复。

数据访问代码示例

主库访问示例

@Repository
public class SavedUserProfilesDALImpl implements SavedUserProfilesDal {
    private static final Logger logger = LoggerFactory.getLogger(SavedUserProfilesDal.class);

    private final MongoTemplate mongoTemplate;

    public SavedUserProfilesDALImpl(@Qualifier("torchMongoTemplate") MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    @Override
    public SavedUserProfiles save(SavedUserProfiles savedUserProfile) {
        logger.info("MONGO: Executing query save / update UserSavedQuery with userId {}", savedUserProfile.getUserId());
        try {
            return mongoTemplate.save(savedUserProfile);
        } catch (Exception ex) {
            logger.error("Unable to perform Mongo Operation Save SavedUserProfiles  {}", ex.getLocalizedMessage());
            throw new ServiceUnavailableException("Unable to perform Mongo Operation {" + ex.getLocalizedMessage() + "}", "SavedUserProfiles");
        }
    }
}

非主库访问示例

@Repository
public class ThirdPartyDALImpl implements ThirdPartyContentDAL {
    private final static Logger logger = LoggerFactory.getLogger(ThirdPartyDALImpl.class);

    private final MongoTemplate mongoTemplate;

    public ThirdPartyDALImpl(@Qualifier("projectInformationMongoTemplate") MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    @Override
    public ThirdPartyContent fetchContentById(String thirdPartyContentId) {
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(thirdPartyContentId));
        try {
            return mongoTemplate.findOne(query, ThirdPartyContent.class);
        } catch (Exception ex) {
            throw new ServiceUnavailableException("Unable to perform Mongo Operation {" + ex.getLocalizedMessage() + "}", "Project");
        }
    }
}

请求帮助

目前判断问题出在多库连接的配置上,因为单库连接服务在相同网络、防火墙、VPC环境下无异常。希望能帮忙定位并解决频繁出现的超时告警问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 09:35:22