日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務,提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

前言

不知你大規(guī)模地用過redis嗎?還是僅僅作為緩存的工具?在Redis中使用最多的就是集合了,舉個例子,如下場景:

  • 簽到系統(tǒng)中,一天對應一系列的用戶簽到記錄。
  • 電商系統(tǒng)中,一個商品對應一系列的評論。
  • 交友系統(tǒng)中,某個用戶的一系列的好友。

Redis中集合的特點無非是一個Key對應一系列的數(shù)據(jù), 但是數(shù)據(jù)的作用往往是為了統(tǒng)計的,比如:

  • 交友系統(tǒng)中,需要統(tǒng)計每天的新增好友,以及雙方的共同好友。
  • 電商系統(tǒng)中,需要統(tǒng)計評論列表中的最新評論。
  • 簽到系統(tǒng)中,需要統(tǒng)計連續(xù)一個月的簽到的用戶數(shù)量。

大型互聯(lián)網(wǎng)應用中,數(shù)據(jù)量是巨大的,少說百萬,千萬,甚至是一個億,比如電商巨頭淘寶,交友巨頭微信、微博;辦公巨頭釘釘?shù)?,哪一個的用戶不是上億?

只有針對不同場景,選擇合適的集合,統(tǒng)計才能更方便。

一、聚合統(tǒng)計

聚合統(tǒng)計指的是多個元素聚合的結果,比如統(tǒng)計多個集合的交集、并集、差集。

在你需要對多個集合做聚合統(tǒng)計的時候,Set集合是個不錯的選擇,除了其中無重復的數(shù)據(jù)外,Redis還提供了對應的API。

1.交集

在上述的例子中交友系統(tǒng)中統(tǒng)計雙方的共同好友正是聚合統(tǒng)計中的交集。

在Redis中可以userid作為key,好友的userid作為value,如下圖:

統(tǒng)計兩個用戶的共同好友只需要兩個Set集合的交集,命令如下;

SINTERSTORE userid:new userid:20002 userid:20003

上述命令運行完成后,userid:new這個key中存儲的將是userid:20002、userid:20003兩個集合的交集。

2.差集

舉個例子:假設交友系統(tǒng)中需要統(tǒng)計每日新增的好友,此時就需要對臨近兩天的好友集合取差集了,比如2020/11/1日的好友是set1,2020/11/2日的好友是set2,此時只需要對set1和set2做差集。

此時的結構應該如何設計呢?如下圖:

userid:20201101這個key記錄了userid用戶的2020/11/1日的好友集合。

差集很簡單,只需要執(zhí)行SDIFFSTORE命令,如下:

SDIFFSTORE user:new userid:20201102 userid:20201101

執(zhí)行完畢,此時的user:new這集合將是2020/11/2日新增的好友。

這里還有一個更貼切的例子,微博上有個可能認識的人功能,可以使用差集,即是你朋友的好友減去你們共同的好友即是可能認識的人。

3.并集

還是差集的那個例子,假設需要統(tǒng)計2020/11/01和2020/11/2總共新增的好友,此時只需要對這兩日新增好友的集合做一個并集。命令如下:

SUNIONSTORE userid:new userid:20201102 userid:20201101

此時新的集合userid:new則是兩日新增的好友。

4.總結

Set集合的交差并的計算復雜度很高,如果數(shù)據(jù)量很大的情況下,可能會造成Redis的阻塞。

那么如何規(guī)避阻塞呢?建議如下:

  • 在Redis集群中選一個從庫專門負責聚合統(tǒng)計,這樣就不會阻塞主庫和其他的從庫了
  • 將數(shù)據(jù)交給客戶端,由客戶端進行聚合統(tǒng)計。

二、排序統(tǒng)計

在一些電商網(wǎng)站中可以看到商品的評論總是最新的在上面,這個是怎么做的呢?

最新評論列表包含了所有的評論,這就要集合對元素進行保序存儲了。也就是說集合中的元素必須按序存儲,稱之為有序集合。

Redis中的四種集合中List和Sorted Set屬于有序集合。

但是List和Sorted Set有何區(qū)別呢?到底使用哪一種呢?

List是按照元素進入順序進行排序,而Sorted Set可以根據(jù)元素權重來排序。

比如可以根據(jù)元素插入集合的時間確定權值,先插入的元素權重小,后插入的元素權重大。

針對這一例子中,顯然這兩種都是能夠滿足要求的,List中分頁查詢命令LRANGE和Sorted Set分頁查詢命令ZRANGEBYSCORE。

但是就靈活性來說,List肯定不適合,List只能根據(jù)先后插入的順序排序,但是大多數(shù)的場景中可能并不只是按照時間先后排序,可能還會按照一些特定的條件,此時Sorted Set就很合適了,只需要根據(jù)獨有的算法生成相應的權重即可。

三、二值狀態(tài)統(tǒng)計

二值狀態(tài)指的是取值0或者1兩種;在簽到打卡的場景中,只需要記錄簽到(1)和未簽到(0)兩種狀態(tài),這就是典型的二值狀態(tài)統(tǒng)計。

二值狀態(tài)的統(tǒng)計可以使用Redis的擴展數(shù)據(jù)類型Bitmap,底層使用String類型實現(xiàn),可以把它看成是一個bit數(shù)組。關于詳細內(nèi)容后續(xù)介紹.........

