Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to implement Redis distributed Lock in Redlock

2025-01-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article will explain in detail how to implement the Redis distributed lock in Redlock. The content of the article is of high quality, so the editor shares it for you as a reference. I hope you will have some understanding of the relevant knowledge after reading this article.

Common implementation

When it comes to Redis distributed locks, most people will think: setnx+lua, or know set key value px milliseconds nx. The core implementation commands of the latter method are as follows:

-acquire lock (unique_value can be UUID, etc.) SET resource_name unique_value NX PX 30000-release lock (in lua script, be sure to compare value to prevent misunderstanding of lock) if redis.call ("get", KEYS [1]) = ARGV [1] then return redis.call ("del", KEYS [1]) else return 0end

There are three main points in this implementation (where the probability of interview is very high):

The set command uses set key value px milliseconds nx

Value should be unique

Verify the value value when releasing the lock. Do not misunderstand the lock.

In fact, the biggest disadvantage of this kind of tedious is that it only works on one Redis node when locking. Even if the Redis is highly available through sentinel, if the master-slave switch occurs on this master node for some reason, then the lock will be lost:

Got the lock on the master node of Redis

But the locked key has not been synchronized to the slave node

Master failure, failover occurs, slave node is upgraded to master node

Causing the lock to be lost.

Because of this, antirez, author of Redis, put forward a more advanced implementation of distributed lock: Redlock based on distributed environment. The author believes that Redlock is also the only way to make the interviewer the best part of all the distributed lock implementations of Redis.

Redlock implementation

The redlock algorithm proposed by antirez looks like this:

In the distributed environment of Redis, we assume that there are N Redis master. These nodes are completely independent of each other, and there is no master-slave replication or other cluster coordination mechanism. We ensure that locks will be acquired and released in the same way on N instances as in the case of a single instance of Redis. Now let's assume that there are five Redis master nodes, and we need to run these Redis instances on five servers to ensure that they don't all go down at the same time.

To get the lock, the client should do the following:

Gets the current Unix time in milliseconds.

Try to acquire the lock from five instances in turn, using the same key and a unique value (such as UUID). When requesting a lock from Redis, the client should set a network connection and response timeout, which should be less than the lock expiration time. For example, if the automatic failure time of your lock is 10 seconds, the timeout should be between 5 and 50 milliseconds. This prevents the client from waiting for the response result when the server-side Redis has been hung up. If the server does not respond within the specified time, the client should try to request a lock from another Redis instance as soon as possible.

The client uses the current time minus the time to start acquiring the lock (the time recorded in step 1) to get the time to acquire the lock. The lock is successful only if and only if the lock is obtained from most of the Redis nodes, and the time used is less than the lock failure time.

If the lock is taken, the true effective time of the key is equal to the effective time minus the time it takes to acquire the lock (the result of the calculation in step 3).

If, for some reason, the acquisition of the lock fails (the lock has not been obtained on at least one Redis instance or the lock time has exceeded the valid time), the client should unlock it on all Redis instances (even if some Redis instances are not locked at all to prevent some nodes from acquiring the lock but the client does not get a response so that the lock cannot be re-acquired for the next period of time).

Redlock source code

Redisson has encapsulated the redlock algorithm, followed by a brief introduction to its usage and an analysis of the core source code (assuming 5 redis instances).

POM dependence

Org.redisson redisson 3.3.2 usage

First, let's take a look at the distributed locking usage implemented by the redlock algorithm encapsulated by redission, which is very simple, similar to ReentrantLock:

Config config = new Config (); config.useSentinelServers (). AddSentinelAddress ("127.0.0.1 getFairLock 6369", "127.0.0.1 RLock redLock 6379", "127.0.0.1pur6389") .setMasterName ("masterName") .setPassword ("password"). SetDatabase (0); RedissonClient redissonClient = Redisson.create (config); / / you can also getFairLock (), getReadWriteLock () RLock redLock = redissonClient.getLock ("REDLOCK_KEY"); boolean isLock Try {isLock = redLock.tryLock (); / / if 500ms cannot get the lock, it is considered a failure to acquire the lock. 10000ms, that is, 10s is the lock failure time. IsLock = redLock.tryLock (10000, TimeUnit.MILLISECONDS); if (isLock) {/ / TODO if get lock success, do something;}} catch (Exception e) {} finally {/ / anyway, unlock redLock.unlock ();} unique ID

