From principle to practice, analyze the implementation scheme of Redisson distributed lock

Previously we explained how to use Redis to implement distributed locks. It provides simple primitives to implement distributed locks based on Redis. However, Redis also has some shortcomings as an implementation of distributed locks. This article will introduce Redisson to implement distributed locks.

Portal: https://blog.csdn.net/Ascend1977/article/details/131221941

1What is Redisson

Redisson is a distributed Java framework based on Redis. It provides a wealth of functions and tools to help developers solve problems such as data sharing, concurrency control, and task scheduling in distributed systems. By using Redisson, developers can easily operate Redis distributed objects (such as collections, maps, queues, etc.), implement reliable distributed lock mechanisms, and manage and schedule tasks and services in a distributed environment.

Functions provided by Redisson

Distributed objects:

  • Distributed collection (Set, SortedSet, List)

  • Distributed mapping (Map)

  • Distributed queue (Queue, Deque)

  • Distributed lock (Lock)

  • Distributed Counter (AtomicLong)

Distributed current limit:

  • Token Bucket Algorithm (Rate Limiter)

  • Leaky Bucket Algorithm (Rate Limiter)

Distributed publish-subscribe:

  • Publish-subscribe model (Pub-Sub)

  • Message Listener Container

Distributed locks and synchronization:

  • ReentrantLock

  • FairLock

  • Interlock (MultiLock)

  • RedLock

  • ReadWriteLock (ReadWriteLock)

  • Semaphore

  • Latch (CountDownLatch)

  • CyclicBarrier

Distributed services and task scheduling:

  • Remote Service

  • Distributed task scheduler (Task Scheduler)

  • Distributed delay queue (Delayed Queue)

Distributed Geospatial Index:

  • Geolocation storage

  • Geolocation search

Distributed Bloom Filter and Bloom Filter.

Distributed cache:

  • Local caching of Redis

  • Spring cache annotation support

Distributed connection pool:

  • Support connection pool management and maintenance

Redis Cluster and Sentinel support:

  • Support Redis cluster mode

  • Support Redis sentry mode

  • For scenarios deployed using Redis clusters, Redisson can automatically identify and operate multiple nodes in the cluster to ensure high availability and scalability of data. For scenarios deployed using Redis sentinel mode, Redisson can monitor and switch to available master-slave nodes to achieve high reliability and fault tolerance.

Spring integration:

  • Seamless integration with Spring framework

  • Support Spring cache annotations

2Redisson distributed lock

Features of Redisson’s distributed lock

Thread safety: Distributed locks can ensure data consistency and reliability in multi-thread and multi-process environments.

  • Reentrancy: The same thread can acquire the same lock multiple times to avoid deadlock problems.

  • Lock timeout: Supports setting the validity period of the lock to prevent the lock from being occupied for a long time and causing system problems.

  • Blocking lock acquisition: When a thread tries to acquire a lock, if the lock is already occupied by another thread, the thread can choose to wait until the lock is released.

  • Non-blocking lock acquisition: When a thread tries to acquire a lock, if the lock is already occupied by another thread, the thread will not wait, but will immediately return information that the lock acquisition failed.

Disadvantages of Redisson’s distributed lock

Single point of failure: Redisson’s distributed lock depends on the Redis cluster. If the Redis cluster fails or is unavailable, the reliability and availability of the distributed lock may be affected. Therefore, when using Redisson distributed locks, special attention needs to be paid to the stability and high availability of the Redis cluster.

Lock competition: When multiple threads request to acquire distributed locks at the same time, lock competition may occur. If lock competition is intense, it may lead to performance degradation and request timeouts. In addition, since Redisson distributed locks are implemented based on Redis, if the processing capacity of the Redis node cannot satisfy highly concurrent lock requests, the lock requests may be delayed or blocked.

Deadlock risk: In a distributed environment, due to network communication, node failure and other factors, the lock may not be released normally, causing deadlock problems. The lock timeout, automatic release mechanism, etc. need to be properly designed and used to reduce the risk of deadlock.

Lock granularity management: In a distributed environment, lock granularity management is an important issue. Locks that are too fine-grained may cause concurrency performance to degrade, while locks that are too coarse-grained may affect the scalability and concurrency performance of the system. The lock granularity needs to be appropriately selected based on specific business scenarios and concurrent access modes.

Data consistency: Using distributed locks to ensure the atomicity of multiple operations is one of the most common application scenarios. However, distributed locks usually only provide coarse-grained mutually exclusive access and cannot guarantee complete data consistency. In some specific application scenarios, additional measures may be required to ensure the eventual consistency of the data.

Redisson distributed lock source code analysis

public interface RLock extends Lock, RLockAsync {
    String getName();
 
    void lockInterruptibly(long var1, TimeUnit var3) throws InterruptedException;
 
    boolean tryLock(long var1, long var3, TimeUnit var5) throws InterruptedException;
 
    void lock(long var1, TimeUnit var3);
 
    boolean forceUnlock();
 
    boolean isLocked();
 
    boolean isHeldByThread(long var1);
 
    boolean isHeldByCurrentThread();
 
    int getHoldCount();
 
    long remainTimeToLive();
}

The RLock interface mainly inherits the Lock interface, which is the core interface provided by Redisson for distributed locks. It defines methods such as acquiring locks and releasing locks, and extends many methods.

like:

