利用redis實現分布式鎖


分布式鎖一般有三種實現方式:

1. 數據庫樂觀鎖;

2. 基於ZooKeeper的分布式鎖;

3. 基於Redis的分布式鎖;

這里大概說一下三種方式的優缺點,數據庫樂觀鎖優點是實現簡單,只需要for update關鍵詞就可以實現,缺點是無法滿足高並發量以及數據庫讀寫頻繁的系統

ZooKeeper分布式鎖無論是從性能以及實現的功能來說都是非常優秀,只是在開發起來需要一定的基礎,對新手可能不是很友好

而本文主要講第三種利用redis實現分布式鎖,優點是開發相對簡單,能滿足一定並發量的系統,缺點是存在線程爭搶鎖的問題,當並發量到達一定級別,多個線程去爭搶同一個鎖,對性能的影響較大


事務以及原子性

雖然Redis是單線程運行,但是在分布式的情況下對同一資源進行操作還是會出現問題,下圖是一個簡單的例子

所以一定要保證tomcat1以及tomcat2讀寫的原子性,既讀與寫要么都執行,要么都不執行。關於事務的原子性可以查詢這里

那么如何保證呢,redis在2.6中加入了lua腳本功能可以輕松的解決這個問題,下面是一個簡單的例子實現了上述的加100操作

Jedis jedis = jedisPool.getResource();
String script = "local a = redis.call('get', KEYS[0])   a = a + 100   redis.call('set', a)";

jedis.eval(script, 1, rname+"Lock",RedisCacheFactory.FactoryUUID,"1000");

分布式鎖的具體實現

大概講一下思路:首先加鎖的方式是向redis里存入一個KEY-VALUE,KEY存入的加鎖對象可以是方法、類、數據等等,VALUE存入持有鎖的節點(例如tomcat1)

大概整理了一下幾個問題:

Q:為什么VALUE存入持有鎖的節點

A:為的是防止A加的鎖被B給解除,保證只有持有鎖的節點才能解鎖

Q:怎么存入持有鎖的節點

A:這里只是我的思路是在tomcat啟的時候生成一個uuid作為該tomcat的token存入到VALUE中

 

Q:怎么防止死鎖

A:利用Redis設置鍵的過期時間

下面貼出部分代碼,僅供參考

加鎖

JedisPool jedisPool = new JedisPool(new JedisPoolConfig(),RedisInstance.hostName,Integer.parseInt(RedisInstance.port),5000,password);
Jedis jedis = jedisPool.getResource();
// key1 : key值  argv1 :value值     argv2  :過期時間 
String script = "if redis.call('EXISTS',KEYS[1]) ==0 then redis.call('set',KEYS[1],ARGV[1]) redis.call('EXPIRE',KEYS[1],ARGV[2]) return 1  else return 0 end";
long result =  (long) jedis.eval(script, 1, rname+"Lock",RedisCacheFactory.FactoryUUID,"1000");
jedis.close();
jedisPool.close();

解鎖

JedisPool jedisPool = new JedisPool(new JedisPoolConfig(),RedisInstance.hostName,Integer.parseInt(RedisInstance.port),5000,password);
Jedis jedis = jedisPool.getResource();
String script = "if redis.call('EXISTS',KEYS[1]) ==1 and redis.call('GET',KEYS[1])==ARGV[1]  then return redis.call('del',KEYS[1]) else return 0 end";
long result =  (long) jedis.eval(script, 1, rname+"Lock",RedisCacheFactory.FactoryUUID);
jedis.close();
jedisPool.close();

 以上僅個人意見,如有錯誤的地方,還請各位海涵。

后面可能會整合這次緩存改造的所有環節發出來給大家參考 一下

補充說明一下:lua操作redis時如果操作多個key不在同一節點下會出錯,原因是因為Cluster會將數據自動分布到不同的節點(虛擬的16384個slot,具體看這里)。

解決辦法 后面會貼出詳細教程


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM