Implementation of distributed lock __zookeeper based on zookeeper

Source: Internet
Author: User
Tags event listener throw exception zookeeper zookeeper client
I. Introduction of Distributed Locks
    Distributed locks are mainly used to protect mutually exclusive access to shared resources across processes, across hosts and across networks in a distributed environment to ensure data consistency.
Ii. Introduction of the framework
    Before introducing using zookeeper to implement distributed locks, look at the current system architecture diagram first 

third, the distribution of the lock to obtain ideas

1. General idea of obtaining distributed lock

When acquiring a distributed lock, create a temporary sequential node under the locker node and delete the temporary node when releasing the lock. The client invokes the CreateNode method to create a temporary order node under Locker, and then calls GetChildren ("locker") to obtain all the child nodes under the locker, noting that no watcher is set at this time. After the client acquires all of the child node path, it is assumed that the client acquires the lock if it finds that it has the smallest number of child nodes previously created. If you find that the node you created is not the smallest of all child nodes and that you have not acquired the lock, then the client needs to find the node that is smaller than itself, and then call the exist () method on it and register the event listener with it locker. After that, let this node of concern be deleted, then the client's watcher will receive the corresponding notification, at this time again to determine whether the node you created is the locker child node ordinal number is the smallest, Rugao is to acquire the lock, if not then repeat the above steps to continue to obtain a node smaller than their own and register for listening. There is a lot of logic to be judged in the current process.

2. Acquiring the core algorithm flow of distributed lock

The following is a flowchart to analyze the complete algorithm for acquiring a distributed lock, as follows:

Explanation: When client a wants to acquire a distributed lock, it first creates a temporary sequential node (node_n) under Locker and immediately acquires all (first-level) child nodes under Locker.

Because there will be multiple clients at the same time for the lock, so the number of child nodes under locker will be greater than 1. For sequential nodes, the feature is that the node name is automatically followed by a numeric number,

The number of nodes created first is less than created, so the child nodes can be sorted from small to large by the number order of the node name suffixes, so that the first is the order node that was first created.

At this point it represents the first client to secure the lock. This determines whether the smallest node is a Node_n created before client A, and if so, it means that client a acquires the lock.

If not, the lock is already acquired by another client, so client a waits for it to release the lock, which is the client B waiting for the lock to delete the node that it created.

Then, by listening to the deletion event of the sequential node that is smaller than node_n, we know if client B has released the lock, and if so, then client a gets all the child nodes under locker.

Again, compare it to the Node_n node that you created, until you created the node_n that is the smallest ordinal number in all child nodes of Locker, which means that client a acquires the lock. code implementation of distributed lock based on zookeeper

1. Defining a distributed Lock interface

