vmagent如何快速采集和转发Metrics
vmagent如何快速采集和转发Metrics
本文介绍了vmagent的设计细节,参考自:vmagent-how-it-works
VictoriaMetrics agent是一个轻量级工具,用于采集不同源的指标。vmagent可以在转发指标前(通过"relabeling")定制指标(降低基数、流聚合、去重等)。

第一步:通过API或抓取方式接收数据
HTTP API方式
并发限速
vmagent会通过一个并发限速器来读取数据,默认情况下,允许2x CPU core数目的并发insert请求(-maxConcurrentInserts),如果所处环境的网络较慢,可以适当提高该值来优化数据传输速率。
如果一个请求阻塞超过1分钟(-insert.maxQueueDuration),vmagent会返回503。

解压缩
在读取数据之后,vmagent需要根据请求头部的压缩类型来解压数据。vmagent支持3种remote write协议:Snappy、Zstandard(zstd)、Gzip。VictoriaMetrics的remote write协议采用的是zstd,相比其他方式,它可以降低2~4倍的网络流量,但需要额外约10%的CPU资源。

抓取方式
除通过HTTP API push方式获取数据外,vmagent还支持按照一定间隔从目标抓取指标。该方式与prometheus的pull方式相同:
config:
global:
scrape_interval: 10s
scrape_configs:
- job_name: "kubernetes-service-endpoints-slow"
scrape_interval: 5m
scrape_timeout: 30s
...
当数据加载到内存之后,有两种处理模式:流模式(以chunk为单位处理)和一次性处理模式。
流模式和一次性处理模式
这两种方式都各有优缺点。对于较小的数据,一次性处理更加高效;而对于较大的数据,使用流模式,以64 KB为单位处理数据,对资源来说更加友好。

默认情况下,当数据超过1MB(-promscrape.minResponseSizeForStreamParse)时,vmagent会自动转换为流模式。
第二步:全局relabel和降低基数
现在,已经将原始数据转换为时序数据,vmagent需要将数据发送到远端存储。如果存储系统down(可能因为过载或出现故障),则vmagent会将数据发送到一个本地存储(默认启用),避免丢失该存储的数据。
如果禁用持久化队列,则直接丢弃数据。

为了在内存和性能方面保持高效,vmagent将数据拆分为块(block),每个块有2个限制:10,000条样本(-remoteWrite.maxRowsPerBlock)或100,000个labels(通常是10倍的采样量)。
当一个时序块就绪后,会引入一个全局采样限速器来控制vmagent每秒可以采集的样本数(-maxIngestionRate),默认没有限制。

高基数时序数据会对远端存储造成压力。为此,可以通过-remoteWrite.maxHourlySeries 和 -remoteWrite.maxDailySeries控制一定周期内唯一时序数据的最大数目,超过限制的时序数据都将被丢弃,默认无限制。

第三步:全局去重和流聚合
这两种方式都是为了降低数据量,前者会导致数据丢失,后者采用的是一种数据聚合方式。
vmagent还可以去重,移除不需要的时序数据,目标是在一个特定的时间帧( -streamAggr.dedupInterval)内仅保留最重要的数据点。例如将全局去重间隔设置为30s,则vmagent会:
- 在30s的窗口内,对于同一个时间序列,vmagent会仅保留最新的一条样本,即具有最高时间戳的样本。
- 如果两条样本具有相同的时间戳,则保留具有最高值的那条。

下一步是流聚合,这是一种在将指标发送到存储(远端或本地)之前对指标进行浓缩或总结的方式。
假设每秒采集的数据量比较大,对每条数据进行保存会占用大量空间,且会放慢查询速度,同时又不希望因为使用去重而导致数据丢失,此时可以采用流聚合。
例如下面流聚合方式:
- match: '{__name__=~".+_total"}'
interval: 5m
outputs: [total]
这种情况下,每5分钟会保存一个以"_total"结尾的指标点。因此,如果原始指标为some_metric_total,则聚合后的指标为some_metric_total:5m_total,这样就减少了数据量,且不会丢失重要的信息。
在启用流聚合后,vmagent会将数据发送到一个聚合器,聚合器具有自己的内存缓存,最终通过后台将缓存刷新到远端存储。
默认情况下,聚合器只会"偷取"并丢弃匹配聚合规则的时序数据,作为聚合器的输入。有如下两种模式:
-streamAggr.keepInput:默认false。是否同时保存匹配和不匹配的input时间序列。如果为true,则都保存,为false,则按照-streamAggr.dropInput处理。-streamAggr.dropInput:默认false。是否丢弃所有input时间序列或仅丢弃匹配的时间序列,如果为true,则丢弃所有input 时间序列,为false,则仅丢弃匹配的input时间序列

