文章图片
① 对现有网站业务的冲击,如果秒杀程序部署到现有的服务器上,可能导致整个网站瘫痪
解决方法
把秒杀活动部署到单独的机子上,并且用单独的域名
② 高并发,用户在秒杀活动开始之前会不停的刷新页面,如果用php脚本连接数据库的方式,会对服务器的压力较大
解决方法
使用静态页面,并且使用cdn缓存,解决带宽压力大等问题
③ 避免用户直接通过下单连接下单
解决方法
带个随机参数,在秒杀开始之前才能得到
【php秒杀系统架构设计实例】④ 控制抢购按钮,页面设计为静态页面并且使用了cdn缓存,如何点亮抢购按钮
解决方法
js文件后面带个随机版本号,这样不会被cdn缓存,直接到达服务器,来控制按钮点亮,这个js文件要小,不然会对服务器带来带宽的压力
⑤ 抢购程序设计,如果直接使用数据库事务,数据库压力太大
解决方法
使用redis或memcache等内存缓存,速度快还能解决超卖等问题
抢购静态页面代码
秒杀! - 锐客网 - 01天01时01分01秒
nocdn.js生成脚本
- $redis = new \Redis();
- if ($redis->connect('127.0.0.1','6379') == false) {
- die($redis->getLastError());
- }
- //设置token
- $token=md5(rand(100,10000));
- $redis->set("token",$token);
- $hl=fopen("public/js/nocdn.js","w");
- $js=<<
- var button = ''+
- '秒杀已经开始'+
- '
文章图片
';- $(".jingshan").html(button);
- $(function(){
- var flag=1;
- $("#qianggou").click(function(){
- if(flag!=1){
- return ;
- }
- flag=2;
- var token='{$token}';
- var url="http://192.168.128.128/redis.php"
- $.ajax({
- type: "POST",
- url: url,
- data: "token="+token,
- success: function(msg){
- alert( "Data Saved: " + msg );
- }
- });
- })
- })
- EOF;
- fwrite($hl, $js);
- fclose($hl);
内容主要是显示秒杀的按钮,生成随机的参数,生成ajax的提交脚本,如果要跨域使用jsonp【推荐阅读: js跨域4种解决方案】
抢购代码
- $redis = new \Redis();
- if ($redis->connect('127.0.0.1','6379') == false) {
- die($redis->getLastError());
- }
- //判断用户是否已经抢购
- if($redis->hexists("mywatchlist","user_id_")==1){
- exit("已经抢购");
- }
- //带参数的url
- if($redis->get("token")!=$_GET['token']){
- exit("参数错误");
- }
- $redis->watch("mywatchkey"); //命令用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断
- $mywatchkey=$redis->get("mywatchkey");
- $limit=10;
- if($mywatchkey>=$limit){
- exit("活动结束");
- }
- $redis->multi(); //事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性(atomic)地执行。
- $redis->set("mywatchkey",$mywatchkey+1);
- //sleep(5); //测试watch
- $rob_result = $redis->exec(); //按命令执行的先后顺序排列。 当操作被打断时,返回空值 nil,在php中成功返回array(0->1)失败返回空
- if($rob_result){
- //保证库存,原子判断,确保当两个客户同时访问 Redis 服务器得到的是更新后的值
- if($redis->incr("stock")>$limit){
- echo "抢购失败,请重试";
- }
- echo "抢购成功";
- //抢购成功
- //$redis->hSet("mywatchlist","user_id_".mt_rand(1, 9999),time());
- $redis->LPUSH("success",rand(1,20));
- }else{
- echo "抢购失败,请重试";
- }
- exit;
用ab测试没有超卖的问题
- ab -n 1000 -c 1000 http://127.0.0.1/redis.php
下面来解释一下原因,
时间 | 客户端 A | 客户端 B |
---|---|---|
T1 | WATCH name |
|
T2 | MULTI |
|
T3 | SET name peter |
|
T4 | SET name john |
|
T5 | EXEC |
所以结果是name等于
john
上面的代码
sleep(5)
可以测试,就会发现出现少买的问题,我测试去除sleep
之后不会出现这个问题上面就是我的秒杀设计
Demo:http://pan.baidu.com/s/1bWa1cE
推荐阅读
- 对GO切片的理解
- 小程序商城网站开发秒杀模块篇
- 盲盒购物网站系统开发建设 第三篇
- Netty核心概念之ChannelHandler&Pipeline&ChannelHandlerContext
- 简单的线程池实现多线程对大文件的读取
- SSH 端口转发与 SOCKS 代理
- Ubuntu16.04/Scala2.11.8安装教程
- 学习PHP中的高精度计时器HRTime扩展
- 使用OpenResty+Lua实现灰度测试(金丝雀)
- 使用源码编译安装PHP扩展