Redis源码中hyperloglog结构的实现原理是什么

Redis源码中hyperloglog结构的实现原理:1、密集存储结构;2、稀疏存储结构;3、存储转换;4、计数缓冲;5、对象头。密集存储结构是指,连续 16384 个 6bit 串成的字符串位图,结构比较简单。

Redis源码中hyperloglog结构的实现原理是什么-Worktile社区

1、密集存储结构

Redis内部使用字符串位图来存储HyperLogLog所有桶的计数值,密集存储的结构非常简单,就是连续 16384 个 6bit 串成的字符串位图。

通过桶的编号,计算他的6bit计算值:offset_bytes代表6bit计数值的起始字节位置偏移,而offset_bits表示起始比特位置偏移,例如idx代表桶的编号且位2,则offset_bytes = (idx*6)/8 = 1 ,offset_bits = (idx * 6)%8 = 4,所有第2个字节的第5位是bucket 2的计数值。需要注意的是字节位序是左边是低位,右边是高位,正好与平时我们接触到的相反。

如offset_bits小于2,那么6bit在一个字节内部,对应代码:

val = buffer[offset_bytes] >> offset_bits  # 向右移位

如果offset_bits大于2,那么就会跨越字节边界,需要两个字节拼接起来,对应代码:

# 低位值
low_val = buffer[offset_bytes] >> offset_bits
# 低位个数
low_bits = 8 - offset_bits
# 拼接,保留低6位
val = (high_val << low_bits | low_val) & 0b111111

2、稀疏存储结构

稀疏存储适用于很多计数值都是零的情况。

当多个连续桶的计数值都是零时,Redis使用一个字节来表示多少个桶的计数值都是零即00xxxxxx,前缀俩个零表示接下来的6bit整数值加1就是零值计数器的数量,比如 00010101表示连续 22 个零值计数器;6bit非常多能表示连续64个零值计数器,如果大于64个,采用来个字节表示即01xxxxxx yyyyyyyy,后面的 14bit 可以表示非常多连续 16384 个零值计数器。

如果连续几个桶的计数值非零,那就使用形如 1vvvvvxx 这样的一个字节来表示。中间 5bit 表示计数值,尾部 2bit 表示连续几个桶。它的意思是连续 (xx +1) 个计数值都是 (vvvvv + 1)。比如 10101011 表示连续 4 个计数值都是 11。注意这两个值都需要加 1,因为任意一个是零都意味着这个计数值为零,那就应该使用零计数值的形式来表示。注意计数值最大只能表示到32,而 HyperLogLog 的密集存储单个计数值用 6bit 表示,最大可以表示到 63。当稀疏存储的某个计数值需要调整到大于 32 时,Redis 就会立即转换 HyperLogLog 的存储结构,将稀疏存储转换成密集存储。

Redis 为了方便表达稀疏存储,它将上面三种字节表示形式分别赋予了一条指令:

  • ZERO:len 单个字节表示 00[len-1],连续非常多64个零计数值
  • VAL:value,len 单个字节表示 1[value-1][len-1],连续 len 个值为 value 的计数值
  • XZERO:len 双字节表示 01[len-1],连续非常多16384个零计数值

3、存储转换

当计数值达到一定程度后,稀疏存储将不可逆一次性转换成密集型存储,但要满足两个条件

  • 任意一个计数值从 32 变成 33,因为VAL指令已经无法容纳,它能表示的计数值最大为 32;
  • 稀疏存储占用的总字节数超过 3000 字节,这个阈值可以通过 hll_sparse_max_bytes 参数进行调整。

4、计数缓冲

计数为啥要增加缓冲:HyperLogLog的总计数值时根据16384个桶计数值进行调和平均后再基于修正因子公示计算出来的,它要遍历所有桶以及还要处理浮点数,这计算相对来说比较大,所以Redis使用一个64bit的字段缓冲这个总计数值,该字段较高如果是1,表示该缓冲已过期,如果是0,那么剩下的63bit就是该缓冲值。

HyperLogLog中任意一个桶的计数值发生变化,都会将计数缓冲设为过期。

5、对象头

