1. 程式人生 > >Redis學習筆記(七)jedis超時重試機制注意事項

Redis學習筆記(七)jedis超時重試機制注意事項

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框架都會有超時重試機制,在使用的時候要注意。