Redis做活跃用户统计利器之HyperLoglog

网站经常有这样的需求:统计日活用户数,有哪些实现方式呢?

使用#

1、用redis的set集合。

用户登录以后,把用户id添加到redis的set中,set会自动进行去重,类似于这样:

Copy Highlighter-hljs
127.0.0.1:6379> sadd users_2019_06_17 user1 (integer) 1 127.0.0.1:6379> sadd users_2019_06_17 user2 (integer) 1 127.0.0.1:6379> sadd users_2019_06_17 user3 (integer) 1

很显然,只需要一条scard命令:

Copy Highlighter-hljs
127.0.0.1:6379> scard users_2019_06_17 (integer) 3

可以看出来,2019年6月17号的用户数是3个。

很简单,但是集合只适用于用户数比较少的场合,假如用户有100万,set存储100万个id号,如果一个id号占32个字节,总共就是差不多32M,一个月就是960M 差不多一个G了!

2、用Bitmap。

我们存放100万个id号需要100万个bit位,也就是100万/8 = 125K字节,直接用以id号和100万取余,余数作为bit的索引:

Copy Highlighter-hljs
127.0.0.1:6379> setbit login_2019_06_17  10000 1 (integer) 0 127.0.0.1:6379> setbit login_2019_06_17 1024 1 (integer) 0 127.0.0.1:6379> setbit login_2019_06_17 238 1 (integer) 0 127.0.0.1:6379> setbit login_2019_06_17 3434 1 (integer) 0

这时候同样,只要一条bitcount就能查出来用户数:

Copy Highlighter-hljs
127.0.0.1:6379> bitcount login_2019_06_17 (integer) 4

此时存储100万个用户,只需要125K个字节,一个月才4M。

还有没有占存储空间更少的办法?

3、用redis的HyperLogLog

Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

原理很复杂就不说了,只说下用法:

Copy Highlighter-hljs
127.0.0.1:6379> pfadd login.2019_06_17 user1 (integer) 1 127.0.0.1:6379> pfadd login.2019_06_17 user2 (integer) 1 127.0.0.1:6379> pfadd login.2019_06_17 user3 (integer) 1 127.0.0.1:6379> pfadd login.2019_06_17 user4 (integer) 1 127.0.0.1:6379> pfcount login.2019_06_17 (integer) 4

此时存储100万个独立用户只需要15K左右,一个月才480K左右!

需要注意的是HyperLogLog的统计结果并不是一个精确的值,误差在0.81%左右,但是对于统计用户数这种场景来说足够了。

总结#

三种方式:
1)、使用Redis的set集合
2)、使用Bitmap
3)、使用HyperLogLog(推荐)

posted @   caibaotimes  阅读(117)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
历史上的今天:
2021-01-06 dcat-admin
2021-01-06 在Laravel外独立使用Eloquent
点击右上角即可分享
微信分享提示
CONTENTS