Distributed lock implementation mode one based on zookeeper distribution lock

Source: Internet
Author: User
Tags mutex zookeeper
distributed Lock implementation method A distributed lock based on zookeeper
One. Why do I use distributed locks?
When the number of application servers exceeds 1, access to the same data can cause access violations (especially write conflicts). Simply using relational databases, such as MySQL, can be implemented with transactions to implement locks, and optimistic locks can be implemented using version numbers, and the biggest flaw is usability degradation (poor performance). The use of database transactions to implement a database is somewhat stretched for gleasy applications that meet large-scale concurrent access requests. In addition, for some applications that do not rely on database, such as Distributed File system, in order to ensure the correctness of the same file in a large number of read and write operations, distributed locks must be introduced to constrain concurrent operation of the same file.

two. Requirements for distributed Locks1. High performance (distributed locks cannot be the performance bottleneck of the system)
2. Avoid deadlocks (the node that gets the lock does not cause other nodes to never continue)
3. Support Lock re-entry

three. Scenario 1, distributed locks based on zookeeper
/** * Distributedlockutil.java * Distributed lock Factory class, all distributed request by the factory class responsible for * * public class Distributedlockutil {private Stati  
    C Object Schemelock = new Object ();  
    private static Object Mutexlock = new Object ();  
    private static map<string, object> Mutexlockmap = new Concurrenthashmap ();  
    Private String schema; Private map<string, distributedreentrantlock> cache = new Concurrenthashmap<string, Distributedreentrantlock  
  
    > ();  
  
    private static map<string, distributedlockutil> instances = new Concurrenthashmap ();  
        public static Distributedlockutil getinstance (String schema) {distributedlockutil u = instances.get (schema);  
                if (U = = null) {synchronized (schemelock) {u = instances.get (schema);  
                    if (U = = null) {u = new Distributedlockutil (schema);  
                Instances.put (schema, u);  
      }  
            }  
        }  return u;  
    Private Distributedlockutil (String schema) {This.schema = schema;  
        Private Object Getmutex (String key) {Object mx = mutexlockmap.get (key);  
                if (mx = = null) {synchronized (mutexlock) {mx = mutexlockmap.get (key);  
                    if (mx = = null) {mx = new Object ();  
                Mutexlockmap.put (key, MX);  
    }} return MX; Private Distributedreentrantlock Getlock (String key) {Distributedreentrantlock lock = cache.get (key)  
        ;  
                if (lock = null) {synchronized (Getmutex (key)) {lock = Cache.get (key);  
                    if (lock = = null) {lock = new Distributedreentrantlock (key, schema);  
                Cache.put (key, lock);  
    }} return lock;  
  
}    public void Reset () {A for (String S:cache.keyset ()) {Getlock ()) (s). Unlock (); }/** * Attempt to lock * if the current thread already owns the lock, return false directly, indicating that you do not need to lock again, you should not call unlock for unlocking * @param ke Y * @return * @throws interruptedexception * @throws keeperexception/Public Lockstat lock (String key) throws Interruptedexception, keeperexception {if (Getlock (key). Isowner ()) {return L  
        Ockstat.noneed;  
        } getlock (key). Lock ();  
    return lockstat.success; public void Clearlock (String key) throws Interruptedexception, keeperexception {synchronized (getmut  
            EX (key) {Distributedreentrantlock L = cache.get (key);  
            L.clear ();  
        Cache.remove (key);  
        } public void Unlock (String key, Lockstat stat) throws Interruptedexception, Keeperexception {  
    Unlock (key, stat, false);  
 } 
    public void unlock (String key, Lockstat Stat, Boolean keepalive) throws Interruptedexception, Keeperexception {  
        if (stat = null) return;  
            if (LockStat.SUCCESS.equals (stat)) {Distributedreentrantlock lock = Getlock (key);  
            Boolean haswaiter = Lock.unlock (); if (!haswaiter &&!keepalive) {synchronized (Getmutex (key)) {Lock.clear (  
                    );  
                Cache.remove (key);  
}}} public static enum Lockstat {noneed, SUCCESS}   }

/** * Distributedreentrantlock.java * The lock contention between local threads, first using the virtual machine internal locking mechanism, reduce the communication overhead between nodes/public class Distributedreentrantlock {  
    private static final Logger Logger = Logger.getlogger (Distributedreentrantlock.class);  
  
    Private Reentrantlock Reentrantlock = new Reentrantlock ();  
    Private Writelock Writelock;  
  
    Private Long timeout = 3 * 60 * 1000;  
    Private final Object Mutex = new Object ();  
    Private String dir;  
  
    Private String schema;  
            Private final Exitlistener Exitlistener = new Exitlistener () {@Override public void execute () {  
        Initwritelock ();  
  
    }  
    };  
        Private synchronized void Initwritelock () {logger.debug ("Initialize Writelock");  
                Writelock = new Writelock (dir, new Locklistener () {@Override public void lockacquired () {  
                Synchronized (mutex) {mutex.notify ();  
  
         }  
            }   @Override public void lockreleased () {}}, schema);  
        if (writelock!= null && WRITELOCK.ZK!= null) {WriteLock.zk.addExitListener (Exitlistener);  
        } synchronized (Mutex) {mutex.notify ();  
        } public Distributedreentrantlock (String dir, string schema) {this.dir = dir;  
        This.schema = schema;  
    Initwritelock (); public void Lock (long timeout) throws Interruptedexception, keeperexception {reentrantlock.lock ();  
            Multithreading competition, first get the first layer lock try {boolean res = Writelock.trylock ();  
                if (!res) {synchronized (mutex) {mutex.wait (timeout); } if (Writelock = null | |!writelock.isowner ()) {throw new Interruptedexception (  
                "Lock timeout"); catch (INterruptedexception e) {reentrantlock.unlock ();  
        Throw e;  
            catch (Keeperexception e) {reentrantlock.unlock ();  
        Throw e;  
    } public void Lock () throws Interruptedexception, Keeperexception {lock (timeout);  
    public void Destroy () throws Keeperexception {Writelock.unlock ();  
        public Boolean unlock () {if (!isowner ()) return false;  
            try {writelock.unlock (); Reentrantlock.unlock ();//multithreading competition, free outermost lock catch (RuntimeException e) {reentrantlock.unlock ();  
        When competing, release the outermost lock throw e;  
    return Reentrantlock.hasqueuedthreads (); public Boolean Isowner () {return reentrantlock.isheldbycurrentthread () && Writelock.isown  
    ER ();  
    public void Clear () {writelock.clear ();   }  
  
}

/** * Writelock.java * Based on ZK lock implementation * One of the simplest scenarios is as follows: * 1. Node A request to lock, registered in a specific path (session self-add node), get an ID number 1 * 2. Node B request lock, register yourself under a specific path (session from Add point), get an ID number 2 * 3. Node A gets all node IDs, to determine that they are the smallest node number, and then get the lock * 4. Node B gets all the node IDs, determines that it is not the smallest node, and then listens to the maximum node (node A) Change event * 5. Node A gets the lock, handles the business 
 , Dispose, release the lock (Delete yourself) * 6. Node B receives the Node A change event, judging that it is already the minimum node number, and then get the lock. * * public class Writelock extends Zkprimative {private static final Logger LOG = Logger.getlogger (writelock.class  
  
    );  
    Private Final String dir;  
    Private String ID;  
    Private Locknode Idname;  
    Private String ownerID;  
    Private String Lastchildid;  
    Private byte[] data = {0x12, 0x34};  
  
    Private Locklistener callback;  
        Public Writelock (String dir, string schema) {Super (schema, true);  
    This.dir = dir;  
        Public Writelock (String dir, Locklistener callback, string schema) {This (dir, schema); <a href = "http://www.nbso.ca/" > NBSO online casino reviews</a > This.callback = callback;  
    Public Locklistener Getlocklistener () {return this.callback;  
    public void Setlocklistener (Locklistener callback) {this.callback = callback;  
            public synchronized void Unlock () throws RuntimeException {if (ZK = null | | zk.isclosed ()) {  
        Return  
            } if (id!= null) {try {zk.delete (ID,-1);  
                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; '}} Private class LockWatcher implements watcher {public void process (Watchedevent E  Vent) {Log.debug ("Watcher Fired on Path: Event.getpath ()" State: "Event.getstate ()"  
            Type "Event.gettype ());  
            try {trylock ();  
            catch (Exception e) {Log.warn ("Failed to acquire Lock:" E, E);  
            }} 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 ("FoundID created last time: "id";  
            } break; } if (id = = NULL) {id = zookeeper.create (dir "/" prefix, data, AC  
  
            L, ephemeral_sequential);  
            if (log.isdebugenabled ()) {Log.debug ("Created ID:" id);   
        }} public void Clear () {if (ZK = null | | zk.isclosed ()) {return;  
        try {zk.delete (dir,-1);  
        catch (Exception e) {log.error ("Clear error:" E, E); } public synchronized Boolean Trylock () throws Keeperexception, interruptedexception {if (ZK =  
            = null) {Log.info ("ZK is empty");  
        return false;  
            if (zk.isclosed ()) {Log.info ("ZK is closed");  
        return false;  
  
        } ensurepathexists (dir);  
     Log.debug ("ID:" id);   Do {if (id = = NULL) {Long sessionId = Zk.getsessionid ();  
                String prefix = "x" SessionId "-";  
                Idname = new Locknode (ID);  
            Log.debug ("Idname:" Idname);  
                } if (id!= null) {list<string> names = Zk.getchildren (dir, false);  
                            if (Names.isempty ()) {Log.warn ("No Children in:" dir "when we ' ve just" "Created one!  
                    Lets recreate it ... ");  
                id = null;  
                    else {sortedset<locknode> sortednames = new treeset<locknode> ();  
                    for (String name:names) {sortednames.add (New Locknode (dir "/" name));  
                    } ownerid = Sortednames.first (). GetName ();  
                    Log.debug ("All:" Sortednames); Sortedset<locknode> LEssthanme = Sortednames.headset (idname);  
                    Log.debug ("Less Than Me:" Lessthanme);  
                        if (!lessthanme.isempty ()) {Locknode lastchildname = Lessthanme.last ();  
                        Lastchildid = Lastchildname.getname ();  
                        if (log.isdebugenabled ()) {Log.debug ("Watching Less Than me node:" Lastchildid);  
                        } Stat Stat = Zk.exists (Lastchildid, New LockWatcher ());  
                        if (stat!= null) {return boolean.false; else {Log.warn ("could not find" "stats for Les  
                        s than me: "Lastchildname.getname ()); } else {if (Isowner ()) {if (callback!=)  
                        NULL) {        Callback.lockacquired ();  
                        return boolean.true;  
        }}} while (id = = NULL);  
    return boolean.false;  
    Public String Getdir () {return dir; public Boolean Isowner () {return id!= null && ownerid!= null && id.equals (ownerid)  
    ;  
    Public String GetId () {return this.id;   }  
}



Distributed locks implemented using this scheme, it can solve the problem of lock reentry well, and use session node to avoid deadlock; performance, according to the author self-test results, lock unlock each time is an operation, this scheme to achieve the distributed lock, TPS is about 2000-3000, the performance is more general;


---end---


Related Article

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.