写点什么

Prometheus 远程写入 InfluxDB,遇到 OOM 引发的错误怎么解?

2020 年 12 月 10 日

Prometheus远程写入InfluxDB,遇到OOM引发的错误怎么解?

一、问题场景


InfluxDB 作为时序数据库被广泛应用于监控领域的数据持久化工作,在数据持久化的运行过程中,往往会遇到各种各样的错误,MAX-VALUE-PER-TAG 是在 InfluxDB 写入时为避免 OOM 问题所引发的保护性错误。


本文通过 Prometheus 远程写入 InfluxDB 进行业务系统监控数据持久化的视角,来介绍一下 max-value-per-tag 错误(如下图)产生的原因及解决措施,以期能为大家在使用 InfluxDB 时提供一些经验和参考。



二、成因分析


在 Prometheus 远程写入 InfluxDB 的场景中,导致此问题产生的主要原因是由于通过 Prometheus 远程写入 InfluxDB 的监控指标中包含了多个具有较高离散度的标签数据所引起。举例如下:


  • 设置 Exporter 暴露的监控指标,使监控指标中包含具有高离散度的标签要素,此类标签不用多,一两个即可,例如:全局系统跟踪号(每个指标自增 1)、交易时间(每个指标实时抓取系统时间)等;

  • 设置完监控指标后,我们通过 Prometheus 将采集的指标持续不断的写入 InfluxDB。(注:Prometheus 会使用 snappy 压缩算法将含有预先定义的如下数据结构信息流使用 protobuf 协议传输至 InfluxDB);



  • InfluxDB 收到数据流后会将监控数据指标名作为表名(measurement)、所有标签作为索引字段(tags)、样本值作为常规字段(field)进行解析和存储:




  • 在存储时,InfluxDB 会将由标签组成的索引字段(tags)默认保存在内存中,目的是为了避免索引字段取值过多而导致程序申请内存过大而引起的操作系统运行异常,即 OOM 问题;

  • 为了避免 OOM 问题的发生,InfluxDB 提供了 max-values-per-tag 保护参数,该参数的初始阈值为 100000,即当某一索引字段(tags)取值数量超过该阈值时,会引发该条时序记录写入失败:




  • 综上所述,当 Prometheus 持续写入数据至 InfluxDB 一段时间后,由这些高离散度的标签形成的索引字段(tags)数量便会达到 max-values-per-tag 阈值设定限制,从而导致后续监控数据写入失败。


三、解决方案


解决方案 1


1)方案简述


由上一章节描述可知,InfluxDB 将索引数据默认保存在内存中主要是为了解决 OOM 问题,但如果我们的使用场景只是为了做监控数据持久化,即基本上只会做写入操作,是否可以将这些索引数据保存在磁盘中呢?


InfluxDB 提供了通过配置参数(如下图所示),将索引数据由内存转移到磁盘进行保存的功能。索引保存于磁盘虽然读取速度不如存储在内存快,但理论上可以解决 max-values-per-tag 问题。



2)测试验证


①在 InfluxDB 配置文件中进行 index-version=tsi1 的配置,配置完成后,/var/lib/influxdb/data 的数据库实例路径中将创建 index 路径集和索引落盘所需的相关数据文件;


②设置具有类似全局系统跟踪号、交易时间等高离散度标签的监控指标,通过 Pushgateway 进行监控指标推送,模拟平均 100TPS 交易场景下的 InfluxDB 数据储存情况;


③持续运行 12 小时后,InfluxDB 运行正常,所有监控指标成功写入,但通过对/var/lib/influxdb/data 的数据库实例路径容量进行观察,发现平均每小时新增磁盘使用空间约 300M(index 增长 50M,tsm 增长 120M,_series 增长 130M)。由此测算得知,在平均 100TPS 的交易场景下保存监控数据所需磁盘空间如下:



3)测试结论