对象头要存一些附加的字段,例如总计数缓冲、存储类型等:

struct hllhdr {
    char magic[4];      /* 魔术字符串"HYLL" */
    uint8_t encoding;   /* 存储类型 HLL_DENSE or HLL_SPARSE. */
    uint8_t notused[3]; /* 保留三个字节未来可能会使用 */
    uint8_t card[8];    /* 总计数缓存 */
    uint8_t registers[]; /* 所有桶的计数器 */
};

HyperLogLog整体的内部结构就是对象头加上16384个桶的计数值位图。

不能使用HyperLogLog指令来操作普通字符串,因为内部要检查对象头魔术字符串是否位HYLL。

如果字符串以 “HYLL\x00” 或者 “HYLL\x01” 开头,那么就可以使用 HyperLogLog 的指令:

127.0.0.1:6379> set codehole "HYLL\x01whatmagicthing"
OK
127.0.0.1:6379> get codehole
"HYLL\x01whatmagicthing"
127.0.0.1:6379> pfadd codehole python java golang
(integer) 1

这是因为 HyperLogLog 在执行指令前需要对内容进行格式检查,这个检查就是查看对象头的 magic 魔术字符串是否是 “HYLL” 以及 encoding 字段是否是 HLL_SPARSE=0 或者 HLL_DENSE=1 来判断当前的字符串是否是 HyperLogLog 计数器。如果是密集存储,还需要判断字符串的长度是否恰好等于密集计数器存储的长度:

int isHLLObjectOrReply(client *c, robj *o) {
    ...
    /* Magic should be "HYLL". */
    if (hdr->magic[0] != 'H' || hdr->magic[1] != 'Y' ||
        hdr->magic[2] != 'L' || hdr->magic[3] != 'L') goto invalid;
    if (hdr->encoding > HLL_MAX_ENCODING) goto invalid;
    if (hdr->encoding == HLL_DENSE &&
        stringObjectLen(o) != HLL_DENSE_SIZE) goto invalid;
    return C_OK;
invalid:
    addReplySds(c,
        sdsnew("-WRONGTYPE Key is not a valid "
               "HyperLogLog string value.\r\n"));
    return C_ERR;
}

HyperLogLog 和 字符串的关系就好比 Geo 和 zset 的关系。你也可以使用任意 zset 的指令来访问 Geo 数据结构,因为 Geo 内部存储就是使用了一个纯粹的 zset来记录元素的地理位置。

延伸阅读

HyperLogLog算法

HyperLogLog算法是一种非常巧妙的近似统计大量去重元素数量的算法,它内部维护了16384个桶来记录各自桶的元素数量,当一个元素过来,它会散列到其中一个桶。当元素到来时,通过 hash 算法将这个元素分派到其中的一个小集合存储,同样的元素总是会散列到同样的小集合。这样总的计数就是所有小集合大小的总和。使用这种方式精确计数除了可以增加元素外,还可以减少元素。

一个HyperLogLog实际占用的空间大约是 13684 * 6bit / 8 = 12k 字节。但是在计数比较小的时候,大多数桶的计数值都是零。如果 12k 字节里面太多的字节都是零,那么这个空间是可以适当节约一下的。Redis 在计数值比较小的情况下采用了稀疏存储,稀疏存储的空间占用远远小于 12k 字节。相对于稀疏存储的就是密集存储,密集存储会恒定占用 12k 字节。

文章标题:Redis源码中hyperloglog结构的实现原理是什么,发布者:Z, ZLW,转载请注明出处:https://worktile.com/kb/p/34716

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Z, ZLWZ, ZLW认证作者
上一篇 2023年1月8日 上午5:30
下一篇 2023年1月8日 上午6:18

