PHP + Redis 实现简单消息队列

元胞汐流
• 阅读 190

PHP + Redis 实现简单消息队列

Redis做消息队列的好处在于它的轻量级,高并发,延迟敏感,应用场景有 即时数据分析、秒杀计数器、缓存等

Redis做消息队列待解决的问题:

1、消息的可靠性: 没有相应的机制保证消息的消费,当消费者消费失败的时候,消息体丢失,需要手动处理。生产者只管向队列中插入数据,不管消费者是否成功消费。

2、消费者挂掉消息不会丢失,但是需要重新触发一下消费者,才能够继续消费消息。

代码如下:

lib.php 是工具文件,里面有数据库的连接、Redis的连接:

<?php
/**
 * 获取数据库连接
 *
 * @param $host
 * @param $username
 * @param $password
 * @param $database
 * @return mysqli
 */
function getDBConnection($host, $username, $password, $database){
    $connection = new mysqli('p:'.$host, $username, $password, $database);
    if (!$connection) {
        echo "Error: Unable to connect to MySQL." . PHP_EOL;
        echo "Debugging errno: " . mysqli_connect_errno() . PHP_EOL;
        echo "Debugging error: " . mysqli_connect_error() . PHP_EOL;
        exit;
    }
    mysqli_query($connection, "set names 'utf8'");
    return $connection;
}
 
/**
 * 获取Redis连接
 *
 * @param $host
 * @param $port
 * @param string $password
 * @param int $database
 * @return Redis
 */
function getRedis($host='127.0.0.1', $port='6379', $password=null, $database=0){
    $redis = new Redis();
    if(!$redis->connect($host, $port)){
        die("Redis连接失败:IP或端口有误");
    }
    if(!empty($password) && !$redis->auth($password)){
        die("Redis连接失败:密码错误");
    }
    if($database){
        $redis->select($database);
    }
    // work中 subscribe 如果一段时间没有接到消息,就会停掉然后停掉,所以加这个语句让其永不超时
    $redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
    return $redis;
}
 
/**
 * 打印消息日志
 *
 * @param $msg
 */
function stdout($msg=null){
    $msg = '['.date('Y-m-d H:i:s').']'.$msg.chr(10);;
    fwrite(STDOUT, $msg);
}

register.php 是消息发布者,注释的是将消息存入数据库部分的代码。

  首先想消息存入 register_users 队列中,存入的 key是register_users;value是一个list,消息全部存入其中。用 redis-cli 查看数据的命令是:

LRANGE register_users 0 -1

register.php:

<?php
require './lib.php';
$name = $argv[1];
$mobile = $argv[2];
if(empty($name) || empty($mobile)){
    die("参数错误");
}
// $connection = getDBConnection('localhost:3306', 'root', 'root', 'blog');
// // 开启事务
// mysqli_begin_transaction($connection);
// $sql = "insert into mq_user(name, mobile) values ('$name', '$mobile')";
// if(!mysqli_query($connection, $sql)){
//     die("写入用户信息失败,原因:".$connection->error);
// }
$redis = getRedis();
// 添加消息
$result = $redis->lpush('register_users', json_encode(array('name'=>$name, 'mobile'=>$mobile), JSON_UNESCAPED_UNICODE));
if($result === false){
    mysqli_rollback($connection);
    die("添加消息队列失败");
}
// 发布消息
$redis->publish('register_success', 'ok');
// 所有操作完成后提交事务
// mysqli_commit($connection);
// $connection->close();
$redis->close();

work.php 做为消息的消费者

<?php
require './lib.php';
$redis = getRedis();
$redis->subscribe(['register_success'], function ($instance, $channelName, $message) {
    if($channelName == "register_success" && $message = "ok") {
        $redis = getRedis();
        while($redis->lsize("register_users")>0) {
            $arr = $redis->brPop(['register_users'], 20);
            if(count($arr)) {
                $userInfo = json_decode($arr[1], true);
                stdout("新注册用户信息:");
                stdout("姓名:".$userInfo['name']);
                stdout("手机号:".$userInfo['mobile']);
                stdout();
                sleep(3);
            }
        }
    }
});

register.php将消息放入redis 的 register_users队列中,然后再使用 publish 将 register_success 消息发不出去。work.php 使用 subscribe 订阅register_success 的消息。接收到 register_success 消息之后,读取 register_users 的消息进行处理。

PHP + Redis 实现简单消息队列

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
1年前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Stella981 Stella981
3年前
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解2016年09月02日00:00:36 \牧野(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fme.csdn.net%2Fdcrmg) 阅读数:59593
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Nginx反向代理upstream模块介绍
!(https://oscimg.oschina.net/oscnet/1e67c46e359a4d6c8f36b590a372961f.gif)!(https://oscimg.oschina.net/oscnet/819eda5e7de54c23b54b04cfc00d3206.jpg)1.Nginx反
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
元胞汐流
元胞汐流
Lv1
我懂人性薄凉却忍不住追随他的脚步
文章
2
粉丝
0
获赞
0