phprediszset延迟队列_php使⽤redis实现延时队列延时队列⽤途
订单30分钟未⽀付⾃动取消
实现⽅式
轮询mysql
redis zset
RabbitMQ
其他开源实现
mysql轮询效率低,⼀般不考虑使⽤,这⾥主要使⽤redis zset来实现
Redis Zset
原理
1.向zset中插⼊数据
score保存订单超时时间戳,订单如果30s后超时,将当时时间戳+30即可
value保存订单ID
2.轮询zset
根据score值范围查询【0,当前时间戳】即为要处理的订单
使⽤zrem删除此订单ID,若删除成功就开始处理订单超时逻辑
源码
Class DelayQueue
{
public $redis;
/**
* 连接mysql
* DelayQueue constructor.
* @throws Exception
*/
public function __construct()
{
$redis = new \Redis();
$res = $redis->connect('127.0.0.1', 6379, 5);
if ($res === false) {
throw new Exception('连接失败');
}
$this->redis = $redis;
}
/**
* 插⼊延时队列
* @param $key
* @param $value
* @param $score
* @throws Exception
*/
public function set($key, $value, $score)
{
$res = $this->redis->zAdd($key, ['NX'], $score, $value);
if ($res == 0) {
throw new Exception('⼊队列失败');
}
}
/**
* 处理延时队列
* @param $key
*/
public function deal($key)
{
while (true) {
$res = $this->redis->zRangeByScore($key, 0, time(), ['limit' => [0, 1]]); echo '正常处理' . PHP_EOL;
if (empty($res)) {
sleep(1);
continue;
}
$value = $res[0];
$res = $this->redis->zRem($key, $value);
//在多线程处理时,只有删除成功的才有订单处理权
if ($res) {
//处理订单处理逻辑,更新订单状态,给⽤户发送提醒消息
var_dump(sprintf("订单【%s】30分钟未⽀付,已⾃动取消", $value));
/
/如果这⾥的任务处理失败,需要重新加⼊延时队列
}
php延时函数}
}
}
$model = new DelayQueue();
//zset key名
$key = "order:delayqueue";
// 订单ID
$ordId = "S000001";
$model->set($key, $ordId, time() + 10);//10s之后处理$ordId = "S000002";
$model->set($key, $ordId, time() + 30);//30s之后处理$ordId = "S000003";
$model->set($key, $ordId, time() + 60);//60s之后处理$model->deal($key);
运⾏效果
总结
优点
实现简单
缺点
轮询redis,会造成⽆⽤的IO消耗
可能有1s延时
只有单线程处理
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论