最近使用redis集羣進行incr操做,老是發現計數不許確,後來通過檢查發現redis在執行incr超時會執行重試機制,形成計數不許確,測試代碼:java
/** * 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的時候設置的超時時間過短了,致使其超時重試。
incr
將超時時間設置的大一些。redis
咱們在使用這些開源框架的時候,必定要全面瞭解其運做原理,這樣才能事半功倍。另外須要注意,想httpclient、dubbo等RPC框架都會有超時重試機制,在使用的時候要注意。安全