一, 基於資料庫實現分布式鎖
悲觀鎖
利用select … where … for update 排他鎖
注意: 其他附加功能與實現一基本一致,這裡需要注意的是「where name=lock 」,name欄位必須要走索引,否則會鎖表。有些情況下,比如表不大,mysql優化器會不走這個索引,導致鎖表問題。
樂觀鎖
所謂樂觀鎖與前邊最大區別在於基於cas思想,是不具有互斥性,不會產生鎖等待而消耗資源,操作過程中認為不存在併發衝突,只有update version失敗後才能覺察到。我們的搶購、秒殺就是用了這種實現以防止超賣。
通過增加遞增的版本號字段實現樂觀鎖
二, 基於快取(redis等)實現分布式鎖
使用命令介紹:
(1)setnx
setnx key val:當且僅當key不存在時,set乙個key為val的字串,返回1;若key存在,則什麼都不做,返回0。
(2)expire
expire key timeout:為key設定乙個超時時間,單位為second,超過這個時間鎖會自動釋放,避免死鎖。
(3)delete
delete key:刪除key
在使用redis實現分布式鎖的時候,主要就會使用到這三個命令。
實現思想:
(1)獲取鎖的時候,使用setnx加鎖,並使用expire命令為鎖新增乙個超時時間,超過該時間則自動釋放鎖,鎖的value值為乙個隨機生成的uuid,通過此在釋放鎖的時候進行判斷。
(2)獲取鎖的時候還設定乙個獲取的超時時間,若超過這個時間則放棄獲取鎖。
(3)釋放鎖的時候,通過uuid判斷是不是該鎖,若是該鎖,則執行delete進行鎖釋放。
分布式鎖的簡單實現**:
複製**
1 /**
2 * 分布式鎖的簡單實現** 4 /
5 public class distributedlock
1213 /*
14 * 加鎖
15 * @param lockname 鎖的key
16 * @param acquiretimeout 獲取超時時間
17 * @param timeout 鎖的超時時間
18 * @return 鎖標識
19 /
20 public string lockwithtimeout(string lockname, long acquiretimeout, long timeout)
42 // 返回-1代表key沒有設定超時時間,為key設定乙個超時時間
43 if (conn.ttl(lockkey) == -1)
4647 try catch (interruptedexception e)
52 }
53 } catch (jedi***ception e) finally
59 }
60 return retidentifier;
61 }
6263 /*
64 * 釋放鎖
65 * @param lockname 鎖的key
66 * @param identifier 釋放鎖的標識
67 * @return
68 */
69 public boolean releaselock(string lockname, string identifier)
86 retflag = true;
87 }
88 conn.unwatch();
89 break;
90 }
91 } catch (jedi***ception e) finally
97 }
98 return retflag;
99 }
100 }
複製**
測試剛才實現的分布式鎖
例子中使用50個執行緒模擬秒殺乙個商品,使用–運算子來實現商品減少,從結果有序性就可以看出是否為加鎖狀態。
模擬秒殺服務,在其中配置了jedis執行緒池,在初始化的時候傳給分布式鎖,供其使用。
複製**
public class service
public void seckill() }
複製**
模擬線程進行秒殺服務;
複製**
public class threada extends thread
@override
public void run() public class test }}
複製**
結果如下,結果為有序的:
這裡寫描述
若注釋掉使用鎖的部分:
複製**
public void seckill()
複製**
從結果可以看出,有一些是非同步進行的:
這裡寫描述
三, 基於zookeeper實現分布式鎖
zookeeper是乙個為分布式應用提供一致性服務的開源元件,它內部是乙個分層的檔案系統目錄樹結構,規定同乙個目錄下只能有乙個唯一檔名。基於zookeeper實現分布式鎖的步驟如下:
(1)建立乙個目錄mylock;
(2)執行緒a想獲取鎖就在mylock目錄下建立臨時順序節點;
(3)獲取mylock目錄下所有的子節點,然後獲取比自己小的兄弟節點,如果不存在,則說明當前執行緒順序號最小,獲得鎖;
(4)執行緒b獲取所有節點,判斷自己不是最小節點,設定監聽比自己次小的節點;
(5)執行緒a處理完,刪除自己的節點,執行緒b監聽到變更事件,判斷自己是不是最小的節點,如果是則獲得鎖。
這裡推薦乙個apache的開源庫curator,它是乙個zookeeper客戶端,curator提供的interprocessmutex是分布式鎖的實現,acquire方法用於獲取鎖,release方法用於釋放鎖。
優點:具備高可用、可重入、阻塞鎖特性,可解決失效死鎖問題。
缺點:因為需要頻繁的建立和刪除節點,效能上不如redis方式。
四,對比
資料庫分布式鎖實現
缺點:1.db操作效能較差,並且有鎖表的風險
2.非阻塞操作失敗後,需要輪詢,占用cpu資源;
3.長時間不commit或者長時間輪詢,可能會占用較多連線資源
redis(快取)分布式鎖實現
缺點:1.鎖刪除失敗 過期時間不好控制
2.非阻塞,操作失敗後,需要輪詢,占用cpu資源;
zk分布式鎖實現
缺點:效能不如redis實現,主要原因是寫操作(獲取鎖釋放鎖)都需要在leader上執行,然後同步到follower。
總之:zookeeper有較好的效能和可靠性。
從理解的難易程度角度(從低到高)資料庫 > 快取 > zookeeper
從實現的複雜性角度(從低到高)zookeeper >= 快取 > 資料庫
從效能角度(從高到低)快取 > zookeeper >= 資料庫
從可靠性角度(從高到低)zookeeper > 快取 > 資料庫
分布式 分布式鎖
本質是利用redis的setnx 方法的特性來加鎖,setnx 即key不存在則設定key,否則直接返回false,要求在分布式系統中使用同乙個redis服務,以下提供兩種解決方案 1 直接使用redistemplate 這其實並不能完全保證高併發下的安全問題,因為可能在鎖過期之後該執行緒尚未執行完...
分布式伺服器技術選型
附 幾種反向 伺服器比較 整體上看rabbitmq的綜合性能會更佳一些 附 mq框架的比較 附 三大web伺服器對比分析 apache lighttpd,nginx 附 常用的分布式快取的對比 附 分布式檔案系統mfs ceph glusterfs lustre的對比 附 分布式搜尋和分析引擎對比 ...
分布式專題 分布式鎖
在傳統的單體應用架構中,遇到併發安全性問題時我們可以通過同步鎖synchronized,同步 塊,reentrantlock等方式都可以解決,但隨著業務的發展,單體應用架構不能滿足龐大的使用者請求量,於是分布式系統應用而生,在分布式系統中,由於每個系統都執行在不同的伺服器上,有著不同的jvm,所以j...