使用Redis Zset來處理活動常用排行榜(精確排行)

jaysun發表於2019-02-16

嚴格的排行榜

一個嚴格的排行榜,必須要滿足每個人的排序都是有實際意義的,簡單來說就是即使兩個人的分數一樣,那麼也要分出先後來。
活動週期在92天以內的話,那麼我們就可以使用200w加活動結束時間作為數字A來保證排行榜的順序正確

在很大的活動中,比如獎項很大,第10名和第11名,可能獎金的額度相差了幾萬、幾千。這個時候我們在做處理的時候就要小心了。我們要維護一個公平的排行榜。為了滿足這樣一個排行榜,我們需要在score的後面新增一個時間戳相關的係數。舉個例子:

使用者a 100 分 14:00 最後加分
使用者b 100 分 14:20 最後加分

那麼按照排行榜的規定來算,使用者a要排在使用者b之前。
但是我們在進行排行的時候,不能將時間直接加到分數後面,否則就排序反了,這個時候我們要用一個足夠大的數A來減去時間戳,並且要保證位數在整個活動期間不變。

首先我們要理解一個redis的排序,redis的zset中的score值為double型別,精度只有16位,事實上在儲存9999999999999999 16位整數的時候,會變為17位的10000000000000000,超過17位會變為科學計數法1e+17

在活動中,我們要保證使用者的分數不能丟失,所以必須保證在16位以內,一個使用者最多的粉絲是5000w如果一個活動期間能保證所有的使用者給他刷分,那麼可能是億級別的,但是實際上按照之前的活動量來看,最多能到千萬級別。

這個時候我們按照1億來算,長度要保證在9位,然後剩下的排重用的時間戳的精度,要保證在7位,也就是說我們要保證整個活動期間足夠大的數減去時間戳的開始時間和結束時間都是7位數。

首先保證數字A-結束時間為一個7位數 ,那麼我們要給這個結束時間+1000000 (一百萬) 得到數字A,這樣能最低限度保證活動結束之前時間戳係數的位數不變為7位數。
然後我們要保證數字A-活動開始時間也是一個七位數,也就是說開始時間和結束時間之間的跨度只能是900w,一旦超過900w,那麼數字A減去開始時間就會得到一個8位數。

但是100w是一個臨界點,我們100w和結束時間相加得到數字A,可能會因為活動結束時間的延長導致效果變成了為結束時間+99w 得到數字A,這個時候,活動最後結束的分數係數的位數就變為了6位,這簡直就是個災難。

所以我們將100w擴大為200w,這樣相應的就給活動的結束時間增加了(100w/3600/24 = 11)天的時間。但是得到的效果將 活動的跨度週期減小到了800w秒,也就是(8000000/86400=92)天。所以說,如果活動週期在92天以內的話,那麼我們就可以使用200w加活動結束時間作為數字A來保證排行榜的順序正確。

相關文章