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