这里需要注意的是,全局去重也会被应用到流聚合中,首先会在去重间隔内过滤数据,然后再将数据刷新到聚合器中。另外,若要同时使用去重和流聚合,则需要保证流聚合间隔要大于去重间隔,且为去重间隔的倍数。
此外还可以针对单条流设置去重。下面配置中,每分钟会聚合一次数据,且每30s的窗口内会执行去重过滤。
- match: '{__name__=~".+_total"}'
interval: 1m
outputs: [total]
dedup_interval: 30s
第四步:分片(sharding)和复制(replication)
至此处理的仍然是时序数据块(10,000条采样或100,000个labels)。下面需要考虑将数据发往远端存储,有两种策略:
- 复制:如果有多个远端存储 (
-remoteWrite.url),则vmagent会将所有时序数据发往每个远端存储。 - 分片:如果设置了分片标识 (
-remoteWrite.shardByURL),则不会将相同的数据发到每个存储系统中,而会切分这些数据,然后均匀分布到各个存储中。

对于分片,vmagent会针对每个时间序列,使用xxHash函数对组合的labels进行哈希计算,并用生成的64-bit哈希值来决定时间序列的归属。可以通过-remoteWrite.shardByURL.labels指定用于计算分片的labels,以及使用-remoteWrite.shardByURL.ignoreLabels来忽略计算分片的labels。
为了提高数据的可用性,可以启用分片复制(-remoteWrite.shardByURLReplicas),即一个分片有多个副本。默认情况下。一个分片只有一个副本(无复制)。

第五步:对每个远端存储进行微调,四舍五入采样值
至此,可以使用分片或复制的方式将数据发往目的地。每个远端存储都对应一个管理器,称为"远端写入上下文"(remoteWriteCtx),该上下文负责处理上面提到的所有操作,但仅针对单个存储。下面看下如何针对单个存储处理流聚合和去重:
- 首先针对单个远端存储执行relabel(
-remoteWrite.urlRelabelConfig) - 执行流聚合 (
-remoteWrite.streamAggr.config)。需要注意的是,不要混用全局流聚合和单存储流聚合 - 执行去重 (
-remoteWrite.streamAggr.dedupInterval) - 最后为所有时序数据添加全局标签 (
-remoteWrite.label),这些标签不受relabel的影响

另外vmagent还可以修改时序数据的值:
- 有效数字法(
-remoteWrite.significantFigures):处理数字的精度,如12345.6789四舍五入到2位有效数字后变为12000 - 小数点位 (
-remoteWrite.roundDigits):负责处理保留多少位小数点,如12345.6789四舍五入到小数点后2位后变为12345.68
第六步:刷新:Fast Queue
下一步将数据刷新到内存队列,称为"fast queue",它是一个混合系统,包含内存队列和基于文件的队列(持久队列)。fast queue用于保存由于远端存储跟不上采样速率而累积的样本。
在前面的处理中,vmagent使用snappy或zstd解压了时序数据,这里需要在将其发送到fast queue之间再次压缩。如果压缩之后的数据块大于8MB (-remoteWrite.maxBlockSize),则vmagent会将其一切为二,如果仍然大于8MB,则继续递归拆分,直到达到8MB的限制。

