Redis distributed lock of little understanding

1, in a distributed system, we use the locking mechanism can only guarantee the same JVM that only one thread access, but in a distributed system will not work in the lock, and this time we should use distributed lock (there variety, here refers to the redis)

2, which may be used in order redis setnx (key, value) to achieve Distributed Lock

  SETNX : When the key is not present set up, return 1, if present, returns 0 for failure. Use this command if you want to mix expire (key, time) to set the expiration time, but there are problems with this combination, as follows:

   try {
        if (redisclient. setnx(key 1) == 1) { //1
            redisClient.expire(key, 1000);//2
        }
    } finally {
        redisClient.del(key);
    }

  As the code, look no problem, but in extreme cases if finished at a 2 not perform this time the machine is down, the lock will be indefinite, and will not be removed, that is setnx expire and are disposed two commands do not have atomic . To address this issue, you can use the following command redis2.6 version set (key, value, expirefime, NX) to solve this command with setnx the same, but more time expired, can solve this problem.

3, after solve this problem, there is also a problem: If the program code execution is not completed within the time expires, then the other thread to acquire the lock other machines, this will result in two threads simultaneously execute a piece of code, and the A machine (expired the case has not finished execution) in fiηa11y will delete key, leading to accidental deletion B machine to lock (lock to get the current machine) of

  1, at this time we can start on the same machine a thread guard (as described above in Examples A machine to open a daemon thread), the thread is the main role in prolonging the operation time of the key to expire, to ensure that the code is completed . 2, with regard to accidental deletion, we can value be set to a thread id, before deleting determine what is own thread ID, that is the case then delete code like the following

     try {
            ....
        } finally {
            if (threadId equals(redisclient get(key)) {//1
                redisclient.del(key);//2
            }
        }

  Normally at this time no problem, but here's 1 and 2, any connection with the previous question similar --- does not have the atomicity , they still can go wrong, but there is no atomic redis command support access to delete, how to solve it? We can work Lua script to solve, such as in this case could write something like

     String luascript = "if redis call('get, KeY[1])==ARGV[l] then return redis.call('del', KEY[1]) else return 0 end";
        redisClient.eval(luaScript, Collection.singletonList(key), Collection.singletonlist(threadId));

4, here, basically no problem, the final code is as follows

  try {
        String luascript = "if redis call('get, KeY[1])==ARGV[l] then return redis.call('del', KEY[1]) else return 0 end";
        string threadId = Thread.currentThread() getId();
        while (redisclient set(key, threadId, 1000, NX) == 1) {
         // dosomething()
        }
    } finally {
        redisClient.eval(luaScript, Collection.singletonList(key), Collection.singletonlist(threadId));
    }

 

 

Guess you like

Origin www.cnblogs.com/zhangweicheng/p/11495971.html