Redis基数统计之HyperLogLog小内存大用处
轉(zhuǎn)載:https://blog.csdn.net/azhegps/article/details/71158952
我們一直都知道,redis幾大常用數(shù)據(jù)結(jié)構(gòu),字符串、散列、列表、集合、有序集合。其實(shí)后來(lái)Redis做了很多補(bǔ)充,其中之一就是HyperLogLog,另外的還有GEO(地理位置),是3.2版本加的。這里我們就來(lái)簡(jiǎn)單介紹下HyperLogLog結(jié)構(gòu)。
???????先說(shuō)用處:這個(gè)結(jié)構(gòu)可以非常省內(nèi)存的去統(tǒng)計(jì)各種計(jì)數(shù),比如注冊(cè)ip數(shù)、每日訪問(wèn)IP數(shù)、頁(yè)面實(shí)時(shí)UV(PV肯定字符串就搞定了)、在線用戶數(shù)等。
???????這里看到所有的用處都是xxx數(shù),所以這個(gè)數(shù)據(jù)結(jié)構(gòu)的特點(diǎn)就是,可以比較準(zhǔn)確的估算出你要統(tǒng)計(jì)的數(shù)量,但是卻無(wú)法知道統(tǒng)計(jì)的詳細(xì)內(nèi)容。比如統(tǒng)計(jì)每日訪問(wèn)IP數(shù),可以獲取當(dāng)時(shí)訪問(wèn)過(guò)的IP總數(shù)量,但是沒(méi)法知道這些IP都是什么。有得必有失,當(dāng)然你要統(tǒng)計(jì)上面提到的那些內(nèi)容,可以用集合來(lái)處理,這樣可以知道數(shù)量,也能獲得所有的詳細(xì)列表。但是一個(gè)大型的網(wǎng)站,每天IP比如有100萬(wàn)個(gè)呢,我們粗算一個(gè)IP消耗15字節(jié),那么100萬(wàn)個(gè)IP就是15M,如果1千萬(wàn),就是150M。
????????再來(lái)看看我們的HyperLogLog,在Redis中每個(gè)鍵占用的內(nèi)容都是12K,理論存儲(chǔ)近似接近2^64個(gè)值,不管存儲(chǔ)的內(nèi)容是什么。12K,知道這個(gè)數(shù)據(jù)結(jié)構(gòu)的作用了吧。這也是為什么他不能知道里面的詳細(xì)內(nèi)容了。這是一個(gè)基于基數(shù)估算的算法,只能比較準(zhǔn)確的估算出基數(shù),可以使用少量固定的內(nèi)存去存儲(chǔ)并識(shí)別集合中的唯一元素。而且這個(gè)估算的基數(shù)并不一定準(zhǔn)確,是一個(gè)帶有 0.81% 標(biāo)準(zhǔn)錯(cuò)誤(standard error)的近似值。HyperLogLog結(jié)構(gòu),在范圍允許的情況下無(wú)論多少值,都只會(huì)占用12K內(nèi)存。
???????這樣比如我們把每日IP記錄下來(lái),假設(shè)每天有一億個(gè)IP訪問(wèn),如果使用集合的話,一天的內(nèi)存使用就是1.5G,假設(shè)我們存儲(chǔ)一個(gè)月的記錄,就需要45G容量。但是使用HyperLogLog的話,一天12K,一個(gè)月360K。如果我們不需要知道IP具體信息的話,完全可以把這些記錄留在內(nèi)存一年、或者不刪都行。如果需要,我們也會(huì)把所有的IP訪問(wèn)記錄通過(guò)其他途徑存儲(chǔ)起來(lái)。把每天的信息存儲(chǔ)起來(lái),我們可以計(jì)算每月IP總數(shù)(MERGE),一年的IP總數(shù)等(去重)。
???????下面介紹一下HyperLogLog的命令,其實(shí)他和集合的命令比較像,只是命令少,不能獲取列表而已。另外這個(gè)數(shù)據(jù)結(jié)構(gòu)需要2.8.9及以上的版本才能使用哦~
PFADD
????????在執(zhí)行這個(gè)命令之后,HyperLogLog內(nèi)部的結(jié)構(gòu)會(huì)被更新,并有所反饋,如果執(zhí)行完之后HyperLogLog內(nèi)部的基數(shù)估算發(fā)生了變化,那么就會(huì)返回1,否則(認(rèn)為已經(jīng)存在)就返回0。這個(gè)命令還有一個(gè)比較神器的就是可以只有鍵,沒(méi)有值,這樣的意思就是只是創(chuàng)建空的鍵,不放值。如果這個(gè)鍵存在,不做任何事情,返回0;不存在的話就創(chuàng)建,并返回1。這個(gè)命令的時(shí)間復(fù)雜度為O(1),命令例子:
redis> PFADD ?ip:20160929 ?"1.1.1.1" ?"2.2.2.2" ?"3.3.3.3"
(integer) 1
redis> PFADD ?ip:20160929 "2.2.2.2" ?"4.4.4.4" ?"5.5.5.5" ?# 存在就只加新的
(integer) 1
redis> PFCOUNT ?ip:20160929 ?# 元素估計(jì)數(shù)量沒(méi)有變化
(integer) 5
redis> PFADD ?ip:20160929 "2.2.2.2" ?# 存在就不會(huì)增加
(integer) 0
PFCOUNT
????????其實(shí)在上面的學(xué)習(xí)中我們已經(jīng)用過(guò)這個(gè)了,這里再來(lái)介紹下。當(dāng)命令作用于單個(gè)鍵的時(shí)候,返回這個(gè)鍵的基數(shù)估算值。如果鍵不存在,則返回0。當(dāng)作用于多個(gè)鍵的時(shí)候,返回這些鍵的并集估算值。類似于把這些鍵都合并了之后,在調(diào)用這個(gè)命令輸出。這個(gè)命令在作用于單個(gè)值的時(shí)候,時(shí)間復(fù)雜度為O(1),并且具有非常低的平均常數(shù)時(shí)間;在作用于N個(gè)值的時(shí)候,時(shí)間復(fù)雜度為O(N),這個(gè)命令的常數(shù)復(fù)雜度會(huì)比較低些。命令例子:
redis> PFADD ?ip:20160929 ?"1.1.1.1" ?"2.2.2.2" ?"3.3.3.3"
(integer) 1
redis> PFCOUNT ?ip:20160929
(integer) 3
redis> PFADD ?ip:20160928 ?"1.1.1.1" ?"4.4.4.4" ?"5.5.5.5"
(integer) 1
redis> PFCOUNT ?ip:20160928 ?ip:20160929
(integer) 5
PFMERGE
???????合并(merge)多個(gè)HyperLogLog為一個(gè)HyperLogLog。其實(shí)這個(gè)也很好理解,而合并后的估算基數(shù)也近似于所有HyperLogLog估算基數(shù)的并集。這個(gè)命令的第一個(gè)參數(shù)為目標(biāo)鍵,剩下的參數(shù)為要合并的HyperLogLog。命令執(zhí)行時(shí),如果目標(biāo)鍵不存在,則創(chuàng)建后再執(zhí)行合并。這個(gè)命令的時(shí)間復(fù)雜度為O(N),其中N為要合并的HyperLogLog的個(gè)數(shù)。不過(guò)這個(gè)命令的常數(shù)時(shí)間復(fù)雜度比較高。命令例子:
redis> PFADD ?ip:20160929 ?"1.1.1.1" ?"2.2.2.2" ?"3.3.3.3"
(integer) 1
redis> PFADD ?ip:20160928 ?"1.1.1.1" ?"4.4.4.4" ?"5.5.5.5"
(integer) 1
redis> PFMERGE ip:201609 ? ip:20160928 ? ip:20160929
OK
redis> PFCOUNT ?ip:201609
(integer) 5
總結(jié)
以上是生活随笔為你收集整理的Redis基数统计之HyperLogLog小内存大用处的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 搭建人人开源后台管理平台
- 下一篇: 强化学习之DQN(附莫烦代码)