zoukankan      html  css  js  c++  java
  • PHP使用Redis实现消息队列

    消息队列可以使用MySQL来实现,可以参考博客PHP使用MySQL实现消息队列,虽然用MySQL可以实现,但是一般不这么用,因为MySQL的数据都存在硬盘中,而从硬盘中对MySQL的操作,I/O花费的代价很大,所以一般使用缓存来实现,因为缓存的数据是在内存中,访问内存的速度远快于访问硬盘的速度。另一方面,Redis有list类型的数据结构,非常适合做消息队列。

    这里举一个很简单的秒杀例子:秒杀的名额只有5个,即消息队列的长度为5,名额已经满了之后,通知后来的人已经秒杀结束。然后后台会从消息队列中读取数据,然后将数据存到数据库中。因为消息队列长度只有5个,而且秒杀的那短短1,2秒并没有直接操作数据库,所以对于数据库来说,并没有什么压力。

    先看一下数据库表(seckill)的结构:

    mysql> desc seckill;
    +----------+---------+------+-----+---------+----------------+
    | Field    | Type    | Null | Key | Default | Extra          |
    +----------+---------+------+-----+---------+----------------+
    | id       | int(11) | NO   | PRI | NULL    | auto_increment |
    | order_id | int(11) | NO   |     | NULL    |                |
    | mobile   | int(8)  | YES  |     | 8888888 |                |
    +----------+---------+------+-----+---------+----------------+
    3 rows in set (0.11 sec)
    

      然后是进行秒杀的用户程序(user.php),为了模拟,这里使用for循环来实现在短时间内发起大量的请求,但是要知道这是不准确的。

    <?php
        $redis=new Redis();
        $redis->connect("127.0.0.1",6379);
    
        $key="seckill";
        for($i=0;$i<10;$i++){
            $order_id=rand(100000,999999);
            $mobile=rand(11111111,99999999);
            $value=$order_id."#".$mobile;//连接之后作为值
            if($redis->llen("seckill") <5 ){
                echo "秒杀成功,订单号为$order_id, 手机号为$mobile
    ";
                $redis->lpush($key,$value);
            } else {
                echo "秒杀已经结束
    ";
            }
        }
    ?>
    

      运行结果:

    [root@localhost ~]# php user.php
    秒杀成功,订单号为643275, 手机号为50104929
    秒杀成功,订单号为393012, 手机号为31213041
    秒杀成功,订单号为994790, 手机号为23107569
    秒杀成功,订单号为186135, 手机号为36549273
    秒杀成功,订单号为821972, 手机号为11217760
    秒杀已经结束
    秒杀已经结束
    秒杀已经结束
    秒杀已经结束
    秒杀已经结束
    

      

    然后是后台程序将redis中订单读出,处理后存进数据库。

    <?php
        $redis=new Redis();
        $redis->connect("127.0.0.1",6379);
        $pdo=new PDO("mysql:host=localhost;dbname=test","root","root");
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
        $stmt=$pdo->prepare("insert into seckill(id,order_id,mobile) values(?,?,?)");
        $key="seckill";
    
        while($redis->llen($key)){
            //因为消息队列中添加消息是使用lpush,所以这里使用rpop
            $order=$redis->rpop($key);
            list($order_id,$mobile)=explode("#",$order);
            echo "正在处理订单$order_id	";
            try{
                $res=$stmt->execute(array(null,$order_id,$mobile));
                if(!$res){
                    throw new PDOException("wrong");
                }
            } catch (PDOException $e){
                echo $e->getMessage();
                echo "订单处理失败
    ";
                $redis->rpush($key,$order_id."#".$mobile);//将数据恢复达到队列中
                continue;
            }
            echo "订单处理完成
    ";
        }
    ?>

      运行:

    [root@localhost ~]# php consumer.php
    正在处理订单643275      订单处理完成
    正在处理订单393012      订单处理完成
    正在处理订单994790      订单处理完成
    正在处理订单186135      订单处理完成
    正在处理订单821972      订单处理完成

      查看数据库:

    mysql> select * from seckill;
    +----+----------+----------+
    | id | order_id | mobile   |
    +----+----------+----------+
    |  1 |   643275 | 50104929 |
    |  2 |   393012 | 31213041 |
    |  3 |   994790 | 23107569 |
    |  4 |   186135 | 36549273 |
    |  5 |   821972 | 11217760 |
    +----+----------+----------+
    5 rows in set (0.00 sec)
    

      

  • 相关阅读:
    定义函数的三种形式
    函数的定义
    文件修改的两种方式
    文件的高级应用
    with管理文件操作上下文
    SQL Server 823,824 错误
    SQL Server 无法启动的 4 种原因
    SQL Server 查看正在运行的事务信息的 2 种方法。
    MySQL 指定数据库字符集的 3 种方法。
    MYSQL 注释的 3 方法
  • 原文地址:https://www.cnblogs.com/-beyond/p/8214361.html
Copyright © 2011-2022 走看看