虽然通过修改配置参数,将索引数据由内存转到磁盘写入,解决了 max-value-per-tag 的警告问题,但对磁盘空间消耗过大,造成磁盘空间消耗过大的原因如下:


  • InfluxDB 对同一监控指标的时序数据进行索引数据存储维护时,会对索引取值(集合)进行笛卡尔乘积处理;



  • 监控指标中的高离散度标签形成的索引字段使得上述笛卡尔乘积变得异常庞大。


由此可以看出,InfluxDB 更偏向于高效读写大数量时序变化数据,索引字段作为其快速数据查询的基础,一般是由不随时间变化的信息要素组成,而不是具体的数据信息,所以,用于标识监控指标唯一性的高离散度标签信息不适合作为 InfluxDB 的索引字段。


解决方案 2


1)方案简述


在监控系统中,高离散度的标签往往是作为监控告警的辅助信息使用,而不会作为监控维度的分析,所以将这些标签放入索引的意义不大。第二种方案就是通过对 InfluxDB 进行客户化,将这些高离散度的标签作为常规字段进行存储。


2)测试验证


①对 InfluxDB 进行客户化开发,在接收到 Prometheus 的远程写入请求时先对监控指标数据进行预处理,仅将指标名保留为索引字段,而将高离散度的标签去除索引属性转变为常规字段进行存储,代码修改样例如下:




②InfluxDB 客户化改造后,模拟解决方案 1 中测试验证的第 2 步操作,经过 12 小时的测试验证,InfluxDB 运行正常,未出现 max-value-per-tag 的警告问题,且磁盘空间只增长了几十 M,满足了不超过索引上限和磁盘空间占用较小的需求。


③但是在验证数据正确性时发现:对于同一批次抓取的多条监控指标具有相同的时间戳,原本应该基于时间戳标签插入多条监控数据变成了基于同一批次时间戳的更新操作,失去了使用时间戳标签区别监控指标的意义。


3)测试结论


由于 Prometheus 周期性抓取指标的特性,对于同一批次抓取的多条监控指标具有相同的批次时间戳,在远程写入时被 InfluxDB 解析成了具有同一时间戳、同一索引(指标名)的重复时序数据,原本应该进行多次数据插入的动作变成了未被预期的针对同一条时序数据的多次更新操作,造成了远程数据集写入缺失,从而此方案虽然解决了 max-value-per-tag 的警告问题和磁盘存储空间的问题,但无法满足监控数据持久性要求。


解决方案 3


1)方案简述


通过前 2 个方案的测试结论可知,既然 InfluxDB 不适合存储具有高离散度标签的时序数据,那么我们就将高离散度标签的时序数据在写入 InfluxDB 前进行屏蔽处理。


2)测试验证


①通过修改 Prometheus 的 remote_write 配置段,将具有高离散度标签的监控指标进行屏蔽设定,去除具有高离散度标签的监控指标向 InfluxDB 的写入请求。



②配置完成后,模拟解决方案 1 中测试验证的第 2 步操作,经过 12 小时的测试验证,InfluxDB 运行正常,未出现 max-value-per-tag 的警告问题,磁盘和系统资源占用情况适中。


3)测试结论


本方案其实是对 InfluxDB 不适合存储具有高离散度标签的时序数据结论的一个论证,通过技术手段规避了 max-value-per-tag 问题的产生,保证了非高离散度标签的监控数据持久化及 InfluxDB 的稳定运行。


四、总结


通过以上 3 个解决方案的过程描述,造成 max-value-per-tag 问题的主要原因是由于监控指标中存在着高离散度的标签,由于 InfluxDB 不适合存储具有高离散度标签的时序数据,在实际开发过程中,遇到高离散度的标签时建议将其只作为监控指标在监控系统中进行临时性存储,而无需将其在 InfluxDB 中进行持久化存储(注:Prometheus 可以通过配置文件的配置在本地存储一定天数的监控指标,默认 15 天)。


