1、併發下鎖的問題:其實這有兩個問題,第一併發下資料的髒讀髒寫,第二就是防止併發下導致為了防止髒讀髒寫的而產生的其他問題(例如死鎖)。
這裡不再闡述相關的鎖機制,我只說明專案中使用的鎖以及遇到的問題。
庫存中心這裡我使用了三種機制:悲觀鎖、樂觀鎖、資料庫cas操作。
個人認為悲觀鎖、樂觀鎖最終還是在**邏輯層面去控制資料讀寫,悲觀鎖實現簡單,但是坑多,樂觀鎖實現稍微複雜,效率也較高。cas則是在我們寫**時時時刻刻要考慮到的問題,他能保證我們少走坑,保證資料準確性。
1.1為何使用悲觀鎖:
不言而喻,使用簡單,對一般專案而言,併發要求不是非常高的前提下,悲觀鎖足以適用。但是悲觀鎖使用起來搞不好就死鎖。
1.1.1使用坑點:不排序基本就會死鎖,對悲觀鎖一定要排序(第
一、主鍵排序,針對有些場景不適用,比如存在更新或者插入資料的混合操作,第
二、其他字段排序,針對mysql、oracle等排序或者查詢的字段必須是主鍵或者增加了索引的字段,不然會直接鎖表,pgsql則還是行級鎖,不過防止一切問題,還是針對加索引的字段排序。)
排序的資料跟更新資料順序必須一致,不然一定死鎖(這裡不僅僅包括查詢出來的資料,還要包括相關的資料,舉個栗子:我查詢庫存資料,但是我同時要寫入流水、單據、虛倉、渠道倉,特別是流水、虛倉、渠道倉都涉及我排序的字段,所以全部進行統一的排序)。
2.1樂觀鎖實現的思考:
關於很多例子都會說樂觀鎖增加版本號啥的去控制,一開始沒有真正理解其意以為增加版本空或者其他去做,這裡的版本號實際上卻是這個資料單次操作的唯一憑證,不存在多次操作的可能,有的時候會考慮修改時間作為版本號其實也是不太合適的,這個我覺得更多考慮的是場景來操作,比如單據那麼他就有個狀態可以做唯一憑證的版本號。
2.2資料庫本身的cas操作:
這裡提到的是pgsql的insert into... on conflict do update set... 這個是最容易忽略的,至少一開始我就是這樣的,從我自身來看我有的時候還是更多考慮**層面的東西,其實樂觀鎖悲觀鎖還是更多是邏輯上的處理,外加資料庫的鎖,它更像是基於上層的操作,而cas則是資料庫自身的操作。不知道這樣說明不明白,但是他的效率相對樂觀鎖悲觀鎖是最高的。這樣的操作對於單一的場景是推薦用的,如果是複雜場景就沒法使用,後面會說明為何。
2、庫存資料的坑
庫存中心本身根據場景的不同涉及到資料的變化是一連串的,而不是單一的,面對更多的場景肯定會有考慮不全的情況(比如贏家大概60多種變化場景),外加上正逆向的操作,資料核對你可以想象。
那麼如何做才能讓自己優雅的甩鍋呢,我想大家都喜歡聽這個吧,啊哈哈。玩笑話,接下來的這樣做是讓我們更高效的定位到問題,避免花費大量時間做了沒用的事。
對庫存來說庫存的準確性必須保證,但是它變化無常,所以首先我們需要庫存變化流水,一方面是使用方核對庫存賬使用,另一方面是作為庫存變化遺跡供我們檢查使用,所以不管業務方要求是什麼,我們自身需要把所有場景的庫存流水都要記錄出來,業務方需要什麼給他們展示即可(這裡有個插曲,本身庫存可用庫存、鎖定庫存流水,但是贏家不要這些,他們只要實際庫存(可以+鎖定),中間屈服了把可用、鎖定給去掉了,記得當時彬彬說過這些留著對庫存用,當時沒理解真諦後面才發現讓人頭疼,所以後面全給加上了)那麼這個加上後還缺在庫存變化之前的前值,這個一定要查詢並做日誌列印出來,這個核對庫存變化非常關鍵的一步,因為在實際場景中可能會存在庫存的無序變化/階梯跳動,這樣的庫存是有問題的,這個時候需要知道是什麼情況導致的,是**邏輯處理有問題還是本身庫存就有問題,好甩鍋啊切記~
一旦需要列印期初庫存,說白了這資料可能需要加鎖了或者樂觀鎖吧,這也就是我上面說的複雜情況下cas操作就不行了,不是不行,而是沒有了實際效果。那麼有了這兩個基本可以確定庫存的變化了,還有就是需要知道入口單據以及明細項這是作為變更庫存的重要條件。最後列印庫存變化流水也是可以檢驗庫存流水的處理邏輯是否有問題了。
由於贏家專案時間的緊迫性,後面的鎖操作,cas操作都是快速使用上的,沒有過多整合,這裡面對於庫存流水操作也是屬於逆向操作了增加了複雜度,後面不再使用這裡不再贅述。
庫存與第三方系統互動(sap、wms等),如果不是需要同步的話,全部使用非同步形式。這裡同樣需要記錄互動日誌不管成功失敗
以上是個人在專案的總結以及個人拙見,如有不妥之處歡迎指正交流。
高併發下的庫存扣減方案
那年還很low db 剛開始我們的營銷專案組身單力薄,人微言輕 那時營銷業務才剛開始發展,此時我們把業務放到第一位,技術方案為滿足時間內業務發展所讓步。大家應該可以猜到,這個時候我們很low的庫存扣減方案 直接上資料庫。根據業務訴求,每個活動會儲存乙份實時變化的庫存,參與活動時,實時扣減資料庫,操作...
高併發下減少鎖競爭
1.減少鎖的持有時間,將不需要鎖的操作從同步 塊的移除。可以優化的 class attributestore 優化之後的 class attributestore if location null return false else return pattern.matches regex,loca...
高併發下防止庫存超賣 方案1關聯式資料庫鎖
所謂庫存超賣是指在併發量大的情況下,賣出去的商品數量比實際庫存多,如秒殺系統 1 超賣舉例 總庫存 4個商品 請求人 a 1個商品 b 2個商品 c 3個商品 偽 select 庫存數量 from 庫存表 where 商品id if 庫存數量 扣減庫存數量 update 庫存表 set 庫存數量 庫...