当前位置:网站首页>Redis lock Optimization Practice issued by gaobingfa
Redis lock Optimization Practice issued by gaobingfa
2022-07-03 15:11:00 【Miss, do you fix the light bulb】
background : Reduce inventory by simulating the second kill activity of the mall , Given inventory 300
Code :
@RestController
public class IndexControllerCOPY {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@RequestMapping("/deduct_stock")
public String deductStock() {
int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock")); // jedis.get("stock")
if (stock > 0) {
int realStock = stock - 1;
stringRedisTemplate.opsForValue().set("stock", realStock + ""); // jedis.set(key,value)
System.out.println(" Deduction succeeded , Surplus stock :" + realStock);
} else {
System.out.println(" Deduction failed , Insufficient inventory ");
}
// }
return "end";
}
}
Prerequisite : Simulated cluster deployment mode , Inventory operation , So start two Tomcat example ,8080 and 9080 port . And use nginx Load balancing , The configuration is shown in the figure below ;

start-up redis, Then start two more instances , use jmeter Pressure measurement , By visiting 80 port , Give Way nginx Listen to the corresponding service execution request ,1 second 200 A request to try , The pressure measurement configuration is shown in the figure below :

View results :
It can be found that the inventory is repeatedly deducted , Sell more than one commodity , Oversold , Obviously not . How to solve this problem at this time ? Some Taoist friends may say that this is because there is no lock , So in 8080 I saw oversold in the server , Good to meet your needs , I locked it in the test :
@RestController
public class IndexControllerCOPY {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@RequestMapping("/deduct_stock")
public String deductStock() {
synchronized (this){
int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock")); // jedis.get("stock")
if (stock > 0) {
int realStock = stock - 1;
stringRedisTemplate.opsForValue().set("stock", realStock + ""); // jedis.set(key,value)
System.out.println(" Deduction succeeded , Surplus stock :" + realStock);
} else {
System.out.println(" Deduction failed , Insufficient inventory ");
}
}
return "end";
}
}


You can find : The first 198 stay 8080 and 9080 Services have appeared . So understand , Yours synchronize Just lock the thread , I am in cluster mode , It is impossible for your lock to be added to another process . as for 8080 Why do services appear 2 strip 197 The record of , Smart, guess for yourself , Very simple. (8080 Internal volume ,9080 Fish every day ,8080 Human modified value , Covered by Mr. fishing ).
Well, I'm busy today , Further optimization and continue next time , If someone needs to see it , I'll find time to improve .
Today, I will continue to talk about how to ensure data consistency in the cluster mode
《-----------------------------------------------------------------------------------------》
So much foreshadowing has been done to tell everyone : Cannot pass in cluster or distributed mode synchronize perhaps ReentrantLock To maintain data consistency
There are many solutions , Can pass zookeeper Or redis Of setnx Order to solve
Here I use redis Examples continue :
First of all, let's set the quantity of goods to 200, Modify the code to use redis Of setnx command ,jmeter Do pressure test .