内存队列
内存队列实际上是一个简单的golang buffer channel,FIFO队列。
当vmagent启动时,默认它会启动2倍CPU core的workers(goroutines,如果需要处理更多数据,可以通过-remoteWrite.queues增加workers数目)。每个worker有5s的时间从内存队列读取数据,如果无法及时读取所有的数据,则剩余的数据会被刷新到文件队列。可以使用-memory.allowedPercent (默认 60%) 或 -memory.allowedBytes调节内存中应该保存的数据块数目。默认计算方式如下:
maxInmemoryBlocks := allowed memory / number of remote storage / maxRowsPerBlock / 100
// clamp(value, min, max)
clamp(maxInmemoryBlocks, 2, queue * 100)
记住,每个块包含10,000条样本(-remoteWrite.maxRowsPerBlock),并确保内存中至少有2个块,且每个队列不超过100个块。
总结一下,什么时候数据会被刷新到磁盘?
- worker超时:如果一个worker无法在5s之内读取所有的内存数据,则剩余数据会被刷新到磁盘
- 积压的磁盘队列:如果磁盘队列中仍然有等待刷新到远端存储的数据,则新的块会被直接刷新到磁盘
- 内存限制:如果达到内存队列上限,则新块会被立即刷新到磁盘
基于文件的队列
刷新到磁盘的数据会被保存到-remoteWrite.tmpDataPath指定的目录中(默认 /vmagent-remotewrite-data)。
与内存队列相同,文件队列也有大小限制(-remoteWrite.maxDiskUsagePerURL,默认0,即无限制)。如果达到上限,则vmagent会通过丢弃老的块来确保数据不会溢出。刷新到磁盘的数据会被保存到chunks文件中,每个chunk大小为512MB,chunk中的block包含两部分:
- Header:8字节的首部,表示block的大小
- Payload:实际的时序数据
const MaxBlockSize = 32 * 1024 * 1024 // 32 MB,块压缩上限为32MB
const DefaultChunkFileSize = (MaxBlockSize + 8) * 16 // over 512 MB
block的上限约为32MB,加8字节的首部,因此每个chunk文件最多可以有16个blocks。

这些chunk文件保存在/vmagent-remotewrite-data/persistent-queue/<url_id>_<url_hash>/<byte_offset>目录中。
/tmpData/persistent-queue
│
└── 1_B075D19130BC92D7
├── 0000000000000000 # 512 MB chunk file
├── 0000000002000000 # 512 MB chunk file
├── 0000000004000000 # 512 MB chunk file
├── 0000000006000000 # 512 MB chunk file
├── flock.lock
└── metainfo.json
vmagent使用buffered writting方式写入chunk文件,buffer的大小取决于内存设定 (-memory.allowedPercent, 默认 60%, 或 -memory.allowedBytes),计算方式为:
// clamp(x, min, max)
bufferSize := clamp(allowed memory / 8 KB, 4 KB, 512 KB)
即,如果内存为2GB,则buffer大小为250KB,适用于4KB~250KB范围。
这样去重器会按照去重间隔将数据刷新到流聚合器,然后流聚合器会周期性地将数据刷新到fast queue。
第七步:刷新到远端存储
在vmagent启动时,它会启动一些worker来从fast queue(内存以及文件队列)拉取数据块,然后处理并尝试将这些数据发往远端存储。每个远端存储都有其特定数目的workers,通常为2倍的CPU core (-remoteWrite.queues)。
每个worker会从队列拉取一个时序数据块,首先检查内存队列,如果为空,则检查文件队列,如果都为空,则等待新数据。

