HyperLogLog
- 采用基数算法实现,它设有 16384 个桶进行独立计数,也就是 2 的 14 次方,每个桶占 6 位,1字节等于8位,所以2 的 14 次方乘以 6 再除以 8,就等于 12k 字节了。它根据输入元素来计算基数,而不是存储元素本身。
- 占用空间小,无论统计多少个数据,最多占用12K的内存。(redis 设有 16384个桶,每个桶里的数据最多需要6位进行存储,16384 x 6 / 8 约等于 12k 字节)
- 它统计值时存在误差,标准误差为0.81%
- 缺点:HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样返回输入的各个元素。
HyperLogLog 使用场景(UV:网站的独立访客)
- 根据用户的IP来统计访问量,需要去重,同一个用户一天之内的多次访问请求只能计数一次,所以每个网页请求都需要带上用户的ID,无论是登录用户还是未登录的游客,都需要一个唯一ID来标识。
- 最开始容易想到的是为每一个页面设置一个独立的 set 集合来存储当天访问该页面的所有用户ID,但如果页面访问量非常大,比如几千万的 UV,这样 set 集合就会非常大,浪费了空间,而且对于这个 UV 值,一般情况下并不需要多么的精确,比如 100 万和 101 万,对于这个场景,并没什么大的区别。所以想到了采用 redis 的 HyperLogLog 数据结构来实现。
- HyperLogLog 提供不精确的去重计数方案,标准误差为 0.81%,这个精确度已经可以满足 UV 的统计需求了,而且占用的内存不超过12k。
Bitmap 位图(DAU:日活跃用户)
- 位图不是特殊的数据结构,它其实就是普通的字符串,也就是 byte 数组,用 getbit 和 setbit 来操作,能够统计精确的值。
- 可以用于布尔型数据的存取,比如用户一年的签到记录,签到了是1,没签到是0,记录365天,通过 bitcount 指令来统计用户一共签到了多少天,每个签到记录只占用一位,365位大约是46个字节大小,用户上亿时,大大节约了内存空间。
- Redis 的位数组是自动扩展,如果设置了某个偏移位置超出了现有的内容范围,就会自
动将位数组进行零扩充。(也就是进行扩充,初始值为0)