Redis Distributed Lock thinking

Source: Internet
Author: User
Tags delete key redis

A general lock can only be addressed to multiple threads of a single process, or to multiple processes on a single machine. In the case of multiple machines, access to the same resource requires the access process or line Chengga lock for each machine, and this is the distributed lock. Distributed locks can be implemented using multiple-computer shared caching (such as Redis). Redis's command document [1], Implementing and analyzing reference documentation [2].

Using Redis's Get, Setnx, Getset, del Four commands, you can implement distributed locks based on Redis: Got key: To read the value of a key from the Redis, if the key does not correspond to value, return nil, If the stored value is not a string type, returns an error setnx key value: means to store a key pair to the Redis, but succeeds only if the key does not exist, returns 1, otherwise fails, returns 0, does not change key's value Getset key: Sets the values of the given key to Value and returns the old value of the key. Returns the nil when the old value does not exist, when the old value is not a string type, returns the Error del key: means delete key, when key does not exist do not do operation, return delete key number

On the lock thinking, loop:
0, the value of SETNX is the current machine time + estimated operation time as the expiration time of the lock. This is to prevent the thread that acquired the lock from hanging off and unable to release the lock and cause the deadlock.
0.1, return 1, proof has obtained the lock, returned
0.2, return 0, get lock failure, need to check lock timeout time
1, get access to the lock, using the failure time to determine whether the lock is invalid.
1.1, lock timeout time may be removed from the release of the lock, at this time did not get the lock, should be recycled lock logic.
2, lock timeout time success
2.1, the lock does not time out, hibernate, recycle lock
2.2, the lock timeout, but at this time can not directly release the lock delete. Because it is possible for multiple threads to read the lock timeout at this time, if the lock is deleted directly, all threads may delete a lock on the last delete lock and a new one, and multiple threads will enter the critical section to create a competitive state.
3, at this time using the idea of optimistic lock, with Getset again to get the old time of the lock timeout.
3.1, if you get lock old timeout time successfully
3.1.1, equal to the last time the lock was acquired, proved that no one else had moved the lock during the two operation, and that the lock had been acquired at this time
3.1.2, not equal to the last time the lock timeout was acquired, indicates that someone had first moved the lock and failed to acquire the lock. Although you have modified the expiration time for others, the modified expiration time is not significant because the conflicting threads are extremely short of time. This depends on the time consistency of all machines.
3.2, if the lock old timeout time fails, prove that the current thread is the first in the lock after the failure to add a lock thread, so also get the lock
4, other circumstances have not obtained the lock, the circulation setnx bar

Thinking about unlocking:
At the time of the lock, if locked, the return timeout, as the time to unlock the voucher, unlock the key values and credentials in the lock. When I think about unlocking, there are two ways to do this:
1, unlock before get the value of the key values, judge is not the same as their own credentials. However, there are some problems: the possibility of a get return to nil, which means that there is another thread that gets the lock and returns a nil with the release, but does not equal to its own credentials. Because of the getset step, when two competing threads are in this process, the existence of the thread credentials holding the lock is not equal to value, but the value is the value of the thread setting in the slower step.

2, unlock before the use of vouchers to determine whether the lock has timed out, if there is no timeout, direct deletion, if the timeout, waiting for the lock automatically expired, so as not to accidentally delete someone else's lock. But this kind of writing is also problematic, because of the uncertainty of thread scheduling, it is not correct to unlock in absolute sense that it can be used for a long time between deletions.

Sample code

public class Redislock {private static final Logger Logger = Loggerfactory.getlogger (Redislock.class);

    Obviously Jedis also needs to configure itself to initialize private Jedis Jedis = new Jedis ();

    The default lock 15 seconds, try to circumvent the lock time is too short caused by the error release private static final Long default_lock_time = 15 * 1000;  Attempt to lock a lock, set the number of attempts to lock and timeout (milliseconds), the default minimum 15 seconds//The key to return this lock when successful, unlock when the lock and key///failure is required to return an empty string to lock (string lock, int retrycount, long timeout) {preconditions.checkargument (RetryCount > 0 && timeout > 0, "R
        Etry Count <= 0 or timeout <= 0! "); Preconditions.checkargument (RetryCount < Integer.max_value && Timeout < Long.max_value-default_lock_
        Time, "Retry the count is too the big or timeout is too big!");
        String $lock = Preconditions.checknotnull (lock) + "_redis_lock";
        Long $timeout = timeout + default_lock_time;
        String ret = null;
            Retry a certain number of times, or not, give up try {long I, status; for (i = 0, Status = 0; Status = = 0 && i < RetryCount; ++i) {//attempt to lock, and set timeout time to current machine time + timeout if (status = Jedis.setnx ($lock, ret = long.tostring (Sys Tem.currenttimemillis () + $timeout))) = = 0) {//Acquire lock failed, view lock timeout String time = Jedis.
                    Get ($lock);
                    Between lock and check, the lock is removed and an attempt is made to reset the lock if (time = null) {continue; The timeout stamp for//lock is less than the current time, proving that the lock has timed out if (Long.parselong (time) < System.currenttimemillis ()
                        {String oldtime = Jedis.getset ($lock, Long.tostring (System.currenttimemillis () + $timeout));
                            if (oldtime = null | | oldtime.equals (TIME)) {//Get the lock, jump out of the loop
                        Break
                    } try {TimeUnit.MILLISECONDS.sleep (1L); catch (IntErruptedexception e) {logger.error ("Lock key:{} sleep failed!", lock); }} if (i = = RetryCount && Status = 0) {logger.info ("L
                Ock key:{} failed! ", lock);
            Return "";
            }//Lock plus Expiration Time Jedis.pexpire ($lock, $timeout);
            Logger.info ("Lock key:{} succsee!", lock);
        return ret; catch (Exception e) {logger.error ("Redis Lock key:{} failed!
            Cached exception: ", lock, E);
        Return "";
        }//Release lock locks, require incoming lock and key//make every effort to ensure that the lock is deleted, but do not guarantee to get public void ReleaseLock (string lock, string key) {
        String $lock = Preconditions.checknotnull (lock) + "_redis_lock";
        Preconditions.checknotnull (key);
            try {Long timeout = Long.parselong (key); Lock has not timed out, the lock also belongs to itself can be deleted//But because of the uncertainty of the running of the thread, in fact, can not fully guarantee that the lock still belongs to the deletion when the actual delete operation, distanceThe above statement may have been a long time if (timeout <= system.currenttimemillis ()) {Jedis.del ($lock);
            Logger.info ("Release lock:{} with key:{} success!", lock, Key); else {logger.info ("lock:{} with key:{} timeout!
            Wait to expire ", lock, Key); } catch (Exception e) {logger.error ("Redis release {}" and key:{} failed!
        Cached exception: ", lock, Key, E); }
    }
}

2, unlock before the use of vouchers to determine whether the lock has timed out, if there is no timeout, direct deletion, if the timeout, waiting for the lock automatically expired, so as not to accidentally delete someone else's lock. But this kind of writing is also problematic, because of the uncertainty of thread scheduling, it is not correct to unlock in absolute sense that it can be used for a long time between deletions. For the new Redis, the Set method achieves a command execution with two parameters. This can also be achieved by using pipeline in older versions of Redis.

About unlocking I only think so much, hope to have help, welcome to make more bricks to exchange.

Reference Links:
[1].http://doc.redisfans.com/
[2].http://blog.csdn.net/ugg/article/details/41894947

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.