1. 減庫存 一般下單減庫存的流程大概是這樣的: 1、查詢商品庫存。這裡直接查的Redis中的庫存。 2、Redis中的庫存減1。這裡用到的Redis命令是:incrby -1 3、扣減資料庫中的庫存。這裡用資料庫樂觀鎖,不用額外加鎖 4、非同步刷新Redis中的庫存 5、定時掃描超時未支付的交易,庫 ...
1. 減庫存
一般下單減庫存的流程大概是這樣的:
1、查詢商品庫存。這裡直接查的Redis中的庫存。
2、Redis中的庫存減1。這裡用到的Redis命令是:incrby -1
3、扣減資料庫中的庫存。這裡用資料庫樂觀鎖,不用額外加鎖
4、非同步刷新Redis中的庫存
5、定時掃描超時未支付的交易,庫存加回去
總結一下這個流程就是:先減redis庫存,再減資料庫庫存,最後刷新redis庫存
用到的Redis命令可能:DECR key 或者 INCRBY key -1
更新資料庫的SQL可能是這樣的:
update 商品庫存表 set 庫存 = 庫存 - 1 where 商品ID = xxx and 庫存 > 0;
或者
update 商品庫存表 set 庫存 = 庫存 - 1 where 商品ID = xxx and version = xxx;
用樂觀鎖是一種比較好的方式,而且一遍ID欄位都有索引,可以充分利用MySQL行級鎖
這種方式還有一個比較巧妙的地方是,利用redis的單線程來操作庫存,而且又是原子命令,可以避免併發問題
同時,先減redis庫存後可以防止後續因庫存不足而造成下單失敗
最後,資料庫更新完以後,再通過MQ非同步刷新緩存,可以使得redis中的庫存誤差不會太大
交易系統會定時掃描超時未支付的訂單,然後用MQ非同步通知訂單和商品中心,將訂單關閉,庫存再放回去
2. 加鎖
加鎖(比如:基於Redis的分散式鎖)
MQ可以把並行轉成串列,但是並不能很好的解決併發訪問的問題,只能靠鎖
加鎖會影響性能,但是影響不大。假設我們用Redisson分散式鎖,操作redis只需要幾毫秒,因此這點兒損耗不是什麼大問題。都是這麼玩兒的,不加鎖還能怎麼辦呢。
3. 記憶體緩存
在cms管理後臺修改數據後,同步或非同步刷新redis緩存,同時利用zookeeper刷新記憶體緩存,這樣就可以不用等到需要用的時候再從redis中同步。
一定要避免redis大key,最常見的就是hash key,設置的時候不註意,一不小心裡面就幾千個field了,這對查詢非常不利,可以取模進行分片。
一定要避免HGETALL命令,利用Pinpoint可以幫助我們分析每個請求在每個操作所消耗的時候,從而有助於我們優化
數據遷移用Canal
https://redis.io/commands/incr