Distributed cache can solve the bottleneck that the memory of single server cannot expand indefinitely. In distributed cache applications, you encounter multiple client contention issues. At this time, a distributed lock is required, and the client with the lock has permission to operate.
Memcached and Redis are common distributed cache building schemes, and the following are examples of implementation methods based on Memcached and Redis distributed locks.
Memcached Distributed lock
Memcached can use the Add command, which is added only if the key does not exist , or is not processed. Memcached all commands are atomic and add the same key concurrently, only one will succeed.
Using this principle, a lock lockkey can be defined first, and add succeeds in thinking that it is getting the lock. and set the [ Expiration timeout ] Time to ensure that there is no deadlock after the outage .
After the specific operation, determine whether this operation has timed out. If the timeout is not removed, the lock is removed if it does not time out.
Pseudo code:
1 if(MC. ADD ("Lockkey","Value", ExpiredTime))2 {3 //Get the lock4 Try5 {6 //Do business function7 8 //Check Timeout9 if(!checkedtimeout ())Ten { OneMc. Delete ("Lockkey"); A } - } - Catch(Exception e) the { -Mc. Delete ("Lockkey"); - } - +}
Redis Distributed Locks
Redis does not have an add command, but there is setnx(SET if not eXists) if the given key already exists, then SETNX does not do any action. Set success, return 1 . Setting failed, returns 0 .
The SETNX command cannot set the expiration time, and you need to use the EXPIRE command to set the expiration time.
Pseudo code:
int lockresult = Rd. Setnx ("Lockkey", "Value"); if (Lockresult = = 1) { //[1] get lock //[2] Set timeout expiration Time Rd. EXPIRE ("Lockkey", expiredtime); Try { //do business function //Check timeout if (! Checkedtimeout ()) { Rd. DEL ("Lockkey"); } } catch (Exception e) { Rd. DEL ("Lockkey"); } }
There is a great potential risk to this approach. [1] After the lock is taken, then [2] is set to expire. If the outage occurs during this period, the expiration time is not set. The default cache expiration policy for Redis, this lock will not be released, resulting in deadlocks.
Therefore, it is not recommended to use this method to implement the lock timeout expiration policy in other ways:
1:setnx value = Current time + expiration timeout, return 1 get lock, return 0 does not get lock. Ext. 2.
2: get gets the value. Determines whether the lock has expired timeout. If timed out, turn 3.
3:getset ( The value of the given key is set to value and the old value of key is returned ),getset value = Current time + The expiration time-out period, the value of which is determined if it is still timed out, that means to get the lock, otherwise did not get the lock.
From 2 to 3, the timeout will be overwritten multiple times, but this will not have any effect.
Pseudo code:
String expiredtime = DateTime.Now.AddMinutes (locktimeoutminutes). ToString (); int lockresult = Rd. Setnx ("Lockkey", ExpiredTime); BOOL Getlock = false; if (Lockresult = = 1) {//Get lock Getlock = true; } else {string curexpiredtime = Rd. GET ("Lockkey"); Check lock Timeout if (Checkedlocktimeout (ExpiredTime)) {ExpiredTime = DateTime.Now . AddMinutes (locktimeoutminutes). ToString (); String newexpiredtime = Getset (ExpiredTime); if (Checkedlocktimeout (newexpiredtime)) {//get lock Getlock = True }}} if (Getlock) {try { Do business function//Check timeout if (! CheckedtiMeout ()) {Rd. DEL ("Lockkey"); }} catch (Exception e) {Rd. DEL ("Lockkey"); } }
Personally, the practice is still imperfect.
Zookeeper distributed lock, the next chapter to study.
Reference:
Zheng, e-commerce topic V: Distributed lock jeffkit with Redis for distributed locks
Memcached and Redis distributed lock scheme