自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何用Redis統(tǒng)計(jì)海量UV?

存儲(chǔ) 存儲(chǔ)軟件 Redis
我們先思考一個(gè)常見的業(yè)務(wù)問題:如果你負(fù)責(zé)開發(fā)維護(hù)一個(gè)大型的網(wǎng)站,有一天老板找產(chǎn)品經(jīng)理要網(wǎng)站每個(gè)網(wǎng)頁(yè)每天的 UV 數(shù)據(jù),然后讓你來(lái)開發(fā)這個(gè)統(tǒng)計(jì)模塊,你會(huì)如何實(shí)現(xiàn)?

[[416080]]

前言

我們先思考一個(gè)常見的業(yè)務(wù)問題:如果你負(fù)責(zé)開發(fā)維護(hù)一個(gè)大型的網(wǎng)站,有一天老板找產(chǎn)品經(jīng)理要網(wǎng)站每個(gè)網(wǎng)頁(yè)每天的 UV 數(shù)據(jù),然后讓你來(lái)開發(fā)這個(gè)統(tǒng)計(jì)模塊,你會(huì)如何實(shí)現(xiàn)?

統(tǒng)計(jì)uv的常用方法以及優(yōu)缺點(diǎn)

其實(shí)要是單純的統(tǒng)計(jì)pv是比較好辦的,直接用redis的incr就行,但是uv的話,它要去重,同一個(gè)用戶一天之內(nèi)的多次訪問請(qǐng)求只能計(jì)數(shù)一次。這就要求每一個(gè)網(wǎng)頁(yè)請(qǐng)求都需要帶上用戶的 ID,無(wú)論是登陸用戶還是未登陸用戶都需要一個(gè)唯一 ID 來(lái)標(biāo)識(shí)。

set

比較容易想到的是為每一個(gè)頁(yè)面一個(gè)獨(dú)立的 set 集合來(lái)存儲(chǔ)所有當(dāng)天訪問過(guò)此頁(yè)面的用戶 ID。當(dāng)一個(gè)請(qǐng)求過(guò)來(lái)時(shí),我們使用 sadd 將用戶 ID 塞進(jìn)去就可以了。通過(guò) scard 可以取出這個(gè)集合的大小,這個(gè)數(shù)字就是這個(gè)頁(yè)面的 UV 數(shù)據(jù)。沒錯(cuò),這是一個(gè)非常簡(jiǎn)單的方案。

但是,如果你的頁(yè)面訪問量非常大,比如一個(gè)爆款頁(yè)面幾千萬(wàn)的 UV,你需要一個(gè)很大的 set 集合來(lái)統(tǒng)計(jì),這就非常浪費(fèi)空間。如果這樣的頁(yè)面很多,那所需要的存儲(chǔ)空間是驚人的。

hash

hash和set在處理uv的問題上其實(shí)類似,把用戶id作為hash的key的確可以去重,但是如果訪問量大了之后也會(huì)消耗很大的內(nèi)存空間

bitmap

bitmap同樣是一種可以統(tǒng)計(jì)基數(shù)的方法,可以理解為用bit數(shù)組存儲(chǔ)元素,例如01101001,表示的是[1,2,4,8],bitmap中1的個(gè)數(shù)就是基數(shù)。bitmap也可以輕松合并多個(gè)集合,只需要將多個(gè)數(shù)組進(jìn)行異或操作就可以了。bitmap相比于Set,Hash也大大節(jié)省了內(nèi)存,我們來(lái)粗略計(jì)算一下,統(tǒng)計(jì)1億個(gè)數(shù)據(jù)的基數(shù),需要的內(nèi)存是:100000000/8/1024/1024 ≈ 12M。

雖然bitmap在節(jié)省空間方面已經(jīng)有了不錯(cuò)的表現(xiàn),但是如果需要統(tǒng)計(jì)1000個(gè)對(duì)象,就需要大約12G的內(nèi)存,顯然這個(gè)結(jié)果仍然不能令我們滿意。在這種情況下,HyperLogLog將會(huì)出來(lái)拯救我們。

HyperLogLog

這就是本節(jié)要引入的一個(gè)解決方案,Redis 提供了 HyperLogLog 數(shù)據(jù)結(jié)構(gòu)就是用來(lái)解決這種統(tǒng)計(jì)問題的。HyperLogLog 提供不精確的去重計(jì)數(shù)方案,雖然不精確但是也不是非常不精確,標(biāo)準(zhǔn)誤差是 0.81%,這樣的精確度已經(jīng)可以滿足上面的 UV 統(tǒng)計(jì)需求了。

HyperLogLog 數(shù)據(jù)結(jié)構(gòu)是 Redis 的高級(jí)數(shù)據(jù)結(jié)構(gòu),它非常有用,但是令人感到意外的是,使用過(guò)它的人非常少。

使用方法

Redis 的位數(shù)組是自動(dòng)擴(kuò)展,如果設(shè)置了某個(gè)偏移位置超出了現(xiàn)有的內(nèi)容范圍,就會(huì)自動(dòng)將位數(shù)組進(jìn)行零擴(kuò)充。

