繞過條件競爭多次領取優惠卷,這種問題出現的原理是:多個線程同時訪問同一個共享代碼、變量、文件等沒有進行鎖操作或者同步操作的場景中。通常的web處理方式是通過單線程線性完成的,如果出現多線程并發請求的情況,數據處理邏輯就可能出現異常。
接口:/api/coupon/receive
修復建議:
一般是使用mysql的鎖機制、或者使用redis的原子性、單線程特性來解決。
本次修復采用了限制接口請求頻率的方案來解決,因為我們在遇到這個bug之前已經實現了限制接口頻率的功能,另外急于工期,所以臨時這樣解決。最終還是計劃使用redis來從根源解決這個問題。
該問題可延伸出秒殺場景下的庫存超賣、簽到場景下的多次簽到領取獎勵等。大家可以測試排查下相關場景是否存在該問題。
修復方法:
1:安裝 composer安裝 topthink/think-throttle 依賴;
composer require topthink/think-throttle
注意:執行composer 安裝依賴命令的時候最好先git提交一下代碼,或者備份一下, 因為依稀記得當時安裝這個依賴的時候導致項目提交git的時候出現了一個關于git子模塊的問題,當時排查出來是因為composer更新了一個名為alipaysdk/easysdk的依賴,這個依賴又依賴于xin/container這個,然而這個xin/container依賴文件夾內部有.git的文件夾,因為我對git子模塊不太熟悉,所以當時git提交報錯后,我直接將xin/container文件夾內的兩個子目錄里的.git刪掉即可。
2:對領取優惠券接口使用頻率限制配置(也可以對任意想要限制頻率的接口進行設置)
說明:
1. 對相關接口配置\think\middleware\Throttle中間件,1/10表示10秒內僅允許一個請求;
2. key中一定要使用到用戶的唯一uid;
3. 另外就是這個中間件一定要放在認證中間件AuthTokenMiddleware后面,否則request中獲取不到用戶的uid信息。