PHP+ redis实现延迟队列
使用的是redis有序集合的特性来完成。大致思路如下:
(1).下单成功通过zadd key score value命令把订单信息写入到集合中,例如
key:order
score:指定要执行的时间戳(单位秒)
value:订单id
集合的最终元素成员如下
score value
1603620459 202010250100
1603620460 202010250101
(2).通过zrangebyscore命令取需要执行的元素,例如
ZRANGEBYSCORE order (0 1603620500
例如查询score大于0,并且score小于当前时间戳的数据
(3).查询到数据我们应该从集合中删除此元素,使用zrem命令即可,如果删除的失败,说明已经被其他进程消费,可以丢弃。
我编写了一个PHP的实现。
<?php
class DelayQueue
{
public static $name = null;
public static $handler = null;
public static function add($score, $value)
{
return static::$handler->zAdd(static::$name, $score, $value);
}
public static function get($e_score, $s_score = 0, $limit = 10, $remove = true)
{
$list = static::$handler->zRangeByScore(static::$name, $s_score, $e_score, ['limit' => [0, $limit]]);
if ($remove)
{
foreach ($list as $key => $value)
{
if (!static::del($value)) unset($list[$key]);
}
}
return $list;
}
public static function del($value)
{
return static::$handler->zRem(static::$name, $value);
}
}
(4).生成者的代码:
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
DelayQueue::$name = 'order';
DelayQueue::$handler = $redis;
$time = time() + 30;
$orderId = uniqid();
DelayQueue::add($time, $orderId);
(5).消费者代码:
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
DelayQueue::$name = 'order';
DelayQueue::$handler = $redis;
$time = time();
$list = DelayQueue::get($time);
foreach ($list as $value)
{
echo "订单Id:" . $value . PHP_EOL;
}
(6).其他从队列取值的写法说明:
(1).在队列中查询time<=1603597141 and time>=0 的元素(同时队列中会自动删除符合条件的元素)
$time = 1603597141;
$list = DelayQueue::get($time);
(2).在队列中查询time<=1603597141 and time>=1603597132 的元素(同时队列中会自动删除符合条件的元素)
$time1 = 1603597413;
$time2 = 1603597132;
$list = DelayQueue::get($time1, $time2);
(3).在队列中查询time<=1603597141 and time>=1603597132 的元素,只返回1条(同时队列中会自动删除这条元素)
$time1 = 1603597555;
$time2 = 1603597132;
$list = DelayQueue::get($time1, $time2,1);
(4).在队列中查询time<=1603597141 and time>=1603597132 的元素返回10条即可,不删除队列数据,仅查看数据
$time1 = 1603597693;
$time2 = 1603597132;
$list = DelayQueue::get($time1, $time2, 10, false);
(7).解决有序集合元素值不得重复的问题:
Redis有序集合中元素内容不得重复,上面实例中都是传递的订单Id,如果我们想投递多次相同订单Id,何如?
(1).Value中传递唯一Id,同订单Id组合的Json形式,例如
$data = [
'order_id'=>1,
'order_uniqid'=>uniqid()
];
$res = DelayQueue::add(time() + 30, json_encode($data));
(2).Value中前X位存储订单Id,后X位存储唯一Id(推荐)
有序集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
2020-06-08 php数组截取