大型PHP电商网站商品秒杀功能实现思路分析
项目背景介绍
- 关键点
- 高可用:双活
- 高并发:负载均衡、安全过滤
- 设计思路
- 静态页面:cdn、网址隐藏、页面压缩、缓存机制
- 动态页面:排队、异步、资质抢购
- 其他建议
- 百度的建议:opcode缓存、cdn、更大的服务器实例
- 阿里的建议:云监控、云盾、ecs、oss、rds、cdn
秒杀项目架构分析
- 认清当前的环境、形式
- 用户:超大量、正常/坏人
- 地域:全国各地
- 业务流程:[前台]商品展示、登记、[后台]数据接入、数据处理
技术实现要点分析
商品展示层
页面状态
- 商品展示:秒杀倒计时页面
- 秒杀进行中:点击进入秒杀页面
- 秒杀活动结束:提示活动已结束
用户登记层
页面状态
- 秒杀进行中:秒杀登记页面
- 秒杀结束了:秒杀结束页面
数据接入层
页面功能
- 数据校验:完成对数据、用户验证
- 存入nosql队列:去重复、排序数据
- 检测商品最大数量:提示活动已结束
数据处理层
页面功能
- 数据持久化:转存nosql数据到mysql数据
- 存入nosql队列:去重复、排序数据
- 检测商品最大数量:提示活动已结束
代码实现分析
第一层:商品展示层
知识点
页面/服务器优化、CDN网络加速、隐藏跳转页面、状态切换
- 秒杀页脚本
- miao.sh
#!/usr/bin/env bash date >> /root/456.txt # 删除秒杀等待页面 rm -rf '/var/www/html/index.html' # 复制秒杀页面到/var/www/html/index.html cp '/var/www/html/index_sale.html' '/var/www/html/index.html'
- 计划任务
- crontab linux计划任务
# 目前每分钟执行一次,具体各自配置
*/1 * * * * root /bin/miao.sh
- 秒杀结束
- set_file.php
index_over.html覆盖/var/www/html/index.html
<?php
//第一步:删除文件
$file_path = 'index.html';
$f = file_exists($file_path) && unlink($file_path);
//第二步:生成自己需要的文件
$file_path = 'index.html';
$myfile = fopen($file_path, "w");
//获取文件内容
$file_path = 'index_over.html';
$txt = file_get_contents($file_path);
fwrite($myfile, $txt);
第二层:用户登记层
知识点
格外增加:token加/解密、ajax跨域
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
var url = "./miaosha.php";
$("#qianggou").click(function () {
var myphone = $("#myphone").val();
var mynumber = $("#mynumber").val();
var data = {
'phone': myphone,
'number': mynumber,
};
});
$.ajax({
url: url,
data: data,
dataType: 'jsonp',
jsonp: "callback",//传递给请求处理程序或页面的,用以获取jsonp回调函数名的参数名(默认为:callback)
jsonpCallback: "success_jsonpCallback",//自定义的jsonp回调函数名称,默认为jquery自动生成的随机函数
success: function (cc) {
if (cc.msg = "ok") {
$.cookie('miao', 'ok')
}
},
error: function () {
$.cookie('miao', null)
},
timeout: 300
});
//检测是否秒杀了
var miao = $.cookie('miao')
if (miao) {
alert('你已秒杀');
}
</script>
</body>
</html>
第三层:数据接入层
知识点
数据校验、存入队列、商品数量检测
#miaosha.php
<?php
namespace miaosha;
//允许指定域名访问、防止跨域
header('Access-Control-Allow-Origin:http://xxxxx.cn');
$redis = new \Redis();
//获取$.ajax提交的数据
$value = ['phone' => 'xxxx', 'number' => '1'];
$value = serialize($value);
if (setValue($value) == "overflow") {
//执行set_file.php秒杀结束
} else {
$data = ['msg' => 'ok'];
}
//返回结果到前台
$callback = $_GET['callback'];
echo $callback . '(' . json_encode($data) . ')';
function setValue($value)
{
$redis = new \Redis();
//设置基数标志位
if (!$redis->get('flat')) {
$redis->set('flat', 1);
}
//检测溢出,最大100
if ($redis->get('flat') > 100) {
return 'overflow';
}
//插入非重复数据
if ($redis->zAdd('miaoKey', $redis->get('flat'), $value)) {
$redis->incr('flat');
}
}
function getValue()
{
$redis = new \Redis();
return $redis->zRange('miaoKey', 0, -1);
}
第四层:数据处理层
知识点
数据持久化
#set_mysql.php
<?php
//转存信息,进入到mysql进行数据持久化
$redis = new \Redis();
$data = $redis->zRange('miaoKey', 0, -1);
//插入mysql....
抢购升级
加机器(简单粗暴),高峰过后会浪费
- 系统解耦(资源隔离,当前业务放在单独的集群上面)
- 限流和过载保护(根据后端承载能力,进行限流,防止全网挂掉,使用redis承载海量QPS)
- 高峰期做docker弹性扩缩容处理
- 做一套独立的秒杀系统(秒杀系统挂了,也不影响其他正常运行)
- 整个系统采用GO重新开发,极大提高了系统的性能(十台php可能才承载2万QPS,十台go能承载50万QPS)
- 降级预案
- 分析异常请求,设置黑白名单
秒杀接入层 1.长连接 2.ip黑名单 3.抢购开关(突发事件,需要关闭) 4.url校验 5.refer白名单 6.id黑名单
本作品采用《CC 协议》,转载必须注明作者和本文链接
setValue
函数不能防止超卖秒杀商品数量多少个?需要十台设备,这个系统有点大