最近做spring+spring boot1.2 升到spring boot 2.2版本的时候发现, mongodb一直连不上,主要是原有的阿里云配置连接,和腾讯云的相差很大,尤其是连接加密方面,经过多方定位,排查连接方法,和各种方式,终于查出mongodb的连接配置有一个地方是不同的,下面是报错:
Exception thrown during connection pool background maintenance task
2021-09-18T02:08:44.965869943Z
2021-09-18T02:08:44.965873409Z com.mongodb.MongoSocketOpenException: Exception opening socket
2021-09-18T02:08:44.965876735Z at com.mongodb.internal.connection.SocketStream.open(SocketStream.java:70)
2021-09-18T02:08:44.965879419Z at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:128)
2021-09-18T02:08:44.965881994Z at com.mongodb.internal.connection.UsageTrackingInternalConnection.open(UsageTrackingInternalConnection.java:50)
2021-09-18T02:08:44.965884639Z at com.mongodb.internal.connection.DefaultConnectionPool$UsageTrackingInternalConnectionItemFactory.create(DefaultConnectionPool.java:530)
2021-09-18T02:08:44.965887404Z at com.mongodb.internal.connection.DefaultConnectionPool$UsageTrackingInternalConnectionItemFactory.create(DefaultConnectionPool.java:518)
2021-09-18T02:08:44.965890159Z at com.mongodb.internal.connection.ConcurrentPool.createNewAndReleasePermitIfFailure(ConcurrentPool.java:181)
2021-09-18T02:08:44.965892835Z at com.mongodb.internal.connection.ConcurrentPool.ensureMinSize(ConcurrentPool.java:175)
2021-09-18T02:08:44.96589544Z at com.mongodb.internal.connection.DefaultConnectionPool$3.run(DefaultConnectionPool.java:317)
2021-09-18T02:08:44.965898034Z at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
2021-09-18T02:08:44.965900659Z at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
2021-09-18T02:08:44.965903183Z at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
2021-09-18T02:08:44.965915216Z at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
2021-09-18T02:08:44.965917882Z at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
2021-09-18T02:08:44.965920366Z at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
2021-09-18T02:08:44.96592286Z at java.lang.Thread.run(Thread.java:745)
2021-09-18T02:08:44.965925305Z Caused by: java.net.SocketTimeoutException: connect timed out
2021-09-18T02:08:44.96592777Z at java.net.PlainSocketImpl.socketConnect(Native Method)
2021-09-18T02:08:44.965930234Z at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
2021-09-18T02:08:44.965932729Z at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
2021-09-18T02:08:44.965935835Z at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
2021-09-18T02:08:44.965938369Z at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
2021-09-18T02:08:44.965940805Z at java.net.Socket.connect(Socket.java:589)
2021-09-18T02:08:44.965943259Z at com.mongodb.internal.connection.SocketStreamHelper.initialize(SocketStreamHelper.java:64)
2021-09-18T02:08:44.965945724Z at com.mongodb.internal.connection.SocketStream.initializeSocket(SocketStream.java:79)
2021-09-18T02:08:44.965948208Z at com.mongodb.internal.connection.SocketStream.open(SocketStream.java:65)
2021-09-18T02:08:44.965950683Z ... 14 common frames omitted
2021-09-18T02:08:44.965953117Z
腾讯的连接方式:
MongoConfiguration
import com.mongodb.*;
import com.mongodb.client.MongoDatabase;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import java.util.ArrayList;
import java.util.List;
/**
* mongoDB配置
* @author chengge
*/
@Configuration
@ConditionalOnClass(MongoDbFactory.class)
public class MongoConfiguration {
@Bean
@ConfigurationProperties(value = MongoProperties.MONGO_PROPERTIES_PREFIX)
public MongoProperties getMongoSettingsProperties(){
return new MongoProperties();
}
/**
* 覆盖容器中默认的MongoDbFacotry Bean
*/
public MongoDbFactory mongoDbFactory(MongoProperties properties) {
MongoClientOptions.Builder builder = new MongoClientOptions.Builder();
builder.connectionsPerHost(properties.getMaxConnectionsPerHost());
builder.minConnectionsPerHost(properties.getMinConnectionsPerHost());
builder.threadsAllowedToBlockForConnectionMultiplier(
properties.getThreadsAllowedToBlockForConnectionMultiplier());
builder.serverSelectionTimeout(properties.getServerSelectionTimeout());
builder.maxWaitTime(properties.getMaxWaitTime());
builder.maxConnectionIdleTime(properties.getMaxConnectionIdleTime());
builder.maxConnectionLifeTime(properties.getMaxConnectionLifeTime());
builder.connectTimeout(properties.getConnectTimeout());
builder.socketTimeout(properties.getSocketTimeout());
builder.sslEnabled(properties.getSslEnabled());
builder.sslInvalidHostNameAllowed(properties.getSslInvalidHostNameAllowed());
builder.alwaysUseMBeans(properties.getAlwaysUseMBeans());
builder.heartbeatFrequency(properties.getHeartbeatFrequency());
builder.minHeartbeatFrequency(properties.getMinHeartbeatFrequency());
builder.heartbeatConnectTimeout(properties.getHeartbeatConnectTimeout());
builder.heartbeatSocketTimeout(properties.getHeartbeatSocketTimeout());
builder.localThreshold(properties.getLocalThreshold());
// 创建认证客户端
MongoClientURI connStr = new MongoClientURI(properties.getAddressList(),builder);
MongoClient mongoClient = new MongoClient(connStr);
// // 创建MongoDbFactory
MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongoClient, properties.getDbName());
return mongoDbFactory;
}
//第一个数据库 默认作为主数据库 需要添加注解 @Primary ,后面的数据库不需要这个注解
@Bean
public MongoTemplate getMongoTemplate() {
return new MongoTemplate(mongoDbFactory(getMongoSettingsProperties()) );
}
}
MongoProperties
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.ArrayList;
/**
* mongoDB配置
* @author chengge
*/
@Setter
@Getter
@ToString
public class MongoProperties {
public static final String MONGO_PROPERTIES_PREFIX = "spring.mongo";
private Integer minConnectionsPerHost = 0;
private Integer maxConnectionsPerHost = 100;
private Integer threadsAllowedToBlockForConnectionMultiplier = 5;
private Integer serverSelectionTimeout = 30000;
private Integer maxWaitTime = 120000;
private Integer maxConnectionIdleTime = 0;
private Integer maxConnectionLifeTime = 0;
private Integer connectTimeout = 10000;
private Integer socketTimeout = 0;
private Boolean socketKeepAlive = false;
private Boolean sslEnabled = false;
private Boolean sslInvalidHostNameAllowed = false;
private Boolean alwaysUseMBeans = false;
private Integer heartbeatConnectTimeout = 20000;
private Integer heartbeatSocketTimeout = 20000;
private Integer minHeartbeatFrequency = 500;
private Integer heartbeatFrequency = 10000;
private Integer localThreshold = 15;
/**
* 连接最大数
*/
private Integer connectionsPerHost = 50;
/**
* 等待连接数
*/
private Integer waitingConnectionsNumber = 50;
/**
* mongo的jar包
*/
private String mapPackage;
private String authenticationDatabase;
private String address;
private String dbName;
private String auth;
private String password;
private int port;
private String addressList;
}
application.yml
spring:
mongo:
mapPackage: com.*.*.model
address: localhost:27017
auth: user
password: password
dbName: db-name
addressList: mongodb://user:password@localhost:27017/db_name?authSource=admin&replicaSet=cmgo-79qlu0kn_0
阿里的配置文件:
MongoConfiguration
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import java.util.ArrayList;
import java.util.List;
/**
* mongoDB配置
* @author chengge
*/
@Configuration
@ConditionalOnClass(MongoDbFactory.class)
public class MongoConfiguration {
@Bean
@ConfigurationProperties(value = MongoProperties.MONGO_PROPERTIES_PREFIX)
public MongoProperties getMongoSettingsProperties(){
return new MongoProperties();
}
/**
* 覆盖容器中默认的MongoDbFacotry Bean
*/
public MongoDbFactory mongoDbFactory(MongoProperties properties) {
MongoClientOptions.Builder builder = new MongoClientOptions.Builder();
builder.connectionsPerHost(properties.getMaxConnectionsPerHost());
builder.minConnectionsPerHost(properties.getMinConnectionsPerHost());
builder.threadsAllowedToBlockForConnectionMultiplier(
properties.getThreadsAllowedToBlockForConnectionMultiplier());
builder.serverSelectionTimeout(properties.getServerSelectionTimeout());
builder.maxWaitTime(properties.getMaxWaitTime());
builder.maxConnectionIdleTime(properties.getMaxConnectionIdleTime());
builder.maxConnectionLifeTime(properties.getMaxConnectionLifeTime());
builder.connectTimeout(properties.getConnectTimeout());
builder.socketTimeout(properties.getSocketTimeout());
// builder.socketKeepAlive(properties.getSocketKeepAlive());
builder.sslEnabled(properties.getSslEnabled());
builder.sslInvalidHostNameAllowed(properties.getSslInvalidHostNameAllowed());
builder.alwaysUseMBeans(properties.getAlwaysUseMBeans());
builder.heartbeatFrequency(properties.getHeartbeatFrequency());
builder.minHeartbeatFrequency(properties.getMinHeartbeatFrequency());
builder.heartbeatConnectTimeout(properties.getHeartbeatConnectTimeout());
builder.heartbeatSocketTimeout(properties.getHeartbeatSocketTimeout());
builder.localThreshold(properties.getLocalThreshold());
MongoClientOptions mongoClientOptions = builder.build();
// MongoDB地址列表
List serverAddresses = new ArrayList<>();
for (String address : properties.getAddress()) {
String[] hostAndPort = address.split(":");
String host = hostAndPort[0];
Integer port = Integer.parseInt(hostAndPort[1]);
ServerAddress serverAddress = new ServerAddress(host, port);
serverAddresses.add(serverAddress);
}
// 连接认证
MongoCredential mongoCredential = MongoCredential.createCredential(properties.getAuth()[0], properties.getDbName(), properties.getPassword());
// 创建认证客户端
MongoClient mongoClient = new MongoClient(serverAddresses, mongoCredential, mongoClientOptions);
// // 创建MongoDbFactory
MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongoClient, properties.getDbName());
return mongoDbFactory;
}
//第一个数据库 默认作为主数据库 需要添加注解 @Primary ,后面的数据库不需要这个注解
@Bean
public MongoTemplate getMongoTemplate() {
return new MongoTemplate(mongoDbFactory(getMongoSettingsProperties()));
}
}
MongoProperties
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.ArrayList;
/**
* mongoDB配置
* @author chengge
*/
@Setter
@Getter
@ToString
public class MongoProperties {
public static final String MONGO_PROPERTIES_PREFIX = "spring.mongo";
private Integer minConnectionsPerHost = 0;
private Integer maxConnectionsPerHost = 100;
private Integer threadsAllowedToBlockForConnectionMultiplier = 5;
private Integer serverSelectionTimeout = 30000;
private Integer maxWaitTime = 120000;
private Integer maxConnectionIdleTime = 0;
private Integer maxConnectionLifeTime = 0;
private Integer connectTimeout = 10000;
private Integer socketTimeout = 0;
private Boolean socketKeepAlive = false;
private Boolean sslEnabled = false;
private Boolean sslInvalidHostNameAllowed = false;
private Boolean alwaysUseMBeans = false;
private Integer heartbeatConnectTimeout = 20000;
private Integer heartbeatSocketTimeout = 20000;
private Integer minHeartbeatFrequency = 500;
private Integer heartbeatFrequency = 10000;
private Integer localThreshold = 15;
/**
* 连接最大数
*/
private Integer connectionsPerHost = 50;
/**
* 等待连接数
*/
private Integer waitingConnectionsNumber = 50;
/**
* mongo的jar包
*/
private String mapPackage;
private String authenticationDatabase;
private ArrayList address;
private String dbName;
private String[] auth;
private char[] password;
private int port;
}
application.yml
spring:
mongo:
mapPackage: com.*.*.model
address: localhost:27017
auth: user
password: password
dbName: db-name
以上的方式主要是因为腾讯的mongodb对3.0和4.0的版本连接做了很大的限制,而阿里云则对mongodb的连接没有做这么大的限制。
好啦以上就是我个人所得经验,如果有不足的地方,或者有需要改进的地方和更好的建议,请大家联系我哦。
都看到这里了,点个关注把。