1

常用方法三种

一、set集合(精准、耗费空间)

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

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命令:

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了!

二、bitMap(精准、空间损耗一般)

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

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就能查出来用户数:

127.0.0.1:6379> bitcount login_2019_06_17
(integer) 4

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

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

三、hyperLogLog(有误差,省空间)

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

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

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

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

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%左右,但是对于统计用户数这种场景来说足够了。

本文非原创,原文地址:https://mp.weixin.qq.com/s/t0...
另外,附上HyperLogLog原理文章:
https://www.jianshu.com/p/096...

原理我也没摸透,回头有兴趣再来研究。
我的理念是:先!用!在!说!
任何技术问题,在不能很快理解原理的时候,那么先用。会用了,回头再来学原理快很多。程序有时间复杂度空间复杂度,我们的职业生涯同样也有,看大家怎么去定位


Jtoman
24 声望3 粉丝