天天看點

基于Redis 千萬級使用者排行榜最佳實踐

Redis 是一個開源的,記憶體中的資料結構存儲系統,可以用作資料庫、緩存和消息隊列中間件。它支援多種類型的資料結構,如 字元串(string), Hash, 清單(List), 集合(Set), 有序集合(Sorted Set) 。 内置了 複制(replication),LUA腳本(Lua scripting), LRU驅動事件(LRU eviction),事務(Transactions) 和不同級别的 磁盤持久化(Persistence), 并通過 Redis哨兵(Sentinel)和自動分區(Cluster)提供高可用性

根據Redis支援的幾大資料結構, 我們可以在多個場景加以應用, 目前應用最廣泛的場景主要用于以下幾大類:

基于Web服務的分布式會話Session存儲 消息隊列 排行榜 計數器 釋出/訂閱

此文主要講解個人是如何處理千萬級别使用者排行榜并持久化使用者排行榜使用者資料

由于排行榜的不同業務需求, 需要從不同角度去考慮排行榜的榜單生成規則. 目前我們主要研究實時榜和曆史榜單

在這裡, 我們采用Redis Sorted Set資料結構來處理排行榜資料, 根據官方文檔定義:

Redis Sorted sets — Sorted sets are a data type which is similar to a mix between a Set and a Hash. Like sets, sorted sets are composed of unique, non-repeating string elements, so in some sense a sorted set is a set as well.

​ However while elements inside sets are not ordered, every element in a sorted set is associated with a floating point value, called the score (this is why the type is also similar to a hash, since every element is mapped to a value).

​ 然而,雖然Set中的元素沒有被排序,但排序集中的每個元素都與一個浮點值相關聯,這個值稱為得分(這也是為什麼該類型與哈希類似,因為每個元素都映射到一個值)。

​ Moreover, elements in a sorted sets are taken in order (so they are not ordered on request, order is a peculiarity of the data structure used to represent sorted sets). They are ordered according to the following rule:

​ 此外,Sorted Set中的元素是按順序排列的(而不是按加入的先後順序排序的,并且這個順序是用于表示排序集的資料結構的一個特性)。

​ 在Sorted Set中添加、删除或更新一個成員都是非常快速的操作,其時間複雜度為集合中成員數量的對數。由于Sorted Set中的成員在集合中的位置是有序的,是以,即便是通路位于集合中部的成員也仍然是非常高效的。

Sorted Set底層的實作是跳躍表(Skip List),插入和删除的效率都很高.

在redis的源碼中,找到zset的定義如下(server.h):

插入節點對應的方法源碼(t_zset.c):

​ 這裡我們Server語言采用php, 是以代碼風格為php文法:

​ 1, 資料錄入

​ 2, 排行榜日榜

​ 3, 排行榜月榜

​ 是以redis提供了一種特定的标簽{},這個{}内的字元串才參與計算hash slot.列如:{user}:aaa與{user}:bbb 這兩個集合可以確定在同一個slot上,可以使用zunionstore求它們的并集。是以,在處理這種需要合并redis曆史資料時,如果是在redis叢集環境下,需要特别注意。

在基于redis的整個排行榜的設計過程中,我們還需要考慮的

排行榜key的數量:確定key的數量是可控的,可設定過期時間的,就設定明顯的過期時間, 如果确實由于空間不足, 可以持久化到DB中處理

占用空間評估:Redis中排行榜資料記憶體占用情況進行評估, 防止不需要的排行榜資料長期占用記憶體

<a href="http://redis.cn/">http://redis.cn/</a>

<a href="https://redis.io/commands/cluster-keyslot">https://redis.io/commands/cluster-keyslot</a>