www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]前言不知你大規(guī)模的用過(guò)Redis嗎?還是僅僅作為緩存的工具了?在Redis中使用最多的就是集合了,舉個(gè)例子,如下場(chǎng)景:簽到系統(tǒng)中,一天對(duì)應(yīng)一系列的用戶簽到記錄。電商系統(tǒng)中,一個(gè)商品對(duì)應(yīng)一系列的評(píng)論。交友系統(tǒng)中,某個(gè)用戶的一系列的好友。Redis中集合的特點(diǎn)無(wú)非是一個(gè)Key對(duì)應(yīng)一系...

前言

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

  1. 簽到系統(tǒng)中,一天對(duì)應(yīng)一系列的用戶簽到記錄。
  2. 電商系統(tǒng)中,一個(gè)商品對(duì)應(yīng)一系列的評(píng)論。
  3. 交友系統(tǒng)中,某個(gè)用戶的一系列的好友。
Redis中集合的特點(diǎn)無(wú)非是一個(gè)Key對(duì)應(yīng)一系列的數(shù)據(jù), 但是數(shù)據(jù)的作用往往是為了統(tǒng)計(jì)的,比如:

  1. 交友系統(tǒng)中,需要統(tǒng)計(jì)每天的新增好友,以及雙方的共同好友。
  2. 電商系統(tǒng)中,需要統(tǒng)計(jì)評(píng)論列表中的最新評(píng)論。
  3. 簽到系統(tǒng)中,需要統(tǒng)計(jì)連續(xù)一個(gè)月的簽到的用戶數(shù)量。
大型互聯(lián)網(wǎng)應(yīng)用中,數(shù)據(jù)量是巨大的,少說(shuō)百萬(wàn),千萬(wàn),甚至是一個(gè)億,比如電商巨頭淘寶,交友巨頭微信、微博;辦公巨頭釘釘?shù)?,哪一個(gè)的用戶不是上億?

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

聚合統(tǒng)計(jì)

聚合統(tǒng)計(jì)指的是多個(gè)元素聚合的結(jié)果,比如統(tǒng)計(jì)多個(gè)集合的交集并集、差集

在你需要對(duì)多個(gè)集合做聚合統(tǒng)計(jì)的時(shí)候,Set集合是個(gè)不錯(cuò)的選擇,除了其中無(wú)重復(fù)的數(shù)據(jù)外,Redis還提供了對(duì)應(yīng)的API

交集

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

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

給你一個(gè)億的keys,Redis如何統(tǒng)計(jì)?
統(tǒng)計(jì)兩個(gè)用戶的共同好友只需要兩個(gè)Set集合的交集,命令如下;

SINTERSTORE?userid:new?userid:20002?userid:20003
上述命令運(yùn)行完成后,userid:new這個(gè)key中存儲(chǔ)的將是userid:20002userid:20003兩個(gè)集合的交集。

差集

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

此時(shí)的結(jié)構(gòu)應(yīng)該如何設(shè)計(jì)呢?如下圖:

給你一個(gè)億的keys,Redis如何統(tǒng)計(jì)?
userid:20201101這個(gè)key記錄了userid用戶的2020/11/1日的好友集合。

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

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

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

并集

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

SUNIONSTORE??userid:new?userid:20201102?userid:20201101
此時(shí)新的集合userid:new則是兩日新增的好友。

總結(jié)

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

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

  1. Redis集群中選一個(gè)從庫(kù)專門(mén)負(fù)責(zé)聚合統(tǒng)計(jì),這樣就不會(huì)阻塞主庫(kù)和其他的從庫(kù)了
  2. 將數(shù)據(jù)交給客戶端,由客戶端進(jìn)行聚合統(tǒng)計(jì)。

排序統(tǒng)計(jì)

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

最新評(píng)論列表包含了所有的評(píng)論,這就要集合對(duì)元素進(jìn)行保序存儲(chǔ)了。也就是說(shuō)集合中的元素必須按序存儲(chǔ),稱之為有序集合。

Redis中的四種集合中ListSorted Set屬于有序集合。

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

List是按照元素進(jìn)入順序進(jìn)行排序,而Sorted Set可以根據(jù)元素權(quán)重來(lái)排序。 比如可以根據(jù)元素插入集合的時(shí)間確定權(quán)值,先插入的元素權(quán)重小,后插入的元素權(quán)重大。

