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类型实现秒杀.
注:
- 比如大的用户量也去用
mysql
.而别的也在用mysql
.在高峰期.大批量的对数据库进行操作会直接把mysql
的资源耗光. 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();