相关推荐

  • 实现精细化管理的需求管理策略与方法

    需求管理的策略与方法实现精细化管理,包含:1、建立综合性需求框架、2、采纳迭代式需求优化、3、运用数据分析提高预测准确性、4、构建跨部门沟通平台、5、实行动态需求调整制度。通过建立综合性需求框架,可以将各个需求及其优先级进行结构化排序,并确保管理过程的透明度和连贯性。 在实现精细化管理的过程中,确立…

    2023年12月18日
    31500
  • 项目管理台账有哪些

    项目管理台账主要包括1、项目概览表、2、进度计划表、3、成本跟踪表、4、风险登记册、5、问题跟踪表、6、变更控制表、7、资源分配表、8、沟通档案表、9、署主要成果表。特别要说明的是,项目概览表为项目管理中的基石,其为所有相关人员提供项目的高层次信息,如项目名称、项目经理、起止日期、重要里程碑、项目目…

    2024年1月8日
    72600
  • DevOps在不同行业中的应用

    DevOps作为软件开发与IT运维的一套实践,已在多个行业中被广泛采纳以优化生产流程和效率。在金融服务行业,DevOps通过提升投放速度、确保合规性来强化服务质量;在电子商务领域,实现快速迭代、处理高交易量确保平台稳定性;在制造业中,DevOps通过整合物联网(IoT)设施、优化供应链来提升智能制造…

    2023年12月13日
    30300
  • 项目部如何管理资金账户

    资金账户管理对项目部来说至关重要,因为它直接关系到项目的财务健康和运行效率。项目部管理资金账户的核心方式包括:设立专用账户、严格财务审计、合理编制预算、及时结算账目以及强化流动资金管理。贯彻这些管理原则有助于确保项目资金的合规使用、风险控制和资金效率。 设立专用账户是保障项目资金独立性和专项性的前提…

    2024年4月10日
    5100
  • 职场数据分析需要什么工具

    职场数据分析主要需要以下工具:1、Excel或者Google表格;2、Python或者R;3、Tableau或者PowerBI;4、SQL;5、Hadoop或者Spark;6、Jupyter Notebook。其中,Excel或者Google表格是进行初步数据整理和基础分析的工具。 1、Excel或…

    2023年7月18日
    33000
  • ChatGPT-4.0对企业客户服务有哪些具体应用

    ChatGPT-4.0在企业客户服务中具备多样化的应用,能够极大程度优化客户体验。主体应用包括:1、即时客户咨询回复;2、智能客服系统集成;3、个性化推荐引擎构建;4、自然语言处理能力强化数据分析;5、客户反馈自动收集与分析;6、多语种支持提升国际服务能力。通过这些核心应用的详细解析,可以了解Cha…

    2023年11月29日
    45100
  • 工作管理app哪个好用

    好用的工作管理app有:一、Worktile;二、PingCode;三、ClickUp;四、简道云;五、Todoist;六、Any.do;七、Things-Mac;八、Tower。Worktile是国内的一款通用型的任务管理、计划管理软件。 一、Worktile 1、简介 Worktile是国内的一…

    2023年4月9日
    1.1K00
  • 项目库如何登陆设备管理器

    项目库中登录设备管理器的核心方式包括具备管理员权限、安装必要驱动程序、通过网络进行远程访问、以及使用专业的设备管理软件。一般来说,项目库是指存储项目信息、配置和相关数据的数据库或文件库,而设备管理器通常是指操作系统中用于查看和管理硬件设备的组件。要登录到设备管理器并管理项目库中的设备,首先需要确保有…

    2024年4月11日
    3900
  • bi商业智能是做什么的

    bi商业智能(Business Intelligence),又称商业智慧或商务智能,指用现代数据仓库技术、线上分析处理技术、数据挖掘和数据展现技术进行数据分析以实现商业价值。bi商业智能的核心功能:1、数据采集;2、ETL和数据建模;3、数据可视化;4、报告分析。 一、bi商业智能概念 商业智能(B…

    2023年3月17日
    40000
  • 项目管理的信息系统有哪些

    项目管理的信息系统有:一、PingCode;二、Worktile;三、Asana;四、Trello;五、Wrike。PingCode是国内软件研发项目管理软件。功能以及解决的问题有:能够支持看板、敏捷等多种项目的管理;管理团队目标,监控单/多项目的进度、管理计划分配资源。 一、PingCode Pi…

    2023年4月27日
    69300

发表回复

登录后才能评论
注册PingCode 在线客服
站长微信
站长微信
电话联系

400-800-1024

工作日9:30-21:00在线

分享本页
返回顶部