(網絡學習)三、秒殺系統與壓力測試

課程:PHP秒殺設計 https://www.imooc.com/video/19863php

一、環境準備

a.安裝壓測工具ab

sudo apt-get install apache2-utils -y

Nginx下limit_req模塊burst參數超詳細解析html

b.nginx環境配置

#建立規則:以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)
  • 若是沒有設置,則全部請求會依次等待排隊

c.php環境

更新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)服務

d.環境測試

失敗狀況 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分鐘內不支付取消訂單 => 回滾預扣庫存

a.需求點分析

一、查庫存
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'

b.應用知識點

扣庫存同步核心代碼: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

相關文章
相關標籤/搜索