当前位置:网站首页>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 ~
边栏推荐
- 模拟卷Leetcode【普通】1061. 按字典序排列最小的等效字符串
- leetcode 24. 两两交换链表中的节点
- 数据库-当前读与快照读
- Win10 cannot operate (delete, cut) files
- D - How Many Answers Are Wrong
- [postman] collections configuration running process
- Database isolation level
- Application of Lie group in gtsam
- Simulation volume leetcode [general] 1091 The shortest path in binary matrix
- B - The Suspects
猜你喜欢
曼哈顿距离和-打印菱形
【C语言】字符串左旋
Understanding of processes and threads
Full link voltage measurement: building three models
进程和线程的理解
【微信小程序】搭建开发工具环境
Postman核心功能解析-参数化和测试报告
Selenium source code read through · 9 | desiredcapabilities class analysis
Caused by:org. gradle. api. internal. plugins . PluginApplicationException: Failed to apply plugin
Manage configuration using Nacos
随机推荐
D - How Many Answers Are Wrong
在uni-app中使用腾讯视频插件播放视频
RestTemplate、Feign实现Token传递
【Postman】Collections配置运行过程
JWT-JSON WEB TOKEN
Buuctf-[[gwctf 2019] I have a database (xiaoyute detailed explanation)
自定义指定路由上的Gateway过滤器工厂
JWT-JSON WEB TOKEN
An article was uncovered to test the truth of outsourcing companies
selenium源码通读·9 |DesiredCapabilities类分析
Isam2 and incrementalfixedlagsmooth instructions in gtsam
Detailed explanation of P problem, NP problem, NPC problem and NP hard problem
[eolink] PC client installation
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
曼哈顿距离与曼哈顿矩形-打印回字型矩阵
10M25DCF484C8G(FPGA) AMY-6M-0002 BGA GPS模块
G - Supermarket
leetcode 24. 两两交换链表中的节点
Caused by:org.gradle.api.internal.plugins . PluginApplicationException: Failed to apply plugin
Win10 cannot operate (delete, cut) files