The king solution among distributed locks - Redisson
Aug 24, 2023 pm 03:31 PM
There are various solutions on the Internet for implementing distributed locks in Redis, but what is the king solution?
The answer is: Redisson.
Let’s first take a look at what the Redis official website says about distributed locks:

The framework of the Java version of distributed locks is Redisson.
This practical content will be based on my open source project PassJava to integrate Redisson.
I uploaded backend
, frontend
, 小program
to the same warehouse, you can use Github
or codeyun
visit. The address is as follows:
Github: https://github.com/Jackson0714/PassJava-Platform
Code Cloud:https: //gitee.com/jayh2018/PassJava-Platform
Supporting Tutorial: www.passjava.cn
Before the actual combat, let’s take a look at the usage The principle of Redisson.
1. What is Redisson?
If you have been using Redis before, you will get twice the result with half the effort by using Redisson. Redisson provides the simplest and most convenient way to use Redis.
The purpose of Redisson is to promote the separation of concerns (Separation of Concern) of Redis among users, so that users can focus more on processing business logic.
Redisson is a Java in-memory data grid (In-Memory Data Grid) implemented on the basis of Redis.

Netty Framework: Redisson adopts the NIO-based Netty framework, which can not only serve as the Redis underlying driver client , it has the function of providing connection to various configuration forms of Redis, the function of sending Redis commands synchronously, asynchronously, asynchronously streaming or pipeline, LUA script execution processing, and the function of processing the returned results
Basic data structure: The native Redis
Hash
,List
,Set
,String
,Geo
,HyperLogLog
and other data structures are encapsulated into the most familiarmapping (Map)
, ## in Java #List,
Set,
General Object Bucket,
Geospatial Bucket,
Cardinality estimation algorithm (HyperLogLog)and other structures,
Distributed data structure: On this basis, distribution is also provided Multimap, LocalCachedMap, SortedSet, ScoredSortedSet, LexSortedSet, Queue, Blocking Queue, Bounded Blocking Queue, Deque, Blocking Deque, Blocking Fair Queue, Delayed Queue, Bloom Filter , atomic integer (AtomicLong), atomic double-precision floating point number (AtomicDouble), BitSet and other distributed data structures that Redis does not originally have.
Distributed lock: Redisson also implements higher-level locks like distributed lock
Lock
mentioned in the Redis document Application scenarios. In fact, Redisson does not stop there. On the basis of distributed locks, it also providesInterlock (MultiLock)
,ReadWriteLock (ReadWriteLock)
,Fair Lock (Fair Lock)
,Red Lock (RedLock)
,Semaphore (Semaphore)
,Expirable Semaphore (PermitExpirableSemaphore)
andLocking (CountDownLatch)
These are basic components that are crucial to multi-threaded high-concurrency applications. It is through the implementation of high-order application solutions based on Redis that Redisson becomes an important tool for building distributed systems.Node: Redisson as an independent node can be used to independently execute other nodes published to
Distributed Execution Service
and Remote tasks inDistributed Scheduling Service
.
2. Integrate Redisson
There are two options for integrating Redisson with Spring Boot:
Programmatic configuration. File mode configuration.
This article introduces how to integrate Redisson programmatically.
2.1 Introducing Maven dependencies
Introduce redisson’s maven dependencies in the pom.xml of the passjava-question microservice.
<!-- https://mvnrepository.com/artifact/org.redisson/redisson --> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.15.5</version> </dependency>
2.2 Custom configuration class
The following code is the configuration of single node Redis.
@Configuration public class MyRedissonConfig { /** * 對 Redisson 的使用都是通過 RedissonClient 對象 * @return * @throws IOException */ @Bean(destroyMethod="shutdown") // 服務(wù)停止后調(diào)用 shutdown 方法。 public RedissonClient redisson() throws IOException { // 1.創(chuàng)建配置 Config config = new Config(); // 集群模式 // config.useClusterServers().addNodeAddress("127.0.0.1:7004", "127.0.0.1:7001"); // 2.根據(jù) Config 創(chuàng)建出 RedissonClient 示例。 config.useSingleServer().setAddress("redis://127.0.0.1:6379"); return Redisson.create(config); } }
2.3 Test configuration class
Create a new unit test method.
@Autowired RedissonClient redissonClient; @Test public void TestRedisson() { System.out.println(redissonClient); }
We run this test method and print out redissonClient
org.redisson.Redisson@77f66138
3. Distributed reentrant lock
3.1 Reentrant Lock test
Redisson distributed reentrant lock based on RedisRLock
The Java object implements the java.util.concurrent.locks.Lock
interface. It also provides asynchronous (Async), reflective (Reactive) and RxJava2 standard interfaces.
RLock lock = redisson.getLock("anyLock"); // 最常見的使用方法 lock.lock();
We use the passjava open source project to test two points of reentrant locks:
(1) Multiple threads seize the lock. Do subsequent locks need to wait? ? (2) If the service where the thread that preempted the lock is stopped, will the lock be released?
3.1.1 Verification 1: Are reentrant locks blocking?
In order to verify the above two points, I wrote a demo program: the code process is to set the WuKong-lock
lock, then lock it, print the thread ID, and wait for 10 seconds to release the lock. Finally, the response is returned: "test lock ok".
@ResponseBody @GetMapping("test-lock") public String TestLock() { // 1.獲取鎖,只要鎖的名字一樣,獲取到的鎖就是同一把鎖。 RLock lock = redisson.getLock("WuKong-lock"); // 2.加鎖 lock.lock(); try { System.out.println("加鎖成功,執(zhí)行后續(xù)代碼。線程 ID:" + Thread.currentThread().getId()); Thread.sleep(10000); } catch (Exception e) { //TODO } finally { lock.unlock(); // 3.解鎖 System.out.println("Finally,釋放鎖成功。線程 ID:" + Thread.currentThread().getId()); } return "test lock ok"; }
Verify the first point first and use two http requests to test the preemption lock.
Requested URL:
http://localhost:11000/question/v1/redisson/test/test-lock

第一個(gè)線程對應(yīng)的線程 ID 為 86,10秒后,釋放鎖。在這期間,第二個(gè)線程需要等待鎖釋放。
第一個(gè)線程釋放鎖之后,第二個(gè)線程獲取到了鎖,10 秒后,釋放鎖。
畫了一個(gè)流程圖,幫助大家理解。如下圖所示:

第一步:線程 A 在 0 秒時(shí),搶占到鎖,0.1 秒后,開始執(zhí)行等待 10 s。 第二步:線程 B 在 0.1 秒嘗試搶占鎖,未能搶到鎖(被 A 搶占了)。 第三步:線程 A 在 10.1 秒后,釋放鎖。 第四步:線程 B 在 10.1 秒后搶占到鎖,然后等待 10 秒后釋放鎖。
由此可以得出結(jié)論,Redisson 的可重入鎖(lock)是阻塞其他線程的,需要等待其他線程釋放的。
3.1.2 驗(yàn)證二:服務(wù)停了,鎖會釋放嗎?
如果線程 A 在等待的過程中,服務(wù)突然停了,那么鎖會釋放嗎?如果不釋放的話,就會成為死鎖,阻塞了其他線程獲取鎖。
我們先來看下線程 A 的獲取鎖后的,Redis 客戶端查詢到的結(jié)果,如下圖所示:

WuKong-lock 有值,而且大家可以看到 TTL 在不斷變小,說明 WuKong-lock 是自帶過期時(shí)間的。
通過觀察,經(jīng)過 30 秒后,WuKong-lock 過期消失了。說明 Redisson 在停機(jī)后,占用的鎖會自動(dòng)釋放。

那這又是什么原理呢?這里就要提一個(gè)概念了,看門狗
。

3.2 看門狗原理
如果負(fù)責(zé)儲存這個(gè)分布式鎖的 Redisson 節(jié)點(diǎn)宕機(jī)以后,而且這個(gè)鎖正好處于鎖住的狀態(tài)時(shí),這個(gè)鎖會出現(xiàn)鎖死的狀態(tài)。為了避免這種情況的發(fā)生,Redisson內(nèi)部提供了一個(gè)監(jiān)控鎖的看門狗
,它的作用是在Redisson實(shí)例被關(guān)閉前,不斷的延長鎖的有效期。
默認(rèn)情況下,看門狗的檢查鎖的超時(shí)時(shí)間是30秒鐘,也可以通過修改Config.lockWatchdogTimeout來另行指定。
如果我們未制定 lock 的超時(shí)時(shí)間,就使用 30 秒作為看門狗的默認(rèn)時(shí)間。只要占鎖成功,就會啟動(dòng)一個(gè)定時(shí)任務(wù)
:每隔 10 秒重新給鎖設(shè)置過期的時(shí)間,過期時(shí)間為 30 秒。
如下圖所示:

當(dāng)服務(wù)器宕機(jī)后,因?yàn)殒i的有效期是 30 秒,所以會在 30 秒內(nèi)自動(dòng)解鎖。(30秒等于宕機(jī)之前的鎖占用時(shí)間+后續(xù)鎖占用的時(shí)間)。
如下圖所示:

3.3 設(shè)置鎖過期時(shí)間
我們也可以通過給鎖設(shè)置過期時(shí)間,讓其自動(dòng)解鎖。
如下所示,設(shè)置鎖 8 秒后自動(dòng)過期。
lock.lock(8, TimeUnit.SECONDS);
如果業(yè)務(wù)執(zhí)行時(shí)間超過 8 秒,手動(dòng)釋放鎖將會報(bào)錯(cuò),如下圖所示:

所以我們?nèi)绻O(shè)置了鎖的自動(dòng)過期時(shí)間,則執(zhí)行業(yè)務(wù)的時(shí)間一定要小于鎖的自動(dòng)過期時(shí)間,否則就會報(bào)錯(cuò)。
四、王者方案
上一篇我講解了分布式鎖的五種方案:Redis 分布式鎖|從青銅到鉆石的五種演進(jìn)方案,這一篇主要是講解如何用 Redisson 在 Spring Boot 項(xiàng)目中實(shí)現(xiàn)分布式鎖的方案。
因?yàn)?Redisson 非常強(qiáng)大,實(shí)現(xiàn)分布式鎖的方案非常簡潔,所以稱作王者方案
。
原理圖如下:

