1. 程式人生 > >mongoDB 常見三種異常解析 (附配置)

mongoDB 常見三種異常解析 (附配置)

配置

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) {

        }