JedisPool資源池優化
背景
合理的JedisPool資源池參數設置能為業務使用Redis保駕護航,本文將對JedisPool的使用、資源池的參數進行詳細說明,最後給出“最合理”配置。
一、使用方法
以官方的2.9.0為例子(Jedis Release),Maven依賴如下:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
<scope>compile</scope>
</dependency>
Jedis使用apache commons-pool2對Jedis資源池進行管理,所以在定義JedisPool時一個很重要的參數就是資源池GenericObjectPoolConfig,使用方式如下,其中有很多資源管理和使用的參數(具體看第二節)
注意:後麵會提到建議用JedisPoolConfig代替GenericObjectPoolConfig
GenericObjectPoolConfig jedisPoolConfig = new GenericObjectPoolConfig();
jedisPoolConfig.setMaxTotal(..);
jedisPoolConfig.setMaxIdle(..);
jedisPoolConfig.setMinIdle(..);
jedisPoolConfig.setMaxWaitMillis(..);
...
JedisPool的初始化如下:
// redisHost和redisPort是實例的IP和端口
// redisPassword是實例的密碼
// timeout,這裏既是連接超時又是讀寫超時,從Jedis 2.8開始有區分connectionTimeout和soTimeout的構造函數
JedisPool jedisPool = new JedisPool(jedisPoolConfig, redisHost, redisPort, timeout, redisPassword);
執行命令如下:
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
//具體的命令
jedis.executeCommand()
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
//注意這裏不是關閉連接,在JedisPool模式下,Jedis會被歸還給資源池。
if (jedis != null)
jedis.close();
}
二、參數說明
JedisPool保證資源在一個可控範圍內,並且提供了線程安全,但是一個合理的GenericObjectPoolConfig配置能為應用使用Redis保駕護航,下麵將對它的一些重要參數進行說明和建議:
在當前環境下,Jedis連接就是資源,JedisPool管理的就是Jedis連接。
1. 資源設置和使用
序號 | 參數名 | 含義 | 默認值 | 使用建議 |
---|---|---|---|---|
1 | maxTotal | 資源池中最大連接數 | 8 | 設置建議見下節 |
2 | maxIdle | 資源池允許最大空閑的連接數 | 8 | 設置建議見下節 |
3 | minIdle | 資源池確保最少空閑的連接數 | 0 | 設置建議見下節 |
4 | blockWhenExhausted | 當資源池用盡後,調用者是否要等待。隻有當為true時,下麵的maxWaitMillis才會生效 | true | 建議使用默認值 |
5 | maxWaitMillis | 當資源池連接用盡後,調用者的最大等待時間(單位為毫秒) | -1:表示永不超時 | 不建議使用默認值 |
6 | testOnBorrow | 向資源池借用連接時是否做連接有效性檢測(ping),無效連接會被移除 | false | 業務量很大時候建議設置為false(多一次ping的開銷)。 |
7 | testOnReturn | 向資源池歸還連接時是否做連接有效性檢測(ping),無效連接會被移除 | false | 業務量很大時候建議設置為false(多一次ping的開銷)。 |
8 | jmxEnabled | 是否開啟jmx監控,可用於監控 | true | 建議開啟,但應用本身也要開啟 |
2.空閑資源監測
空閑Jedis對象檢測,下麵四個參數組合來完成,testWhileIdle是該功能的開關。
序號 | 參數名 | 含義 | 默認值 | 使用建議 |
---|---|---|---|---|
1 | testWhileIdle | 是否開啟空閑資源監測 | false | true |
2 | timeBetweenEvictionRunsMillis | 空閑資源的檢測周期(單位為毫秒) | -1:不檢測 | 建議設置,周期自行選擇,也可以默認也可以使用下麵JedisPoolConfig中的配置 |
3 | minEvictableIdleTimeMillis | 資源池中資源最小空閑時間(單位為毫秒),達到此值後空閑資源將被移除 | 1000 * 60 * 30 = 30分鍾 | 可根據自身業務決定,大部分默認值即可,也可以考慮使用下麵JeidsPoolConfig中的配置 |
4 | numTestsPerEvictionRun | 做空閑資源檢測時,每次的采樣數 | 3 | 可根據自身應用連接數進行微調,如果設置為-1,就是對所有連接做空閑監測 |
為了方便使用,Jedis提供了JedisPoolConfig,它本身繼承了GenericObjectPoolConfig設置了一些空閑監測設置
public class JedisPoolConfig extends GenericObjectPoolConfig {
public JedisPoolConfig() {
// defaults to make your life with connection pool easier :)
setTestWhileIdle(true);
//
setMinEvictableIdleTimeMillis(60000);
//
setTimeBetweenEvictionRunsMillis(30000);
setNumTestsPerEvictionRun(-1);
}
}
所有默認值可以從org.apache.commons.pool2.impl.BaseObjectPoolConfig中看到。
三、資源池大小(maxTotal)、空閑(maxIdle minIdle)設置建議
1.maxTotal:最大連接數
實際上這個是一個很難回答的問題,考慮的因素比較多:
- 業務希望Redis並發量
- 客戶端執行命令時間
- Redis資源:例如 nodes(例如應用個數) * maxTotal 是不能超過redis的最大連接數。
- 資源開銷:例如雖然希望控製空閑連接,但是不希望因為連接池的頻繁釋放創建連接造成不必靠開銷。
以一個例子說明,假設:
一次命令時間(borrow|return resource + Jedis執行命令(含網絡) )的平均耗時約為1ms,一個連接的QPS大約是1000
業務期望的QPS是50000
那麼理論上需要的資源池大小是50000 / 1000 = 50個。但事實上這是個理論值,還要考慮到要比理論值預留一些資源,通常來講maxTotal可以比理論值大一些。
但這個值不是越大越好,一方麵連接太多占用客戶端和服務端資源,另一方麵對於Redis這種高QPS的服務器,一個大命令的阻塞即使設置再大資源池仍然會無濟於事。
2. maxIdle minIdle
maxIdle實際上才是業務需要的最大連接數,maxTotal是為了給出餘量,所以maxIdle不要設置過小,否則會有new Jedis(新連接)開銷,而minIdle是為了控製空閑資源監測。
連接池的最佳性能是maxTotal = maxIdle ,這樣就避免連接池伸縮帶來的性能幹擾。但是如果並發量不大或者maxTotal設置過高,會導致不必要的連接資源浪費。
可以根據實際總OPS和調用redis客戶端的規模整體評估每個節點所使用的連接池。
3.監控
實際上最靠譜的值是通過監控來得到“最佳值”的,可以考慮通過一些手段(例如jmx)實現監控,找到合理值。
四、常見問題
1.資源“不足"
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
…
Caused by: java.util.NoSuchElementException: Timeout waiting for idle object
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:449)
或者
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
…
Caused by: java.util.NoSuchElementException: Pool exhausted
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:464)
兩種情況均屬於無法從資源池獲取到資源,但第一種是超時,第二種是因為blockWhenExhausted為false根本就不等。
遇到此類異常,不要盲目的認為資源池不夠大,第三節已經進行了分析。具體原因可以排查:網絡、資源池參數設置、資源池監控(如果對jmx監控)、代碼(例如沒執行jedis.close())、慢查詢、DNS等問題。
具體可以參考該文章:https://www.atatech.org/articles/77799
2. 預熱JedisPool
由於一些原因(例如超時時間設置較小原因),有的項目在啟動成功後會出現超時。JedisPool定義最大資源數、最小空閑資源數時,不會真的把Jedis連接放到池子裏,第一次使用時,池子沒有資源使用,會new Jedis,使用後放到池子裏,可能會有一定的時間開銷,所以也可以考慮在JedisPool定義後,為JedisPool提前進行預熱,例如以最小空閑數量為預熱數量
List<Jedis> minIdleJedisList = new ArrayList<Jedis>(jedisPoolConfig.getMinIdle());
for (int i = 0; i < jedisPoolConfig.getMinIdle(); i++) {
Jedis jedis = null;
try {
jedis = pool.getResource();
minIdleJedisList.add(jedis);
jedis.ping();
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
}
}
for (int i = 0; i < jedisPoolConfig.getMinIdle(); i++) {
Jedis jedis = null;
try {
jedis = minIdleJedisList.get(i);
jedis.close();
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
}
}
廣告
雲數據庫Redis版(ApsaraDB for Redis)是一種穩定可靠、性能卓越、可彈性伸縮的數據庫服務。基於飛天分布式係統和全SSD盤高性能存儲,支持主備版和集群版兩套高可用架構。提供了全套的容災切換、故障遷移、在線擴容、性能優化的數據庫解決方案。歡迎各位購買使用:雲數據庫 Redis 版
招聘:阿裏雲-技術專家-KVstore
崗位描述:
- 負責阿裏雲Redis源碼開發維護
- 負責阿裏雲Redis cluster開發與設計
崗位要求:
- 精通C/C++,熟悉TCP, Linux Kernel等優先
- 數據結構,算法等基礎知識紮實
- 5年後台係統的設計與開發,或3年分布式係統的設計與開發,運維過大型分布式係統
- 精通至少一項開源NoSQL產品。Redis,mongodb,memcached等優先。
- 有雲服務產品或基於SSD的係統開發經驗優先
- 善於創新,樂於挑戰,有責任心,良好團隊精神
- 良好的表達能力,能夠清晰和準確地描述問題,發現並解決問題能力
最後更新:2017-11-08 20:35:09
上一篇:
Jedis常見異常匯總
下一篇:
Keras編解碼模型序列預測
內容安全策略(CSP),防禦 XSS 攻擊的好助手
Java的EE框架的輕量級和重量級
sdcc 2017深圳站峰會:技術人的充電時刻,200分鍾QA交流!
阿裏健康2017年度醫藥電商業績亮麗:年收入預計達6億元
使用 Elizabeth 為應用生成隨機樣本數據
Android 真的悲劇了? 將與Chrome OS融為一體
Git學習-->GitLab如何屏蔽掉注冊功能?
java學習路線圖------(java1234)
ZED-Board從入門到精通係列(六)——Vivado+OpenRISC
未能正確加載“VSTS for Database Professionals Sql Server Data-tier Application”包。