課程: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