一旦获取到有效的块,worker会将它们发送到远端存储。如果vmagent需要停止(重启或重调度),则它会等待5s来结束请求发送。
vmagent使用限速器(-remoteWrite.rateLimit)来限制发送到远端存储的数据速率,默认无限制。
vmagent如何快速采集和转发Metrics的更多相关文章
- Flink - metrics
Metrics是以MetricsGroup来组织的 MetricGroup MetricGroup 这就是个metric容器,里面可以放subGroup,或者各种metric 所以主要的接口就是注 ...
- 《ServerSuperIO Designer IDE使用教程》-2.与硬件网关数据交互,并进行数据级联转发,直到云端。发布:v4.2.1版本
v4.2.1 更新内容:1.重新定义数据转发文本协议,使网关与ServerSuperIO以及之间能够相关交互数据.2.扩展ServerSuperIO动态数据类的方法,更灵活.3.修复Designer增 ...
- 使用日志服务进行Kubernetes日志采集
阿里云容器服务Kubernetes集群集成了日志服务(SLS),您可在创建集群时启用日志服务,快速采集Kubernetes 集群的容器日志,包括容器的标准输出以及容器内的文本文件. 新建 Kubern ...
- 采集并分析Nginx访问日志
日志服务支持通过数据接入向导配置采集Nginx日志,并自动创建索引和Nginx日志仪表盘,帮助您快速采集并分析Nginx日志. 许多个人站长选取了Nginx作为服务器搭建网站,在对网站访问情况进行分析 ...
- 利用Metrics+influxdb+grafana构建监控平台(转)
转自http://www.jianshu.com/p/fadcf4d92b0e 这里再配合Influxdb和Grafana可以构建一个非常漂亮的实时监控界面. Grafana监控界面 采集数据(Met ...
- Runtime 运行时之一:消息转发
解释一 上一篇文章咱们提到了Runtime的消息传递机制,主要围绕三个C语言API来展开进行的.这篇文章我将从另外三个方法来描述Runtime中另一个特性:消息转发机制. 一.消息转发机制 当向某个对 ...
- 微服务监控之二:Metrics+influxdb+grafana构建监控平台
系统开发到一定的阶段,线上的机器越来越多,就需要一些监控了,除了服务器的监控,业务方面也需要一些监控服务.Metrics作为一款监控指标的度量类库,提供了许多工具帮助开发者来完成自定义的监控工作. 使 ...
- 用js采集网页数据并插入数据库最快的方法
今天教大家一个快速采集网站数据的方法,因为太晚了,直接上例子,这里以采集易车网的产品数据为例. 思路:利用js获取网页数据并生成sql命令,执行sql命令把采集的数据插入数据库. 1.用谷歌浏览器或者 ...
- kubernetes pod的弹性伸缩———基于pod自定义custom metrics(容器的IO带宽)的HPA
背景 自Kubernetes 1.11版本起,K8s资源采集指标由Resource Metrics API(Metrics Server 实现)和Custom metrics api(Promet ...
- AMS 新闻视频广告的云原生容器化之路
作者 卓晓光,腾讯广告高级开发工程师,负责新闻视频广告整体后台架构设计,有十余年高性能高可用海量后台服务开发和实践经验.目前正带领团队完成云原生技术栈的全面转型. 吴文祺,腾讯广告开发工程师,负责新闻 ...
随机推荐
- PHP中几种常见的开发模式
设计模式 单例模式 $_instance必须声明为静态的私有变量 构造函数和析构函数必须声明为私有,防止外部程序new 类从而失去单例模式的意义 getInstance()方法必须设置为公有的,必须 ...
- USB2.0 DP DM VBUS
在USB 2.0中,设备成功枚举的标志可以通过观察 D+ (dp).D- (dm) 和 VBUS 引脚的电压波形来判断.以下是这些信号在USB 2.0枚举过程中常见的状态: VBUS (5V供电): ...
- 从浏览器输入url到回车发生了什么
1. 域名解析,即把域名解析成以为唯一的ip ps:ip是每个网站的对应的一个key,域名是为了语义化,方便使用而设计的 : ps:第一次域名解析需要花费较长的时间,所以一般第一次解析就会把DNS解析 ...
- 00 通过 Pytorch 实现 Transformer 框架完整代码
博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from=333.1007.0.0 b 站直接看 配套 github 链接:https:// ...
- kubernetes日志回滚测试
kubernetes日志回滚测试 操作节点 podName 查询日志的命令 得到结果 初始pod ms-zipkin-deployment-5949c78884-4x5h7 kubectl logs ...
- DiTAC:不知如何提升性能?试试这款基于微分同胚变换的激活函数 | ECCV'24
非线性激活函数对深度神经网络的成功至关重要,选择合适的激活函数可以显著影响其性能.大多数网络使用固定的激活函数(例如,ReLU.GELU等),这种选择可能限制了它们的表达能力.此外,不同的层可能从不同 ...
- v-if的使用方式
一.语法 其中<span></span>可以换成<div></div>, <div></div>的可以换成<templet ...
- 关于在有动态的Scroll Bar情况下页面内容的对齐问题
关于在有动态的Scroll Bar情况下页面内容的对齐问题 问题场景 一个标题行 + 一些内容行 要求在内容行超过指定行数时 将多出的行隐藏,并展示Scroll Bar的来提示用户可以下划查看更多内容 ...
- spring boot下跨域安全配置
1 @Bean 2 public FilterRegistrationBean corsFilter() { 3 final UrlBasedCorsConfigurationSource sourc ...
- 计算机网络常见面试题(一):TCP/IP五层模型、TCP三次握手、四次挥手,TCP传输可靠性保障、ARQ协议
文章目录 一.TCP/IP五层模型(重要) 二.应用层常见的协议 三.TCP与UDP 3.1 TCP.UDP的区别(重要) 3.2 运行于TCP.UDP上的协议 3.3 TCP的三次握手.四次挥手 3 ...