PHP/REDIS 实现消息队列服务

1 篇文章 0 订阅
1 篇文章 0 订阅

普通消息队列

producer(生产者)

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

// 生成任务
$tasks = [];
for ($i = 0; $i < 3; $i++) {
    $tasks[] = $i;
}

// 投递任务给消费者
$res = $redis->lPush("tasks", ...$tasks);

consumer(消费者)

$redis = new Redis();

$redis->connect('127.0.0.1', 6379);

// 思考问题: 空轮询不但拉高了客户端的 CPU,redis 的 QPS 也会被拉高
// 空轮询是什么?
// 就是无论列表里面是否存在数据那么都一直不停执行 pop

while (true) {
    // blpop/brpop 阻塞读在队列没有数据的时候,会立即进入休眠状态,一旦数据到来,则立刻醒过来。
    // 消息的延迟几乎为零。用blpop/brpop替代前面的lpop/rpop,就完美解决了上面的问题
    $res = $redis->brPop("tasks", 20);
    if (!$res) {
        // 未取到数据
        // sleep(1);
        // sleep 用上面睡眠的办法可以解决问题。但是有个小问题,那就是睡眠会导致消息的延迟增大。
        // 如果只有 1 个消费者,那么这个延迟就是 1s。
        // 解决方案: 如果有多个消费者,这个延迟会有所下降,因为每个消费者的睡觉时间是岔开来的
        continue;
    } else {
        // 进行消费
        echo "消费成功" . PHP_EOL;
        sleep(1); // 模拟耗时业务
    }
}

延时队列消息

producer(生产者)

// 消费者客户端
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);


// 生成任务
$tasks = [];
for ($i = 0; $i < 50; $i++) {
    array_push($tasks, time() + $i);
    array_push($tasks, str_shuffle('asdfghjklqwertyuiopzxcvbnm1234567890'));
}

// Redis Zadd 命令用于将一个或多个成员元素及其分数值加入到有序集当中
// 投递任务
$res = $redis->zAdd('delay-queue', [], ...$tasks);

if ($res) {
    echo 'success' . PHP_EOL;
} else {
    echo 'fail: zadd error' . PHP_EOL;
}

consumer(消费者)

$redis = new Redis();

$redis->connect('127.0.0.1', 6379);

$key = 'delay-queue';

while (true) {
    // Redis Zrangebyscore 返回有序集合中指定分数区间的成员列表。有序集成员按分数值递增(从小到大)次序排列
    $msg = $redis->zRangeByScore($key, 0, time(), ['limit' => [0, 1]]);
    if (count($msg) > 0) {
        // Redis Zrem 命令用于移除有序集中的一个或多个成员,不存在的成员将被忽略
        $success = $redis->zRem($key, $msg[0]);
        // 如果是多个客户端进行消费,多线程多进程争抢任务的关键。
        // 它的返回值决定了当前实例有没有抢到任务,因为 loop 方法可能会被多个线程、多个进程调用。
        // 同一个任务可能会被多个进程线程抢到,通过 zrem 来决定唯一的属主。
        if ($success) {
            echo "消费成功: {$msg[0]}" . PHP_EOL;
            sleep(1);// 模拟耗时业务
        } else {
            echo "消费失败" . PHP_EOL;
        }
    } else {
        // 无消息 休息一秒 防止客户端CUP飙升 降低 redis 的QPS数
        sleep(1);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值