Implementation of---Distributed lock based on Redis

Source: Internet
Author: User
Tags delete key redis uuid zookeeper
Overview

At present, almost a lot of large-scale Web sites and applications are distributed deployment, data consistency in distributed scenarios has always been a relatively important topic. The distributed Cap theory tells us that "none of the distributed systems can meet both consistency (consistency), availability (availability), and partition fault tolerance (Partition tolerance) at most, at the same time." "So many systems will have to make a choice at the beginning of the design. In the vast majority of the Internet scene, the need to sacrifice strong consistency in exchange for the high availability of the system, often only need to ensure "final consistency", as long as the final time is acceptable to the user within the scope.

In many scenarios, in order to ensure the final consistency of data, we need a lot of technical solutions to support, such as distributed transactions, distributed locks and so on. using Redis to realize distributed lock reason Redis has a high performance Redis command for this support is good, the implementation is more convenient to use the command introduction

setnx

Setnx Key Val
If and only if key does not exist, set a string with a key of Val, return 1, and if key exists, do nothing and return 0.

expire

Expire Key Timeout
Set a time-out for key, in second, over which the lock is automatically freed to avoid deadlocks.

Delete

Delete key
Delete key

These three commands are used primarily when implementing distributed locks using Redis. Implement

Jedis is used to connect to Redis.

realize the idea of acquiring a lock, use SETNX lock, and use the expire command to add a time-out for the lock, more than that time to automatically release the lock, the value of the lock is a randomly generated UUID, through this when the lock is released to judge. When the lock is acquired, a time-out is also set, and if the time is exceeded, the acquisition lock is discarded. When the lock is released, the lock is judged by the UUID, and if the lock is performed, the delete is executed for lock release.

The core code for a distributed lock is as follows:

Import Redis.clients.jedis.Jedis;
Import Redis.clients.jedis.JedisPool;
Import redis.clients.jedis.Transaction;

Import redis.clients.jedis.exceptions.JedisException;
Import java.util.List;


Import Java.util.UUID;

    public class Distributedlock {private final jedispool jedispool;
    Public Distributedlock (Jedispool jedispool) {this.jedispool = Jedispool;
     }/** * Lock * @param locaname Lock key * @param acquiretimeout Get timeout * @param timeout lock time-out * @return Lock Identifier */public string Lockwithtimeout (string locaname, Long Acquiret
        Imeout, long timeout) {Jedis conn = null;
        String retidentifier = null;
            try {//Get Connection conn = Jedispool.getresource ();
            Randomly generates a value String identifier = Uuid.randomuuid (). toString ();
            The lock name, which is the key value String Lockkey = "Lock:" + locaname; Time-out, locked after lock int L is automatically releasedOckexpire = (int) (timeout/1000);
            Gets the time-out of the lock, which is longer than the time to discard the lock long end = System.currenttimemillis () + acquiretimeout;
                    while (System.currenttimemillis () < end) {if (Conn.setnx (lockkey, identifier) = = 1) {
                    Conn.expire (Lockkey, Lockexpire);
                    Returns a value that is used to release the lock time acknowledgment retidentifier = identifier;
                return retidentifier; }//Return-1 for key does not set timeout time, set a timeout for key if (Conn.ttl (lockkey) = = 1) {con
                N.expire (Lockkey, Lockexpire);
                } try {Thread.Sleep (10);
                } catch (Interruptedexception e) {thread.currentthread (). interrupt ();
        }}} catch (Jedisexception e) {e.printstacktrace ();
            } finally {if (conn! = null) {conn.close ();
  }      } return retidentifier; }/** * Release lock * @param lockname LOCK key * @param identifier The identity of the release lock * @return */public Bo
        Olean ReleaseLock (String lockname, string identifier) {Jedis conn = null;
        String Lockkey = "Lock:" + lockname;
        Boolean retflag = false;
            try {conn = Jedispool.getresource ();
                while (true) {//monitor lock, ready to start Transaction conn.watch (Lockkey); Determine if the lock is not that, if the lock is removed, the lock is released if (Identifier.equals (Conn.get (Lockkey))) {Trans
                    Action transaction = Conn.multi ();
                    Transaction.del (Lockkey);
                    list<object> results = transaction.exec ();
                    if (results = = null) {continue;
                } Retflag = true;
                } conn.unwatch ();
            Break }
        }catch (Jedisexception e) {e.printstacktrace ();
            } finally {if (conn! = null) {conn.close ();
    }} return Retflag; }
}

Test

Here's a simple example to test the distributed lock that you just implemented.
The example uses 50 threads to simulate the second kill of a commodity, using the-operator to reduce the product, from the order of the results can be seen whether the locking state.

Simulates a kill service in which a Jedis thread pool is configured, which is passed to the distributed lock for use at initialization time.

Import Redis.clients.jedis.JedisPool;
Import Redis.clients.jedis.JedisPoolConfig;

public class Service {
    private static jedispool pool = null;

    static {
        Jedispoolconfig config = new Jedispoolconfig ();
        Set maximum number of connections
        config.setmaxtotal (+);
        Set maximum idle number
        Config.setmaxidle (8);
        Set maximum wait time
        Config.setmaxwaitmillis (+ +);
        Whether validation is required when borrow an Jedis instance, and if true, all Jedis instances are available
        Config.settestonborrow (true);
        Pool = new Jedispool (config, "127.0.0.1", 6379, +);
    }

    Distributedlock lock = new Distributedlock (pool);

    int n =;

    public void Seckill () {
        //returns the value of the lock for the release of the lock when judged by
        String indentifier = lock.lockwithtimeout ("Resource", 5000, );
        System.out.println (Thread.CurrentThread (). GetName () + "acquired lock");
        System.out.println (--n);
        Lock.releaselock ("Resource", indentifier);
    }
}

Impersonate a thread for a second kill service

public class Threada extends Thread {
    Private service service;

    Public Threada (Service service) {
        this.service = service;
    }

    @Override public
    Void Run () {
        service.seckill ();
    }
}

public class Test {public
    static void Main (string[] args) {
        Service service = new service ();
        for (int i = 0; i < i++) {
            Threada Threada = new Threada (service);
            Threada.start ();}}}

The results are as follows and the results are ordered.

If you comment out the part that uses the lock

public void Seckill () {
    //returns the value of the lock for the release of the lock when judged
    //string indentifier = lock.lockwithtimeout ("Resource", (+);
    System.out.println (Thread.CurrentThread (). GetName () + "acquired lock");
    System.out.println (--n);
    Lock.releaselock ("Resource", indentifier);
}

As you can see from the results, some are asynchronous.

In a distributed environment, it is sometimes important to lock out resources, such as snapping up a resource, which can be well controlled by using distributed locks.
Of course, in the specific use, also need to consider a number of factors, such as the selection of time-outs, the acquisition of lock time has a great impact on concurrency, the implementation of the distributed lock is only a simple implementation, mainly a thought.

Using zookeeper to implement distributed locks, the reliability of using zookeeper is greater than distributed locks implemented with Redis, but the performance of Redis is better than that.

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.