【博客676】VictoriaMetrics缓存限制之:布隆过滤器

news2024/12/25 10:11:31

VictoriaMetrics缓存限制之:布隆过滤器

1、场景

VictoriaMetrics的vmstorage组件接收上游传递过来的指标,在​​现实场景中,指标的数量级或者瞬态指标可能会非常可怕,如果不限制缓存的大小,就会存在由于缓存导致插入速度过慢的风险错过了。

slow insert问题参考官方issue:what-is-a-slow-insert

2、VictoriaMetrics解决办法:布隆过滤器

在这里插入图片描述

为此,vmstorage提供了两个参数:maxHourlySeries和maxDailySeries,用于限制每小时/每天添加到缓存的唯一序列。

唯一序列指表示唯一的时间序列,如metrics{label1=“value1”,label2=“value2”}属于一个时间序列,但多条不同值的metrics{label1=“value1”,label2=“value2”}属于同一条时间序列。victoriaMetrics使用如下方式来获取时序的唯一标识:

func getLabelsHash(labels []prompbmarshal.Label) uint64 {
	bb := labelsHashBufPool.Get()
	b := bb.B[:0]
	for _, label := range labels {
		b = append(b, label.Name...)
		b = append(b, label.Value...)
	}
	h := xxhash.Sum64(b)
	bb.B = b
	labelsHashBufPool.Put(bb)
	return h

限速器的初始化

victoriaMetrics使用了一个类似限速器的概念,限制每小时/每天新增的唯一序列,但与普通的限速器不同的是,它需要在序列级别进行限制,即判断某个序列是否是新的唯一序列,如果是,则需要进一步判断一段时间内缓存中新的时序数目是否超过限制,而不是简单地在请求层面进行限制。

hourlySeriesLimiter = bloomfilter.NewLimiter(*maxHourlySeries, time.Hour)
dailySeriesLimiter = bloomfilter.NewLimiter(*maxDailySeries, 24*time.Hour)

新建限速器的函数,传入一个最大(序列)值,以及一个刷新时间。该函数中会:

  • 1、初始化一个限速器,限速器的最大元素个数为maxItems
  • 2、则启用了一个goroutine,当时间达到refreshInterval时会重置限速器
func NewLimiter(maxItems int, refreshInterval time.Duration) *Limiter {
	l := &Limiter{
		maxItems: maxItems,
		stopCh:   make(chan struct{}),
	}
	l.v.Store(newLimiter(maxItems)) //1
	l.wg.Add(1)
	go func() {
		defer l.wg.Done()
		t := time.NewTicker(refreshInterval)
		defer t.Stop()
		for {
			select {
			case <-t.C:
				l.v.Store(newLimiter(maxItems))//2
			case <-l.stopCh:
				return
			}
		}
	}()
	return l
}

限速器只有一个核心函数Add,当vmstorage接收到一个指标之后,会(通过getLabelsHash计算该指标的唯一标识(h),然后调用下面的Add函数来判断该唯一标识是否存在于缓存中。

如果当前存储的元素个数大于等于允许的最大元素,则通过过滤器判断缓存中是否已经存在该元素;否则将该元素直接加入过滤器中,后续允许将该元素加入到缓存中。

func (l *Limiter) Add(h uint64) bool {
	lm := l.v.Load().(*limiter)
	return lm.Add(h)
}

func (l *limiter) Add(h uint64) bool {
	currentItems := atomic.LoadUint64(&l.currentItems)
	if currentItems >= uint64(l.f.maxItems) {
		return l.f.Has(h)
	}
	if l.f.Add(h) {
		atomic.AddUint64(&l.currentItems, 1)
	}
	return true
}

上面的过滤器采用的是布隆过滤器,核心函数为Has和Add,分别用于判断某个元素是否存在于过滤器中,以及将元素添加到布隆过滤器中。

过滤器的初始化函数如下,bitsPerItem是个常量,值为16。bitsCount统计了过滤器中的总bit数,每个bit表示某个值的存在性。bits以64bit为单位的(后续称之为slot,目的是为了在bitsCount中快速检索目标bit)。计算bits时加上63的原因是为了四舍五入向上取值,比如当maxItems=1时至少需要1个unit64的slot。

func newFilter(maxItems int) *filter {
	bitsCount := maxItems * bitsPerItem
	bits := make([]uint64, (bitsCount+63)/64)
	return &filter{
		maxItems: maxItems,
		bits:     bits,
	}
}

为什么bitsPerItem为16?

在代码中,k为4(hashesCount),期望的漏失率为0.003(可以从官方的filter_test.go中看出),则要求总存储和总元素的比例为15,为了方便检索slot(64bit,为16的倍数),将之设置为16。

	if p > 0.003 {
		t.Fatalf("too big false hits share for maxItems=%d: %.5f, falseHits: %d", maxItems, p, falseHits)
	}

在这里插入图片描述

下面是过滤器的Add操作,目的是在过滤器中添加某个元素。Add函数中没有使用多个哈希函数来计算元素的哈希值,转而改变同一个元素的值,然后对相应的值应用相同的哈希函数,元素改变的次数受hashesCount的限制。

  • 1、获取过滤器的完整存储,并转换为以bit单位
  • 2、将元素h转换为byte数组,便于xxhash.Sum64计算
  • 3、后续将执行hashesCount次哈希,降低漏失率
  • 4、计算元素h的哈希
  • 5、递增元素h,为下一次哈希做准备
  • 6、取余法获取元素的bit范围
  • 7、获取元素所在的slot(即uint64大小的bit范围)
  • 8、获取元素所在的slot中的bit位,该位为1表示该元素存在,为0表示该元素不存在
  • 9、获取元素所在bit位的掩码
  • 10、加载元素所在的slot的数值
  • 11、如果w & mask结果为0,说明该元素不存在,
  • 12、将元素所在的slot(w)中的元素所在的bit位(mask)置为1,表示添加了该元素
  • 13、由于Add函数可以并发访问,因此bits[i]有可能被其他操作修改,因此需要通过重新加载(14)并通过循环来在bits[i]中设置该元素的存在性
func (f *filter) Add(h uint64) bool {
	bits := f.bits
	maxBits := uint64(len(bits)) * 64 //1
	bp := (*[8]byte)(unsafe.Pointer(&h))//2
	b := bp[:]
	isNew := false
	for i := 0; i < hashesCount; i++ {//3
		hi := xxhash.Sum64(b)//4
		h++ //5
		idx := hi % maxBits //6
		i := idx / 64 //7
		j := idx % 64 //8
		mask := uint64(1) << j //9
		w := atomic.LoadUint64(&bits[i])//10
		for (w & mask) == 0 {//11
			wNew := w | mask //12
			if atomic.CompareAndSwapUint64(&bits[i], w, wNew) {//13
				isNew = true//14
				break
			}
			w = atomic.LoadUint64(&bits[i])//14
		}
	}
	return isNew
}

Has只是Add函数的缩减版,无需设置bits[i]:

func (f *filter) Has(h uint64) bool {
	bits := f.bits
	maxBits := uint64(len(bits)) * 64
	bp := (*[8]byte)(unsafe.Pointer(&h))
	b := bp[:]
	for i := 0; i < hashesCount; i++ {
		hi := xxhash.Sum64(b)
		h++
		idx := hi % maxBits
		i := idx / 64
		j := idx % 64
		mask := uint64(1) << j
		w := atomic.LoadUint64(&bits[i])
		if (w & mask) == 0 {
			return false
		}
	}
	return true
}

3、Bloom Filters 容错率计算,布隆过滤器大小如何设置

参数解析:

  • m:m表示内存大小(多少个位)
  • n:n表示去重对象的数量
  • k:哈希函数的数量(也即seed的个数,假设hash函数对同一输入每次执行都不同输出,那k就是连续执行几次,以降低漏失率)

容错率计算参考表:

在这里插入图片描述

4、原理综述

对于插入一个series,看是否达到了限速器的最大数量,如果没达到则直接插入,如果达到了,则使用布隆过滤器来判断是否为已有series,如果是则允许写入,如果不是则拒绝

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/684002.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

模拟电路系列分享-运放的关键参数4

目录 概要 整体架构流程 技术名词解释 1.定义 2.优劣范围 3.理解 技术细节 1.压摆率 1.定义∶ 2.优劣范围 3.理解︰ 2.单位增益带宽 1.定义∶ 2.优劣范围︰ 3.理解∶ 小结 概要 提示&#xff1a;这里可以添加技术概要 例如&#xff1a; 实际运放与理想运放具有很多差别。理想…

jumpserver【基本使用教程】

目录 目录 【1】管理用户 【2】系统用户 【3】普通用户 【4】添加资产&#xff08;可以添加的有&#xff1a;服务器、网络设备、数据库应用&#xff09; 【5】权限划分 【6】验证&#xff08;使用普通用户登录资产&#xff09; 【7】查看是否有记录 【8】添加数据库资产…

2023全球智博会奏响AI产业发展的四重共振

2023年6月25日为期三天的第五届全球人工智能产品应用博览会&#xff08;简称“全球智博会”&#xff09;在苏州国际博览中心盛大启幕。金鸡湖畔汇聚院士专家、领军智囊、顶尖企业&#xff0c;为人工智能关键技术突破、产业化创新应用、科技产品研发落地、经济深度融合等方面提供…

解密EEMD分析:Rlibeemd包带你玩转信号分解和时间序列预测

一、简介 1.1 什么是EEMD? EEMD&#xff08;Ensemble Empirical Mode Decomposition&#xff09;是一种信号分解方法&#xff0c;它旨在分解非线性、非平稳或非白噪声的信号&#xff0c;以揭示复杂信号的局部特征和周期性成分。EEMD不同于传统的余弦变换、小波变换等线性变换…

按键控制蜂鸣器实验

目录 按键控制蜂鸣器实验 1、简介 2、实验任务 3、程序设计 3.1、顶层模块代码 3.2、按键消抖模块代码 3.3、蜂鸣器控制模块代码 4、仿真验证 5、板上下载验证 5.1、硬件设计 5.2、添加约束文件.xdc 5.3、板上下载验证 按键控制蜂鸣器实验 蜂鸣器&#xff08;Buzze…

微机保护主程序框图原理

微机保护主程序框图如图2&#xff0d;5所示。 一、初始化 “初始化”是指保护装置在上电或按下复位键时首先执行的程序&#xff0c;它主要是对单片微机&#xff08;CPU&#xff09;及可编程扩展芯片的工作方式、参数的设置&#xff0c;以便在后面的程序中按预定方案工作。例如…

荨麻疹【指南共识】

慢性自发性荨麻疹达标治疗专家共识&#xff08;2023&#xff09; 参考文献&#xff1a;中华医学会皮肤性病学分会&#xff0c; 中国医师协会皮肤科医师分会. 慢性自发性荨麻疹达标治疗专家共识&#xff08;2023&#xff09;[J]&#xff0e; 中华皮肤科杂志&#xff0c;2023, e2…

在React+ts中集成高德地图(保姆级教程)

前往高德地图开发平台高德开放平台 | 高德地图API 一&#xff1a;申请高德key 去高德官网去创建一个属于自己的地图应用 &#xff08;得到key和秘钥&#xff09; 。 首先&#xff0c;我们要注册一个开发者账号&#xff0c;根据实际情况填写&#xff0c;身份写个人&#xff1a;…

LwIP系列(3):以太网帧、IP、TCP、UDP、IGMP、ICMP帧格式详解

前言 TCP/IP 本质上是软件协议&#xff0c;而LwIP也是对软件协议进行解析处理&#xff0c;所以我们有必要了解下以太网帧、IP、TCP、UDP、IGMP、ICMP帧格式&#xff0c;这样在代码中&#xff0c;才能有的放矢。 以太网帧框架 以太网帧是最底层的原始数据&#xff0c;帧框架如…

Linux用户密码管理

密码复杂度设置 之前写过一篇文章&#xff0c;通过编辑/etc/pam.d下的配置文件来信hi先密码复杂度设置。 这里介绍另一种方法&#xff0c;使用authconfig名来配置。 如果没有安装该软件&#xff0c;输入如下命令安装: yum install authconfig -y 设置方法如下: authconfi…

力扣动态规划专题(六)编辑距离与回文问题 步骤及C++实现

文章目录 392. 判断子序列动态规划双指针 115.不同的子序列583. 两个字符串的删除操作方法一方法二 72. 编辑距离647. 回文子串动态规划双指针 516.最长回文子序列 392. 判断子序列 动态规划 步骤 确定dp数组以及下标的含义 dp[i][j] 表示以下标i-1为结尾的字符串s&#xff0c…

Json数据 通用提取工具 Web版

问题来源 楼主使用Golang 实现了一款通用型 JSON 数据提取工具&#xff0c;支持自动识别 JSON 数据节点并有序提取为 CSV 文件。 看到大家有这样的评论&#xff0c;顺手实现下&#xff0c;~~ 尴尬的是搞完了 &#xff0c;发现 这个论坛注册不足15天&#xff0c;不能回复评论。晕…

迅为RK3568开发板系统编程手册全新升级

iTOP-3568开发板C应用编程手册全新升级&#xff0c;《iTOP-RK3568开发板系统编程手册》旨在帮助刚入门的用户进行入门规划和学习&#xff0c;为系统编程基础指导手册。 第1部分 系统编程初探 第1章 系统编程初探 1.1 什么是系统编程 1.2 系统编程的作用 1.3 系统调用和C语言库函…

R语言使用xlsx包、安装包的经验以及切换工作目录的方法

R语言使用xlsx包 首先不同于读取txt和csv文件&#xff0c;R语言读取xlsx文件需要安装xlsx包 使用下面命令进行安装xlsx install.packages(“xlsx”) 安装过程非常顺利&#xff0c;需要附带安装其它几个包。如果安装出现错误&#xff0c;可以尝试切换网络&#xff0c;使用手机热…

2-css-1

一 CSS 初体验 CSS 定义&#xff1a;层叠样式表 (Cascading Style Sheets&#xff0c;缩写为 CSS&#xff09;&#xff0c;是一种样式表语言&#xff0c;用来描述HTML文档的呈现&#xff08;美化内容&#xff09; CSS 书写在什么位置&#xff1f; title 标签下方哪个标签里面…

2-css-5

一 定位 1 认识 作用&#xff1a;灵活的改变盒子在网页中的位置 实现&#xff1a; 定位模式&#xff1a;position边偏移&#xff1a;设置盒子的位置 left right top bottom 2 相对定位 position: relative 特点&#xff1a; 不脱标&#xff0c;占用自己原来位置显示模式…

如何将JSON对象转化为java对象,如何将java对象转化为JSON对象

如何将JSON对象转化为java对象&#xff0c;如何将java对象转化为JSON对象 一、在java中如何构建一个JSON对象 在java中我们可以通过创建JsonObject对象的方式来为其添加相应的参数属性&#xff0c;进而构造JSON对象 1、导入JsonObject的依赖 JsonObject是Gson库中的一个类&…

数据结构--数据结构的基本概念

数据结构–数据结构的基本概念 知识总览&#xff1a; 数据结构的三要素 #mermaid-svg-jflLhauniFK26Yxb {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-jflLhauniFK26Yxb .error-icon{fill:#552222;}#mermaid-svg-…

软件测试已经人员饱和了?是否选择退出这个行业?

铺天盖地的职场内卷文章充斥我们眼球&#xff0c;给大家带来山大压力&#xff0c;内心焦虑。据闻&#xff0c;2023年有1070万高校应届毕业生涌入用人市场&#xff0c;其中有多少人将卷入软件测试行业呢&#xff1f;而最近大厂毕业之风盛行&#xff0c;对外输出人才&#xff0c;…

从小白到大神之路之学习运维第46天---第三阶段----Ceph分布式存储系统(CentOS7.9版本下安装部署ceph)

第三阶段基础 时 间&#xff1a;2023年6月25日 参加人&#xff1a;全班人员 内 容&#xff1a; Ceph分布式存储系统 目录 一、Ceph概述 二、Ceph 的工作原理和工作流程 三、Ceph 组件包括 1. RADOS 2. OSD 3. MON 4. MDS 5. RGW 6. RBD 7. CephFS 四、安装部…