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
相关产品推荐
相关产品推荐

