课程:PHP秒杀设计 https://www.imooc.com/video/19863php
sudo apt-get install apache2-utils -y
Nginx下limit_req模块burst参数超详细解析html
#建立规则:以ip限流,申请10M内存用来存储访问的频次信息、速率是1个每秒 limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s; #应用规则location{}: 使用规则,突发流量能够burst(2)个排队、再超过丢弃 limit_req zone=mylimit burst=2 nodelay;
nodelay:node
- 若是设置,会在瞬时提供处理(burst + rate)个请求的能力,>请求超过(burst + rate)的时候就会直接返回503,永远不存>在请求须要等待的状况。(这里的rate的单位是:r/s)
- 若是没有设置,则全部请求会依次等待排队
更新mysql
cd /home/wwwroot/cluster sed -ri "s/root\/tmp\/dk/home\/wwwroot\/cluster/g" `grep -rl "root\/tmp\/dk" .` vim rec.php.sh #%s/php7\:1.10/php7\:1.11/g # 重启n3(带防火墙的nginx)服务
失败状况 Failed requests/Complete requestsnginx
ab -n1000 -c50 'http://192.168.1.111:8084/index.html' //0/1000 ab -n1000 -c50 'http://192.168.1.111:8084/a.php' //0/1000 ab -n1000 -c50 'http://192.168.1.111/phpinfo.php' //724/1000
场景:git
1.某商品库存1000
2.并发读100w
3.并发抢购100w
收到并发请求:github
预扣库存 => 建立订单 => 支付 => 数据入库 10分钟内不支付取消订单 => 回滚预扣库存
一、查库存 curl 'http://192.168.1.111:8080/seckill/api.php?act=getStock&product_id=1&user_id=1' ab -n1000 -c50 'http://192.168.1.111:8080/seckill/api.php?act=getStock&product_id=1&user_id=1' ____查询功能会应对最大的请求压力,请求落到php缓存(apcu)上,无缓存时查询redis库。 二、扣库存 curl 'http://192.168.1.111:8080/seckill/api.php?act=buy&product_id=1&user_id=1' ab -n1000 -c50 'http://192.168.1.111:8080/seckill/api.php?act=buy&product_id=1&user_id=1' ____(单件商品)扣库存应对秒杀订单提交,参数存有:库存总数、本机预售限额数、本机订单数: 1、本地预售缓存(APC_LOCAL_USE)加当前请求(+1)比较本地预售库存(APCU_LOCAL_STOCK)、超过则拒绝, 2、去redis库报入、看总预售数(REDIS_REMOTE_USE_COUNT)是否小于库存总数(REDIS_REMOTE_TOTAL_COUNT)、 不小于则拒绝, 3、添加用户信息到订单队列(REDIS_REMOTE_QUEUE)。 三、同步库存至本地缓存 curl 'http://192.168.1.111:8080/seckill/api.php?act=sync&product_id=1&user_id=1' ____把本机缓存与redis数据同步:redis上的库存总数(REDIS_REMOTE_TOTAL_COUNT)、 总预售数(REDIS_REMOTE_USE_COUNT)减去本机的预售缓存(APC_LOCAL_USE),成功则把本地预售缓存 (APC_LOCAL_USE)清零、更新本地预售库存(APCU_LOCAL_STOCK)。 四、清空本地缓存 curl 'http://192.168.1.111:8080/seckill/api.php?act=clear&product_id=1&user_id=1' ____清理本地缓存apcu_clear_cache()。 五、重置数据 curl 'http://192.168.1.111:8080/seckill/api.php'
扣库存同步核心代码:redis
//给总预售数 +1 $script = <<<eof local key = KEYS[1] local field1 = KEYS[2] local field2 = KEYS[3] local field1_val = redis.call('hget', key, field1) + 0 local field2_val = redis.call('hget', key, field2) + 0 if(field1_val > field2_val) then return redis.call('HINCRBY', key, field2, 1) end return 0 eof; return self::conRedis()->eval($script, [ self::$REDIS_REMOTE_HT_KEY, self::$REDIS_REMOTE_TOTAL_COUNT, self::$REDIS_REMOTE_USE_COUNT ], 3);
缓存相关函数:apcu_add; apcu_inc; apcu_store; apcu_dec
redis:使用eval执行lua脚本sql
先关闭软件防火墙,本机的8080/8082/8084前面2个没有防火墙,上面端口使用8080的,虚拟机中docker的测试结果:docker
使用VM环境deepin15.11: mysql8 + docker_nginx*1 + docker_redis主从 + docker_php*3 [注] -r 解决:apr_socket_recv: Connection reset by peer (104) -c20000 客户端数默认最大是2w
接口 | 参数 | Complete requests | Failed requests | Time per request | qps |
---|---|---|---|---|---|
查询: getStock | -n1000-c50 -r-n100000-c10000 -r-n1000000-c20000 |
1000 100000 1000000 |
0 102015 1002026 |
12 10 10890 |
4037 4583 1836 |
扣库存: buy | -n1000-c50 -r-n100000-c10000 -r-n1000000-c20000 |
1000 100000 1000000 |
0 100668 1001635 |
13 1964 13040 |
3719 5090 1533 |
定时同步: sync | -n1000-c50 | 1000 | 998 | 632 | 790 |
实例及数据库代码上传:
https://github.com/cffycls/seckill