php使用redis分布式锁,Redis 分布式锁--PHP

原标题:Redis 分布式锁--PHP

Redis 分布式锁的作用

在单机环境下,有个秒杀商品的活动,在短时间内,服务器压力和流量会陡然上升。这个就会存在并发的问题。想要解决并发需要解决一下问题

1、提高系统吞吐率也就是qps 每秒处理的请求书

解决问题一:采用内存型数据库提高系统的qps

解决问题二:就要用到经常会遇到的锁,例如MySQL 有读锁、写锁、排他锁、悲观锁、乐观锁。不过这里只讨论redis来实现锁

简单版设置锁 $redis = new Redis();

$redis->connect('127.0.0.1', 6379); //连接Redis

$expire = 10;//有效期10秒

$key = 'lock';//key

$value = time() + $expire;//锁的值 = Unix时间戳 + 锁的有效期

$lock = $redis->setnx($key, $value);

//判断是否上锁成功,成功则执行下步操作

if(!empty($lock))

{

//下步操作...

}

如果以这样的简单版设置锁就能解决所有问题,未免也太小看 锁在程序中应用了。

按正常的操作示例基本上都是这样写的。但是这样写有一些问题

1、假如有10000 个请求访问了redis 不存在的键,这样请求就是指接到了MySQL数据,造成CPU短时间内达到100%甚至宕机。这样场景俗称缓存击穿造成的缓存雪崩。

解决问题:引用reids setnx方法的作用是,当设置的key 不存在时,设置新的值。这样就避免了缓存击穿的问题。检测键的过期时间,避免产生死锁

解决死锁问题 $expire = 10;//有效期10秒

$key = 'lock';//key

$value = time() + $expire;//锁的值 = Unix时间戳 + 锁的有效期

$status = true;

while($status)

{

$lock = $redis->setnx($key, $value);

if(empty($lock))

{

$value = $redis->get($key);

if($value < time())

{

$redis->del($key);

}

}else{

$status = false;

//下步操作....

}

}

2、分布式集群业务业务场景下,每台服务器是独立存在的。多台服务器怎么通过一个标识来相互竞争锁呢。这里就用到了分布式锁

这里简单介绍一下,以MYSQL 的事务机制来延生。事务四个特性ACID,有四种隔离级别:为提交读、已提交读、可重复读、串行化。这些特性都只在单台服务器上生效。到了分布式集群了,数据在不同的服务器上,紧靠事务很难保持数据的一致性及隔离性,事务的作用就意义不大了。Redis也是如此。

正确的分布式锁的打开方式 /**

* 实现Redis分布锁

*/

$key = 'demo'; //要更新信息的缓存KEY

$lockKey = 'lock:'.$key; //设置锁KEY

$lockExpire = 10; //设置锁的有效期为10秒

//获取缓存信息

$result = $redis->get($key);

//判断缓存中是否有数据

if(empty($result))

{

$status = TRUE;

while ($status)

{

//设置锁值为当前时间戳 + 有效期

$lockValue = time() + $lockExpire;

/**

* 创建锁

* 试图以$lockKey为key创建一个缓存,value值为当前时间戳

* 由于setnx()函数只有在不存在当前key的缓存时才会创建成功

* 所以,用此函数就可以判断当前执行的操作是否已经有其他进程在执行了

* @var [type]

*/

$lock = $redis->setnx($lockKey, $lockValue);

/**

* 满足两个条件中的一个即可进行操作

* 1、上面一步创建锁成功;

* 2、 1)判断锁的值(时间戳)是否小于当前时间 $redis->get()

* 2)同时给锁设置新值成功 $redis->getset()

*/

if(!empty($lock) || ($redis->get($lockKey) < time() && $redis->getSet($lockKey, $lockValue) < time() ))

{

//给锁设置生存时间

$redis->expire($lockKey, $lockExpire);

//******************************

//此处执行插入、更新缓存操作...

//******************************

//以上程序走完删除锁

//检测锁是否过期,过期锁没必要删除

if($redis->ttl($lockKey))

$redis->del($lockKey);

$status = FALSE;

}else{

/**

* 如果存在有效锁这里做相应处理

* 等待当前操作完成再执行此次请求

* 直接返回

*/

sleep(2);//等待2秒后再尝试执行操作

}

}

} 结尾

文章从知识面的广度(mysql)、示例代码优缺点的简介及应用的场景,区别于其他博客文章。嘿嘿~返回搜狐,查看更多

责任编辑:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值