前不久,我做了一下java高並發場景的處理,在這里總結一下:場景主要包括兩個方面:一個是減庫存,一個是記錄訂單。簡單分析一下業務:每個客戶端下單,服務器在數據庫上面都相應的執行兩個操作,第一步把庫存表某條庫存信息update更新一下,同時在訂單表中insert添加一個記錄某某客戶預定了某某商品的信息。這里有個事務和行級鎖的問題。
update庫存表需要行鎖的,也就是說update操作必須是串行化的。然而在高並發的情況下系統整體的處理能力才是最重要的。
我們來分析一下一個事務完成過程中對一條記錄加鎖消耗的時間,
- 開始事務,鎖定庫存記錄,
- 第一步java向數據庫發出update庫存指令,這期間伴隨着網絡延遲和GC的時間。update結束之后,java再次向點單表發出insert指令,期間伴隨着網絡延遲和GC的影響。
- 提交事務,然后釋放鎖。下一個請求開始重復執行。
通過分析可以看到整個事務的執行流程效率不高,尤其是跨網段或者異地傳輸,導致非常大的網絡延遲,都將會導致java程序難以處理高並發。
下面開始優化之路:
思路1:盡量讓每個情況占據的鎖時間越短越好。既然update是加鎖的原因,那么就先insert然后update,這樣每個事務占據行鎖的時間減少了,單位時間內程序能夠處理的並發量就高了。
思路2:減少網絡傳輸和GC的影響。直接在數據庫層面上把這個邏輯實現,可以在數據庫上面使用存儲過程完成一個事務的開始和結束。
思路3:使用MQ。使用redis等緩存做一個原子計數器,用於判斷庫存量。然后把訂單信息insert到數據表中。最后把減庫存的操作交給隊列,讓隊列異步去操作庫存表。