The distributed lock interfaces defined are as follows:

  the public interface Distributedlock {



           /** acquires the lock and waits for/public  Void acquire ()  throws Exception



           if it is not obtained; /**

            * Gets the lock until the timeout

            * @param time Timeout

            * @param unit of the units time parameter

            * @return whether to acquire the lock

            * @throws Exception

            * * Public  Boolean acquire (long time, timeunit unit)  throws Exception;



            /**

             * Release lock

             * @throws Exception

             *

            /public void releases  ()  throws Exception;

}

2. Define a simple mutual-exclusion lock

Defines a mutex class that implements the lock interface defined above, while inheriting a base class Basedistributedlock, which is primarily used to interact with zookeeper, including a method to attempt to acquire a lock and a release lock.

The implementation of the/** lock interface, mainly by means of the inherited parent class Basedistributedlock, the parent class is based on the zookeeper implementation of the distributed lock implementation of the specific details */public class Simpledistributedlockmutex extends Basedistributedlock implements Distributedlock {/* is used to save nodes that implement distributed locks in zookeeper, such as name



   For Locker:/locker, * The node should be a persistent node, under which a temporary sequential node is created to implement the distributed lock/private final String basepath; /* Lock name prefix, the order nodes created under locker For example, all begin with lock-, so that the node is easy to filter without the creation of nodes like this: lock-00000001,lock-000000002*/private staticfinal Stri



   ng lock_name = "lock-";



   /* is used to save a client to create a successful sequential node under Locker, for subsequent related operations use (such as judgment)/private String Ourlockpath; /** * is used to acquire the lock resource, acquire the lock by the parent class acquisition lock @param time to get the lock timeout * @param unit time units * @return acquire the lock * @thr OWS Exception * * Private Boolean Internallock (long time, Timeunit unit) throws Exception {//if Ourlo

        Ckpath is not empty is considered to obtain the lock, the specific implementation details see Attemptlock realization Ourlockpath = Attemptlock (time, unit);

    return Ourlockpath!=null; /** * Incoming Zookeeper Client connection objects, and BasePath * @param Client Zookeeper Connection Object * @param basepath basepath is a persistent node */public Simpledistributedlockmutex (Zkcliente XT client, String basepath) {/* Call the constructor of the parent class to create the BasePath node in zookeeper, and set the prefix for BasePath node pips * While preserving the basepath references to the current class genus

       Sex */Super (CLIENT,BASEPATH,LOCK_NAME);

    This.basepath = BasePath;

        /** get lock until timeout, throw exception after timeout/public void Acquire () throws Exception {//-1 indicates no timeout, timeout is determined by zookeeper

        if (!internallock ( -1,null)) {throw new IOException ("Connection lost!) in the path: ' +basepath+ ' ' cannot acquire the lock!");

      /** * Acquires a lock with timeout/public boolean acquire (long, timeunit) throws Exception {

   Return Internallock (time, unit);

   /** release lock/public void releases () throws Exception {ReleaseLock (Ourlockpath); }

}

3. Implementation details of distributed locks

The key logic of acquiring distributed locks lies in Basedistributedlock, which realizes the details of distributed lock based on zookeeper.

public class Basedistributedlock {private final zkclientext client;
    Private final String path;
    Private final String BasePath;
    Private final String Lockname;

    private static final Integer Max_retry_count = 10;
        Public Basedistributedlock (Zkclientext client, string path, String lockname) {this.client = client;
        This.basepath = path;        
        This.path = Path.concat ("/"). Concat (Lockname);
    This.lockname = Lockname;
    private void Deleteourpath (String ourpath) throws exception{Client.delete (Ourpath); Private String Createlocknode (zkclient client, String path) throws exception{return Client.createephemera
    lsequential (path, NULL);
     /** * The core method of acquiring the lock * @param startmillis * @param millistowait * @param ourpath * @return * @throws Exception * * Private Boolean Waittolock (Long Startmillis, long millistowait, String Ourpath) throws exc eption{Boolean Havethelock = false;

        Boolean dodelete = false; try{while (!havethelock) {//The method implements getting all the sequential nodes under the locker node and sorting from small to large list<strin
                g> children = Getsortedchildren ();

                String sequencenodename = ourpath.substring (Basepath.length () +1);

                Calculates the sort position of the order node created by the client in all child nodes of locker, and if it is sorted to 0, the lock int ourindex = Children.indexof (sequencenodename) is obtained; /* If you do not find a previously created [temporary] sequential node in Getsortedchildren, this means that the node that we created may be removed because of a network flash break and the *zookeeper is deleted.
                    Exception, let's go to the previous level the practice is to catch the exception, and to retry the specified number of times see the following Attemptlock method */if (ourindex<0) {
                throw new Zknonodeexception ("Node not found:" + sequencenodename); ///If the current client creates a node that is greater than 0 in the Locker child node list, the other client has acquired the lock//the current client needs to wait for the other client to release the lock, b

                Oolean Isgetthelock = Ourindex = 0; How to determine if another client has released a lock. Gets the node that is smaller than itself from the list of child nodes, andIt establishes a listening String Pathtowatch = Isgetthelock?

                Null:children.get (ourIndex-1);
                if (isgetthelock) {Havethelock = true; }else{//If the second small node is deleted, it means that the current client's node should be minimal, so use Countdownlatch to implement the wait String Previousse
                    Quencepath = BasePath. Concat ("/"). Concat (Pathtowatch);
                    Final Countdownlatch latch = new Countdownlatch (1); Final Izkdatalistener Previouslistener = new Izkdatalistener () {//Sub point deletion event occurs when the Countdownlatch ends, etc.
                        Wait//At this time also need to restart the program back while, to judge again.            
                        public void handledatadeleted (String datapath) throws Exception {Latch.countdown (); public void Handledatachange (String datapath, Object data) throws E                                    
      Xception {//Ignore                  }
                    }; try{//If the node does not exist, an exception client.subscribedatachanges will occur (previous

                        Sequencepath, Previouslistener);
                            if (millistowait!= null) {millistowait-= (System.currenttimemillis ()-Startmillis);
                            Startmillis = System.currenttimemillis ();    if (millistowait <= 0) {Dodelete = true;
                            Timed out-delete our node break;
                        } latch.await (millistowait, timeunit.microseconds);
                        }else{latch.await ();
                        }}catch (Zknonodeexception e) {//ignore}finally{ Client.unsubscribedatachanges (previousseqUencepath, Previouslistener);
            }}}catch (Exception e) {//Exception requires deletion node Dodelete = true;

        Throw e;
            }finally{//If necessary delete node if (dodelete) {Deleteourpath (Ourpath);
    } return Havethelock;
        private string Getlocknodenumber (String str, string lockname) {int index = Str.lastindexof (lockname);
            if (index >= 0) {index + = lockname.length (); return index <= str.length ()?
        Str.substring (Index): "";
    return str; Private List<string> Getsortedchildren () throws Exception {try{list<string> chil
            dren = Client.getchildren (BasePath);  Collections.sort (Children, new comparator<string> () {public int
                   Compare (String lhs, string rhs) {     Return Getlocknodenumber (LHS, Lockname). CompareTo (Getlocknodenumber (RHS, lockname));
            }
                }
            );

        return children;
            }catch (zknonodeexception e) {client.createpersistent (BasePath, true);
        return Getsortedchildren ();    
    } protected void ReleaseLock (String lockpath) throws exception{Deleteourpath (Lockpath); } protected String Attemptlock (long, Timeunit unit) throws exception{final long Startmillis = Sys
        Tem.currenttimemillis (); Final Long millistowait = (unit!= null)?

        Unit.tomillis (time): null;
        String ourpath = null;
        Boolean hasthelock = false;
        Boolean isdone = false;

        int retrycount = 0;

            Network Flash requires a try while (!isdone) {Isdone = true;
     try{//createlocknode is used to create a [temporary] sequential node of the client to acquire a lock under locker (basepath persistent node)           Ourpath = createlocknode (client, path); /** * This method is used to determine whether or not you have acquired the lock, that is, the order node that you created is the smallest in all child nodes of locker * If no lock is acquired, wait for the release of the other client lock and retry later until the lock is acquired

            or Timeout * * Hasthelock = Waittolock (Startmillis, millistowait, Ourpath); }catch (zknonodeexception e) {if (retrycount++ < max_retry_count) {Isdone = Fal
                Se
                }else{throw E;
        }} if (Hasthelock) {return ourpath; return null;}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.