zookeeper实现分布式锁的原理及具体使用案例
zookeeper跟redis一樣,也是基于內存的。
官網:
http://zookeeper.apache.org/
zookeeper是分布式系統的協調服務,提供配置管理、分布式協同、命名的中心化服務以及服務注冊發現等。
zookeeper分布式鎖的實現原理:
zookeeper實現分布式鎖采用其提供的有序臨時節點+監聽來實現。臨時節點只要客戶端斷開連接就會被刪除,正好可以利用這一特性實現鎖。
zookeeper是由java語言開發的。
zookeeper中的節點類型:
節點就是用于存儲數據的,在zookeeper中,節點是類似于文件系統的目錄的結構。
①永久節點。會進行持久化,重啟不會丟失。
②臨時節點。存儲在內存中,不會持久化,重啟服務或斷開連接數據會丟失。
節點中存儲的數據可以進行排序。
當節點中的數據有更新或是節點被刪除時,會觸發zookeeper的通知機制告知客戶端,因為zookeeper一直在監聽所有的節點。
領紅包具體案例:
【具體業務邏輯是:先查詢下數據庫,判斷用戶的紅包數據是否為空,是則插入紅包數據,否則不讓插入】
①引入zkclient依賴:
<!--zookeeper客戶端zkclient--><!-- https://mvnrepository.com/artifact/com.101tec/zkclient --><dependency><groupId>com.101tec</groupId><artifactId>zkclient</artifactId><version>0.11</version></dependency>②代碼實現:
接口:
package com.zhangxueliang.demo.springbootdemo.zookeeperLock;public interface ZookeeperLock {//加鎖void lock();//解鎖void unlock();}?抽象類:
package com.zhangxueliang.demo.springbootdemo.zookeeperLock;import org.I0Itec.zkclient.ZkClient;import java.util.concurrent.CountDownLatch;/*** @ProjectName springbootdemo_src* @ClassName AbstractZookeeperLock* @Desicription tryLock和waitLock方法使用到了模板方法設計模式* @Author Zhang Xueliang* @Date 2020/1/13 14:19* @Version 1.0**/ public abstract class AbstractZookeeperLock implements ZookeeperLock {protected String lock;protected CountDownLatch countDownLatch;//門閂(倒計數器)protected String zk_address = "127.0.0.1:2181";protected ZkClient zkClient = new ZkClient(zk_address);/*** 加鎖*/@Overridepublic final void lock() {//嘗試獲取鎖if (tryLock()){//已經拿到鎖System.out.println("獲取鎖成功。。。");}else {//嘗試獲取鎖未成功,等待獲取鎖,阻塞,如果此處已經不阻塞了,那么可以繼續往下執行代碼waitLock();//上面的阻塞結束了,那么我可以繼續獲取鎖,遞歸一下}}/*** 釋放鎖*/@Overridepublic final void unlock() {//關閉連接就解鎖了if(zkClient!=null){zkClient.close();//此處也可以使用zkClient.delete(臨時節點)來實現解鎖System.out.println("解鎖成功。。。");}}//嘗試獲取鎖protected abstract boolean tryLock();//等待獲取鎖protected abstract void waitLock(); }鎖實現類:
package com.zhangxueliang.demo.springbootdemo.zookeeperLock;import org.I0Itec.zkclient.IZkDataListener;import java.util.concurrent.CountDownLatch;/*** @ProjectName springbootdemo_src* @ClassName ZookeeperDistributedLock* @Desicription TODO* @Author Zhang Xueliang* @Date 2020/1/13 14:32* @Version 1.0**/ public class ZookeeperDistributedLock extends AbstractZookeeperLock {public ZookeeperDistributedLock(String lockName){lock=lockName;}/*** 嘗試獲取鎖* @return*/@Overrideprotected boolean tryLock() {try {//創建一個臨時節點zkClient.createEphemeral(lock);return true;}catch (Exception e){return false;}}/*** 等待獲取鎖*/@Overrideprotected void waitLock() {//如果已經有線程創建了臨時節點,那么其他線程就只能等待,不能再創建該臨時節點//此時我就監聽(就是訂閱數據的改變)你這個臨時節點,如果該節點被刪除了我就等待結束,就又可以創建臨時節點//1.訂閱數據改變,就是指定監聽參數中所指定的那個節點IZkDataListener listener = new IZkDataListener() {//監聽改變@Overridepublic void handleDataChange(String s, Object o) throws Exception {}//監聽刪除@Overridepublic void handleDataDeleted(String s) throws Exception {if (countDownLatch!=null){countDownLatch.countDown();}}};//2.判斷鎖的節點是否存在if (zkClient.exists(lock)){countDownLatch = new CountDownLatch(1);try {//當計數器從1變成0之后,等待就會結束了countDownLatch.await();} catch (InterruptedException e) {e.printStackTrace();}}//3.取消訂閱zkClient.unsubscribeDataChanges(lock,listener);}}zookeeper分布式鎖代碼測試:
//測試public static void main(String[] args) {ZookeeperDistributedLock zookeeperDistributedLock = new ZookeeperDistributedLock("/addRedPacket");//一定要帶/ 不然節點添加不成功try{zookeeperDistributedLock.lock();//TODO 具體要鎖住的業務代碼//查詢用戶是否已經領過紅包//添加紅包給用戶}finally {zookeeperDistributedLock.unlock();}}測試時需要將zoo_sample.cfg配置文件中的zookeeper最大連接數調大些:
maxClientCnxns=1000 #默認60啟動兩個端口:
配置nginx.conf實現負載均衡
使用jmeter測試時訪問的是nginx的80端口:
使用jmeter模擬高并發場景:
相關參數配置--
總結
以上是生活随笔為你收集整理的zookeeper实现分布式锁的原理及具体使用案例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mybatis配置文件不在resourc
- 下一篇: JVM内存压缩开启/不开启各占几个字节