1.jedis的使用
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
1.1直連
其實(shí)是tcp連接,底層用了socket。
每次都new Jedis(),使用這個(gè)對(duì)象去執(zhí)行命令,返回對(duì)應(yīng)的結(jié)果,關(guān)閉連接。
Jedis jedis = null;
try(
jedis = new Jedis("192.168.2.103",6379);
jedis.set("hello","word");
String value = jedis.get("hello");
}finally{
if(jedis != null){
jedis.close();
}
}
1.2JedisPool 連接池的使用
每次從JedisPool中借一個(gè)Jedis對(duì)象,Jedis執(zhí)行命令,返回執(zhí)行結(jié)果,歸還Jedis對(duì)象給JedisPool。
這樣不用每次都new Jedis,不用每次都走三次握手、沒(méi)用每次都關(guān)閉Jedis。
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
JedisPool jedisPool = new JedisPool(poolConfig,"192.168.2.103",6379);
Jedis jedis = null;
try{
jedis = jedisPool.getResource();
jedis.set("hello","word");
}catch(Exception e){
e.printStackTrace();
}
finally{
if(jedis != null){
//如果使用的jedispool來(lái)得到的jedis,那cloese操作不是關(guān)閉,而是歸還給線程池
jedis.close();
}
}
直連和使用連接池的對(duì)比
| 連接方式 | 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|---|
| 直連 | 簡(jiǎn)單方便 適用于少量長(zhǎng)期連接的場(chǎng)景 |
存在每次新建/關(guān)閉TCP開(kāi)銷(xiāo) 資源無(wú)法控制,存在連接泄露的可能 Jedis對(duì)象線程不安全 |
| 連接池 | Jedis預(yù)先生成,降低開(kāi)銷(xiāo) 連接池的形式保護(hù)和控制資源的使用 |
相對(duì)于直連,使用相對(duì)麻煩, 尤其在資源管理上需要很多參數(shù)來(lái)保證, 一旦規(guī)劃不合理也會(huì)出現(xiàn)問(wèn)題。 |
2.Jedis連接池配置
資源數(shù)控制參數(shù)
| 參數(shù)名 | 含義 | 默認(rèn)值 | 使用建議 |
|---|---|---|---|
| maxTotal | 資源池最大連接數(shù) | 8 | |
| maxIdle | 資源池允許最大空閑連接數(shù) | 8 | 建議=maxTotal |
| minIdle | 資源池確保最少空閑連接數(shù) | 0 | 預(yù)熱minIdle |
| jmxEnabled | 是否開(kāi)啟jmx監(jiān)控,可用于監(jiān)控 | true | 建議開(kāi)啟 |
適合的maxTotal
其實(shí)這個(gè)參數(shù)是比較難確定的,舉個(gè)例子:
- 命令平均執(zhí)行時(shí)間0.1ms = 0.001s
- 業(yè)務(wù)需要50000 QPS
- maxTotal理論值 = 0.001 * 50000 = 50個(gè)。實(shí)際值要偏大一些
對(duì)于適合的maxTotal而言,我們需要考慮
- 業(yè)務(wù)希望Redis并發(fā)量
- 客戶端執(zhí)行命令時(shí)間
- Redis資源:例如 nodes(例如應(yīng)用個(gè)數(shù)) * maxTotal 是不能超過(guò)redis的最大連接數(shù)
- 資源開(kāi)銷(xiāo):例如雖然希望控制空閑連接,但是不希望因?yàn)檫B接池的頻繁釋放創(chuàng)建連接造成不必靠開(kāi)銷(xiāo)
適合的maxIdle和minIdle
- 建議maxIdle = maxTotal,減少創(chuàng)建新連接的開(kāi)銷(xiāo)
- 建議預(yù)熱minIdle,減少第一次啟動(dòng)后的新連接開(kāi)銷(xiāo)
QPS
QPS即每秒查詢率,是對(duì)一個(gè)特定的查詢服務(wù)器在規(guī)定時(shí)間內(nèi)所處理流量多少的衡量標(biāo)準(zhǔn)。
計(jì)算關(guān)系:
QPS = 并發(fā)量 / 平均響應(yīng)時(shí)間
并發(fā)量 = QPS * 平均響應(yīng)時(shí)間
| 參數(shù)名 | 含義 | 默認(rèn)值 | 使用建議 |
|---|---|---|---|
| blockWhenExhausted | 當(dāng)資源池用盡后,調(diào)用者是否要等待。只有當(dāng)為true時(shí),下面的maxWaitMillis才會(huì)生效 | true | 建議使用默認(rèn)值 |
| maxWaitMillis | 當(dāng)資源池連接用盡后,調(diào)用者的最大等待時(shí)間(單位毫秒) | -1:表示永不超時(shí) | 不建議使用默認(rèn)值 |
| testOnBorrow | 向資源池借用連接時(shí)是否做連接有效性檢查(ping),無(wú)效連接會(huì)被移除 | false | 建議false |
| testOnReturn | 向資源池歸還連接時(shí)是否做連接有效性測(cè)試(ping),無(wú)效連接會(huì)被移除 | false | 建議false |
連接池常見(jiàn)報(bào)錯(cuò)
redis.clients.jedis.exceptions.JedisConnectionException:Could not get a resource from the pool
...
Caused by: java.utils.NoSuchElementException:Timeout waiting for idle object
獲取連接超時(shí),資源池沒(méi)有對(duì)應(yīng)的資源。
redis.clients.jedis.exceptions.JedisConnectionException:Could not get a resource from the pool
...
Caused by: java.utils.NoSuchElementException:Pool exhausted
資源池中資源耗盡。
解決思路
1.慢查詢阻塞:連接池的連接都被hang住了。
2.資源池參數(shù)不合理:QPS高、資源池太小。
3.連接泄露(沒(méi)有close()):此類(lèi)問(wèn)題比較難定位。例如client list、netstat等、最重要是代碼。
4.DNS異常。