Observations :8080 The server 
9090 The server :
redis The remaining inventory of this commodity :
It can be seen that : The two processes did not sell the same goods , And the negotiated quantity finally sold 103+97=200, It's completely in line . stay 5 Seconds 2000 The consistency of data is guaranteed under concurrency .
Of course, there is still room for optimization of the code here :
1. If the program goes wrong , The lock was not released in time , So we put the logic of releasing locks in finally Block of code
package com.redisson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexControllerCOPY {
@Autowired
private StringRedisTemplate stringRedisTemplate;
private volatile int count;
@RequestMapping("/deduct_stock")
public String deductStock() {
// synchronized (this){
// redis Distributed locks for setnx
Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock","value"); // Distributed lock jedis.setnx(k,v)
try {
// If the lock is obtained, it will return true
if (!lock){
return "error";
}
int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock")); // jedis.get("stock")
if (stock > 0) {
int realStock = stock - 1;
stringRedisTemplate.opsForValue().set("stock", realStock + ""); // jedis.set(key,value)
System.out.println(" Deduction succeeded , Surplus stock :" + realStock);
count++;
} else {
System.out.println(" Deduction failed , Insufficient inventory , Total sales "+count);
}
}finally {
// You can't release others' locks without obtaining them
if (lock){
stringRedisTemplate.delete("lock");
}
}
return "end";
}
}
2. For example, if 8080 The service is getting the lock , The business logic has not yet handled the release of locks , The service outage , The lock will not be released , So you can add an expiration time
3. But after adding an expiration time, there will be two other problems , One 、( Threads A The processing time after obtaining the lock is longer than the expiration time of the lock , At this time, another thread B Will get all , At this time, the business of the previous thread is finished , To release the lock is B Of , It reciprocates greatly in turn GUB), The solution is to let each thread release its own lock , How to distinguish ? It's simple , Each locked thread sets a local variable value value , When you want to release the lock, take it out key-value, Judge value Whether it is equal to the value of the current thread stack , Equal release .
package com.redisson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@RestController
public class IndexControllerCOPY {
@Autowired
private StringRedisTemplate stringRedisTemplate;
private volatile int count;
@RequestMapping("/deduct_stock")
public String deductStock() {
String uuid= UUID.randomUUID().toString();
// synchronized (this){
// redis Distributed locks for setnx
Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock","value",10, TimeUnit.MILLISECONDS); // Distributed lock jedis.setnx(k,v)
try {
// If the lock is obtained, it will return true
if (!lock){
return "error";
}
int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock")); // jedis.get("stock")
if (stock > 0) {
int realStock = stock - 1;
stringRedisTemplate.opsForValue().set("stock", realStock + ""); // jedis.set(key,value)
System.out.println(" Deduction succeeded , Surplus stock :" + realStock);
count++;
} else {
System.out.println(" Deduction failed , Insufficient inventory , Total sales "+count);
}
}finally {
// You can't release others' locks without obtaining them
if (lock && uuid.equals(stringRedisTemplate.opsForValue().get("lock"))){
stringRedisTemplate.delete("lock");
}
}
return "end";
}
}
Two 、( Or thread? A The business is not finished , It's time for the lock to expire , Threads B Got the lock , Not good either. , So we need to extend the life of lock ) solve the problem : Ensure that on the premise of adding the expiration time , It is also necessary to ensure that the lock is released after the warehouse inventory operation . Lock for life , Give a child thread a scheduled task iterm,
// After a period of time, check whether the main thread has finished executing , No, just add another expiration time
There is also a good framework here redission It can perfectly solve all the above problems . programme :
// There is an implemented client toolkit
// Import
//
// org.redisson
// redisson
// 3.6.5
//
Tired , Later, I'll make up redisson The first part gives 
package com.redisson;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
@Autowired
private Redisson redisson;
@Autowired
private StringRedisTemplate stringRedisTemplate;
private volatile int count;
@RequestMapping("/deduct_stock")
public String deductStock() {
String lockKey = "product_101";
RLock redissonLock = redisson.getLock(lockKey);
try {
// Lock
redissonLock.lock(); //setIfAbsent(lockKey, clientId, 30, TimeUnit.SECONDS);
// synchronized (this){ Plan one plus synchronized, But it can only solve the situation of stand-alone application in the same process , If distributed deployment is not feasible
int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock")); // jedis.get("stock")
if (stock > 0) {
int realStock = stock - 1;
stringRedisTemplate.opsForValue().set("stock", realStock + ""); // jedis.set(key,value)
count++;
System.out.println(" Deduction succeeded , Surplus stock :" + realStock);
} else {
System.out.println(" Deduction failed , Insufficient inventory , Total sales "+count);
}
// }
} finally {
redissonLock.unlock();
/*if (lock && clientId.equals(stringRedisTemplate.opsForValue().get(lockKey))) { stringRedisTemplate.delete(lockKey); }*/
}
return "end";
}
}
边栏推荐
- 在MapReduce中利用MultipleOutputs输出多个文件
- SQL server installation location cannot be changed
- cpu飙升排查方法
- What is embedding (encoding an object into a low dimensional dense vector), NN in pytorch Principle and application of embedding
- [transform] [practice] use pytoch's torch nn. Multiheadattention to realize self attention
- TPS61170QDRVRQ1
- [transform] [NLP] first proposed transformer. The 2017 paper "attention is all you need" by Google brain team
- 什么是one-hot encoding?Pytorch中,将label变成one hot编码的两种方式
- .NET六大设计原则个人白话理解,有误请大神指正
- 链表有环,快慢指针走3步可以吗
猜你喜欢

What is one hot encoding? In pytoch, there are two ways to turn label into one hot coding

Vs+qt application development, set software icon icon

Yolov5系列(一)——網絡可視化工具netron

Remote server background hangs nohup
![[opengl] advanced chapter of texture - principle of flowmap](/img/dd/6208122fcc578caaf098301b185e03.jpg)
[opengl] advanced chapter of texture - principle of flowmap

Matplotlib drawing label cannot display Chinese problems

Pytorch深度学习和目标检测实战笔记

【可能是全中文网最全】pushgateway入门笔记

el-switch 赋值后状态不变化

5.4-5.5
随机推荐
5.2-5.3
Yolov5 advanced 8 format conversion between high and low versions
Global and Chinese market of Bus HVAC systems 2022-2028: Research Report on technology, participants, trends, market size and share
视觉上位系统设计开发(halcon-winform)-1.流程节点设计
官网MapReduce实例代码详细批注
Composite type (custom type)
Several sentences extracted from the book "leather bag"
Troubleshooting method of CPU surge
Global and Chinese market of air cargo logistics 2022-2028: Research Report on technology, participants, trends, market size and share
[opengl] advanced chapter of texture - principle of flowmap
Dataframe returns the whole row according to the value
Global and Chinese market of marketing automation 2022-2028: Research Report on technology, participants, trends, market size and share
Global and Chinese markets of AC electromechanical relays 2022-2028: Research Report on technology, participants, trends, market size and share
Neon global and Chinese markets 2022-2028: Research Report on technology, participants, trends, market size and share
Global and Chinese markets for ionization equipment 2022-2028: Research Report on technology, participants, trends, market size and share
Kubernetes帶你從頭到尾捋一遍
Global and Chinese market of iron free motors 2022-2028: Research Report on technology, participants, trends, market size and share
Kubernetes - YAML文件解读
Global and Chinese market of lighting control components 2022-2028: Research Report on technology, participants, trends, market size and share
B2020 points candy