柚子快報邀請碼778899分享:zookeeper實現(xiàn)分布式鎖
柚子快報邀請碼778899分享:zookeeper實現(xiàn)分布式鎖
zookeeper提供了分布式環(huán)境下的一致性解決方案。借此我們可以實現(xiàn)分布式鎖,而zookeeper實現(xiàn)的分布式鎖可以有兩種形式
1.分布式公平鎖
公平鎖就是指按照申請的順序來發(fā)放鎖,按照申請順序分為1,2,3,4執(zhí)行順序也是1,2,3,4
我們可以利用zookeeper的臨時順序節(jié)點來實現(xiàn)分布式公平鎖,順序節(jié)點來實現(xiàn)公平鎖,順序節(jié)點會在節(jié)點id的最后維護一個值來保證順序,
如果一個服務(wù)搶到鎖后宕機沒有釋放鎖那么就會陷入死鎖,導(dǎo)致服務(wù)停擺,
redis實現(xiàn)分布式防止這種情況的方法是設(shè)置過期時間,并通過看門狗進行無限續(xù)期,如果服務(wù)宕機,看門狗不能續(xù)期,該記錄就失效,失效后鎖釋放。
zookeeper的方法是使用臨時節(jié)點,臨時節(jié)點在服務(wù)與zookeeper結(jié)束會話時接自動刪除。此時鎖自動釋放。
當(dāng)一個服務(wù)想獲取鎖時,新建一個節(jié)點,如果自身不是順序最小的那個節(jié)點就監(jiān)聽自己的前一個節(jié)點(序號比自己小1的)。如果前一個節(jié)點被刪除了,就獲得鎖。
package org.example;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public class DistributedLock {
private static final String ZOOKEEPER_CONNECTION_STRING = "localhost:2181";
private static final int SESSION_TIMEOUT = 5000;
private static final String LOCK_ROOT = "/locks";
private static final String LOCK_NAME = "lock-";
private ZooKeeper zooKeeper;
private String lockPath;
private String currentLock;
public DistributedLock() throws IOException, InterruptedException, KeeperException {
this.zooKeeper = new ZooKeeper(ZOOKEEPER_CONNECTION_STRING, SESSION_TIMEOUT, null);
ensureRootPath();
}
private void ensureRootPath() throws KeeperException, InterruptedException {
Stat stat = zooKeeper.exists(LOCK_ROOT, false);
if (stat == null) {
zooKeeper.create(LOCK_ROOT, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
}
public void lock() throws KeeperException, InterruptedException {
currentLock = zooKeeper.create(LOCK_ROOT + "/" + LOCK_NAME, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
while (true) {
List
Collections.sort(children);
int index = children.indexOf(currentLock.substring(LOCK_ROOT.length() + 1));
if (index == 0) {
return;
} else {
String prevLock = LOCK_ROOT + "/" + children.get(index - 1);
final CountDownLatch latch = new CountDownLatch(1);
zooKeeper.exists(prevLock, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getType() == Event.EventType.NodeDeleted) {
latch.countDown();
}
}
});
latch.await();
}
}
}
public void unlock() throws KeeperException, InterruptedException {
zooKeeper.delete(currentLock, -1);
}
public void close() throws InterruptedException {
zooKeeper.close();
}
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
DistributedLock distributedLock = new DistributedLock();
distributedLock.lock();
System.out.println("搶到鎖了");
// 執(zhí)行臨界區(qū)代碼
distributedLock.unlock();
System.out.println();
distributedLock.close();
}
}
仍然可能出現(xiàn)死鎖,同一個客戶端多次擁有鎖可能出現(xiàn)死鎖。如果需要實現(xiàn)分布式鎖可以使用Curator框架的InterProcessMutex。他自己維護了一個lockData來確保鎖的可重入,解鎖死鎖。
2.分布式非公平鎖
非公平鎖指搶鎖不按照順序,一直搶誰運氣好就誰拿下。多個服務(wù)一起創(chuàng)建節(jié)點,誰創(chuàng)建成功誰擁有鎖,非順序節(jié)點不允許同名,所以只有一個服務(wù)可以擁有鎖。其他服務(wù)監(jiān)聽該節(jié)點,該節(jié)點被刪除即鎖被釋放時,其余服務(wù)再一起爭搶鎖。
package org.example;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
public class Main {
public static final int NUM = 1;
private static final String ZK_ADDRESS = "127.0.0.1:2181";
private static final String LOCK_PATH = "/lock";
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
ZooKeeper zooKeeper = new ZooKeeper(ZK_ADDRESS, 1000, null);
while (true) {
if (lock(zooKeeper)) {
System.out.println(NUM + "號搶鎖成功");
Thread.sleep(100);
unlock(zooKeeper);
} else {
System.out.println(NUM + "號搶鎖失敗");
}
}
}
public static boolean lock(ZooKeeper zooKeeper) throws InterruptedException, KeeperException {
try {
zooKeeper.create(LOCK_PATH, String.valueOf(NUM).getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
return true;
} catch (KeeperException.NodeExistsException e) {
final CountDownLatch latch = new CountDownLatch(1);
zooKeeper.exists(LOCK_PATH, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getType() == Event.EventType.NodeDeleted) {
latch.countDown();
}
}
});
latch.await();
return lock(zooKeeper);
}
}
public static void unlock(ZooKeeper zooKeeper) throws InterruptedException, KeeperException {
zooKeeper.delete(LOCK_PATH, -1);
}
}
同樣仍可能出現(xiàn)死鎖。
柚子快報邀請碼778899分享:zookeeper實現(xiàn)分布式鎖
相關(guān)閱讀
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。