当前位置:网站首页>PHP uses redis to implement distributed locks
PHP uses redis to implement distributed locks
2022-07-06 06:19:00 【Miapenso】
Recently, when doing a coupon collection function , It is found that under certain concurrence, there will be the problem of repeated coupon collection . After a search operation with dueniang , It is found that distributed locks can be used to solve this problem .
What is distributed lock
Distributed lock is a way to control the synchronous access of shared resources between distributed systems . In distributed systems , It's often necessary to coordinate their movements . If different systems or different hosts of the same system share one or a group of resources , So when you visit these resources , We often need mutual exclusion to prevent interference with each other to ensure Uniformity , This is the time , You need to use distributed locks .
Realization principle
The principle of implementing distributed locks is very simple , Just need a lock , Multiple services acquire locks at the same time , But only one service can get the lock . The service that obtains the lock can execute its own business , Other services that have not obtained the lock need to wait for the lock to be released after the service business that has obtained the lock is completed , Then try to get the lock again .
There are many ways to realize distributed . as follows
- Implementation of distributed lock based on Database , such as mysql
- Implement distributed lock based on cache , such as redis
- be based on Zookeeper Implement distributed locks
Here we use redis To implement distributed locking , Get a before executing the business key, If key Existence means that other services have obtained locks , At this time, you need to wait or return to the busy system . If key non-existent , It indicates that no other service obtains the lock , Put this key Save to redis, And then execute the business , Wait until the business is completed, and then start from redis Delete this key.
php Implementation code
<?php
class RedisLock
{
protected $redis;
public function __construct(){
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$this->redis = $redis;
}
public function getLock($key){
$value = $this->redis->get($key);
return $value;
}
public function setLock($key,$value){
$this->redis->set($key,$value);
}
public function delLock($key){
$lineNumber = $thid->redis->del($key);
return $lineNumber;
}
}
$key = 'your_lock_key';
$value = time();
$redisLock = new RedisLock();
$isLock = $redisLock->get($key);
if($isLock) {
// Existing lock , Go straight back to , No more execution
return false;
}
// There is no lock , Lock
$redisLock->setLock($key,$value);
//todo Execute business logic
sleep(5);
// Unlock
$redisLock->delLock($key);
Use ab To test
Lock
Lock
Lock
Lock
Lock
Lock
Lock
Lock
Executive business
Unlock
Unlock
Executive business
Unlock
Executive business
Unlock
Executive business
Unlock
Unlock
Executive business
Unlock
Lock
Executive business
Unlock
Lock
Executive business
Unlock
From the test results , It is found that there are multiple execution businesses , Not completely locked . This is because we use redis Of set command .set Command is used to set a given key Value . If key Other values have been stored , SET Just overwrite the old value , And ignore the type . This will cause many services to lock successfully , What we want is that only one service can lock successfully .
To solve this problem , Need to know redis Another order of setnx.setnx The order is at the designated key When there is no , by key Set the specified value .
<?php
class RedisLock
{
protected $redis;
public function __construct(){
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$this->redis = $redis;
}
public function getLock($key){
$value = $this->redis->get($key);
return $value;
}
public function setLock($key,$value){
return $this->redis->setnx($key,$value);
}
public function delLock($key){
$lineNumber = $thid->redis->del($key);
return $lineNumber;
}
}
$key = 'your_lock_key';
$value = time();
$redisLock = new RedisLock();
$isLock = $redisLock->get($key);
if($isLock) {
// Existing lock , Go straight back to , No more execution
return false;
}
// There is no lock , Lock
$setLock = $redisLock->setLock($key,$value);
if(!$setLock) {
// Locking failed
return false;
}
//todo Execute business logic
sleep(5);
// Unlock
$redisLock->delLock($key);
Again using ab To test
Lock
Lock
Lock
Lock
Lock
Lock
Lock
Locking failed
Locking failed
Locking failed
Locking failed
Locking failed
Locked
Locked
Locked
Executive business
Unlock
From the test results , In the unlocked state , Multiple services acquire locks at the same time , But only one lock succeeded , All the others return locking failure , The following services directly return locked . thus it can be seen , Locking success .
So is that the end ? It's not . If the business is carried out in a locked situation , In the business process, an exception occurs for some reasons, resulting in the exit without unlocking , Then it will cause deadlock , All the following services cannot acquire the lock again . To solve this problem , We need to set an expiration time for the lock , Prevent deadlock .
<?php
class RedisLock
{
protected $redis;
public function __construct(){
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$this->redis = $redis;
}
public function getLock($key){
$value = $this->redis->get($key);
return $value;
}
public function setLock($key,$value,$second){
$setnx = $this->redis->setnx($key,$value);
if(!$setnx) {
return $setnx;
}
$expire = $this->redis->expire($key,$second);
if(!$expire) {
$this->redis->del($key);
}
return $expire;
}
public function delLock($key){
$lineNumber = $thid->redis->del($key);
return $lineNumber;
}
}
$key = 'your_lock_key';
$value = time();
$redisLock = new RedisLock();
$isLock = $redisLock->get($key);
if($isLock) {
// Existing lock , Go straight back to , No more execution
return false;
}
// There is no lock , Lock
$second = 5;
$setLock = $redisLock->setLock($key,$value,$second);
if(!$setLock) {
// Locking failed
return false;
}
//todo Execute business logic
sleep(5);
// Unlock
$redisLock->delLock($key);
So is this the end ? Welcome to tell me in the comment area ~
边栏推荐
- Fault, error, failure of functional safety
- 一文揭开,测试外包公司的真 相
- Summary of anomaly detection methods
- Selenium source code read through · 9 | desiredcapabilities class analysis
- 模拟卷Leetcode【普通】1091. 二进制矩阵中的最短路径
- 10m25dcf484c8g (FPGA) amy-6m-0002 BGA GPS module
- 黑猫带你学eMMC协议第10篇:eMMC读写操作详解(read & write)
- leaflet 地图
- 二维码的前世今生 与 六大测试点梳理
- CoordinatorLayout+NestedScrollView+RecyclerView 上拉底部显示不全
猜你喜欢
Redis 核心技术与实战之 基本架构:一个键值数据库包含什么?
F - True Liars (种类并查集+DP)
浅谈专项测试之弱网络测试
Manhattan distance and Manhattan rectangle - print back font matrix
Buuctf-[bjdctf2020]zjctf, but so (xiaoyute detailed explanation)
PAT(乙级)2022年夏季考试
把el-tree选中的数组转换为数组对象
Application du Groupe Li dans gtsam
oscp raven2靶机渗透过程
Database - current read and snapshot read
随机推荐
Postman核心功能解析-参数化和测试报告
Testing of web interface elements
RestTemplate、Feign实现Token传递
【C语言】字符串左旋
MySQL之基础知识
Database isolation level
CoordinatorLayout+NestedScrollView+RecyclerView 上拉底部显示不全
Detailed explanation of P problem, NP problem, NPC problem and NP hard problem
黑猫带你学UFS协议第8篇:UFS初始化详解(Boot Operation)
Win10 cannot operate (delete, cut) files
[postman] dynamic variable (also known as mock function)
P问题、NP问题、NPC问题、NP-hard问题详解
Understanding of processes and threads
[no app push general test plan
【Postman】测试(Tests)脚本编写和断言详解
Application du Groupe Li dans gtsam
Simulation volume leetcode [general] 1091 The shortest path in binary matrix
Simulation volume leetcode [general] 1414 The minimum number of Fibonacci numbers with a sum of K
Simulation volume leetcode [general] 1249 Remove invalid parentheses
Buuctf-[gxyctf2019] no dolls (xiaoyute detailed explanation)