作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!


正文

VictoriaMetrics中使用uint64类型来表示一个MetricID,且MetricID是递增的。

因此有这些一些需求:

  1. 需要缓存某一类metricID的集合,例如某个MetricQL的查询结果对应很多个MetricID;
  2. 需要对多个metricID的集合取交集和并集等操作。

并且:

  • 占用的内存要尽可能的小
  • 要避免大量的小对象,否则会对GC造成很大压力
  • 插入、检查是否存在某个ID、并集计算、交集计算等要尽可能的快

VictoriaMetrics-1.72.0-cluster/lib/uint64set/uint64set.go 这里的代码很好的满足了上述需求。

下面我来分析它的实现原理。

1.结构

  • 整个uint64按位分成多个部分,每个部分分别采用各自的插入和查找策略。相当于分级存储。
  • 高32位先建一个桶
    • 桶的个数动态增加
    • metricID是递增的,因此在这样的业务场景下,高32位通常是0
  • 高16位再建一个存储桶,这里的策略与上面相似。
    • 桶的个数动态的增加
    • 通常桶内的值是顺序增加的,插入过程只能顺序查找
    • 在做集合计算的阶段,可以先对桶排序。
  • 低16位的处理稍稍复杂一些:
    • 当元素个数在56个以内时,直接在一个uint16的数组里顺序追加和顺序搜索
    • 当元素超过56个时,建立一个1024个元素的数组,数组的元素是uint64类型
    • uint64类型一共64个位,用每个位来代表0-63的某个值。相比用64个uint8来存储,空间节省了8倍。

2.插入过程

  • 先确定高32位的分桶(如果没有就新增这个分桶)
  • 在32位的分桶上,再确定高16位的分桶(如果没有就新增这个分桶)
  • 在16位的分桶上,检查是否在56个元素以内
    • 56个元素以内,直接在[]uint8数组上追加
    • 超过56个元素,创建1024个元素的uint64数组,并把56个元素添加进去
  • 16位的分桶上,通过前10位值作为下标,确定uint64数组的位置
  • 把低6位的值,转换为一个uint64上的mask(值为N就把第N位置1),然后与上一步确定的uint64取bit or运算

3.查找过程

  • 先确定高32位的分桶
  • 再确定高16位的分桶
  • 如果不存在1024个元素的分桶,就在56个元素的数组里面顺序查找
  • 如果存在1024个元素的分桶,根据高10位获得下标
  • 根据低6位,看uint64中对应的位是否是1

4.交集运算过程

  • 先对a,b两个集合的32位分桶进行排序
  • 依次偏移a,b两个集合32位分桶的下标,直到分桶值对齐
    • 通过分桶的匹配,可以快速淘汰大量的值
  • 32位分桶的值相等后,继续比较高16位的分桶。比较方法与上面相同。
  • 低16位的值,比较1024个元素的数组。两个uint64做bit and运算,即可完成取交集。

5.总结

  1. uint64set类,首先考虑了业务场景。在绝大多数高32位都相同的大量数据的情况下,能够取得很好的效果。
  • 相反:如果是大量随机的uint64值,这里的方法不见得会更好
  1. 相比map而言,插入和查找做不到O(1)的性能,但是分段查找也不会太差
  2. 相比map而言,内存上的好处非常多:
  • 数据的扩容方便且快速,map可能需要多次扩容+rehash才行
  • 更加节约内存
  • 对GC的压力很小
  1. 对并集、交集等集合操作,分桶能够快速避开不合适的数据的比较,性能极高。

如果想看具体的源码的注释,请移步我上传的VM注释版的源码

希望对你有用,have fun