代碼如下所示:
// 1.設(shè)置分布式鎖 RLock lock = redisson.getLock("lock"); // 2.占用鎖 lock.lock(); // 3.執(zhí)行業(yè)務(wù) ... // 4.釋放鎖 lock.unlock();
和之前 Redis 的方案相比,簡潔很多。
下面講解下 Redisson 的其他幾種分布式鎖,相信大家在以后的項(xiàng)目中也會用到。
五、分布式讀寫鎖
基于 Redis 的 Redisson 分布式可重入讀寫鎖RReadWriteLock
Java對象實(shí)現(xiàn)了java.util.concurrent.locks.ReadWriteLock
接口。其中讀鎖和寫鎖都繼承了 RLock
接口。
寫鎖是一個(gè)排他鎖(互斥鎖),讀鎖是一個(gè)共享鎖。
讀鎖 + 讀鎖:相當(dāng)于沒加鎖,可以并發(fā)讀。 讀鎖 + 寫鎖:寫鎖需要等待讀鎖釋放鎖。 寫鎖 + 寫鎖:互斥,需要等待對方的鎖釋放。 寫鎖 + 讀鎖:讀鎖需要等待寫鎖釋放。

示例代碼如下:
RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock"); // 最常見的使用方法 rwlock.readLock().lock(); // 或 rwlock.writeLock().lock();
另外Redisson還通過加鎖的方法提供了leaseTime
的參數(shù)來指定加鎖的時(shí)間。超過這個(gè)時(shí)間后鎖便自動(dòng)解開了。
// 10秒鐘以后自動(dòng)解鎖 // 無需調(diào)用unlock方法手動(dòng)解鎖 rwlock.readLock().lock(10, TimeUnit.SECONDS); // 或 rwlock.writeLock().lock(10, TimeUnit.SECONDS); // 嘗試加鎖,最多等待100秒,上鎖以后10秒自動(dòng)解鎖 boolean res = rwlock.readLock().tryLock(100, 10, TimeUnit.SECONDS); // 或 boolean res = rwlock.writeLock().tryLock(100, 10, TimeUnit.SECONDS); ... lock.unlock();
六、分布式信號量
基于Redis的Redisson的分布式信號量(Semaphore)Java對象RSemaphore
采用了與java.util.concurrent.Semaphore
相似的接口和用法。同時(shí)還提供了異步(Async)、反射式(Reactive)和RxJava2標(biāo)準(zhǔn)的接口。
關(guān)于信號量的使用大家可以想象一下這個(gè)場景,有三個(gè)停車位,當(dāng)三個(gè)停車位滿了后,其他車就不停了。可以把車位比作信號,現(xiàn)在有三個(gè)信號,停一次車,用掉一個(gè)信號,車離開就是釋放一個(gè)信號。

