Redis學習筆記(七)jedis超時重試機制注意事項
阿新 • • 發佈:2018-12-30
redis系列文章目錄
jedis客戶端在建立連線時會設定一個超時,並且會有重試機制。
問題起源
在使用jedis客戶端的時候,我測試了一下incr
命令,該命令在執行過程中是原子的,所以理論上不會出現問題(不論單執行緒還是多執行緒)
程式碼如下:
/**
* incrf:
* 將 key 中儲存的數字值增一。
如果 key 不存在,那麼 key 的值會先被初始化為 0 ,然後再執行 INCR 操作。
如果值包含錯誤的型別,或字串型別的值不能表示為數字,那麼返回一個錯誤。
本操作的值限制在 64 位(bit)有符號數字表示之內。
這是一個針對字串的操作,因為 Redis 沒有專用的整數型別,所以 key 內儲存的字串被解釋為十進位制 64 位有符號整數來執行 INCR 操作。
返回值: 執行 INCR 命令之後 key 的值。
這裡有問題,最終資料結果大於10000
這是因為設定的超時時間太小了,他去重試了,所以最終結果大於10000
*/
@Test
public void incrTest() throws InterruptedException {
/**
* 測試執行緒安全
*/
jedisCluster.del("incrNum");
final AtomicInteger atomicInteger = new AtomicInteger(0);
final CountDownLatch countDownLatch = new CountDownLatch(10);
ExecutorService executorService = Executors.newFixedThreadPool(10 );
for(int i = 0 ; i < 10 ; i ++){
executorService.submit(new Runnable() {
@Override
public void run() {
//每個執行緒增加1000次,每次加1
for(int j = 0 ; j < 1000 ; j ++){
atomicInteger.incrementAndGet();
jedisCluster.incr("incrNum" );
}
countDownLatch.countDown();
}
});
}
countDownLatch.await();
System.out.println(jedisCluster.get("incrNum"));
System.out.println(atomicInteger);
}
這是個多執行緒的demo,不管多執行緒還是單執行緒,我最終得到的結果都是比10000大。這就奇怪了,incr
是原子的,理論上不應該會這樣。我起初以為是jedis客戶端的BUG,後來仔細一看才發現,這不是BUG,是我在建立jediscluster的時候設定的超時時間太短了,導致其超時重試。
我使用的是這個構造方法:
public JedisCluster(Set<HostAndPort> jedisClusterNode, int connectionTimeout, int soTimeout,
int maxAttempts, String password, final GenericObjectPoolConfig poolConfig) {
super(jedisClusterNode, connectionTimeout, soTimeout, maxAttempts, password, poolConfig);
}
- soTimeout: 返回值的超時時間
- maxAttempts:出現異常最大重試次數
解決辦法
將超時時間設定的大一些。
我們在使用這些開源框架的時候,一定要全面瞭解其運作原理,這樣才能事半功倍。另外需要注意,想httpclient、dubbo等RPC框架都會有超時重試機制,在使用的時候要注意。