mysql解耦案列

  简单做一个队列处理订单系统和配送系统,首先创建一个订单表.

CREATE TABLE `order_queue` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `order_id` int(10) unsigned NOT NULL COMMENT '订单id',
  `mobile` varchar(11) NOT NULL DEFAULT '0' COMMENT '手机号',
  `address` varchar(20) NOT NULL DEFAULT '0' COMMENT '地址',
  `status` tinyint(2) NOT NULL DEFAULT '0' COMMENT '订单状态',
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8

入队系统

/*接受用户订单信息并写入队列*/
include_once '../vendor/mysql.php';/**/

if (!empty($_GET['mobile'])) {
    $order_id = rand(10000, 99999);
    /*订单信息存入队列表中*/
    $insert = [
        'mobile' => $_GET['mobile'],
        'order_id' => $order_id,
        'address' => 'BeiJing',
        'status' => 0,
        'created_at' => date('Y-m-d H:i:s')
    ];
    $mysql = new Mysql();
    $res = $mysql->insert($insert, 'order_queue');
    if ($res) {
        echo $res . '插入成功';
    } else {
        echo $res . '插入失败';
    }
}

出队系统

/**
 * 处理订单并标记状态
 * Created by PhpStorm.
 * User: qvbilam
 * Date: 2019-04-21
 * Time: 01:39
 */
$mysql = mysqli_connect('127.0.0.1', 'root', 'root', 'order_queue');
/*处理订单前防止其他的数据修改导致数据混乱。所以使用锁*/
mysqli_query($mysql, 'LOCK TABLE a WRITE');
/*todo查处所有的没有配送的订单。然后进行配货处理。 最后修改订单状态*/
$sql = 'update order_queue set status=1,updated_at= "' . date('Y-m-d H:i:s') . '" where status=0';
$res = mysqli_query($mysql, $sql);
if ($res) {
    echo '修改成功';
} else {
    echo '修改失败';
}
/*解锁*/
mysqli_query($mysql, 'UNLOCK TABLES');

第三方mysql类库

  为了方便数据库操作,网上有很多的数据类库.自行选择下载.不嫌麻烦可以写原生的哦~

shell脚本

date "+%G-%m-%d %H:%M:%S"
cd /data/wwwroot/queue/mysql/goods
/usr/local/php/bin/php index.php

执行shell

crontab -e
# 添加
*/1 * * * * /data/wwwroot/queue/mysql/bash.sh >> /data/wwwroot/queue/mysql/crontab.log 2>&1

  可以看到结果是成功的.但是有个问题,他每次都会输出时间.不管有没有结果.这样时间久了会浪费很多的内存,也不便于查询.所以我还是用PHP写一个脚本吧...方便省事~
创建queue.php

<?php

class Result
{
    function goodShellRes()
    {
        $shell = 'cd /data/wwwroot/queue/mysql/goods || /usr/local/php/bin/php index.php';
        $result = shell_exec($shell);
        if(!empty($result)){
            echo date("Y-m-d H:i:s") . $result . PHP_EOL;
        }
    }
}
(new Result())->goodShellRes();

  执行文件如果报错

PHP Warning:  
shell_exec() has been disabled for security reasons 
in /data/wwwroot/queue/mysql/base.php on line 8
# 是因为PHP禁用了shell_exec()

# 查找php.ini
find /usr -name php.ini 
# 修改php.ini,查找'disable_functions='去掉禁用的shell_exec()
# 重启php
service php-fpm restart
# 修改之前的bash.sh文件
cd /data/wwwroot/queue/mysql
/usr/local/php/bin/php queue.php
# 以上是bash.sh文件的内容
# crontab 内容(无需修改)
*/1 * * * * //data/wwwroot/queue/mysql/bash.sh >> /data/wwwroot/queue/mysql/crontab.log 2>&1
# 查看结果
cat crontab.log
2019-06-20 15:03:01修改成功

2019-06-20 15:07:01修改成功

Redis流量削峰案例

  Redis的List类型实现秒杀.
注:

  1. 比如大的用户量也去用mysql.而别的也在用mysql.在高峰期.大批量的对数据库进行操作会直接把mysql的资源耗光.
  2. redis数据能持久化.会定期的把数据写到磁盘中.所以不需要害怕断电的情况,比memcache有优势.

Reids命令

命令介绍
lpush/lpushx将值插入到(/存在)头部
rpush/rpushx将值插入到(/存在)尾部
lpop移除并获取第一个元素
rpop移除最后一个元素并获取值
ltrim保留指定区间的元素
llen获取列表的长度
lset通过索引设置列表元素的值
lindex通过索引获取列表中的元素
lrange获取列表中指定范围的一些元素

创建对列表

CREATE TABLE `redis_queue` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `uid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '用户id',
  `time_stamp` varchar(20) NOT NULL DEFAULT '0' COMMENT '参与秒杀时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8

处理用户请求

/**
 * 接受用户请求的数据
 * 加载redis组件
 * Created by PhpStorm.
 * User: qvbilam
 * Date: 2019-04-22
 * Time: 17:30
 */

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

for ($i = 0; $i < 20; $i++) {
    //接受用户uid
//    $uid = $_GET['uid'];
    $uid = rand(1000, 9999);
//获取redis已有的数量
    $num = 10;
    if ($redis->lLen($redis_name) < 10) {
        $redis->rPush($redis_name, $uid . '%' . microtime());
        echo $uid . '参与成功';
    } else {
        echo '秒杀结束';
    }
}

$redis->close();

用户请求入库

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis_name = 'miaosha';
$sql = mysqli_connect('127.0.0.1', 'root', 'root', 'order_queue');


while (true) {
    $user = $redis->lpop($redis_name);
    if (!$user || $user != 'nil') {
        sleep(2);
    }
    $user_arr = explode('%', $user);
    $uid = $user_arr[0];
    $time = time();
    $query = 'insert into redis_queue (uid,time_stamp) values ("' . $uid . '","' . $time . '")';
    $res = mysqli_query($sql, $query);
    /*没有插入成功就继续去排队。因为是从左侧取出。所以左侧插回*/
    if (!$res) {
        $redis->lPush($redis_name, $user);
    }
}
$redis->close();
Last modification:February 18th, 2020 at 10:23 pm