天天看點

Redis輕松優雅實作榜單功能背景介紹場景模拟總結

背景介紹

衆所周知,在網際網路項目中,我們用Redis的場景非常之多,Redis的出現,很大程度補償了memcached這類key/value存儲的不足,

在部分場合可以對關系資料庫起到很好的補充作用,使用起來也是非常的友善,多種資料結構讓你能更加優雅、輕松的面對各種場景,公司主要做直播行業的,

單純Redis執行個體就有上百台,是以這邊用Redis也是很頻繁的,下面将介紹如果用Redis簡易、輕松的去實作各種榜單。

場景模拟

1.日榜實作

假如有一個活動需求,需要你統計每天每個直播間收禮榜單以及貢獻者榜單,思考下,你會怎麼做?

嗯,聰明的你3秒鐘不到就已經想到了要使用Redis的有序清單來進行統計,

沒錯,Redis的有序清單基本能實作大多的榜單統計功能,下面咱們先拿這個簡單需求來開刀。

1.設計資料結構
字段名稱定義(member):

{
    直播房間ID:roomId, 貢獻者ID:userId
}

雖然貢獻者可以在每個房間上榜,但房間ID唯一,是以根據這兩ID組合可保證唯一性

根據當地時間作為KEY(key)例如 20210630 確定每一天榜單


送禮總價值(score):這個玩意是異步處理的,是以確定每次計算就行了

2.操作
ZADD key score member
至此完事

3.查詢
ZREVRANGE key start stop

這樣子就将每天的榜單查詢出來了,so easy!
           

2.周榜實作

單純按自然周來統計的話,跟日榜沒啥差別,如果時最近N日榜單,假設繼續上面的活動需求,不僅要每日榜單,還需要看近N日的榜單,這時你會怎麼弄?

你要是存在資料庫裡,這個問題非常的好辦,直接SQL按時間周期查就完事了,
當然這種高頻熱點資料你反複在庫裡讀寫簡直就是找死。

由于Redis這玩意是非關系型,好家夥這時你可能會把每一天資料查出來然後再統一排序?
這種方式當然不可取,首先每天的資料榜單都是一個獨立KEY,每個KEY的member和score都是不同的,這種方式雖然可實作,但整體接口響應時間...
前期資料少可能沒啥影響,一但量大了,這就是挖坑,後面還得自己填。

正确做法是使用redis有序清單自帶的合并操作

指令:
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
别看指令這麼長啊,其實很簡單:
destination:目标KEY 這裡命名一個新KEY,用于查詢近N日榜單的KEY
key:你可以填當日
numkeys:要合并KEY的數量   查詢近N-1天,這裡填N-1
[key ...]:要合并KEY名稱數組 N天前除了當日的KEY名稱
WEIGHTS: 乘法因子
AGGREGATE:聚合的方式,我們這邊計算的是總榜是以使用SUM
當然,你用redis封裝的庫的API使用起來更加簡單、優雅
           

合并操作時間複雜度:O(N)+O(M log(M)), N 為給定有序集基數的總和, M 為結果集的基數。

總結

采用Redis實作榜單具有天然的優勢,其豐富的資料結構,簡易使用的API讓我們能輕松實作一個榜單功能,當然用的時候也要注意以下幾個問題

  1. 使用時緩存擊穿與緩存穿透的問題
  2. Redis當機(主從、叢集架構下基本很少出現)、 Redis服務不可用時的預案處理
  3. 緩存一緻性問題
路漫漫其修遠兮,吾願與君上下而求索,非常感謝各位帥哥、靓妹的點贊、收藏和評論,關注我,隻實戰不理論,我們下期見