配置
mongoDB配置
<mongo:mongo-client id="mongoClient" host="${mongo.host}" port="${mongo.port}" credentials="${mongo.user}:${mongo.pwd}@${mongo.defaultDbName}">
<mongo:client-options
connections-per-host="${mongo.connectionsPerHost}"
min-connections-per-host="${mongo.minConnectionsPerHost}"
threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}"
connect-timeout="${mongo.connectTimeout}"
max-wait-time="${mongo.maxWaitTime}"
socket-keep-alive="${mongo.socketKeepAlive}"
socket-timeout="${mongo.socketTimeout}"
description="${mongo.description}"
max-connection-idle-time="${mongo.maxConnectionIdleTime}"
max-connection-life-time="${mongo.maxConnectionLifeTime}"
heartbeat-socket-timeout="${mongo.heartbeatSocketTimeout}"
heartbeat-connect-timeout="${mongo.heartbeatConnectTimeout}"
min-heartbeat-frequency="${mongo.minHeartbeatFrequency}"
heartbeat-frequency="${mongo.heartbeatFrequency}" />
</mongo:mongo-client>
mongo.host=127.0.0.1
mongo.port=27017
mongo.defaultDbName=data
mongo.user=test
mongo.pwd=123456
# 最大连接数,每一台服务器
mongo.connectionsPerHost=1
# 可阻塞线程队列容量
mongo.threadsAllowedToBlockForConnectionMultiplier=5
# 每一台服务器的最小连接数
mongo.minConnectionsPerHost=1
#连接超时时间 1分钟
mongo.connectTimeout=60000
#等待时间 120000 2 * 60 * 1000
mongo.maxWaitTime=120000
#Socket超时时间
mongo.socketTimeout=0
#保持连接
mongo.socketKeepAlive=true
mongo.description=mongodb
## 连接空闲时间8小时,否则连接太过频繁
mongo.maxConnectionIdleTime=28800000
mongo.maxConnectionLifeTime=0
#mongo 心跳
mongo.heartbeatSocketTimeout=10000
mongo.heartbeatConnectTimeout=15000
mongo.minHeartbeatFrequency=5000
mongo.heartbeatFrequency=100000
异常1 MongoWaitQueueFullException
请求线程过多时,阻塞的线程放入不到队列之中,
线程数量 - connectionsPerHost > threadsAllowedToBlockForConnectionMultiplier * connectionsPerHost
线程数量 = connectionsPerHost * (threadsAllowedToBlockForConnectionMultiplier + 1)
根据以上公式可以得出
增大threadsAllowedToBlockForConnectionMultiplier 或者 connectionsPerHost 即可
通过多线程模拟即可
com.mongodb.MongoWaitQueueFullException: Too many threads are already waiting for a connection. Max number of threads (maxWaitQueueSize) of 5 has been exceeded.
at com.mongodb.connection.DefaultConnectionPool.createWaitQueueFullException(DefaultConnectionPool.java:274)
at com.mongodb.connection.DefaultConnectionPool.get(DefaultConnectionPool.java:93)
at com.mongodb.connection.DefaultConnectionPool.get(DefaultConnectionPool.java:86)
at com.mongodb.connection.DefaultServer.getConnection(DefaultServer.java:77)
at com.mongodb.binding.ClusterBinding$ClusterBindingConnectionSource.getConnection(ClusterBinding.java:86)
at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java:422)
at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:415)
at com.mongodb.operation.BaseWriteOperation.execute(BaseWriteOperation.java:133)
at com.mongodb.operation.BaseWriteOperation.execute(BaseWriteOperation.java:60)
at com.mongodb.Mongo.execute(Mongo.java:819)
at com.mongodb.Mongo$2.execute(Mongo.java:802)
at com.mongodb.DBCollection.executeWriteOperation(DBCollection.java:340)
at com.mongodb.DBCollection.insert(DBCollection.java:335)
at com.mongodb.DBCollection.insert(DBCollection.java:326)
at com.mongodb.DBCollection.insert(DBCollection.java:296)
at com.mongodb.DBCollection.insert(DBCollection.java:262)
at com.mongodb.DBCollection.insert(DBCollection.java:199)
at org.springframework.data.mongodb.core.MongoTemplate$9.doInCollection(MongoTemplate.java:1054)
at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:482)
... 22 more
异常2 MongoTimeoutException
阻塞队列的线程等待连接超时
解决方案:: 增大maxWaitTime参数
复现方案: 通过多线程、大数据量,无索引查询。调小maxWaitTime测试即可
Caused by: com.mongodb.MongoTimeoutException: Timeout waiting for a pooled item after 5000 MILLISECONDS
at com.mongodb.internal.connection.ConcurrentPool.get(ConcurrentPool.java:127)
at com.mongodb.connection.DefaultConnectionPool.getPooledConnection(DefaultConnectionPool.java:256)
at com.mongodb.connection.DefaultConnectionPool.get(DefaultConnectionPool.java:97)
at com.mongodb.connection.DefaultConnectionPool.get(DefaultConnectionPool.java:86)
at com.mongodb.connection.DefaultServer.getConnection(DefaultServer.java:77)
at com.mongodb.binding.ClusterBinding$ClusterBindingConnectionSource.getConnection(ClusterBinding.java:86)
at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java:431)
at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:406)
at com.mongodb.operation.FindOperation.execute(FindOperation.java:709)
at com.mongodb.operation.FindOperation.execute(FindOperation.java:81)
at com.mongodb.Mongo.execute(Mongo.java:810)
at com.mongodb.Mongo$2.execute(Mongo.java:797)
at com.mongodb.DBCursor.initializeCursor(DBCursor.java:871)
at com.mongodb.DBCursor.hasNext(DBCursor.java:142)
at com.mongodb.DBCursor.one(DBCursor.java:680)
at com.mongodb.DBCollection.findOne(DBCollection.java:831)
at com.mongodb.DBCollection.findOne(DBCollection.java:794)
at com.mongodb.DBCollection.findOne(DBCollection.java:741)
at org.springframework.data.mongodb.core.MongoTemplate$FindOneCallback.doInCollection(MongoTemplate.java:2197)
at org.springframework.data.mongodb.core.MongoTemplate$FindOneCallback.doInCollection(MongoTemplate.java:2181)
at org.springframework.data.mongodb.core.MongoTemplate.executeFindOneInternal(MongoTemplate.java:1925)
... 18 more
异常3 MongoInterruptedException
由于线程被中断导致mongo查询被中断
查询中断异常
Caused by: com.mongodb.MongoInterruptedException: Interrupted acquiring a permit to retrieve an item from the pool
at com.mongodb.internal.connection.ConcurrentPool.acquirePermit(ConcurrentPool.java:186)
at com.mongodb.internal.connection.ConcurrentPool.get(ConcurrentPool.java:126)
at com.mongodb.connection.DefaultConnectionPool.getPooledConnection(DefaultConnectionPool.java:256)
at com.mongodb.connection.DefaultConnectionPool.get(DefaultConnectionPool.java:97)
at com.mongodb.connection.DefaultConnectionPool.get(DefaultConnectionPool.java:86)
at com.mongodb.connection.DefaultServer.getConnection(DefaultServer.java:77)
at com.mongodb.binding.ClusterBinding$ClusterBindingConnectionSource.getConnection(ClusterBinding.java:86)
at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java:422)
at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:397)
at com.mongodb.operation.CountOperation.execute(CountOperation.java:232)
at com.mongodb.operation.CountOperation.execute(CountOperation.java:55)
at com.mongodb.Mongo.execute(Mongo.java:810)
at com.mongodb.Mongo$2.execute(Mongo.java:797)
at com.mongodb.DBCollection.getCount(DBCollection.java:1004)
at com.mongodb.DBCollection.count(DBCollection.java:854)
at org.springframework.data.mongodb.core.MongoTemplate$8.doInCollection(MongoTemplate.java:779)
at org.springframework.data.mongodb.core.MongoTemplate$8.doInCollection(MongoTemplate.java:777)
at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:482)
... 33 common frames omitted
Caused by: java.lang.InterruptedException: null
at java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos(AbstractQueuedSynchronizer.java:1326)
at java.util.concurrent.Semaphore.tryAcquire(Semaphore.java:409)
at com.mongodb.internal.connection.ConcurrentPool.acquirePermit(ConcurrentPool.java:180)
... 50 common frames omitted
复现程序
final Thread t1 = new Thread(() -> {
userRepository.findOneByName(UUID.randomUUID().toString());
userRepository.findOneByName(UUID.randomUUID().toString());
userRepository.findOneByName(UUID.randomUUID().toString());
userRepository.findOneByName(UUID.randomUUID().toString());
userRepository.findOneByName(UUID.randomUUID().toString());
userRepository.findOneByName(UUID.randomUUID().toString());
});
t1.start();
Thread.sleep(10000);
t1.interrupt();
while (true) {
}