1. 數據庫樂觀鎖;redis
2. 基於ZooKeeper的分佈式鎖;數據庫
3. 基於Redis的分佈式鎖;緩存
這裏大概說一下三種方式的優缺點,數據庫樂觀鎖優勢是實現簡單,只須要for update關鍵詞就能夠實現,缺點是沒法知足高併發量以及數據庫讀寫頻繁的系統tomcat
ZooKeeper分佈式鎖不管是從性能以及實現的功能來講都是很是優秀,只是在開發起來須要必定的基礎,對新手可能不是很友好併發
而本文主要講第三種利用redis實現分佈式鎖,優勢是開發相對簡單,能知足必定併發量的系統,缺點是存在線程爭搶鎖的問題,當併發量到達必定級別,多個線程去爭搶同一個鎖,對性能的影響較大分佈式
雖然Redis是單線程運行,可是在分佈式的狀況下對同一資源進行操做仍是會出現問題,下圖是一個簡單的例子高併發
因此必定要保證tomcat1以及tomcat2讀寫的原子性,既讀與寫要麼都執行,要麼都不執行。關於事務的原子性能夠查詢這裏性能
那麼如何保證呢,redis在2.6中加入了lua腳本功能能夠輕鬆的解決這個問題,下面是一個簡單的例子實現了上述的加100操做ui
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)lua
大概整理了一下幾個問題:
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,具體看這裏)。
解決辦法 後面會貼出詳細教程