PHP Yii操作redis streams/XREADGROUP

应用场景

Redis Stream 是 Redis 5.0 版本新增加的数据结构。

Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。

简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。

而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。

详请可见:Redis Stream

此处只讲业务中xadd(作为消息生产者)搭配xreadgroup(消费组消费数据消息)的应用。

框架版本以Yii2.0为例,需保证redis版本为5.0以上。

生产者:

通常生产者由频繁请求的客户端异步发送消息,此处自己模拟第三方客户端作为生产者向自己发送消息。

    public const LIST_RECORD_KEY = 'redisKey';

    /**
     * XADD 测试自生产发送消息
     */
    public function producer()
    {
        //模仿异步接口调用,生产队列
        $key = self::LIST_RECORD_KEY;
        $redis = Yii::$app->redis;
        $i = 0;
        //发送100条消息
        while ($i < 100) {
            $data = 10000 + $i;
            $redis->xadd(self::LIST_RECORD_KEY, '*', 'name', $data);
            //redis command:XADD redisKey * name 10000
            $i ++;
            sleep(1);
        }
    }

消费者

消费组可设置多个,此处设置一个消费组为例,如果队列中有耗时任务,可将该任务交给另一个消费组处理。

    /**
     * XREADGROUP 消费组消费队列消息
     */
    public function getCampaignRule()
    {
        $redis = Yii::$app->redis;
        //消费组名称
        $groupName = 'gid:test01';
        //消费者
        $consumerName = 'test02';
        //获取当前队列长度
//        $length = $redis->xlen(self::LIST_RECORD_KEY);
        //接收消费前防止重名先销毁消费组,销毁后无法继续上一次的任务执行
//        $destroy = $redis->xgroup('DESTROY', self::LIST_RECORD_KEY, $groupName);
        
        //创建消费组后不销毁一直存在,断线重连后重启服务会报错,但会接着之前的消息处理,抛出异常不用管
        try {
            //创建消费组,头部开始消费
            $group = $redis->xgroup('create', self::LIST_RECORD_KEY, $groupName, '0');
            //创建消费组,尾部开始消费
            //$group = $redis->xgroup('create', self::LIST_RECORD_KEY, $groupName, '$');
        } catch (\Throwable $e) {
            echo 'create group failed:' . $e->getMessage();
            saveLog(['data' => ['create group failed'], 'error' => $e->getMessage()], "automatic_xread", true);
        }

        //获取stream信息
//        $xinfo = $redis->xinfo('stream', self::LIST_RECORD_KEY);
        while (1) {
            echo 'pending...' . PHP_EOL;
            //最后的'>'参数不可省略,继续执行后面的任务
            $read = $redis->xreadgroup('GROUP', $groupName, $consumerName, 'COUNT', 10, 'STREAMS', self::LIST_RECORD_KEY, '>');
            print_r($read);
            $info = $read[0][1] ?? [];
            if (empty($info)) {
                continue;
            }
            $msgCount = count($info);
            for ($a = 0; $a < $msgCount; $a ++) {
                //每条消息的id
                $msgId = $info[$a][0] ?? 0;
                
                //处理业务逻辑
                #coding...
                
                //将处理过的消息挂起
                $xack = $redis->xack(self::LIST_RECORD_KEY, $groupName, $msgId);
                echo PHP_EOL;
            }
            sleep(1);
        }
    }

脚本运行生产者:

php yii automatically/producer

 

 脚本运行消费组:

yii automatically/get-campaign-rule

 

上图中的抛出异常是因为之前创建过同名的消费组,为了能断线重连继续执行上次的任务,此处的消费组请勿重命名,直接无视该报错即可

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值