基於ZooKeeper的分散式鎖和佇列
在分散式系統中,往往需要一些分散式同步原語來做一些協同工作,上一篇文章介紹了Zookeeper的基本原理,本文介紹下基於Zookeeper的Lock和Queue的實現,主要程式碼都來自Zookeeper的官方recipe。
鎖(Lock)
完全分散式鎖是全域性同步的,這意味著在任何時刻沒有兩個客戶端會同時認為它們都擁有相同的鎖,使用 Zookeeper 可以實現分散式鎖,需要首先定義一個鎖節點(lock root node)。
需要獲得鎖的客戶端按照以下步驟來獲取鎖:
- 保證鎖節點(lock root node)這個父根節點的存在,這個節點是每個要獲取lock客戶端共用的,這個節點是PERSISTENT的。
-
第一次需要建立本客戶端要獲取lock的節點,呼叫 create( ),並設定 節點為EPHEMERAL_SEQUENTIAL型別,表示該節點為臨時的和順序的。如果獲取鎖的節點掛掉,則該節點自動失效,可以讓其他節點獲取鎖。
-
在父鎖節點(lock root node)上呼叫 getChildren( ) ,不需要設定監視標誌。 (為了避免“羊群效應”).
-
按照Fair競爭的原則,將步驟3中的子節點(要獲取鎖的節點)按照節點順序的大小做排序,取出編號最小的一個節點做為lock的owner,判斷自己的節點id
是否就為owner id,如果是則返回,lock成功。如果不是則呼叫 -
如果第4步監聽exist的watch被觸發,則繼續按4中的原則判斷自己是否能獲取到lock。
釋放鎖:需要釋放鎖的客戶端只需要刪除在第2步中建立的節點即可。
注意事項:
一個節點的刪除只會導致一個客戶端被喚醒,因為每個節點只被一個客戶端watch,這避免了“羊群效應”。
一個分散式lock的實現:
package org.apache.zookeeper.recipes.lock; import org.slf4j.Logger;View Codeimport org.slf4j.LoggerFactory; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import static org.apache.zookeeper.CreateMode.EPHEMERAL_SEQUENTIAL; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.ACL; import org.apache.zookeeper.data.Stat; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; /** * A <a href="package.html">protocol to implement an exclusive * write lock or to elect a leader</a>. <p/> You invoke {@link #lock()} to * start the process of grabbing the lock; you may get the lock then or it may be * some time later. <p/> You can register a listener so that you are invoked * when you get the lock; otherwise you can ask if you have the lock * by calling {@link #isOwner()} * */ public class WriteLock extends ProtocolSupport { private static final Logger LOG = LoggerFactory.getLogger(WriteLock.class); private final String dir; private String id; private ZNodeName idName; private String ownerId; private String lastChildId; private byte[] data = {0x12, 0x34}; private LockListener callback; private LockZooKeeperOperation zop; /** * zookeeper contructor for writelock * @param zookeeper zookeeper client instance * @param dir the parent path you want to use for locking * @param acls the acls that you want to use for all the paths, * if null world read/write is used. */ public WriteLock(ZooKeeper zookeeper, String dir, List<ACL> acl) { super(zookeeper); this.dir = dir; if (acl != null) { setAcl(acl); } this.zop = new LockZooKeeperOperation(); } /** * zookeeper contructor for writelock with callback * @param zookeeper the zookeeper client instance * @param dir the parent path you want to use for locking * @param acl the acls that you want to use for all the paths * @param callback the call back instance */ public WriteLock(ZooKeeper zookeeper, String dir, List<ACL> acl, LockListener callback) { this(zookeeper, dir, acl); this.callback = callback; } /** * return the current locklistener * @return the locklistener */ public LockListener getLockListener() { return this.callback; } /** * register a different call back listener * @param callback the call back instance */ public void setLockListener(LockListener callback) { this.callback = callback; } /** * Removes the lock or associated znode if * you no longer require the lock. this also * removes your request in the queue for locking * in case you do not already hold the lock. * @throws RuntimeException throws a runtime exception * if it cannot connect to zookeeper. */ public synchronized void unlock() throws RuntimeException { if (!isClosed() && id != null) { // we don't need to retry this operation in the case of failure // as ZK will remove ephemeral files and we don't wanna hang // this process when closing if we cannot reconnect to ZK try { ZooKeeperOperation zopdel = new ZooKeeperOperation() { public boolean execute() throws KeeperException, InterruptedException { zookeeper.delete(id, -1); return Boolean.TRUE; } }; zopdel.execute(); } catch (InterruptedException e) { LOG.warn("Caught: " + e, e); //set that we have been interrupted. Thread.currentThread().interrupt(); } catch (KeeperException.NoNodeException e) { // do nothing } catch (KeeperException e) { LOG.warn("Caught: " + e, e); throw (RuntimeException) new RuntimeException(e.getMessage()). initCause(e); } finally { if (callback != null) { callback.lockReleased(); } id = null; } } } /** * the watcher called on * getting watch while watching * my predecessor */ private class LockWatcher implements Watcher { public void process(WatchedEvent event) { // lets either become the leader or watch the new/updated node LOG.debug("Watcher fired on path: " + event.getPath() + " state: " + event.getState() + " type " + event.getType()); try { lock(); } catch (Exception e) { LOG.warn("Failed to acquire lock: " + e, e); } } } /** * a zoookeeper operation that is mainly responsible * for all the magic required for locking. */ private class LockZooKeeperOperation implements ZooKeeperOperation { /** find if we have been created earler if not create our node * * @param prefix the prefix node * @param zookeeper teh zookeeper client * @param dir the dir paretn * @throws KeeperException * @throws InterruptedException */ private void findPrefixInChildren(String prefix, ZooKeeper zookeeper, String dir) throws KeeperException, InterruptedException { List<String> names = zookeeper.getChildren(dir, false); for (String name : names) { if (name.startsWith(prefix)) { id = dir + "/" + name; if (LOG.isDebugEnabled()) { LOG.debug("Found id created last time: " + id); } break; } } if (id == null) { id = zookeeper.create(dir + "/" + prefix, data, getAcl(), EPHEMERAL_SEQUENTIAL); if (LOG.isDebugEnabled()) { LOG.debug("Created id: " + id); } } } /** * the command that is run and retried for actually * obtaining the lock * @return if the command was successful or not */ public boolean execute() throws KeeperException, InterruptedException { do { if (id == null) { long sessionId = zookeeper.getSessionId(); String prefix = "x-" + sessionId + "-"; // lets try look up the current ID if we failed // in the middle of creating the znode findPrefixInChildren(prefix, zookeeper, dir); idName = new ZNodeName(id); } if (id != null) { List<String> names = zookeeper.getChildren(dir, false); if (names.isEmpty()) { LOG.warn("No children in: " + dir + " when we've just " + "created one! Lets recreate it..."); // lets force the recreation of the id id = null; } else { // lets sort them explicitly (though they do seem to come back in order ususally :) SortedSet<ZNodeName> sortedNames = new TreeSet<ZNodeName>(); for (String name : names) { sortedNames.add(new ZNodeName(dir + "/" + name)); } ownerId = sortedNames.first().getName(); SortedSet<ZNodeName> lessThanMe = sortedNames.headSet(idName); if (!lessThanMe.isEmpty()) { ZNodeName lastChildName = lessThanMe.last(); lastChildId = lastChildName.getName(); if (LOG.isDebugEnabled()) { LOG.debug("watching less than me node: " + lastChildId); } Stat stat = zookeeper.exists(lastChildId, new LockWatcher()); if (stat != null) { return Boolean.FALSE; } else { LOG.warn("Could not find the" + " stats for less than me: " + lastChildName.getName()); } } else { if (isOwner()) { if (callback != null) { callback.lockAcquired(); } return Boolean.TRUE; } } } } } while (id == null); return Boolean.FALSE; } }; /** * Attempts to acquire the exclusive write lock returning whether or not it was * acquired. Note that the exclusive lock may be acquired some time later after * this method has been invoked due to the current lock owner going away. */ public synchronized boolean lock() throws KeeperException, InterruptedException { if (isClosed()) { return false; } ensurePathExists(dir); return (Boolean) retryOperation(zop); } /** * return the parent dir for lock * @return the parent dir used for locks. */ public String getDir() { return dir; } /** * Returns true if this node is the owner of the * lock (or the leader) */ public boolean isOwner() { return id != null && ownerId != null && id.equals(ownerId); } /** * return the id for this lock * @return the id for this lock */ public String getId() { return this.id; } }
注意這裡的lock,可能會失敗,會嘗試多次,每次失敗後會Sleep一段時間。
PS:官方的程式碼有個小bug,id和ownerId應該都是全路徑,即id = dir + "/" + name;原始碼在findPrefixInChildren裡有問題。
用於輔助節點大小順序排序的類:
package org.apache.zookeeper.recipes.lock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Represents an ephemeral znode name which has an ordered sequence number and * can be sorted in order * */ class ZNodeName implements Comparable<ZNodeName> { private final String name; private String prefix; private int sequence = -1; private static final Logger LOG = LoggerFactory.getLogger(ZNodeName.class); public ZNodeName(String name) { if (name == null) { throw new NullPointerException("id cannot be null"); } this.name = name; this.prefix = name; int idx = name.lastIndexOf('-'); if (idx >= 0) { this.prefix = name.substring(0, idx); try { this.sequence = Integer.parseInt(name.substring(idx + 1)); // If an exception occurred we misdetected a sequence suffix, // so return -1. } catch (NumberFormatException e) { LOG.info("Number format exception for " + idx, e); } catch (ArrayIndexOutOfBoundsException e) { LOG.info("Array out of bounds for " + idx, e); } } } @Override public String toString() { return name.toString(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ZNodeName sequence = (ZNodeName) o; if (!name.equals(sequence.name)) return false; return true; } @Override public int hashCode() { return name.hashCode() + 37; } public int compareTo(ZNodeName that) { int s1 = this.sequence; int s2 = that.sequence; if (s1 == -1 && s2 == -1) { return this.name.compareTo(that.name); } if (s1 == -1) { return -1; } else if (s2 == -1) { return 1; } else { return s1 - s2; } } /** * Returns the name of the znode */ public String getName() { return name; } /** * Returns the sequence number */ public int getZNodeName() { return sequence; } /** * Returns the text prefix before the sequence number */ public String getPrefix() { return prefix; } }View Code
PS:這個ZNodeName類是被我修改過的,官方的程式碼比較有問題,官方的先用了節點路徑的字首prefix比較,再去比較sequence序號是不對的,這樣會導致sessionid小的總是能拿到鎖。應該直接比較全域性有序的sequence序號,小的先拿到鎖,先到先得。
Zookeeper統一操作ZooKeeperOperation介面:
public interface ZooKeeperOperation { /** * Performs the operation - which may be involved multiple times if the connection * to ZooKeeper closes during this operation * * @return the result of the operation or null * @throws KeeperException * @throws InterruptedException */ public boolean execute() throws KeeperException, InterruptedException; }View Code
因為Zookeeper的操作會失敗,這個類封裝了多次嘗試:
/** * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.zookeeper.recipes.lock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooDefs; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.ACL; import org.apache.zookeeper.data.Stat; import org.apache.zookeeper.recipes.lock.ZooKeeperOperation; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; /** * A base class for protocol implementations which provides a number of higher * level helper methods for working with ZooKeeper along with retrying synchronous * operations if the connection to ZooKeeper closes such as * {@link #retryOperation(ZooKeeperOperation)} * */ class ProtocolSupport { private static final Logger LOG = LoggerFactory.getLogger(ProtocolSupport.class); protected final ZooKeeper zookeeper; private AtomicBoolean closed = new AtomicBoolean(false); private long retryDelay = 500L; private int retryCount = 10; private List<ACL> acl = ZooDefs.Ids.OPEN_ACL_UNSAFE; public ProtocolSupport(ZooKeeper zookeeper) { this.zookeeper = zookeeper; } /** * Closes this strategy and releases any ZooKeeper resources; but keeps the * ZooKeeper instance open */ public void close() { if (closed.compareAndSet(false, true)) { doClose(); } } /** * return zookeeper client instance * @return zookeeper client instance */ public ZooKeeper getZookeeper() { return zookeeper; } /** * return the acl its using * @return the acl. */ public List<ACL> getAcl() { return acl; } /** * set the acl * @param acl the acl to set to */ public void setAcl(List<ACL> acl) { this.acl = acl; } /** * get the retry delay in milliseconds * @return the retry delay */ public long getRetryDelay() { return retryDelay; } /** * Sets the time waited between retry delays * @param retryDelay the retry delay */ public void setRetryDelay(long retryDelay) { this.retryDelay = retryDelay; } /** * Allow derived classes to perform * some custom closing operations to release resources */ protected void doClose() { } /** * Perform the given operation, retrying if the connection fails * @return object. it needs to be cast to the callee's expected * return type. */ protected Object retryOperation(ZooKeeperOperation operation) throws KeeperException, InterruptedException { KeeperException exception = null; for (int i = 0; i < retryCount; i++) { try { return operation.execute(); } catch (KeeperException.SessionExpiredException e) { LOG.warn("Session expired for: " + zookeeper + " so reconnecting due to: " + e, e); throw e; } catch (KeeperException.ConnectionLossException e) { if (exception == null) { exception = e; } LOG.debug("Attempt " + i + " failed with connection loss so " + "attempting to reconnect: " + e, e); retryDelay(i); } } throw exception; } /** * Ensures that the given path exists with no data, the current * ACL and no flags * @param path */ protected void ensurePathExists(String path) { ensureExists(path, null, acl, CreateMode.PERSISTENT); } /** * Ensures that the given path exists with the given data, ACL and flags * @param path * @param acl * @param flags */ protected void ensureExists(final String path, final byte[] data, final List<ACL> acl, final CreateMode flags) { try { retryOperation(new ZooKeeperOperation() { public boolean execute() throws KeeperException, InterruptedException { Stat stat = zookeeper.exists(path, false); if (stat != null) { return true; } zookeeper.create(path, data, acl, flags); return true; } }); } catch (KeeperException e) { LOG.warn("Caught: " + e, e); } catch (InterruptedException e) { LOG.warn("Caught: " + e, e); } } /** * Returns true if this protocol has been closed * @return true if this protocol is closed */ protected boolean isClosed() { return closed.get(); } /** * Performs a retry delay if this is not the first attempt * @param attemptCount the number of the attempts performed so far */ protected void retryDelay(int attemptCount) { if (attemptCount > 0) { try { Thread.sleep(attemptCount * retryDelay); } catch (InterruptedException e) { LOG.debug("Failed to sleep: " + e, e); } } } }View Code
這個類是本客戶端獲取到lock和釋放lock的時候觸發操作的介面:
public interface LockListener { /** * call back called when the lock * is acquired */ public void lockAcquired(); /** * call back called when the lock is * released. */ public void lockReleased(); }View Code
佇列(Queue)
分散式佇列是通用的資料結構,為了在 Zookeeper 中實現分散式佇列,首先需要指定一個 Znode 節點作為佇列節點(queue node), 各個分散式客戶端通過呼叫 create() 函式向佇列中放入資料,呼叫create()時節點路徑名帶"qn-"結尾,並設定順序(sequence)節點標誌。 由於設定了節點的順序標誌,新的路徑名具有以下字串模式:"_path-to-queue-node_/qn-X",X 是唯一自增號。需要從佇列中獲取資料/移除資料的客戶端首先呼叫 getChildren() 函式,有資料則獲取(獲取資料後可以刪除也可以不刪),沒有則在佇列節點(queue node)上將 watch 設定為 true,等待觸發並處理最小序號的節點(即從序號最小的節點中取資料)。
實現步驟基本如下:
前提:需要一個佇列root節點dir
入隊:使用create()建立節點,將共享資料data放在該節點上,節點型別為PERSISTENT_SEQUENTIAL,永久順序性的(也可以設定為臨時的,看需求)。
出隊:因為佇列可能為空,2種方式處理:一種如果為空則wait等待,一種返回異常。
等待方式:這裡使用了CountDownLatch的等待和Watcher的通知機制,使用了TreeMap的排序獲取節點順序最小的資料(FIFO)。
丟擲異常:getChildren()獲取佇列資料時,如果size==0則丟擲異常。
一個分散式Queue的實現,詳細程式碼:
package org.apache.zookeeper.recipes.queue; import java.util.List; import java.util.NoSuchElementException; import java.util.TreeMap; import java.util.concurrent.CountDownLatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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 org.apache.zookeeper.data.ACL; import org.apache.zookeeper.data.Stat; /** * * A <a href="package.html">protocol to implement a distributed queue</a>. * */ public class DistributedQueue { private static final Logger LOG = LoggerFactory.getLogger(DistributedQueue.class); private final String dir; private ZooKeeper zookeeper; private List<ACL> acl = ZooDefs.Ids.OPEN_ACL_UNSAFE; private final String prefix = "qn-"; public DistributedQueue(ZooKeeper zookeeper, String dir, List<ACL> acl){ this.dir = dir; if(acl != null){ this.acl = acl; } this.zookeeper = zookeeper; //Add root dir first if not exists if (zookeeper != null) { try { Stat s = zookeeper.exists(dir, false); if (s == null) { zookeeper.create(dir, new byte[0], acl, CreateMode.PERSISTENT); } } catch (KeeperException e) { LOG.error(e.toString()); } catch (InterruptedException e) { LOG.error(e.toString()); } } } /** * Returns a Map of the children, ordered by id. * @param watcher optional watcher on getChildren() operation. * @return map from id to child name for all children */ private TreeMap<Long,String> orderedChildren(Watcher watcher) throws KeeperException, InterruptedException { TreeMap<Long,String> orderedChildren = new TreeMap<Long,String>(); List<String> childNames = null; try{ childNames = zookeeper.getChildren(dir, watcher); }catch (KeeperException.NoNodeException e){ throw e; } for(String childName : childNames){ try{ //Check format if(!childName.regionMatches(0, prefix, 0, prefix.length())){ LOG.warn("Found child node with improper name: " + childName); continue; } String suffix = childName.substring(prefix.length()); Long childId = new Long(suffix); orderedChildren.put(childId,childName); }catch(NumberFormatException e){ LOG.warn("Found child node with improper format : " + childName + " " + e,e); } } return orderedChildren; } /** * Find the smallest child node. * @return The name of the smallest child node. */ private String smallestChildName() throws KeeperException, InterruptedException {相關推薦
Zookeeper分散式鎖和佇列
1.分散式鎖 分散式鎖,這個主要得益於ZooKeeper為我們保證了資料的強一致性。鎖服務可以分為兩類,一個是保持獨佔,另一個是控制時序。 所謂保持獨佔,就是所有試圖來獲取這個鎖的客戶端,最終只有一個可以成功獲得這把鎖。通常的做法是把zk上的一個znode看作是一把鎖,通過 create z
基於ZooKeeper的分散式鎖和佇列
在分散式系統中,往往需要一些分散式同步原語來做一些協同工作,上一篇文章介紹了Zookeeper的基本原理,本文介紹下基於Zookeeper的Lock和Queue的實現,主要程式碼都來自Zookeeper的官方recipe。 鎖(Lock) 完全分散式鎖是全域性同步的,這意味著在任何時刻沒有兩個客戶端會同時
關於redis中使用鎖機制,( 實現分散式鎖和任務佇列)
場景: 電商網站上有很多秒殺活動,會迎來一個使用者請求的高峰期,可能會有幾十萬幾百萬的併發量,來搶這個手機,在高併發的情形下會對資料庫伺服器或者是檔案伺服器應用伺服器造成巨大的壓力,嚴重時說不定就宕機了; 另一個問題是,秒殺的東西都是有量的,一款手
Java操作Zookeeper實現分散式鎖、佇列
Zookeeper客戶端(Apache Curator) ZooKeeper常用客戶端 - zookeeper自帶的客戶端是官方提供的,比較底層、使用起來寫程式碼麻煩、不夠直接。 - Apache Curator是Apache的開源專案,封裝了zooke
基於Redis的分散式鎖和Redlock演算法
1 前言 前面寫了4篇Redis底層實現和工程架構相關文章,感興趣的讀者可以回顧一下: Redis面試熱點之底層實現篇-1 Redis面試熱點之底層實現篇-2 Redis面試熱點之工程架構篇-1 Redis面試熱點之工程架構篇-2 今天開始來和大家一起學習一下Redis實際應用篇,會寫幾個Redis的常見
如何用 Redis 實現分散式鎖和超時情況處理
目前各種分散式的架構和微服務架構無處不在,在這種類似架構中處理併發和分散式併發問題,本場 Chat 就主要以 Redis 為例,使用分散式鎖的方式如何處理併發問題和避免超時情況的出現,主要從以下幾個方面講述: Redis 的 Setnx 命令是如何實現分散式鎖的; Setnx 的實現鎖的
ZooKeeper - 分散式鎖
ZooKeeper實現分散式鎖的優點:ZK可以建立持久節點、臨時節點和順序節點。臨時節點在會話結束之後,自動被刪除。即使發生宕機,只要超出心跳時間,就會斷開會話,從而刪除臨時節點,不會造成死鎖的現象。 指定競爭的資源,在ZK下生成持久節點。 在
七張圖徹底講清楚ZooKeeper分散式鎖的實現原理【石杉的架構筆記】
歡迎關注個人公眾號:石杉的架構筆記(ID:shishan100) 週一至週五早8點半!精品技術文章準時送上! 一、寫在前面 之前寫過一篇文章(《拜託,面試請不要再問我Redis分散式鎖的實現原理》),給大家說了一下Redisson這個開源框架是如何實現Redis分散式鎖原理的,這篇文章再給大家聊一下ZooKe
zooKeeper分散式鎖的實現原理
ZooKeeper分散式鎖機制 接下來我們一起來看看,多客戶端獲取及釋放zk分散式鎖的整個流程及背後的原理。 首先大家看看下面的圖,如果現在有兩個客戶端一起要爭搶zk上的一把分散式鎖,會是個什麼場景? 如果大家對zk還不太瞭解的話,建議先自行百度一下,簡單瞭解點基本概念,比
ZooKeeper分散式鎖簡單實踐 利用Redis實現分散式鎖
寫在最前面 前幾周寫了篇 利用Redis實現分散式鎖 ,今天簡單總結下ZooKeeper實現分散式鎖的過程。其實生產上我只用過Redis或者資料庫的方式,之前還真沒了解過ZooKeeper怎麼實現分散式鎖。這周簡單寫了個小Demo,更堅定了我繼續使用Redis的信心了。 ZooKeep
ZooKeeper分散式鎖簡單實踐
ZooKeeper分散式鎖的實現原理 在分散式解決方案中,Zookeeper是一個分散式協調工具。當多個JVM客戶端,同時在ZooKeeper上建立相同的一個臨時節點,因為臨時節點路徑是保證唯一,只要誰能夠建立節點成功,誰就能夠獲取到鎖。沒有建立成功節點,就會進行等待,當釋放鎖的時候,採用事件通知給客
zookeeper 分散式鎖
推薦: 1. Curator 實現 <dependency> <groupId>org.apache.curator</groupId> <artifa
淺談ZooKeeper分散式鎖(來自LJ)
目前的應用系統,大部分都是分散式部署的,分散式應用中的資料一致性問題是每個系統都要面臨的問題,分散式的CAP理論告訴我們“一個分散式系統不可能同時滿足一致性(C:Consistency)、可用性(A:Availability)和分割槽容錯性(P:Partition toler
Zookeeper分散式鎖的使用
由於公司引入了dubbo+zookeeper框架,裡面不可避免的引入的zookeeper分散式鎖,所以自己大致瞭解了一下。由於是自己研究,有不正確的地方還請大佬批評指正。 首先先介紹一下自己對zookeeper分散式鎖的理解,之後會引入一版別人的感覺比較好的描述給大家 1
zookeeper-分散式鎖的程式碼實現-【每日五分鐘搞定大資料】
本文涉及到幾個zookeeper簡單的知識點,永久節點、有序節點、watch機制。比較基礎,熟悉的就別看了跳過這篇吧 每個執行緒在/locks節點下建立一個臨時有序節點test_lock_0000000040 獲得/locks節點下所有子節點A、B、C,排序獲得最小值 若當前節點B為最小值則獲得鎖,執
基於Redis分散式鎖(獲取鎖及解鎖)
目前幾乎很多大型網站及應用都是分散式部署的,分散式場景中的資料一致性問題一直是一個比較重要的話題。分散式的CAP理論告訴我們“任何一個分散式系統都無法同時滿足一致性(Consistency)、可用性(Availability)和分割槽容錯性(Partition tolerance),最多隻能同時滿足兩項。
zookeeper學習系列(五)zookeeper分散式鎖機制
大家也許都很熟悉了多個執行緒或者多個程序間的共享鎖的實現方式了,但是在分散式場景中我們會面臨多個Server之間的鎖的問題,實現的複雜度比較高。利用基於google chubby原理開發的開源的zookeeper,可以使得這個問題變得簡單很多。下面介紹幾種可能的實現方式
基於redis分散式鎖實現“秒殺”
最近在專案中遇到了類似“秒殺”的業務場景,在本篇部落格中,我將用一個非常簡單的demo,闡述實現所謂“秒殺”的基本思路。 業務場景 所謂秒殺,從業務角度看,是短時間內多個使用者“爭搶”資源,這裡的資源在大部分秒殺場景裡是商品;將業務抽象,技術角度看,秒殺就是
zookeeper 分散式鎖種類以及優缺點
zookeeper 分散式鎖原理:1 大家也許都很熟悉了多個執行緒或者多個程序間的共享鎖的實現方式了,但是在分散式場景中我們會面臨多個Server之間的鎖的問題,實現的複雜度比較高。利用基於google chubby原理開發的開源的zookeeper,可以使得這個問題變得簡單
CSDN站內最全的zookeeper分散式鎖的講解
1 場景描述 在分散式應用, 往往存在多個程序提供同一服務. 這些程序有可能在相同的機器上, 也有可能分佈在不同的機器上. 如果這些程序共享了一些資源, 可能就需要分散式鎖來鎖定對這些資源的訪問。 2 思路 程序需要訪問共享資料時, 就在"/locks"節點下建立一個sequence型別