天天看點

電商網站高并發下的資料安全

    我們知道在多線程寫入同一個檔案的時候,會存現“線程安全”的問題(多個線程同時運作同一段代碼,如果每次運作結果和單線程運作的結果是一樣的,結果和預期相同,就是線程安全的)。如果是mysql資料庫,可以使用它自帶的鎖機制很好的解決問題,但是,在大規模并發的場景中,是不推薦使用mysql的。秒殺和搶購的場景中,還有另外一個問題,就是“超發”,如果在這方面控制不慎,會産生發送過多的情況。我們也曾經聽說過,某些電商搞搶購活動,買家成功拍下後,商家卻不承認訂單有效,拒絕發貨。這裡的問題,也許并不一定是商家奸詐,而是系統技術層面存在超發風險導緻的。

    1. 超發的原因

    假設某個搶購場景中,我們一共隻有100個商品,在最後一刻,我們已經消耗了99個商品,僅剩最後一個。這個時候,系統發來多個并發請求,這批請求讀取到的商品餘量都是99個,然後都通過了這一個餘量判斷,最終導緻超發。(同文章前面說的場景)

電商網站高并發下的資料安全

    在上面的這個圖中,就導緻了并發使用者b也“搶購成功”,多讓一個人獲得了商品。這種場景,在高并發的情況下非常容易出現。

    2. 悲觀鎖思路

    解決線程安全的思路很多,可以從“悲觀鎖”的方向開始讨論。

    悲觀鎖,也就是在修改資料的時候,采用鎖定狀态,排斥外部請求的修改。遇到加鎖的狀态,就必須等待。

電商網站高并發下的資料安全

    雖然上述的方案的确解決了線程安全的問題,但是,别忘記,我們的場景是“高并發”。也就是說,會很多這樣的修改請求,每個請求都需要等待“鎖”,某些線程可能永遠都沒有機會搶到這個“鎖”,這種請求就會死在那裡。同時,這種請求會很多,瞬間增大系統的平均響應時間,結果是可用連接配接數被耗盡,系統陷入異常。

    3. fifo隊列思路

    那好,那麼我們稍微修改一下上面的場景,我們直接将請求放入隊列中的,采用fifo(first input first output,先進先出),這樣的話,我們就不會導緻某些請求永遠擷取不到鎖。看到這裡,是不是有點強行将多線程變成單線程的感覺哈。

電商網站高并發下的資料安全

    然後,我們現在解決了鎖的問題,全部請求采用“先進先出”的隊列方式來處理。那麼新的問題來了,高并發的場景下,因為請求很多,很可能一瞬間将隊列記憶體“撐爆”,然後系統又陷入到了異常狀态。或者設計一個極大的記憶體隊列,也是一種方案,但是,系統處理完一個隊列内請求的速度根本無法和瘋狂湧入隊列中的數目相比。也就是說,隊列内的請求會越積累越多,最終web系統平均響應時候還是會大幅下降,系統還是陷入異常。

    4. 樂觀鎖思路

    這個時候,我們就可以讨論一下“樂觀鎖”的思路了。樂觀鎖,是相對于“悲觀鎖”采用更為寬松的加鎖機制,大都是采用帶版本号(version)更新。實作就是,這個資料所有請求都有資格去修改,但會獲得一個該資料的版本号,隻有版本号符合的才能更新成功,其他的傳回搶購失敗。這樣的話,我們就不需要考慮隊列的問題,不過,它會增大cpu的計算開銷。但是,綜合來說,這是一個比較好的解決方案。

電商網站高并發下的資料安全

    有很多軟體和服務都“樂觀鎖”功能的支援,例如redis中的watch就是其中之一。通過這個實作,我們保證了資料的安全。

繼續閱讀