redis 分布式锁 PHP
2024-10-20 07:46:53
redis分布式
1.redis是单线程操作
2.分布式会出现的问题,死锁
3.redis分布式(集群)。多台服务器里面都有多个单机redis。然后这些redis之间相互链接。还有查看各个单台服务器之间是否链接成功,也就是心跳检测
4.在数据方面,他们之间有个锁的问题,叫redis分布式锁
## 常规流程
$redisDb = new Redis('127.0.0.1:6379');
// 获取redis里面的数据
$res = $redisDb->LRANGE();
if(!$res) {
// 如果数据不存在,则去mysql里面获取
$mysqlDb = mysqli_connect();
$res = $mysqlDb->select('*');
// 获取玩了之后插入redis
foreach ($res as $k => $v) {
$redisDb->lPush($v);
}
}
return $res;
这里会出现一个问题,在获取redis数据的时候,出现抢锁的情况
改动后的流程
// 设置redis锁
$expire = 10;//有效期10秒
$key = 'lock';//key
$value = time() + $expire;//锁的值 = Unix时间戳 + 锁的有效期 $redisDb = new Redis('127.0.0.1:6379');
// 获取数据之前,先获取锁
$status = true;
while ($status) {
$lock = $redisDb->setnx($key,$value);
if($lock) {
// 如果锁存在且在有效期内,则循环继续获取
$value = $redisDb->get($key);
if($value < time()) {
// 如果在有效期外则删除当前锁,下次进来的时候就直接获取数据且退出循环
$redisDb->del($key);
}
}else{
$status = false;
// 获取redis里面的数据
$res = $redisDb->LRANGE();
if(!$res) {
// 如果数据不存在,则去mysql里面获取
$mysqlDb = mysqli_connect();
$res = $mysqlDb->select('*');
// 获取玩了之后插入redis
foreach ($res as $k => $v) {
$redisDb->lPush($v);
}
}
}
}
这里原本就可以是最终的版本,但是看到一些言论说。假设进程1del锁之前崩了。那锁会一直存在,进程2和进程3会同时或得到锁。
### 最终版
// 设置redis锁
$expire = 10;//有效期10秒
$key = 'lock';//key
$value = time() + $expire;//锁的值 = Unix时间戳 + 锁的有效期 $redisDb = new Redis('127.0.0.1:6379');
// 获取redis里面的数据
$res = $redisDb->LRANGE();
if(!$res) {
$status = true;
while ($status) {
//设置锁值为当前时间戳 + 有效期
$lockValue = time() + $expire;
/**
* 创建锁
* 试图以$lockKey为key创建一个缓存,value值为当前时间戳
* 由于setnx()函数只有在不存在当前key的缓存时才会创建成功
* 所以,用此函数就可以判断当前执行的操作是否已经有其他进程在执行了
* @var [type]
*/
$lock = $redisDb->setnx($key, $lockValue);
/**
* 满足两个条件中的一个即可进行操作
* 1、上面一步创建锁成功;
* 2、 1)判断锁的值(时间戳)是否小于当前时间 $redis->get()
* 2)同时给锁设置新值成功 $redis->getset()
*/
/**
* ($redisDb->get($key) < time() && $redisDb->getSet($key, $lockValue) < time() )
* 这个判断的意思是
* 先判断第一个进程设定的锁是否过期。($redisDb->get($key) < time()
* 获取到的第一个进程的锁的值再给他设定一个新的值。看他的旧值是否过期 $redisDb->getSet($key, $lockValue) < time()
*/
if(!empty($lock) || ($redisDb->get($key) < time() && $redisDb->getSet($key, $lockValue) < time() )) {
//给锁设置生存时间。setnx是系统上给key第一个锁的过期时间,系统不崩,锁会删除。expire是redis自动给key的一个过期时间,系统即使崩了,锁还是会删除
$redisDb->expire($key, $expire);
//***********这里执行业务操作
// 如果数据不存在,则去mysql里面获取
$mysqlDb = mysqli_connect();
$res = $mysqlDb->select('*');
// 获取玩了之后插入redis
foreach ($res as $k => $v) {
$redisDb->lPush($v);
}
//***********并吧数据插入数据库
//以上程序走完删除锁
//检测锁是否过期,过期锁没必要删除
if($redisDb->ttl($key))
$redisDb->del($key);
$status = FALSE; } else {
// 如果锁存在,则表示有其他进程在处理,这里等待
sleep(1);
} } }
return $res;
最新文章
- js picker webapp仿ios picker
- FFT 快速傅里叶变换浅析
- Atitit 代码复用的理解attilax总结
- Java Spring-Spring与Quartz整合
- Writing Text Files On The Client in Oracle Forms 10g
- 统一者管理员指南(Unifier Administration Guide)中文
- Javascript - 数组去重复
- POJ1298_The Hardest Problem Ever_最难的问题_Caesar 密码_C++
- 用FileInputStream读文件,字节数组接收,不知道文件的大小时怎么办
- fastica matlab 转载
- tree btn
- Java基础语法<;七>; 对象与类
- 关于ubuntu服务器上部署postgresql 以及安装pgadmin4管理工具(web版)
- 随便说说 post-processing
- c# List实现原理
- 像Excel一样使用python进行数据分析
- canal 结合 kafka 入门
- Oracleグラントについて
- AspectJ的XML方式完成AOP的开发之切入点的表达式
- JS里关于特殊字符的转义