我们在项目中经常会用到nosql来储存访问率高的数据,大多数就是用redis,凭借着比mysql高得多的qps支持数,这样做确实能提高处理速度。那么,redis就只能用来做数据存储查询吗?当然不是!redis还有很多功能等待使用。
一、原子性:
面对高并发抢购的场景,单用mysql记录来判断库存很容易发生超卖的情况。这时候我们可以利用redis decr原子性做锁,实现防止超卖。
1)使用decr方式:
<?php
$redis = new Redis();
$redis->connect('localhost', '6379');
$key = 'stock';
$data = $redis->decr($key);
if ($data>0){
header('HTTP/1.1 200 success');
echo 'success';
}else{
header('HTTP/1.1 400 Not Found');
echo 'false';
}
2)使用读取重构方式:
<?php
$redis = new Redis();
$redis->connect('localhost', '6379');
$key = 'stock';//redis数据库key [注:默认redis数据库选择第0号数据库]
$data = $redis->get($key);
$data = $data - 1;
$redis->set($key, $data, 600);
if ($data>0){
header('HTTP/1.1 200 success');
echo 'success';
}else{
header('HTTP/1.1 400 Not Found');
echo 'false';
}
我们预先设置stock=200,然后模拟1000并发请求持续性30秒。
1)
2)
从测试结果可以看到,第一种方式执行结果是正确199次,而第二种方式成功814次出现了大量的超卖,如果是在实际的产品中,后果不堪设想。
二、expired过期事件
redis有ttl属性,当数据超过了livetime自动销毁时会触发事件,我们可以监控这个事件来进行业务处理。比如新订单有三十分钟支付时间,我们就设置订单的ttl为30min,过期事件修改订单为取消状态;又比如,一场线上考试定时两小时,我们就设置ttl为2h,事件触发结束考试。
具体监控 redis expired过期事件的使用方法可以看一下我的另一篇文章
https://blog.youkuaiyun.com/u014043168/article/details/109334584
三、消息队列
无可否认redis队列对比起其他专门的消息队列如rabbitmq、activemq等是弱了点,从可选的部署模式、消息的丢失率都是差一点的,但是胜在小巧。当你需要消息队列,但不想多装的软件,而且消息的必要性又不高,这时候请选择redis的消息队列。
consummer
<?php
fuction listen(){
$redis = new Redis();
$redis->connect(’localhost‘,'6379');
$redis->auth(123456);
$key = 'mq_';//redis数据库key [注:默认redis数据库选择第0号数据库]
while(1) {
//从队列最前头取出一个值
$mq_message = $redis->lPop($key);
//TODO 自定义处理
var_dump($mq_message);
}
}
listen();
producer
<?php
$redis = new Redis();
$redis->connect(’localhost‘,'6379');
$redis->auth(123456);
$key = 'mq_';//redis数据库key [注:默认redis数据库选择第0号数据库]
$redis->rPush($key, 'hello mq');
//关闭redis连接
$redis->close();
先cli模式运行consummer,fpm模式运行producer测试推入队列。