有柳巖問:高并發庫存扣減一致性問題,怎么用 Redis 解決?
昨天和大家聊了庫存異常的兩種情況:
- “先查后減”,容易出現異常;
- “先查后設”,冪等性優化,解決重試問題;
- “先查后設,有條件的設”,CAS優化,解決并發問題;
有留言說:可以用redis優化。redis方案是可以的,今天簡單展開說說。
redis一般如何操作庫存?
一般在redis客戶端執行:
$num = GET key$num = $num - $countSET key $num
這樣操作存在什么問題?
在并發量大的時候,會遇到和上一篇文章中提到的并發一致性問題。
是如何利用redis事務操作優化?
本質也是樂觀鎖。
redis的WATCH和EXEC可以提供類似事務的機制:
- WATCH觀察key是否被改動;
- 如果提交時key被改動,EXEC將返回null,表示事務失敗;
保證一致性的庫存扣減可以優化為:
WATCH key$num = GET key$num = $num - $countMULTISET key $numEXEC
在WATCH之后,EXEC執行之前,如果key的值發生變化,則EXEC會失敗。
redis的WATCH為何能夠保證事務性?
本質上,和上一篇文章中提到的樂觀鎖CAS機制是一樣的,詳見:
大部分情況下,redis不同的客戶端會訪問不同的key,所以WATCH碰撞的概率會比較小,在秒殺的業務場景,使用WATCH,也會有一定的沖突,需要針對秒殺業務做單獨的優化。
為什么redis更能應對超高并發的庫存管理?
根本原因,還是redis內存訪問與mysql數據落盤的性能差異。
redis庫存管理有什么需要注意的?
數據具備“易失性”,如果重啟,數據可能丟失,所以redis大部分時候是用來存儲允許cache miss的數據。如果實在要用redis來存儲業務上不能夠丟失的數據,需要重點設計一致性與可用性。
當然,redis也可以固化數據,但如果把redis當做DB用,為什么不直接使用mysql呢?
稍作總結
- 可以使用redis的事務性扣減庫存,其核心原理也是CAS機制;
- redis高性能的核心是內存存儲,一般用來存儲允許cache miss的數據;
- 如果使用redis存儲不允許丟失的數據,需要注意一致性與可用性,這一點上,對比mysql沒有額外優勢;
具體怎么用,還得結合業務折衷。
任何脫離業務的架構設計都是耍流氓!
知其然,知其所以然。
思路比結論更重要。