通过对 max-value-per-tag 问题的分析,我们可以更深入的了解到指标监控及时序存储技术在监控场景中也不是万能的,它比较适用于针对固定标签的指标,并基于时间变化对其进行监控及趋势预测的场景,对于满足不了的场景,建议大家尝试一下日志监控或链路追踪,通过不同的角度去寻找最优的解决方案。


本文转载自: [DBAplus 社群](ID:dbaplus)


原文链接:Prometheus远程写入InfluxDB,遇到OOM引发的错误怎么解?

2020 年 12 月 10 日 13:00525

评论

发布
暂无评论
发现更多内容

蚂蚁二面:MQ消费端遇到瓶颈除了横向扩容外还有其他解决办法?

中间件兴趣圈

面试 RocketMQ 消息中间件

还有高仿项目吗

GitHub指北

阿里p8私藏MyBatis笔记,从入门到精通,纵享源码细节

周老师

Java 编程 程序员 架构 面试

区块链资产追踪系统解决方案,追踪“它”的来龙去脉!

源中瑞-龙先生

软件开发 区块链应用 系统开发 #资产追踪

打通Jira与钉钉和企业微信不再难

YY哥-杨勇

苹果笔记本充不进电的解决方案

石云升

电脑故障 28天写作 3月日更

源码分析-Netty: 高性能之道

程序员架构进阶

Netty RPC 源码剖析 28天写作 3月日更

避免失控:谈谈人与人交往中的恶

boshi

职场 心理 七日更

基于SpringCloud,支持安卓、IOS、包含前后端等等完整网约车项目

Java架构追梦

Java 架构 面试 SpringCloud 网约车项目

Github连夜下架!阿里新产Java全栈面试突击小册太香了

Java王路飞

Java 程序员 架构 面试 分布式

十步输出设计文档

Arvin

设计实践

《Redis 核心技术与实战》学习笔记 05

escray

redis 学习笔记 28天写作 3月日更 Redis 核心技术与实战

Github霸榜半年的阿里并发编程速成笔记究竟有什么魅力?

程序员小毕

Java 程序员 架构 面试 并发编程

2021年Java春招高级面试指南(1到5年Java面试者必备)

比伯

Java 编程 架构 面试 程序人生

Wireshark数据包分析学习笔记Day17

穿过生命散发芬芳

Wireshark 数据包分析 3月日更

2月看的9部电影和1本书

金龟换酒

电影 书籍

[TcaplusDB知识库]TcaplusDB架构描述

TcaplusDB

数据库 nosql Tcaplus

C++线程池ThreadPoolExecutor实现原理

Linux服务器开发

c++ 线程池 后端开发 Linux服务器开发 Linux后台开发

这些面试题你会吗?6年菜鸟开发面试字节跳动安卓研发岗,复习指南

欢喜学安卓

android 程序员 面试 移动开发

我在阿里实习做开源

apache/dubbo-go

微服务 程序人生 云原生 dubbo dubbogo

配置引起事故复盘

风翱

3月日更

数据库备份真的很重要!很重要!很重要!

xiezhr

oracle sql MySQL 运维 数据备份

所谓生产力

ES_her0

3月日更

一口气面了腾讯两个部门!

我是程序员小贱

3月日更

【LeetCode】逆波兰表达式求值Java题解

HQ数字卡

算法 LeetCode 28天写作 3月日更

寻找被遗忘的勇气(二十)

Changing Lin

3月日更

这份1307页Android面试全套真题解析,源码+原理+手写框架

欢喜学安卓

android 程序员 面试 移动开发

MySQL如何选择主键

架构精进之路

MySQL 3月日更

GitOps | 一种云原生的持续交付模型

xcbeyond

CI/CD gitops 3月日更

字符集与校对集概述

在即

28天写作 28天挑战 3月日更

初识Golang之调用方法

Kylin

golang新手 3月日更

演讲经验交流会|ArchSummit 上海站

演讲经验交流会|ArchSummit 上海站

Prometheus远程写入InfluxDB,遇到OOM引发的错误怎么解?-InfoQ