命令

HyperLogLog 提供了兩個(gè)指令 pfadd 和 pfcount,根據(jù)字面意義很好理解,一個(gè)是增加計(jì)數(shù),一個(gè)是獲取計(jì)數(shù)。

具體實(shí)現(xiàn)

pfadd 用法和 set 集合的 sadd 是一樣的,來(lái)一個(gè)用戶 ID,就將用戶 ID 塞進(jìn)去就是。pfcount 和 scard 用法是一樣的,直接獲取計(jì)數(shù)值。關(guān)鍵是它非常省空間,載統(tǒng)計(jì)海量uv的時(shí)候,只占用了12k的空間

  1. 127.0.0.1:6379> pfadd codehole user1 
  2. (integer) 1 
  3. 127.0.0.1:6379> pfcount codehole 
  4. (integer) 1 
  5. 127.0.0.1:6379> pfadd codehole user2 
  6. (integer) 1 
  7. 127.0.0.1:6379> pfcount codehole 
  8. (integer) 2 
  9. 127.0.0.1:6379> pfadd codehole user3 
  10. (integer) 1 
  11. 127.0.0.1:6379> pfcount codehole 
  12. (integer) 3 
  13. 127.0.0.1:6379> pfadd codehole user4 
  14. (integer) 1 
  15. 127.0.0.1:6379> pfcount codehole 
  16. (integer) 4 
  17. 127.0.0.1:6379> pfadd codehole user5 
  18. (integer) 1 
  19. 127.0.0.1:6379> pfcount codehole 
  20. (integer) 5 
  21. 127.0.0.1:6379> pfadd codehole user6 
  22. (integer) 1 
  23. 127.0.0.1:6379> pfcount codehole 
  24. (integer) 6 
  25. 127.0.0.1:6379> pfadd codehole user7 user8 user9 user10 
  26. (integer) 1 
  27. 127.0.0.1:6379> pfcount codehole 
  28. (integer) 10 

簡(jiǎn)單試了一下,發(fā)現(xiàn)還蠻精確的,一個(gè)沒多也一個(gè)沒少。接下來(lái)我們使用腳本,往里面灌更多的數(shù)據(jù),看看它是否還可以繼續(xù)精確下去,如果不能精確,差距有多大。

我們將數(shù)據(jù)增加到 10w 個(gè),看看總量差距有多大。

  1. public class JedisTest { 
  2.   public static void main(String[] args) { 
  3.     Jedis jedis = new Jedis(); 
  4.     for (int i = 0; i < 100000; i++) { 
  5.       jedis.pfadd("codehole""user" + i); 
  6.     } 
  7.     long total = jedis.pfcount("codehole"); 
  8.     System.out.printf("%d %d\n", 100000, total); 
  9.     jedis.close(); 
  10.   } 

跑了約半分鐘,我們看輸出:

  1. > python pftest.py 
  2. 100000 99723 

差了 277 個(gè),按百分比是 0.277%,對(duì)于上面的 UV 統(tǒng)計(jì)需求來(lái)說(shuō),誤差率也不算高。然后我們把上面的腳本再跑一邊,也就相當(dāng)于將數(shù)據(jù)重復(fù)加入一邊,查看輸出,可以發(fā)現(xiàn),pfcount 的結(jié)果沒有任何改變,還是 99723,說(shuō)明它確實(shí)具備去重功能。

責(zé)任編輯:武曉燕 來(lái)源: 程序員小飯
相關(guān)推薦

2025-03-05 08:40:00

RedisJava開發(fā)

2019-12-06 15:20:58

Redis獨(dú)立用戶數(shù)據(jù)庫(kù)

2019-10-17 09:25:56

Spark StreaPVUV

2019-08-01 15:08:37

PythonLine操作系統(tǒng)

2021-05-24 08:58:34

Redis Bitmap 數(shù)據(jù)統(tǒng)計(jì)

2015-07-06 13:36:14

Redis微博關(guān)注關(guān)系

2009-03-24 13:04:55

匯總組織結(jié)構(gòu)Oracle

2024-06-11 10:03:56

2021-03-17 08:11:21

SQL工作日數(shù)據(jù)

2019-09-11 10:23:58

Redis性能存儲(chǔ)

2024-10-06 12:50:25

2015-04-22 14:41:04

云遷移Redis緩存數(shù)據(jù)模型調(diào)整

2023-03-20 07:27:43

2021-03-22 11:10:09

Redis架構(gòu)MQ

2024-10-05 16:00:00

谷歌開源模型

2021-08-04 17:55:38

keysRedis數(shù)據(jù)庫(kù)

2022-08-11 18:27:50

面試Redis分布式鎖

2019-11-26 11:19:40

統(tǒng)計(jì)數(shù)據(jù)互聯(lián)網(wǎng)

2024-03-27 07:55:58

SpringRedis海量

2024-09-03 13:22:33

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)