秒殺過程:
庫存查驗、庫存扣減和訂單處理:
在庫存查驗過程:
支撐大量高並發的庫存查驗請求,我們需要在這個環節使用 Redis 保存庫存量,這樣一來,請求可以直接從 Redis 中讀取庫存並進行查驗。
訂單處理可以在數據庫中執行,但庫存扣減操作,不能交給后端數據庫處理。在數據庫中處理訂單的原因比較簡單,
因為訂單處理會涉及支付、商品出庫、物流等多個關聯操作,這些操作本身涉及數據庫中的多張數據表,要保證處理的事務性,需要在數據庫中完成。而且,訂單處理時的請求壓力已經不大了,數據庫可以支撐這些訂單處理請求。
庫存扣減操作不能在數據庫執行,這是因為,一旦請求查到有庫存,就意味着發送該請求的用戶獲得了商品的購買資格,用戶就會下單了。同時,商品的庫存余量也需要減少一個。如果我們把庫存扣減的操作放到數據庫執行,會帶來兩個問題。額外的開銷。Redis 中保存了庫存量,而庫存量的最新值又是數據庫在維護,所以數據庫更新后,還需要和 Redis 進行同步,這個過程增加了額外的操作邏輯,也帶來了額外的開銷。
可能出現下單量超過實際庫存量,出現超售。由於數據庫的處理速度較慢,不能及時更新庫存余量,這就會導致大量庫存查驗的請求讀取到舊的庫存值,並進行下單。此時,就會出現下單數量大於實際的庫存量,導致出現超售,這就不符合業務層的要求了。
redis方法支持秒殺場景:
支持高並發。Redis 本身高速處理請求的特性就可以支持高並發。而且,如果有多個秒殺商品,我們也可以使用切片集群,用不同的實例保存不同商品的庫存,這樣就避免,使用單個實例導致所有的秒殺請求都集中在一個實例上的問題了。
保證庫存查驗和庫存扣減原子性執行。針對這條要求,我們就可以使用 Redis 的原子操作或是分布式鎖這兩個功能特性來支撐了。
原子操作: Lua 腳本
分布式鎖來保證多個客戶端能互斥執行這兩個操作:使用分布式鎖來支撐秒殺場景的具體做法是,先讓客戶端向 Redis 申請分布式鎖,只有拿到鎖的客戶端才能執行庫存查驗和庫存扣減。
數據傾斜:
1:某一個實例上分布的數據特別多
2:某個實例上數據都是熱點數據,被訪問的非常頻繁
數據傾斜原因:
1:存在bigkey:業務層避免創建bigkey,把集合類型的bigkey拆分成多個小集合,分散保存
bigkey 保存了大量集合元素(集合類型),會導致這個實例的數據量增加,內存資源消耗也相應增加。bigkey 的操作一般都會造成實例 IO 線程阻塞,如果 bigkey 的訪問量比較大,就會影響到這個實例上的其它請求被處理的速度。
2:slot手工分配不均勻:避免把較多的slot分配到一個實例上,進行槽的遷移
進行槽的遷移命令:
在實例5上執行此命令代表要從實例3上導入哈希槽編號為300的槽
1:cluster setslot 300 importing 3
在實例3上執行此命令表示實例三要將哈希槽300遷移到實例5
2:cluster setslot 300 migrating 5
從實例三獲取哈希槽300的100個key,因為 Slot 中的 key 數量可能很多,所以我們需要在客戶端上多次執行下面的這條命令
3:cluster getkeysinslot 300 100
將剛才第三步獲取的100個key中的key1遷移到實例5上的0號數據庫上把遷移的超時時間設置為 timeout(ip為IP 為 192.168.10.5)
4:migrate 192.168.10.5 6379 key1 0 timeout
反復執行migrate命令,直到將100個key遷移完,在執行命令三,重新從哈希槽300中拿數據,重復3,4步直到哈希槽300中的數據
全部遷移完。
3:使用了hash tag,使得大量數據被分配到了一個實例上的同一個slot上:如果是hash tag造成的數據傾斜,優先避免數據傾斜,不適用hash tag
hash tag應用場景:
它主要是用在 Redis Cluster 和 Codis 中,支持事務操作和范圍查詢。因為 Redis Cluster 和 Codis 本身並不支持跨實例的事務操作和范圍查詢,當業務應用有這些需求時,就只能先把這些數據讀取到業務層進行事務處理,或者是逐個查詢每個實例,得到范圍查詢的結果。這樣操作起來非常麻煩,所以,我們可以使用 Hash Tag 把要執行事務操作或是范圍查詢的數據映射到同一個實例上,這樣就能很輕松地實現事務或范圍查詢了。
4:存在熱點數據:采用帶有不同key前綴的多副本方法(
我們把熱點數據復制多份,在每一個數據副本的 key 中增加一個隨機前綴,讓它和其它副本數據不會被映射到同一個 Slot 中。這樣一來,
熱點數據既有多個副本可以同時服務請求,同時,這些副本數據的 key 又不一樣,會被映射到不同的 Slot 中。在給這些 Slot 分配實例時,
我們也要注意把它們分配到不同的實例上,那么,熱點數據的訪問壓力就被分散到不同的實例上了。
熱點數據多副本方法只能針對只讀的熱點數據。如果熱點數據是有讀有寫的話,就不適合采用多副本方法了,因為要保證多副本間的數據一致性,會帶來額外的開銷。
)