One of the most important points in implementing distributed locks is that the value of set should be unique. How does the value of redisson ensure the uniqueness of value? The answer is UUID+threadId. The entry is in redissonClient.getLock ("REDLOCK_KEY"), and the source code is in Redisson.java and RedissonLock.java:

Protected final UUID id = UUID.randomUUID (); String getLockName (long threadId) {return id + ":" + threadId;} acquire the lock

The code for acquiring lock is redLock.tryLock () or redLock.tryLock (10000, 10000, TimeUnit.MILLISECONDS). The final core source code of both is the following code, except that the default lease time (leaseTime) for the former to acquire lock is LOCK_EXPIRATION_INTERVAL_SECONDS, that is, 30s:

RFuture tryLockInnerAsync (long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand command) {internalLockLeaseTime = unit.toMillis (leaseTime) / / the command return commandExecutor.evalWriteAsync (getName (), LongCodec.INSTANCE, command, / / the KEY of the distributed lock cannot exist when acquiring the lock to 5 redis instances. If it does not exist, execute the hset command (hset REDLOCK_KEY uuid+threadId 1) And set the expiration time (also the lease time of the lock) "if (redis.call ('exists', KEYS [1]) = = 0) then" + "redis.call (' hset', KEYS [1], ARGV [2], 1) through pexpire "+" redis.call ('pexpire', KEYS [1], ARGV [1]); "+" return nil; "+" end "+ / / if the KEY of the distributed lock already exists and the value matches, indicating that it is the lock held by the current thread, then the number of reentrants is increased by 1, and the failure time is set" if ('hexists', KEYS [1], ARGV [2]) = = 1) then "+" redis.call (' hincrby', KEYS [1], ARGV [2], 1) "+" redis.call ('pexpire', KEYS [1], ARGV [1]); "+" return nil; "+" end; "+ / / obtain the number of milliseconds of KEY failure time for distributed locks" return redis.call (' pttl', KEYS [1]) ", / / these three parameters correspond to KEYS [1], ARGV [1] and ARGV [2] Collections.singletonList (getName ()), internalLockLeaseTime, getLockName (threadId);}

In the command to acquire the lock

KEYS [1] is Collections.singletonList (getName ()), which represents the key of a distributed lock, namely REDLOCK_KEY.

ARGV [1] is internalLockLeaseTime, that is, the lease time of the lock. The default is 30s.

ARGV [2] is getLockName (threadId), which is the only value of set when acquiring a lock, that is, UUID+threadId:

Release lock

The code to release the lock is redLock.unlock (), and the core source code is as follows:

Protected RFuture unlockInnerAsync (long threadId) {/ / execute the following command to all five redis instances: return commandExecutor.evalWriteAsync (getName (), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, / / if the distributed lock KEY does not exist Then post a message to channel: "if (redis.call ('exists', KEYS [1]) = = 0) then" + "redis.call (' publish', KEYS [2], ARGV [1]) "+" return 1; "+" end; "+ / / if the distributed lock exists but the value does not match, indicating that the lock has been occupied, then directly return" if ('hexists', KEYS [1], ARGV [3]) = 0) then "+" return nil; "+" end "+ / / if the current thread owns the distributed lock, subtract the number of reentrants by 1" local counter = redis.call ('hincrby', KEYS [1], ARGV [3],-1) "if the value of + / / reentrant times minus 1 is greater than 0, which means that the distributed lock has been reentered, then only set the expiration time, and you cannot delete" if (counter > 0) then "+" redis.call ('pexpire', KEYS [1], ARGV [2]); "+" return 0 If the value of "+" else + / / after the number of reentrants minus 1 is 0, indicating that the distributed lock has only been acquired once, then delete the KEY and issue the unlock message "redis.call ('del', KEYS [1]);" + "redis.call (' publish', KEYS [2], ARGV [1]) "+" return 1; "+" end; "+" return nil; ", / / these five parameters correspond to KEYS [1], KEYS [2], ARGV [1], ARGV [2] and ARGV [3] Arrays.asList (getName (), getChannelName ()), LockPubSub.unlockMessage, internalLockLeaseTime, getLockName (threadId)) } on how to implement the Redis distributed lock in Redlock is shared here. I hope the above content can be helpful to everyone and learn more knowledge. If you think the article is good, you can share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 217

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report