我們用 Redisson 來演示上述停車位的場景。
先定義一個(gè)占用停車位的方法:
/** * 停車,占用停車位 * 總共 3 個(gè)車位 */ @ResponseBody @RequestMapping("park") public String park() throws InterruptedException { // 獲取信號量(停車場) RSemaphore park = redisson.getSemaphore("park"); // 獲取一個(gè)信號(停車位) park.acquire(); return "OK"; }
再定義一個(gè)離開車位的方法:
/** * 釋放車位 * 總共 3 個(gè)車位 */ @ResponseBody @RequestMapping("leave") public String leave() throws InterruptedException { // 獲取信號量(停車場) RSemaphore park = redisson.getSemaphore("park"); // 釋放一個(gè)信號(停車位) park.release(); return "OK"; }
為了簡便,我用 Redis 客戶端添加了一個(gè) key:“park”,值等于 3,代表信號量為 park,總共有三個(gè)值。

然后用 postman 發(fā)送 park 請求占用一個(gè)停車位。

Then check the value of park on the redis client and find that it has been changed to 2. Continue to call twice and find that park is equal to 0. When the fourth call is made, you will find that the request has been waiting
, indicating that there are not enough parking spaces. If you want to avoid blocking, you can use tryAcquire or tryAcquireAsync.
We call the method of leaving the parking space again, and the value of park changes to 1, which means there is 1 parking space left.
Note: If the semaphore release operation is performed multiple times, the remaining semaphore will continue to increase instead of being capped after 3.
Other distributed locks:
Fair Lock
Interlock (MultiLock)
Red Lock (RedLock)
##Read-write lock ( ReadWriteLock) Expirable Semaphore (PermitExpirableSemaphore) Latch (CountDownLatch)

The above is the detailed content of The king solution among distributed locks - Redisson. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

What I want to share with you today is distributed locks. This article uses five cases, diagrams, source code analysis, etc. to analyze. Common locks such as synchronized and Lock are all implemented based on a single JVM. What should we do in a distributed scenario? At this time, distributed locks appeared.

Usage scenario 1. The order was placed successfully but the payment was not made within 30 minutes. The payment timed out and the order was automatically canceled. 2. The order was signed and no evaluation was conducted for 7 days after signing. If the order times out and is not evaluated, the system defaults to a positive rating. 3. The order is placed successfully. If the merchant does not receive the order for 5 minutes, the order is cancelled. 4. The delivery times out, and push SMS reminder... For scenarios with long delays and low real-time performance, we can Use task scheduling to perform regular polling processing. For example: xxl-job Today we will pick

With the gradual popularization of distributed systems, distributed locks have become an important means to ensure system stability and data consistency. As a high-performance distributed memory database, Redis has naturally become one of the important implementations of distributed locks. However, in recent years, Etcd has received more and more attention as an emerging distributed consistency solution. This article will discuss the similarities and differences between Redis' implementation of distributed locks and Etcd from aspects such as implementation principles and comparative analysis. The principle of Redis implementing distributed locks The implementation of Redis distributed locks

If you have been using Redis before, you will get twice the result with half the effort by using Redisson. Redisson provides the simplest and most convenient way to use Redis. The purpose of Redisson is to promote users' separation of concerns (Separation of Concern) from Redis, so that users can focus more on processing business logic.

As modern applications continue to evolve and the need for high availability and concurrency grows, distributed system architectures are becoming more common. In a distributed system, multiple processes or nodes run at the same time and complete tasks together, and synchronization between processes becomes particularly important. Since many nodes in a distributed environment can access shared resources at the same time, how to deal with concurrency and synchronization issues has become an important task in a distributed system. In this regard, ZooKeeper has become a very popular solution. ZooKee

需要的Mavenorg.springframework.bootspring-boot-starter-data-redisio.lettucelettuce-coreredis.clientsjedisorg.springframework.sessionspring-session-data-redisorg.redissonredisson3.17.5application-redis.ymlspring:redis:host:106.12.174.220port:6379password

Redisson is a Redis-based caching solution for Java applications. It provides many useful features that make using Redis as a cache in Java applications more convenient and efficient. The caching functions provided by Redisson include: 1. Distributed mapping (Map): Redisson provides some APIs for creating distributed maps. These maps can contain key-value pairs, hash entries, or objects, and they can support sharing among multiple nodes.

With the rapid development of mobile Internet and the explosive growth of data volume, distributed systems are becoming more and more popular. In distributed systems, the problem of concurrent operations has become more and more prominent. When multiple threads request shared resources at the same time, these resources need to be locked to ensure data consistency. Distributed locks are one of the effective solutions for implementing concurrent operations in distributed systems. This article will introduce in detail how to use Redis to implement distributed locks. Redis Basics Redis is a memory-based key-value storage system that is distributed
