Redis系列(四)--HyperLogLong入門實戰和詳解

1、使用場景redis

使用場景:算法

    統計網頁訪問量。spring

思考:怎麼樣統計網頁訪問量,而且一個IP一天訪問屢次同一個頁面,只能算一次?數據結構

分析:1.首先分析該統計數,是否須要正確,其實產品只須要一個大概的,一天100W,和一天110W,其實差很少。若是使用Java的話,那個list能夠去重,同時在內存等相關上要佔很小的比率。函數

解決方式:工具

方式一:傳統方式,集合實現。優化

使用集合(set)來儲存每一個訪客的 IP ,經過集合性質(集合中的每一個元素都各不相同)來獲得多個獨立 IP .可是缺點也很大,假如訪問量很大,你須要一個很大的 set 集合來統計,這就很是浪費空間。若是這樣的頁面不少,那所須要的存儲空間是驚人的。爲這樣一個去重功能就耗費這樣多的存儲空間,值得麼?spa

        使用字符串來儲存每一個 IPv4 地址最多須要耗費 15 字節(格式爲 'XXX.XXX.XXX.XXX' ,好比'192.168.10.127')。code

下表給出了使用集合記錄不一樣數量的獨立 IP 時,須要耗費的內存數量:ip

獨立 IP 數量一天一個月一年

一百萬15 MB 450 MB 5.4 GB

一千萬150 MB 4.5 GB 54 GB

一億1.5 GB 45 GB 540 GB

隨着集合記錄的 IP 愈來愈多,消耗的內存也會愈來愈多。

另外若是要儲存 IPv6 地址的話,須要的內存還會更多一些

 

方式二:redis 2.8.6 版本以後,新的命令功能,HyperLogLong。

Redis 提供了 HyperLogLog 數據結構就是用來解決這種統計問題的。HyperLogLog 提供不精確的去重計數方案,雖然不精確可是也不是很是不精確,標準偏差是 0.81%,這樣的精確度已經能夠知足上面的 UV 統計需求了。

2、概念和實戰

        Redis HyperLogLog 是用來作基數統計的算法,HyperLogLog 的優勢是,在輸入元素的數量或者體積很是很是大時,計算基數所需的空間老是固定 的、而且是很小的。

在 Redis 裏面,每一個 HyperLogLog 鍵只須要花費 12 KB 內存(由於 Redis 對 HyperLogLog 的存儲進行了優化,在計數比較小時,它的存儲空間採用稀疏矩陣存儲,空間佔用很小,僅僅在計數慢慢變大,稀疏矩陣佔用空間漸漸超過了閾值時纔會一次性轉變成稠密矩陣,纔會佔用 12k 的空間。),就能夠計算接近 2^64 個不一樣元素的基 數。這和計算基數時,元素越多耗費內存就越多的集合造成鮮明對比。

可是,由於 HyperLogLog 只會根據輸入元素來計算基數,而不會儲存輸入元素自己,因此 HyperLogLog 不能像集合那樣,返回輸入的各個元素。

        1.使用命令模式

pfadd test:aaron:ip "191.168.1.23"pfadd test:aaron:ip "191.168.1.24"#結果爲2pfcount test:aaron:ip

        2.py代碼





import redis#redis 鏈接pool = redis.ConnectionPool(host='127.0.0.1', port=6379)r = redis.Redis(connection_pool=pool)#HyperLogLogdef her_log():for i in range(100000):r.pfadd("test:log:aaron", "user%d" % i)print (100000, r.pfcount("test:log:aaron"))#主函數,執行行數if __name__ == '__main__':her_log()

        3.Java代碼






package com.example.redis.zfr.demoredis.bit;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.connection.RedisStringCommands;import org.springframework.data.redis.core.RedisCallback;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.stereotype.Component;/*** @author 繁榮Aaron* redis工具類*/@Componentpublic class RedisUtil {@Autowiredprivate RedisTemplate<Object, Object> redisTemplate;/*** 設置 HyperLogLong 的 key 值* @param key* @param value*/public Long pfadd(String key, String value){return redisTemplate.execute((RedisCallback<Long>) con -> con.pfAdd(key.getBytes(),value.getBytes()));}/*** 獲取HyperLogLong 數量* @param key* @return*/public Long pfCount(String key){return redisTemplate.execute((RedisCallback<Long>) con -> con.pfCount(key.getBytes()));    }}

3、思考

1.pf 的內存佔用爲何是 12k?

解決:Redis 的 HyperLogLog 實現中用到的是 16384 個桶,也就是 2^14,每一個桶的 maxbits 須要 6 個 bits 來存儲,最大能夠表示 maxbits=63,因而總共佔用內存就是2^14 * 6 / 8 = 12k字節。

2.兩個頁面合併訪問量怎麼作?

    可使用pfmerge命令。

    命令:

pfadd test:aaron:ip "191.168.1.23"pfadd test:aaron:ip "191.168.1.24"pfadd test:aaron:ip:merge "191.168.1.24"pfadd test:aaron:ip:merge "191.168.1.23"PFMERGE test:aaron:ip:merge:result test:aaron:ip test:aaron:ip:merge#結果爲2PFCOUNT test:aaron:ip:merge:result

4、總結

HyperLogLog 實現獨立 IP 計算功能:

獨立 IP 數量一天一個月一年一年(使用集合)

一百萬12 KB 360 KB 4.32 MB 5.4 GB

一千萬12 KB 360 KB 4.32 MB 54 GB

一億12 KB 360 KB 4.32 MB 540 GB

下表列出了使用 HyperLogLog 記錄不一樣數量的獨立 IP 時,須要耗費的內存數量:

能夠看到,要統計相同數量的獨立 IP ,HyperLogLog 所需的內存要比集合少得多。

相關文章
相關標籤/搜索