Introduction of Redis

Redis is a fully open source, BSD compliant, high-performance key-value database.

Redis and other key-value cache products have the following three features:

  • Redis supports data persistence. Data stored in memory can be saved to disk, which can be reloaded and used upon restart.
  • Redis supports not only simple key-value data, but also lists, sets, zsets, hash and other data structures.
  • Redis supports data backup in master-slave mode.

advantage

  • High performance – Redis can read at 110000 times per second and write at 81000 times per second.
  • Rich data types – Redis supports Strings, Lists, Hashes, Sets, and Ordered Sets operations for binary cases.
  • Atomic – All operations of Redis are atomic, meaning that they either succeed or fail at all. Individual operations are atomic. Multiple operations also support transactions, that is, atomicity, wrapped through MULTI and EXEC instructions.
  • Rich features – Redis also supports Publish/SUBSCRIBE, notifications, key expiration, and more.

Application scenario:

1. Cache, 2. Task queue, 3. Application Rankings, 4. Data expiration processing. 6. Session separation in distributed cluster architecture. The most important application scenario is caching. Today I will talk about the application of Redis in distributed.

The principle of distributed locking

The redis-based setnx command sets a key. If the key does not exist in redis, the setting succeeds. If the key does exist, the setting fails. In the distributed cluster environment, the threads of multiple servers set a key at the same time. The successful setting of the server thread means that the server thread obtains the lock object, and other threads must wait. The thread that acquired the lock needs to remember to release the lock (remove that key) at some point. Here is a simple code snippet for locking and unlocking.

/** * @date 2021/08 */ @Component public class RedisLock { @Autowired private RedisTemplate redisTemplate; private static final Long SUCCESS = 1L; private long timeout = 9999; // Obtain the lock timeout /** * lock, * * @param * @param * @return */ public Boolean tryLock(String key, String value, String value) long expireTime) { Long start = System.currentTimeMillis(); try{ for(;;) {//SET returns OK, Is that acquiring a lock successful Boolean ret = redisTemplate. OpsForValue () setIfAbsent (key, value, expireTime, TimeUnit. SECONDS); if(ret){ return true; } long end = system.currentTimemillis () -start; if (end>=timeout) { return false; }}finally {}} /** * Unlock ** @param * @param * @return */ public Boolean Unlock (String key, String key, String key) String value) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; RedisScript<String> redisScript = new DefaultRedisScript<>(script, String.class); Object result = redisTemplate.execute(redisScript, Collections.singletonList(key),value); if(SUCCESS.equals(result)) { return true; } return false; }}Copy the code

The key to the implementation of distributed lock is to build a storage server outside the distributed application server to store the lock information. At this time, we easily think of Redis. First, we need to build a Redis server to store the lock information.

Several key points to pay attention to when implementing:

1, the lock information must be set to expire timeout, can not let a thread hold a lock for a long time and cause deadlock;

Only one thread can acquire a lock at a time.

Here are some redis commands to use:

Setnx (key, value) : “Set if not exits.” If the key-value does not exist, it is added to the cache successfully and returns 1. Otherwise, 0 is returned.

Get (key) : Gets the value corresponding to the key, or returns nil if it does not exist.

Getset (key, value) : Gets the value corresponding to the key, returns nil if it does not exist, and updates the old value to the new value.

Expire (key, seconds) : sets the validity period of the key-value to seconds seconds.

Here is a Lua script:

The above code, which is the operation logic in the ideal situation, should be adjusted to the actual business if the following situations occur

  1. What happens when Redis finds the lock failed? Interrupt request or loop request? ,
  2. If one of them gets the lock, is it possible for the other to grab the lock?
  3. After the lock expires in advance, client A has not finished executing, and client B obtains the lock. At this time, client A finishes executing, will B’s lock be deleted when client A deletes the lock?

For problem 1: use loop request, loop request to acquire the lock for problem 2: For problem 2, when loop request to acquire the lock, add the sleep function, wait a few milliseconds before executing the loop for problem 3: When lock is stored, the key is random. In this case, every time you delete a key, make sure that the value in the key you save is the same as the value you saved.