天貓Java研發三面:講講Redis實現購物車的設計思路!

  • 2019 年 11 月 22 日
  • 筆記

正文

「好了,最後一個問題:雙11快到了,請講講購物車設計思路。」

購物車是任何一個電商項目都會用到的功能,面試的時候也經常問到,今天我們就來談談Redis下購物車的實現。

1.1. 購物車常見實現方式

傳統的做法是使用關係型資料庫,比如mysql,建立一個cat購物車表,把相關的購物車產品資訊都放到資料庫裡面。

天貓Java研發三面:雙十一快到了!講講Redis實現購物車的設計思路

這樣的設計在功能完全沒問題,但在實際使用中,由於購物車的數據量太大,而且修改頻繁,會導致資料庫的壓力增加,所以在正式項目開發中,一般不會直接使用關係型資料庫來存儲購物車資訊。

既然不用關係型資料庫,但就從非關係型資料庫裡面做選擇了,很多的架構師會選擇使用mongodb存購物車的數據,這也完全可以,mongodb有非常豐富的查詢API,性能也比傳統關係型資料庫要好,使用mongodb確實是個不錯的選擇。

但比起使用mongodb,有部分公司也會使用redis來存放購物車的資訊,比起mongdb的性能,redis的性能要來得更好。

1.2. 開啟持久化

購物車的數據,既然不存在關係型資料庫中,使用redis存儲也不能讓數據丟失,那redis必須開啟持久化,這樣哪怕redis重啟數據也不至於丟失。

Redis有兩種持久化機制,一種叫rdb,一種叫aof。

rdb也叫鏡像文件,存放的是某個時刻redis記憶體數據的一個鏡像。aof就是append only file的簡寫,裡面存放的是日誌文件,準確的來說是存放RESP的指令日誌,這裡RESP指令並不是這次的重點,這裡不做討論。

首先,RDB默認是開啟的,在Redis配置文件裡面,關於RDB的配置如下

天貓Java研發三面:雙十一快到了!講講Redis實現購物車的設計思路

默認的配置最少是60秒並且有10000個key發生變化才會刷新一次鏡像,這樣如果在時間沒到60秒,這個時候redis意外宕機,在這個時間段的數據都會丟失。

你可能會想,是否可以增加一條配置

save 1 1:表示1 秒內如果至少有 1個 key 的值變化,則保存

這樣數據視乎就不會丟失,但這肯定是不行的,每一秒都對redis記憶體的所有數據都寫入一次磁碟變成鏡像文件,這樣對性能影響非常大。

為了防止數據丟失,光從rdb上下手還是不行,默認aof並沒開啟,應該開啟aof日誌文件,這時候得修改配置文件,增加aof的相關配置

appendonly yes

開啟了aof日誌,丟失數據的可能性就減少很多了。

1.3. 業務分析

天貓Java研發三面:雙十一快到了!講講Redis實現購物車的設計思路

以京東的購物車為例,按業務分析,需要完成如下功能:

1.全選功能-獲取所有該用戶的所有購物車商品 2.商品數量-購物車圖標上要顯示購物車裡商品的總數 3.刪除-要能移除購物車裡某個商品 4.增加或減少某個商品的數量

1.4. 數據結構選擇

Redis常用有5種數據類型分別為string,hash,list,set,zset,在這個案例裡面我們選擇使用hash來完成這個購物車功能

先對hash這種數據類型的常用命令進行介紹

redis中hash的添加命令hset,如果key不存在,創建key,存在,則覆蓋原有值

redis 127.0.0.1:6379>hset myhash name enjoy ----給key為myset的鍵值設置鍵為name值為enjoy

redis中hash的查看命令hget

天貓Java研發三面:雙十一快到了!講講Redis實現購物車的設計思路

redis中hash的獲取key包含的field數量的命令hlen

天貓Java研發三面:雙十一快到了!講講Redis實現購物車的設計思路

redis中判斷指定key中指定field是否存在的命令hexists,存在返回1,不存在返回0

天貓Java研發三面:雙十一快到了!講講Redis實現購物車的設計思路

redis中hash刪除命令hdel,刪除一個或多個指定的欄位

天貓Java研發三面:雙十一快到了!講講Redis實現購物車的設計思路

redis中hash如果key或field不存在插入有效,否則不採取操作的命令hsetnx

redis 127.0.0.1:6379>hsetnx myhash sex boy ---設置myhash,field為sex的value為boy,不成功返回0,因為原來存在sex這個欄位並且有值  redis 127.0.0.1:6379>hget myhash sex --輸出"boy"

redis中hash中的value為數值時操作增減的命令hincrby

天貓Java研發三面:雙十一快到了!講講Redis實現購物車的設計思路

批量獲取key/value的命令hmget

redis 127.0.0.1:6379>hmget myhash name age issingle ----輸出結果為:enjoy 20   yes

根據myhash鍵獲取所有的欄位及value的命令hgetall

redis 127.0.0.1:6379>hgetall myhash ----輸出結果為:name age issingle enjoy 20 yes

獲取所有的field的命令hkeys

redis 127.0.0.1:6379>hkeys myhash ---輸出結果為:name age issingle

獲取所有欄位的值的命令hvals

redis 127.0.0.1:6379>hvals myhash ----輸出結果為:enjoy 20 yes

1.5. 業務設計

在購物車的場景下,既然選擇使用hash來完成,可以總體規劃如下:

1.以用戶ID作為key2.以商品id作為field3.以商品的數量作為value

1.5.1. 增加購物車商品

假設現在用戶ID為1001,這用戶往購物車放3個商品,產品的ID為10021,10025,10079,對應的指令應該為

天貓Java研發三面:雙十一快到了!講講Redis實現購物車的設計思路

天貓Java研發三面:雙十一快到了!講講Redis實現購物車的設計思路

1.5.2. 全選功能

全選功能-獲取所有該用戶的所有購物車商品,這個就非常好完成了,使用hgetall 指令就好

hgetall cart:1001 這樣就能把用戶1001的購物車裡面所有商品列出來

天貓Java研發三面:雙十一快到了!講講Redis實現購物車的設計思路

1.5.3. 商品數量

商品數量-購物車圖標上要顯示購物車裡商品的總數,這樣也不難,使用hlen指令就好

hlen cart:1001 顯示3,顯示的是購物車的商品數量

天貓Java研發三面:雙十一快到了!講講Redis實現購物車的設計思路

1.5.4. 刪除商品

刪除-要能移除購物車裡某個商品

hdel cart:1001 10079 刪除了購物車裡商品ID為10079的商品

天貓Java研發三面:雙十一快到了!講講Redis實現購物車的設計思路

1.5.5. 增加商品

增加或減少某個商品的數量

hincrby cart:1001 10021 1 通過這樣指令,使購物車產品id為10021的商品數量增加了1.

天貓Java研發三面:雙十一快到了!講講Redis實現購物車的設計思路

這樣設計的購物車,性能是很好的,而且也減少了資料庫的壓力,在真實的項目中可以考慮這樣使用。