当前位置:网站首页>Redis Guide (8): principle and implementation of Qianfan Jingfa distributed lock
Redis Guide (8): principle and implementation of Qianfan Jingfa distributed lock
2022-06-26 16:09:00 【Xiao Lei】
“ Keep creating , Accelerate growth ! This is my participation 「 Nuggets day new plan · 6 Yuegengwen challenge 」 Of the 6 God , Click to see the event details ”
Preface
This paper mainly focuses on redis The principle and implementation of distributed lock based on .
in the future , Again for redis Problems related to distributed locks are well documented .
One 、 background
Tell us why we need distributed locks ?
When multiple threads operate on the same resource at the same time , We usually use, for example synchronized To ensure that only one thread can acquire the object lock and process the resource at the same time . Under distributed conditions , Each service is deployed independently , At this point, the object of the lock service becomes the current application service , That is, other services can still execute this code , Cause service problems , So if we want to deploy multiple services independently , It can also control the independent execution of resources , Then you need to introduce distributed locks to solve this scenario .
What is distributed lock ?
Distributed lock . It is the implementation of a lock that controls different processes in a distributed system to access the same shared resource .
Distributed lock , It can be understood as “ headquarters “ The concept of .
Headquarters to control lock possession and notify other services to wait . Each independent deployment obtains the lock message from the headquarters , Thus avoiding the possibility of local governments . Distributed locking is such an idea .
We can use a third-party component ( for example redis、zookeeper、 database ) Monitor the global lock , Control the holding and release of the lock .
Two 、 Principle and application of distributed lock
setnx yes [set if not exists] Abbreviation .
take key The value of the set value, If and only if key non-existent , If a given key Already exist , be setnx Don't do anything .
Next , Let's use this command to see a simple example of the use of distributed locks , Understand its internal principle .
2.1 Distributed lock evolution : Stage 1
Code demo as follows :
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111");
if(lock){
// Locking success
Map<String, List<Catelog2VO>> stringListMap = getStringListMap();
redisTemplate.delete("lock");// Delete lock
return stringListMap;
}else{
// Locking failed : retry ( spinlocks )
return getCatalogJsonFromRedis();
}
problem :
This is the most primitive lock use problem , But there is obviously a problem here , If the lock is occupied during the execution of business , Program downtime , At this point, the lock will always be redis in .
terms of settlement :
- Sets the expiration time of the lock , Even if it's not deleted , It will be deleted automatically .
2.2 Distributed lock evolution : Stage 2
Code demo as follows :
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111");
if(lock){
redisTemplate.expire("lock",30,TimeUnit.SECONDS);
// Locking success
Map<String, List<Catelog2VO>> stringListMap = getStringListMap();
redisTemplate.delete("lock");// Delete lock
return stringListMap;
}else{
// Locking failed : retry ( spinlocks )
return getCatalogJsonFromRedis();
}
problem :
- setnx Set it up , Set the expiration time again , Downtime occurs in the middle , There will also be deadlocks .
solve :
- The set expiration time and placeholder must be atomic .redis Support use setnx ex command .
2.3 Distributed lock evolution : Stage 3
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111",30,TimeUnit.SECONDS);
if(lock){
// Locking success
Map<String, List<Catelog2VO>> stringListMap = getStringListMap();
redisTemplate.delete("lock");// Delete lock
return stringListMap;
}else{
// Locking failed : retry ( spinlocks )
return getCatalogJsonFromRedis();
}
You can use a command to complete this locking operation .
problem :
- Is the lock deleted directly ?( If the business is busy , The lock itself has expired , Let's delete , It may delete the lock that others are holding )
solve :
- When locked , Value specified as uuid, Everyone matches their own lock before deleting it .
2.4 Distributed lock evolution : Stage 4
String uuid = UUID.randomUUID().toString();
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid,30,TimeUnit.SECONDS);
if(lock){
// Locking success
Map<String, List<Catelog2VO>> stringListMap = getStringListMap();
String lockValue = redisTemplate.opsForValue().get("lock");
if(uuid.equals(lockValue)){
redisTemplate.delete("lock");// Delete lock
}
return stringListMap;
}else{
// Locking failed : retry ( spinlocks )
return getCatalogJsonFromRedis();
}
There is still a problem with this . It is still possible to delete the values of other threads .
Why? ?
If we redis Get to the Value of lock , And passed equal check , Enter the logic of deleting locks , But at this time , The lock has expired , Automatically deleted , And another thread entry occupies the lock , Then there is a problem , The deleted lock is someone else's lock . The reason is the same as before : During lock comparison and value deletion , It's not an atomic operation .
The solution is to use lua Script to delete .
2.5 Distributed lock evolution : Stage 5
Use lua Script delete lock .
String uuid = UUID.randomUUID().toString();
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid,30,TimeUnit.SECONDS);
if(lock){
Map<String, List<Catelog2VO>> stringListMap;
try{
// Locking success
stringListMap = getStringListMap();
}finally {
// Definition lua Script
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
// Atomic deletion
Integer lock1 = redisTemplate.execute(new DefaultRedisScript<Integer>(script, Integer.class), Arrays.asList("lock", uuid));
}
return stringListMap;
}else{
// Locking failed : retry ( spinlocks )
return getCatalogJsonFromRedis();
}
3、 ... and 、 Distributed lock Redission
3.1 Redission brief introduction
Redisson It's a Redis On the basis of implementation Java In memory data grid (In-Memory Data Grid). It not only provides a series of distributed Java Common objects , There are also many distributed services . These include (BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service) Redisson Provides the use of Redis The simplest and most convenient way .Redisson The aim is to promote the user's understanding of Redis Separation of concerns (Separation of Concern), This allows users to focus more on processing business logic .
redission yes redis Officially recommended clients , Provides RedLock Lock of ,RedLock Inherited from juc Of Lock Interface , Provides interrupts 、 Overtime 、 Try to acquire a lock, etc , Support reentry , Mutual exclusion, etc .
3.2 Use
Import dependence
<!-- Integrate redission As a distributed lock and other functional framework -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.15.2</version>
</dependency>
To configure :
The following is the reference configuration provided on the official website :
// Default connection address 127.0.0.1:6379
RedissonClient redisson = Redisson.create();
// To configure
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);
Config config = new Config();
config.useClusterServers()
.setScanInterval(2000) // Cluster status scan interval time , In milliseconds
// It can be used "rediss://" To enable SSL Connect
.addNodeAddress("redis://127.0.0.1:7000", "redis://127.0.0.1:7001")
.addNodeAddress("redis://127.0.0.1:7002");
RedissonClient redisson = Redisson.create(config);
3.3 Test distributed locks
@Controller
public class TestRedissonClient {
@Autowired
RedissonClient redisson;
@ResponseBody
@GetMapping("/hello")
public String hello(){
// 1、 Get a lock , As long as the name of the lock is the same , It's the same lock
RLock lock = redisson.getLock ("my-lock");
// 2、 Lock
lock.lock ();// Block wait
try {
System.out.println (" Locking success , Executive business ..."+Thread.currentThread ().getId () );
// Simulate long wait
Thread.sleep (20000);
} catch (Exception e) {
e.printStackTrace ( );
}finally {
// 3、 Unlock
System.out.println (" Release the lock ..."+Thread.currentThread ().getId () );
lock.unlock ();
}
return "hello";
}
}
redission Two problems have been solved :
- 1、 Automatic renewal of locks , If the business is too long , Automatically lock a new one during operation 30s, Don't worry about locking for too long . The lock automatically expired and was deleted .
- 2、 Locking business , As long as the operation is completed , The current lock will not be renewed , Even if you don't manually unlock , By default, the lock is in 30s Delete later ( The current thread will call before it is destroyed lock Method )
If lock The timeout time was passed , Just send it to redis Execute the script , Hold the lock , The default timeout is the time we set
If no timeout is specified , Is to use the default open dog time .(30*1000)
As long as the lock is successful , Will start a timed task 【 Reset the expiration time of the lock , The new expiration time is the watchdog's default time 】, every other 10 Second renewal , The renewal period expires .
internaLockLeaseTime【 Watchdog time 】/3 10s .
Best practice ,【 Recommend writing 】
Add a moment , Save time for renewal .
// 10s Auto unlock , The specified time must be greater than the business time ( Otherwise, it will report a mistake , Don't use it if you are not sure )
lock.lock (10, TimeUnit.SECONDS);
3.4 Read-write lock
Only one thread at a time can occupy the read-write lock of write mode , However, multiple threads can occupy the read-write lock of read mode at the same time .
The read / write lock is suitable for the case that the number of reads to the data structure is more than the number of writes , because , Can be shared when the read mode is locked , Locking in write mode means exclusive , So read-write lock is also called sharing - An exclusive lock .
Make sure you can read the latest data , During revision , Writing lock is an exclusive lock . Read lock is a shared lock ,
If the write lock is not released, you have to wait
Write + read : Wait for write lock
Write + read : Wait for the write lock to be released
Write + Write : Blocking mode
read + Write : There's a read lock . Writing also needs to wait
As long as there is writing , Have to wait
3.5 Cache consistency issues
How to keep the data in the cache consistent with the database .
3.5.1 Double write mode
After the database changes , Change cache again .
problem : There will be dirty data
Scheme 1 : Lock
Option two : If delay is allowed ( The data updated today will be displayed tomorrow , Or a few minutes and hours of delay ), Set expiration time ( Suggest )
3.5.2 Failure mode
The database has been modified , Then delete the cache , Wait for the next active query , Update again .
problem : There will be reading and writing , Dirty data
Scheme 1 : Lock
Option two : If you write often , Read less , It is better to operate the database directly , Remove the cache layer .
3.5.3 programme ( Expiration time + Read-write lock )
Whether it's dual write mode or failure mode , Will cause cache inconsistencies . That is, if multiple instances are updated at the same time, something will happen . What do I do ?
(1) If it is user latitude data ( Order data 、 User data ), This concurrency rate is very small , Don't think about it , Cache data plus expiration time , Trigger the active update of read at regular intervals
(2) If it's a menu , Basic data such as commodity introduction , You can also use canal subscribe binlog The way .
(3) Cache data + The expiration time is also sufficient to solve the cache requirements of most businesses .
(4) Ensure concurrent reads by locking + Write , Write + Line up in order as you write . It doesn't matter to read . So it's suitable to use read-write lock .( Business is not about heart data , Allow temporary dirty data to be ignored )
summary :
(1) The data we can put into the cache should not be real-time 、 The requirement of consistency is very high . So when caching data, add expiration time , Make sure you get the latest data every day .
(2) We should not over design , Increase the complexity of the system
(3) When it comes to real-time 、 Data with high consistency requirements , You should check the database , Even if you slow down .
For cache data consistency , We can use Cannal To complete this scenario . Generally for big data projects
边栏推荐
- Solana capacity expansion mechanism analysis (2): an extreme attempt to sacrifice availability for efficiency | catchervc research
- H5 close the current page, including wechat browser (with source code)
- Net基于girdview控件实现删除与编辑行数据
- I want to know how to open an account through online stock? Is online account opening safe?
- 8 自定义评估函数
- JS教程之Electron.js设计强大的多平台桌面应用程序的好工具
- stm32h7b0替代h750程序导致单片机挂掉无法烧录程序问题
- LeetCode 单周赛298,前三题
- 7 user defined loss function
- Arduino UNO + DS1302简单获取时间并串口打印
猜你喜欢
Stepn débutant et avancé
基于 MATLAB的自然过渡配音处理方案探究
OpenSea上如何创建自己的NFT(Polygon)
今年高考英语AI得分134,复旦武大校友这项研究有点意思
Development, deployment and online process of NFT project (2)
Anaconda3安装tensorflow 2.0版本cpu和gpu安装,Win10系统
10 tf. data
清华“神奇药水”登Nature:逆转干细胞分化,比诺奖成果更进一步,网友:不靠精子卵子就能创造生命了?!...
Svg savage animation code
What is the process of switching C # read / write files from user mode to kernel mode?
随机推荐
Failed to get convolution algorithm. This is probably because cuDNN failed to initialize
Acid of redis
(DFS search) acwing 2005 horseshoe
Lifeifei's team applied vit to the robot, increased the maximum speed of planning reasoning by 512 times, and also cued hekaiming's Mae
Svg animation around the earth JS special effects
Analyse panoramique de la chaîne industrielle en amont, en aval et en aval de la NFT « Dry goods»
Failed to get convolution algorithm. This is probably because cuDNN failed to initialize
NFT Platform Security Guide (1)
4 custom model training
The first batch in the industry! Tencent cloud security and privacy computing products based on angel powerfl passed CFCA evaluation
NFT交易原理分析(2)
R language generalized linear model function GLM, GLM function to build logistic regression model, analyze whether the model is over discrete, and use the ratio of residual deviation and residual degr
Development, deployment and online process of NFT project (2)
1-12Vmware新增SSH功能
Svg rising Color Bubble animation
Ideal path problem
6 custom layer
IAR工程适配GD32芯片
Stepn novice introduction and advanced
Tsinghua's "magic potion" is published in nature: reversing stem cell differentiation, and the achievements of the Nobel Prize go further. Netizen: life can be created without sperm and eggs