處理搶購、秒殺應用場景下降「超賣」發生幾個優化方案(php)

加深下文件鎖理論

flock—輕便的諮詢文件鎖定php

說明

image.png

參數

handlemysql

文件系統指針,是典型地由fopen()建立的resource(資源)。redis

operationsql

operation能夠是如下值之一:緩存

  • LOCK_SH取得共享鎖定(讀取的程序)。
  • LOCK_EX取得獨佔鎖定(寫入的程序。
  • LOCK_UN釋放鎖定(不管共享或獨佔)。

若是不但願flock()在鎖定時堵塞,則是LOCK_NB(Windows 上還不支持)。併發

wouldblock高併發

若是鎖定會堵塞的話(EWOULDBLOCK 錯誤碼狀況下),可選的第三個參數會被設置爲TRUE。(Windows 上不支持)性能

返回值

成功時返回TRUE, 或者在失敗時返回FALSE優化

範例

$fp =fopen("lock.txt","w+"); //'w+'_讀寫方式打開,將件指針指向文件頭並將文件大小截爲零。若是文件不存在則嘗試建立之。
    // 加鎖
    if(flock($fp,LOCK_EX|LOCK_NB)){  // 非阻塞模式
        // 執行業務邏輯
        $res=1;
        //執行完成解鎖
        flock($fp,LOCK_UN);
    }else {
        // 其餘進程未解鎖執行
    }

    // 釋放內存 減小502發生
    unset($res);
    $res=null;
    fclose($fp);
$fp = fopen("lock.txt", "w+");
    // 加鎖
    if (flock($fp, LOCK_EX)) {  // 阻塞模式
        // 執行業務邏輯
        $res = 1;
        //執行完成解鎖
        flock($fp, LOCK_UN);
    }

    // 當前進程會一直等其餘進程解鎖文件後繼續執行
    // TODO
    echo "文件解鎖後才能輸出";

    // 釋放內存 減小502發生
    unset($res);
    $res = null;
    fclose($fp);

優化方案

在處理搶購、秒殺應用場景下降「超賣」發生幾個優化方案spa

1: 將庫存字段屬性設爲無符號(unsigned),在庫存爲0,不會出現負數

2:利用mysql的事務(鎖定一行)
select **... for update // 鎖定一行,其餘的操做都會被阻塞,直到鎖定的行提交commit ,其實這樣也存在性能問題,阻塞時間漫長以下圖
image.png

3:redis隊列(推薦)

lpop,lpush,llen

mysql事務在高併發下性能降低很厲害,文件鎖也是,由於Redis全部單個命令的執行都是原子性的,要麼都執行,要麼都不執行注意在使用redis作緩存時候,在更新商品庫存推薦使用hincrby
例如:

$num=0-$goodsNum;
$inventoryNum= $redisObj->hincrby($key, 'num', $num);

同理mysql也是同樣作減法操做

4:使用php文件鎖(阻塞/非阻塞模式)

5:redis鎖處理(推薦)

set方式
setnx方式
setnx+getset方式
相關文章
相關標籤/搜索