学透 Redis HyperLogLog,看这篇就够了( 二 )

  • notused[3]:这是一个 3 字节的字段,目前保留用于未来的扩展,要求这些字节的值必须为零 。
  • card[8]:这是一个 8 字节的字段,用来存储缓存的基数(基数估计的值) 。
  • egisters[]:这个字段是一个可变长度的字节数组 , 用来存储 HyperLogLog 的数据 。

学透 Redis HyperLogLog,看这篇就够了

文章插图
Redis 对 HyperLogLog 的存储进行了优化 , 在计数比较小的时候,存储空间采用系数矩阵,占用空间很小 。
只有在计数很大 , 稀疏矩阵占用的空间超过了阈值才会转变成稠密矩阵,占用 12KB 空间 。
3、出招实战:网页访问量统计在移动互联网的业务场景中,数据量很大 , 系统需要保存这样的信息:一个 key 关联了一个数据集合,同时对这个数据集合做统计做一个报表给运营人员看 。
比如 。
  • 统计一个 APP 的日活、月活数 。
  • 统计一个页面的每天被多少个不同账户访问量(Unique Visitor,UV) 。
  • 统计用户每天搜索不同词条的个数 。
  • 统计注册 IP 数 。
通常情况下,系统面临的用户数量以及访问量都是巨大的,比如百万、千万级别的用户数量,或者千万级别、甚至亿级别的访问信息,咋办呢?
使用 Set 实现一个用户一天内多次访问一个网站只能算作一次 , 所以很容易就想到通过 Redis 的 Set 集合来实现 。
比如微信昵称叫 “Chaya” 的小姐姐访问【爱一个人总是要掉眼泪的风险】这篇文章时,我把这个微信昵称 “Chaya” 存到 Set 集合中 。
SADD 爱一个人总是要掉眼泪的风险:uv 码哥 Chaya 赵小因 Chaya(integer) 3“Chaya” 多次访问这篇文章,Set 的去重特性保证集合中只有一个记录 。接着 , 通过 SCARD 命令,统计页面 UV 。指令返回这个集合的元素个数(也就是微信昵称个数) 。
SCARD 爱一个人总是要掉眼泪的风险:uv(integer) 3使用 HyperLogLog 实现
?Chaya:“Set 集合虽好,如果文章非常火爆达到千万级别,一个 Set 集合就保存了千万个用户的 ID,页面多了消耗的内存也太大了 。”
不要怕 , 只要思想不滑坡,办法总比困难多 。这些就是典型的基数统计应用场景,基数统计:统计一个集合中不重复元素的个数 。
HyperLogLog 的优点在于它所需的内存并不会因为集合的大小而改变 , 无论集合包含的元素有多少个,HyperLogLog 进行计算所需的内存总是固定的,并且是非常少的 。
每个 HyperLogLog 最多只需要花费 12KB 内存,在标准误差 0.81%的前提下,就可以计算 2 的 64 次方个元素的基数 。
HyperLogLog 使用太简单了 。PFADD、PFCOUNT、PFMERGE三个指令打天下 。
PFADD每访问一次页面,调用 PFADD 指令 将这个用户 ID 添加到 HyperLogLog 中 。如下 一共有三个用户访问了这页面,其中 Chaya 访问了两次,但只算一次 。
PFADD 爱一个人总是要掉眼泪的风险:uv 码哥 Chaya 赵小因 Chaya如果执行命令后 HyperLogLog 估计的近似基数发生变化,PFADD则返回 1 , 否则返回 0 。如果指定的键不存在,该命令会自动创建一个空的 HyperLogLog 结构 。
pfadd 命令并不会一次性分配 12k 内存,而是随着基数的增加而逐渐增加内存分配 。
PFCOUNT接下来 , 通过 PFCOUNT 指令获取文章【爱一个人总是要掉眼泪的风险】的 UV 值,可以看到返回值是 3 ,符合预期 。
> PFCOUNT 爱一个人总是要掉眼泪的风险:uv3PFMERGE 合并统计
?Chaya:“还有一个变态需求,对文章进行标签分类,运营说要把都是情感文章标签的几个页面数据合并统计 。”
其中页面的 UV 访问量也需要合并,那这个时候 PFMERGE 就可以派上用场了 , 也就是同样的用户访问这两个页面则只算做一次 。
如下指令,把爱一个人总是要掉眼泪的风险:uv和爱情是幸福和不委屈:uv 两个 HyperLogLog 集合数据合并到情感分类文章:uv这个集合中 。
PFADD 爱情是幸福和不委屈:uv Chaya 赵小因 幸运草# 合并两个页面 UVPFMERGE 情感分类文章:uv 爱一个人总是要掉眼泪的风险:uv 爱情是幸福和不委屈:uv


推荐阅读