針對(duì)這一例子中,顯然這兩種都是能夠滿足要求的,List中分頁(yè)查詢命令LRANGESorted Set分頁(yè)查詢命令ZRANGEBYSCORE

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

二值狀態(tài)統(tǒng)計(jì)

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

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

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

Bitmap 提供了GETBIT/SETBIT 操作,使用一個(gè)偏移值 offset 對(duì) bit 數(shù)組的某一個(gè) bit 位進(jìn)行讀和寫(xiě)。不過(guò),需要注意的是,Bitmap 的偏移量是從 0 開(kāi)始算的,也就是說(shuō) offset 的最小值是 0。當(dāng)使用 SETBIT 對(duì)一個(gè) bit 位進(jìn)行寫(xiě)操作時(shí),這個(gè) bit 位會(huì)被設(shè)置為 1。Bitmap 還提供了 BITCOUNT 操作,用來(lái)統(tǒng)計(jì)這個(gè) bit 數(shù)組中所有1的個(gè)數(shù)。

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

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

SETBIT?userid:10001:202011?1?1?
BitMap是從下標(biāo)0開(kāi)始,因此2號(hào)則是下標(biāo)為1,值設(shè)置為1則表示成功打卡了。

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

GETBIT?userid:10001:202011?1?
第三步,統(tǒng)計(jì)11月的打卡次數(shù),命令如下:

BITCOUNT?userid:10001:202011
那么問(wèn)題來(lái)了,需要統(tǒng)計(jì)你這個(gè)簽到系統(tǒng)中連續(xù)20天的簽到打卡的用戶的總數(shù),如何處理呢?假設(shè)用戶一個(gè)億。

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

Bitmap中還支持同時(shí)對(duì)多個(gè)BitMap按位做、、異或操作,命令如下圖:

給你一個(gè)億的keys,Redis如何統(tǒng)計(jì)?
思路來(lái)了,我們可以將每天的日期作為一個(gè)key,對(duì)應(yīng)的BitMap存儲(chǔ)一億個(gè)用戶當(dāng)天的打卡情況。如下圖:

給你一個(gè)億的keys,Redis如何統(tǒng)計(jì)?
此時(shí)我們只需要對(duì)2020/11/12020/11/20號(hào)的Bitmap做按位操作,最終得到的一個(gè)Bitmap中每個(gè)bit位置對(duì)應(yīng)的值則代表連續(xù)20天打卡的情況,只有連續(xù)20天全部打卡,所在的bit位的值才為1。如下圖:

給你一個(gè)億的keys,Redis如何統(tǒng)計(jì)?
最終可以使用BITCOUNT命令進(jìn)行統(tǒng)計(jì)。

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

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

基數(shù)統(tǒng)計(jì)

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

舉個(gè)栗子:電商網(wǎng)站中通常需要統(tǒng)計(jì)每個(gè)網(wǎng)頁(yè)的UV來(lái)確定權(quán)重,網(wǎng)頁(yè)的UV肯定是需要去重的,在Redis類型中Set支持去重,第一時(shí)間肯定想到的是Set。

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

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

是不是很心動(dòng)?但是HyperLogLog存在誤差的,大概是在0.81%,如果需要精準(zhǔn)的統(tǒng)計(jì),還是需要使用Set。對(duì)于這種網(wǎng)頁(yè)的UV來(lái)說(shuō),足夠了。

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

PFADD?p1:uv?10001?10002?10003?10004
如果存在重復(fù)的元素,將會(huì)自動(dòng)去重。

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

PFCOUNT?p1:uv

總結(jié)

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

給你一個(gè)億的keys,Redis如何統(tǒng)計(jì)?
SetSorted Set支持交集、并集的聚合運(yùn)算,但是Sorted Set不支差集運(yùn)算。

Bitmap也能對(duì)多個(gè)Bitmap做與、異或、或的聚合運(yùn)算。

ListSortedSet都支持排序統(tǒng)計(jì),但是List是根據(jù)元素先后插入順序排序,Sorted Set支持權(quán)重,相對(duì)于List排序來(lái)說(shuō)更加靈活。

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

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

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
關(guān)閉
關(guān)閉