void lock(long leaseTime, TimeUnit unit)

  • Function: Get the lock and set the automatic release time of the lock.

  • parameter:

    • leaseTime: the automatic release time of the lock.

    • unit: time unit.

RFuture lockAsync(long leaseTime, TimeUnit unit)

  • Function: Acquire the lock asynchronously and set the automatic release time of the lock.

  • parameter:

    • leaseTime: the automatic release time of the lock.

    • unit: time unit.

  • Return value: an RFuture object representing the result of an asynchronous operation.

boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException

  • Function: Try to acquire the lock within the specified waiting time and set the automatic release time of the lock.

  • parameter:

    • waitTime: The maximum amount of time to wait to acquire the lock.

    • leaseTime: the automatic release time of the lock.

    • unit: time unit.

  • Return value: If the lock is successfully acquired within the waiting time, true is returned; otherwise false is returned.

  • Exception: If the process of waiting to acquire the lock is interrupted, an InterruptedException is thrown.

Through the above methods, the RLock interface provides more extensions to the lock() method, allowing you to set the automatic release time or perform asynchronous operations when acquiring the lock. This allows for more flexible control of lock behavior and adapts to the needs of different scenarios.

In addition to the above expansions, the RLock interface also provides other methods to support reentrant locks, fair locks, red locks, read-write locks and other features to meet more complex distributed lock requirements.

3Spring Boot integrates Redisson distributed lock

Add Maven dependencies
<!-- Redisson dependency -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.16.2</version>
</dependency>
 
<!-- Spring Data Redis dependency -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Configure Redisson connection application.yml
spring:
  redis:
    cluster:
      nodes:
        - 127.0.0.1:7000
        - 127.0.0.1:7001
        - 127.0.0.1:7002
    password: yourRedisPassword
Create Redisson client
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class RedissonConfig {
 
    @Value("${spring.redis.cluster.nodes}")
    private String clusterNodes;
 
    @Value("${spring.redis.password}")
    private String password;
 
    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useClusterServers()
                .addNodeAddress(clusterNodes.split(","))
                .setPassword(password);
 
        return Redisson.create(config);
    }
}
Use distributed locks

Inject a RedissonClient instance where a distributed lock is required, and use the getLock method to create a distributed lock object (RLock).

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
@Service
public class SomeService {
 
    @Autowired
    private RedissonClient redissonClient;
 
    public void doSomething() {
        String lockKey = "myLock"; // lock key
 
        RLock lock = redissonClient.getLock(lockKey);
        try {
            lock.lock(); // Get lock
            //Execute code that needs lock protection here
        } finally {
            lock.unlock(); // Release the lock
        }
    }
}
RLock.lock()

When using the Rlock.lock() method, if no other thread or process currently holds the lock, the calling thread will obtain the lock immediately and continue executing subsequent code. If another thread or process already holds the lock, the calling thread will be blocked until the lock is released.

In addition, the Rlock.lock() method also has the following characteristics:

  • Reentrancy: The same thread can call the Rlock.lock() method multiple times without causing deadlock. Just make sure that each lock() call has a corresponding unlock() call and match.

  • Timeout mechanism: You can set the timeout period for waiting for the lock through the parameters in the lock() method to avoid waiting because the lock cannot be obtained.

  • Automatic renewal: When a thread holds a lock for longer than the set lock expiration time, Redisson will automatically extend the validity period of the lock to avoid lock expiration due to too long business execution time.

  • Prevent deadlocks: Redisson distinguishes different locks by uniquely identifying the lock ID to prevent deadlocks.

lock() method locking process

b6ad75b03544716dde56cc95b9fcc6ca.png

RLock.unlock()

The RLock.unlock() method is used to release resources protected by Redission distributed locks. It allows the thread holding the lock to actively release the lock, allowing other threads to acquire the lock and access shared resources.

Note:

The RLock.unlock() method should be called after the protected critical section code is executed to ensure that the lock is released in time.

In a multi-threaded environment, the order in which locks are released should correspond to the order in which locks are acquired to avoid deadlock or resource contention problems.

If the current thread does not hold the lock, calling the RLock.unlock() method will not throw an exception and will not affect other threads.

If the Redisson client has just been successfully locked and the leaseTime is not specified, a scheduled task watchdog will be started in the background to check the key every 10 seconds. If the key exists, it will be automatically extended to 30 seconds; if the watchdog scheduled task exists, if If the lock is not actively released, the key will always be locked by the watchdog scheduled task. But if the client goes down, the scheduled task watchdog will be gone, and there will be no lock renewal mechanism. Then after 30 seconds, the key will be automatically deleted and the lock corresponding to the key will be automatically released.

Unlock() method unlocking process

2fe3f0cf67adf84b2a53c771ae55534c.png

Source: blog.csdn.net/Ascend1977/

article/details/131373419

Back-end exclusive technology group

To build a high-quality technical exchange community, HR personnel engaged in programming development and technical recruitment are welcome to join the group. Everyone is also welcome to share their own company’s internal information, help each other, and make progress together!

Speech in a civilized manner, focusing on communication technology, recommendation of positions, and industry discussion

Advertisers are not allowed to enter, and do not trust private messages to prevent being deceived.

31c629128f3c3fd169861798d9cd27f6.png

Add me as a friend and bring you into the group
The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. Cloud native entry-level skills treeHomepageOverview 16,788 people are learning the system