Redis統(tǒng)計(jì)訪問量的3種實(shí)現(xiàn)方式
一、你是否遇到過這些統(tǒng)計(jì)難題?
- 高并發(fā)場景下內(nèi)存爆炸:用Hash統(tǒng)計(jì)日活時(shí),單鍵內(nèi)存占用飆升到10MB?
- 獨(dú)立訪客重復(fù)計(jì)數(shù):用戶多次訪問被重復(fù)統(tǒng)計(jì),導(dǎo)致UV數(shù)據(jù)虛高?
- 近似值誤差過大:百萬級PV統(tǒng)計(jì)時(shí),誤差率超過5%?
這些問題,Redis的3種核心方案能幫你解決!
二、方案一:Hash結(jié)構(gòu)實(shí)時(shí)統(tǒng)計(jì)
適用場景:
- 實(shí)時(shí)統(tǒng)計(jì)獨(dú)立用戶(如日活/周活)
- 需要精確計(jì)數(shù)(如商品點(diǎn)擊次數(shù))
核心代碼:
# 場景:記錄用戶訪問時(shí)間戳(防重復(fù)計(jì)數(shù)) pipeline.hset("user:visits:202310", user_id, time.time()) pipeline.expire("user:visits:202310", 86400) # 每天清理一次 # 統(tǒng)計(jì)當(dāng)前活躍用戶數(shù) current_uv = redis.hlen("user:visits:202310")
參數(shù)說明:
hset
:哈希表存儲用戶ID和最后訪問時(shí)間expire
:自動(dòng)清理過期數(shù)據(jù),避免內(nèi)存泄漏- 痛點(diǎn)解決:通過時(shí)間戳去重,精確統(tǒng)計(jì)獨(dú)立用戶
內(nèi)存優(yōu)化技巧:
- 問題:10萬用戶ID存儲需約
100KB * 10^5 = 10GB
- 方案:使用
user_id:md5
縮短鍵名,內(nèi)存占用可降低至**<1MB/萬用戶**
三、方案二:BitMap統(tǒng)計(jì)獨(dú)立訪客
適用場景:
- 億級用戶規(guī)模的UV統(tǒng)計(jì)
- 內(nèi)存敏感場景(如單機(jī)統(tǒng)計(jì)全站訪問量)
核心代碼:
# 場景:統(tǒng)計(jì)本月訪問過的用戶(假設(shè)用戶ID為整數(shù)) user_id = 123456 redis.setbit("uv:202310", user_id, 1) # 獲取本月UV總數(shù) total_uv = redis.bitcount("uv:202310")
參數(shù)說明:
setbit
:將用戶ID對應(yīng)位設(shè)為1,每個(gè)用戶僅占1bit內(nèi)存bitcount
:統(tǒng)計(jì)所有置位位數(shù),時(shí)間復(fù)雜度O(1)
內(nèi)存對比:
方法 | 100萬用戶內(nèi)存占用 | 精度 |
---|---|---|
Hash | ~100MB | 100% |
BitMap | ~125KB | 100% |
四、方案三:HyperLogLog估算UV
適用場景:
- 超大規(guī)模近似統(tǒng)計(jì)(如全網(wǎng)日活)
- 可接受誤差的場景(誤差率<0.8%)
核心代碼:
# 場景:統(tǒng)計(jì)全站日活(誤差率0.5%) redis.pfadd("uv:202310", user_id) estimated_uv = redis.pfcount("uv:202310")
參數(shù)說明:
pfadd
:將用戶ID加入HyperLogLog結(jié)構(gòu)pfcount
:返回近似值,內(nèi)存占用僅<1KB/百萬用戶
性能對比:
方法 | 1000萬用戶內(nèi)存 | 統(tǒng)計(jì)誤差 |
---|---|---|
BitMap | 1.25MB | 0% |
HyperLogLog | <1KB | 0.5% |
五、實(shí)戰(zhàn)選擇指南
對比表格:
方案 | 內(nèi)存占用 | 精度 | 適用場景 |
---|---|---|---|
Hash | 中(MB級) | 100% | 小規(guī)模精確統(tǒng)計(jì) |
BitMap | 極低(KB級) | 100% | 大規(guī)模精確去重 |
HyperLogLog | 超低(KB級) | <1% | 超大規(guī)模近似統(tǒng)計(jì) |
優(yōu)化建議:
- 混合方案:用Hash統(tǒng)計(jì)小時(shí)級數(shù)據(jù),用HyperLogLog匯總?cè)占墧?shù)據(jù)
- 數(shù)據(jù)分片:對億級用戶ID按user_id % N分片存儲,降低單鍵內(nèi)存壓力
- 冷熱分離:歷史數(shù)據(jù)定期轉(zhuǎn)儲到MySQL,Redis僅保留活躍數(shù)據(jù)
六、總結(jié)
Redis統(tǒng)計(jì)訪問量的本質(zhì)是內(nèi)存優(yōu)化+算法選型的平衡。
- 痛點(diǎn)場景:用BitMap解決內(nèi)存爆炸,用HyperLogLog應(yīng)對超大規(guī)模
- 實(shí)時(shí)需求:Hash結(jié)構(gòu)仍是精確統(tǒng)計(jì)的首選
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Redis Template實(shí)現(xiàn)分布式鎖的實(shí)例代碼
使用Redis的SETNX命令獲取分布式鎖的步驟,接下來通過本文給大家介紹Redis Template實(shí)現(xiàn)分布式鎖的實(shí)例代碼,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-09-09Redis鍵值設(shè)計(jì)的具體實(shí)現(xiàn)
本文主要介紹了Redis鍵值設(shè)計(jì)的具體實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-06-06CentOS7.5使用mysql_multi方式安裝MySQL5.7.28多實(shí)例(詳解)
這篇文章主要介紹了CentOS7.5使用mysql_multi方式安裝MySQL5.7.28多實(shí)例,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01分布式利器redis及redisson的延遲隊(duì)列實(shí)踐
這篇文章為大家主要介紹了分布式利器redis及redisson的延遲隊(duì)列實(shí)踐,搜遍全網(wǎng)好像還沒有使用redisson的延遲隊(duì)列的,redisson作為一個(gè)分布式利器,這么好用的工具沒人用有點(diǎn)可惜2022-03-03redis?zset實(shí)現(xiàn)滑動(dòng)窗口限流的代碼
這篇文章主要介紹了redis?zset實(shí)現(xiàn)滑動(dòng)窗口限流,滑動(dòng)窗口算法思想就是記錄一個(gè)滑動(dòng)的時(shí)間窗口內(nèi)的操作次數(shù),操作次數(shù)超過閾值則進(jìn)行限流,本文通過實(shí)例代碼給大家詳細(xì)介紹,需要的朋友參考下吧2022-03-03