jedis超時重試機制註意事項
阿新 • • 發佈:2017-09-07
del number 十進制 包含 str 沒有 時間 機制 await
最近使用redis集群進行incr操作,總是發現計數不準確,後來經過檢查發現redis在執行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的時候設置的超時時間太短了,導致其超時重試。
解決辦法
將超時時間設置的大一些。
我們在使用這些開源框架的時候,一定要全面了解其運作原理,這樣才能事半功倍。另外需要註意,想httpclient、dubbo等RPC框架都會有超時重試機制,在使用的時候要註意。
jedis超時重試機制註意事項