在簽到統(tǒng)計中,0和1只占了一個bit,即使一年的簽到數(shù)據(jù)才365個bit位。大大減少了存儲空間。

Bitmap 提供了GETBIT/SETBIT 操作,使用一個偏移值 offset 對 bit 數(shù)組的某一個 bit 位進行讀和寫。不過,需要注意的是,Bitmap 的偏移量是從 0 開始算的,也就是說 offset 的最小值是 0。當使用 SETBIT 對一個 bit 位進行寫操作時,這個 bit 位會被設置為 1。Bitmap 還提供了 BITCOUNT 操作,用來統(tǒng)計這個 bit 數(shù)組中所有1的個數(shù)。

鍵值如何設計呢?key可以是userid:yyyyMM,即是唯一id加上月份。假設員工id為10001,需要統(tǒng)計2020/11月份的簽到打卡記錄。

第一步,執(zhí)行命令設置值,假設11月2號打卡了,命令如下:

SETBIT userid:10001:202011 1 1

BitMap是從下標0開始,因此2號則是下標為1,值設置為1則表示成功打卡了。

第二步,檢查該用戶11月2號是否打卡了,命令如下:

GETBIT userid:10001:202011 1

第三步,統(tǒng)計11月的打卡次數(shù),命令如下:

BITCOUNT userid:10001:202011

那么問題來了,需要統(tǒng)計你這個簽到系統(tǒng)中連續(xù)20天的簽到打卡的用戶的總數(shù),如何處理呢?假設用戶一個億。

比如需要統(tǒng)計2020/11/01到2020/11/20天中連續(xù)打卡的人數(shù),如何統(tǒng)計呢?

Bitmap中還支持同時對多個BitMap按位做與、或、異或操作,命令如下圖:

思路來了,我們可以將每天的日期作為一個key,對應的BitMap存儲一億個用戶當天的打卡情況。如下圖:

此時我們只需要對2020/11/1到2020/11/20號的Bitmap做按位與操作,最終得到的一個Bitmap中每個bit位置對應的值則代表連續(xù)20天打卡的情況,只有連續(xù)20天全部打卡,所在的bit位的值才為1。如下圖:

最終可以使用BITCOUNT命令進行統(tǒng)計。

可以嘗試計算下內(nèi)存開銷,每天使用 1 個 1 億位的 Bitmap,大約占 12MB 的內(nèi)存(10^8/8/1024/1024),20 天的 Bitmap 的內(nèi)存開銷約為 240MB,內(nèi)存壓力不算太大。不過,在實際應用時,最好對 Bitmap 設置過期時間,讓 Redis 自動刪除不再需要的簽到記錄,以節(jié)省內(nèi)存開銷。

如果涉及到二值狀態(tài),比如用戶是否存在,簽到打卡,商品是否存在等情況可以使用Bitmap,可以有效節(jié)省內(nèi)存空間。

四、基數(shù)統(tǒng)計

基數(shù)統(tǒng)計指統(tǒng)計一個集合中不重復元素的個數(shù)。

舉個例子:電商網(wǎng)站中通常需要統(tǒng)計每個網(wǎng)頁的UV來確定權重,網(wǎng)頁的UV肯定是需要去重的,在Redis類型中Set支持去重,第一時間肯定想到的是Set。

但是這里有一個問題,Set底層使用的是哈希表和整數(shù)數(shù)組,如果一個網(wǎng)頁的UV達到千萬級別的話(一個電商網(wǎng)站中何止一個頁面),那么對于內(nèi)存的消耗極大。

Redis提供了一個擴展類型HyperLogLog用于基數(shù)統(tǒng)計,計算2^64個元素大概只需要12KB的內(nèi)存空間。

是不是很心動?但是HyperLogLog是存在誤差的,大概是在0.81%,如果需要精準的統(tǒng)計,還是需要使用Set。對于這種網(wǎng)頁的UV來說,足夠了。

在統(tǒng)計網(wǎng)頁UV的時候,只需要將用戶的唯一id存入HyperLogLog中,如下:

PFADD p1:uv 10001 10002 10003 10004

如果存在重復的元素,將會自動去重。

統(tǒng)計也很簡單,使用PFCOUNT命令,如下:

PFCOUNT p1:uv

總結

本文介紹了統(tǒng)計的幾種類型以及應該用什么集合存儲,為了方便理解,作者將支持情況和優(yōu)缺點匯總了一張表格,如下圖:

Set和Sorted Set支持交集、并集的聚合運算,但是Sorted Set不支差集運算。

Bitmap也能對多個Bitmap做與、異或、或的聚合運算。

List和SortedSet都支持排序統(tǒng)計,但是List是根據(jù)元素先后插入順序排序,Sorted Set支持權重,相對于List排序來說更加靈活。

對于二值狀態(tài)統(tǒng)計,判斷某個元素是否存在等場景,建議使用Bitmap,節(jié)省的內(nèi)存空間。

對于基數(shù)統(tǒng)計,在大數(shù)據(jù)量、不要求精準的情況建議使用HyperLogLog,節(jié)省內(nèi)存空間;對于精準的基數(shù)統(tǒng)計,最好還是使用Set集合。

作者丨不才陳某

來源丨公眾號:碼猿技術專欄(ID:oneswholife)

分享到:
標簽:Redis
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定