前段時間公司的項目運行一段時間后出現宕機狀態,靜態頁面雖能打開,但是請求都無法成功。
查看日志,發現請求卡在Opening RedisConnection就不往下走了

看代碼,攔截器中有做redis操作,而不知為何redis操作不往下走了
查看源碼,jedis沒有配置最大等待時間,而默認配置 blockWhenExhausted=true ,獲取不到資源會一直阻塞等待
PooledObject<T> p = null; // Get local copy of current config so it is consistent for entire // method execution //默認配置為true,資源耗盡阻塞 final boolean blockWhenExhausted = getBlockWhenExhausted(); boolean create; final long waitTime = System.currentTimeMillis(); while (p == null) { create = false; p = idleObjects.pollFirst();//從空閑隊列彈出PooledObject if (p == null) { //如果為空,則創建,如果超過最大數,則返回空 p = create(); if (p != null) { create = true; } } if (blockWhenExhausted) { if (p == null) { if (borrowMaxWaitMillis < 0) { //如果沒有配置maxWaitMillis,則去idleObjects等待資源,如果沒有空閑資源就阻塞一直等待 p = idleObjects.takeFirst(); } else { //如果配置了maxWaitMillis,則超時返回 p = idleObjects.pollFirst(borrowMaxWaitMillis, TimeUnit.MILLISECONDS); } } if (p == null) { throw new NoSuchElementException( "Timeout waiting for idle object"); } } else { if (p == null) { throw new NoSuchElementException("Pool exhausted"); } } }
於是增加配置
<property name="maxWaitMillis" value="3000"/>
改了后,這回項目不會阻塞了,但是運行一段時間后,會頻繁的報錯,Could not get a resource from the pool
去網上找了一大圈都不靠譜,還是得自己調試找原因
想想項目中使用redis的情況,感覺一切都很正常,唯一有點值得注意的是
<property name="enableTransactionSupport" value="true" />
public static void releaseConnection(RedisConnection conn, RedisConnectionFactory factory) { if (conn == null) { return; } RedisConnectionHolder connHolder = (RedisConnectionHolder) TransactionSynchronizationManager.getResource(factory); if (connHolder != null && connHolder.isTransactionSyncronisationActive()) { if (log.isDebugEnabled()) { log.debug("Redis Connection will be closed when transaction finished."); } return; } // release transactional/read-only and non-transactional/non-bound connections. // transactional connections for read-only transactions get no synchronizer registered //如果配置了enableTransactionSupport=true,以下條件都不滿足,連接沒有釋放 if (isConnectionTransactional(conn, factory) && TransactionSynchronizationManager.isCurrentTransactionReadOnly()) { unbindConnection(factory); } else if (!isConnectionTransactional(conn, factory)) { if (log.isDebugEnabled()) { log.debug("Closing Redis Connection"); } conn.close(); } }
於是idleobjects的size一直為0,pool會新建PooledObject,等到一段時間后,達到最大資源數,便無法從pool中獲取到資源
嘗試手動釋放資源,果然就可以了
public boolean hasKey(final String key) { try { return redisTemplate.hasKey(key); } finally { //釋放連接 RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory()); } }
參考
(中文) http://www.cnblogs.com/qijiang/p/5626461.html
(原文) https://www.javaworld.com/article/3062899/big-data/lightning-fast-nosql-with-spring-data-redis.html?page=2