【VictoriaMetrics源码阅读】vm中仿照RoaringBitmap的实现:uint64set的更多相关文章

  1. JDK源码阅读-DirectByteBuffer

    本文转载自JDK源码阅读-DirectByteBuffer 导语 在文章JDK源码阅读-ByteBuffer中,我们学习了ByteBuffer的设计.但是他是一个抽象类,真正的实现分为两类:HeapB ...

  2. boost.asio源码阅读(2) - task_io_service

    1.0 task_io_service 在boost.asio源码阅读(1)中,代码已经查看到task_io_service中. 具体的操作调用void task_io_service::init_t ...

  3. 源码阅读笔记 - 1 MSVC2015中的std::sort

    大约寒假开始的时候我就已经把std::sort的源码阅读完毕并理解其中的做法了,到了寒假结尾,姑且把它写出来 这是我的第一篇源码阅读笔记,以后会发更多的,包括算法和库实现,源码会按照我自己的代码风格格 ...

  4. SpringMVC源码阅读:Controller中参数解析

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

  5. caffe-windows中classification.cpp的源码阅读

    caffe-windows中classification.cpp的源码阅读 命令格式: usage: classification string(模型描述文件net.prototxt) string( ...

  6. caffe中batch norm源码阅读

    1. batch norm 输入batch norm层的数据为[N, C, H, W], 该层计算得到均值为C个,方差为C个,输出数据为[N, C, H, W]. <1> 形象点说,均值的 ...

  7. go 中 select 源码阅读

    深入了解下 go 中的 select 前言 1.栗子一 2.栗子二 3.栗子三 看下源码实现 1.不存在 case 2.select 中仅存在一个 case 3.select 中存在两个 case,其 ...

  8. 转-OpenJDK源码阅读导航跟编译

    OpenJDK源码阅读导航 OpenJDK源码阅读导航 博客分类: Virtual Machine HotSpot VM Java OpenJDK openjdk 这是链接帖.主体内容都在各链接中.  ...

  9. openjdk源码阅读导航

    转自:http://rednaxelafx.iteye.com/blog/1549577 这是链接帖.主体内容都在各链接中. 怕放草稿箱里过会儿又坑掉了,总之先发出来再说…回头再慢慢补充内容. 先把I ...

  10. avalon源码阅读(1)

    来源 写angularJS源码阅读系列的时候,写的太垃圾了. 一个月后看,真心不忍直视,以后有机会的话得重写. 这次写avalonJS,希望能在代码架构层面多些一点,少上源码.多写思路. avalon ...

随机推荐

  1. pip升级和卸载安装的第三方库

    pip install --upgrade 第三方库名 pip uninstall 第三方库名

  2. 火山引擎DataLeap联合DataFun发布《数据治理知识地图》

    近期,火山引擎DataLeap和技术社区DataFun联合发布<数据治理知识地图专业版V1>(以下简称"地图"),地图将数据治理的领域.流程.技术.工具等内容进行系统化 ...

  3. python argparse传入布尔参数不生效解决

    前言 在一个需要用到flag作为信号控制代码中一些代码片段是否运行的,比如"--flag True"或者"--flag False". 但是古怪的是无法传入Fa ...

  4. 【redis】 redis linux下安装 redis启动方式 redis典型场景 redis通用命令 数据结构和内部编码 redis字符串类型

    目录 上节回顾 今日内容 1 redis介绍 2 redis linux下安装 3 redis启动方式 3.1 最简启动 3.2 动态参数启动 3.3 配置文件启动 3.4 客户端连接命令 4 red ...

  5. 解读IDC《中国视频云市场跟踪》最新报告,视频云将趋向何方?

    国际权威咨询公司IDC发布<中国视频云市场跟踪(2021 H2)>报告,阿里云连续四年稳居中国视频云整体市场份额第一,整体市场份额占比达26.9%. 时至2021,中国视频云的数字背后 近 ...

  6. ABAP 获取ALV报表中的数据

    当程序中需要获取某张报表展示的ALV数据,又不想重新写一遍查询逻辑,则可以调用该报表,直接将报表的ALV内表的数据获取到,提高开发效率 "-------------------------- ...

  7. Python 3.12 抢先看——关于 f-string 的改动

    Python 3.12 抢先看--关于 f-string 的改动 哈喽大家好,我是咸鱼 相信小伙伴们对 python 中的 f-string 都不陌生 f-string 是格式化字符串的缩写,是以小写 ...

  8. 【第三方库】从编译到运行,轻松学会gflags库

    gflags是Google开源的一个库,可以很方便地定义一些全局变量,并且可以从命令行设置他们的值,广泛应用于各个项目中以及自己平时的开发中.本期参考gflags的官方文档,简单直接介绍下怎么使用这个 ...

  9. HHKB 键盘布局记录以及一些闲言碎语

    HHKB (happy hacking keyboard) 是世界顶级键盘品牌,自 1996 年推出以来畅销至今.与其他键盘不同,HHKB 机身小巧,省略了 F1 - F12 功能键.光标键和 Pag ...

  10. 使用 Serverless Devs 插件快速部署前端应用

    作者| 邓超 Serverless Devs 开源贡献者 背景 我们在 上文 [Aliyun] [FC] 如何使用 @serverless-devs/s 部署静态网站到函数计算 中,详细的介绍了如何通 ...