当前位置:网站首页>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 ~
边栏推荐
- Isam2 and incrementalfixedlagsmooth instructions in gtsam
- Understanding of processes and threads
- GTSAM中李群的運用
- CoordinatorLayout+NestedScrollView+RecyclerView 上拉底部显示不全
- E - food chain
- B - The Suspects
- Significance of unit testing
- 模拟卷Leetcode【普通】1062. 最长重复子串
- Buuctf-[[gwctf 2019] I have a database (xiaoyute detailed explanation)
- Redis 核心技术与实战之 基本架构:一个键值数据库包含什么?
猜你喜欢
Database - current read and snapshot read
Manhattan distance sum - print diamond
Database isolation level
CoordinatorLayout+NestedScrollView+RecyclerView 上拉底部显示不全
isam2运行流程
Buuctf-[[gwctf 2019] I have a database (xiaoyute detailed explanation)
Coordinatorlayout+nestedscrollview+recyclerview pull up the bottom display is incomplete
The ECU of 21 Audi q5l 45tfsi brushes is upgraded to master special adjustment, and the horsepower is safely and stably increased to 305 horsepower
联合索引的左匹配原则
Isam2 operation process
随机推荐
数据库-当前读与快照读
On weak network test of special test
把el-tree选中的数组转换为数组对象
Detailed explanation of P problem, NP problem, NPC problem and NP hard problem
Pat (Grade B) 2022 summer exam
模拟卷Leetcode【普通】1109. 航班预订统计
GTSAM中ISAM2和IncrementalFixedLagSmoother说明
二维码的前世今生 与 六大测试点梳理
PAT(乙级)2022年夏季考试
D - How Many Answers Are Wrong
RestTemplate、Feign实现Token传递
Simulation volume leetcode [general] 1249 Remove invalid parentheses
leaflet 地图
Simulation volume leetcode [general] 1091 The shortest path in binary matrix
调用链监控Zipkin、sleuth搭建与整合
「 WEB测试工程师 」岗位一面总结
[postman] collections - run the imported data file of the configuration
Simulation volume leetcode [general] 1447 Simplest fraction
数字三角形模型 AcWing 1015. 摘花生
[postman] dynamic variable (also known as mock function)