Zabbix与Prometheus之间的数据集成方案

Zabbix与Prometheus之间的数据集成方案

鲍光亚

  1. 简介

随着监控目标种类的增多以及监测环境的复杂化,监控系统也越来越多样化。为了满足各方面的监控需求,一些组织机构不得不同时部署多种监控系统。在同时部署Zabbix和Prometheus两种监控系统的情形下,由于两者的数据结构以及数据处理过程存在很大差异,往往难以对这两种系统的数据进行集中统一处理。在实际情况中,两种系统往往各自独立运行,对数据的处理相应地也需要分别设计,这种数据层面的分割增加了很多额外的成本。本文介绍一种Zabbix与Prometheus之间的数据集成方案,该方案通过对Zabbix监控系统的改造实现了将数值型的Zabbix监控数据实时写入Prometheus系统中,并对该方案进行了压测。这一方案在实现Zabbix与Prometheus监控数据集中统一处理的同时提高了Zabbix监控系统的数据吞吐能力。

2. 原理架构与具体实现

Zabbix采用关系型数据库来存储监控数据,Prometheus使用由标签集构成的多维数据模型,其数据存储则使用自己的时序数据库,该时序数据库能够利用监控数据本身的特点实现很高程度的压缩,从而减少空间占用,提高IO吞吐效率。分析监控数据的表示模型会发现,Zabbix的关系型数据可以转换为Prometheus的多维数据,只不过其维度数是固定的,这种兼容性为两者的数据集成提供了基础。

在监控数据的处理机制方面,Zabbix通过其history syncer进程将监控数据写入数据库,并在需要的时候从数据库读取监控数据加载到缓存。而Prometheus则提供了远程写和远程读接口,可以接受外部系统写入或者读取数据。站在Zabbix的角度来说,通过调整history syncer进程的工作机制,将监控数据构造为Prometheus远程写请求,就可以将数据实时写入Prometheus。同样地,需要读取数据时可通过远程读接口获取。

更关键的一个因素是两者的监控数据结构。Zabbix监控值有double类型、无符号整型(uint64_t)以及3种字符串类型,Prometheus的监控值则是64位浮点数。表面上看,Zabbix中的无符号整型无法与Prometheus兼容,但是分析Prometheus时序数据库的存储结构会发现,其在处理监控值时将64位浮点数视为8个字节进行处理,相当于是无结构的字节流。这意味着Zabbix系统中的double类型、无符号整型以及长度不超过8字节的字符串,都能够正确地存储在Prometheus时序数据库中。由于Zabbix中的字符串类型的监控值难以保证长度一定在8字节以内,本方案只考虑对数值型数据的处理。

关于Zabbix本身提供的实时导出功能,虽然通过导出的文件同样能够将数据实时存储到Prometheus中,但是这一方式会增加额外的数据处理步骤。所以我们没有利用实时导出功能,而是由history syncer进程直接远程写入Prometheus。

本方案最终形成的系统架构如图1所示。其核心内容是Zabbix中的history syncer和Web API通过远程读写API来访问Prometheus TSDB。写数据的过程起源于history syncer进程所构造的history数组,其中每一个元素代表一个监控值。History syncer进程将该数组构造成ProtoBuf消息,其中融合了标签信息。然后ProtoBuf消息经过序列化和snappy压缩,最终传输到Prometheus接口。读取数据的过程则由history syncer进程或者Web API来执行,它们先构造查询消息,然后进行序列化和压缩并发送到Prometheus的远程读接口,随后得到Promehteus的响应消息再进行解析。

图1. 数据集成的系统架构

      在具体实现过程中需要解决整数与浮点数的转换问题。在Zabbix 的C语言部分,因为它本身就是使用union结构来表示不同类型的监控值,所以在存储监控数据时可以很容易地将整数转换为浮点数,反过来在查询数据时也能够很容易地将浮点数转换为整数。

       此外,这一方案还需要为监控项选取标签集,由于标签集数据最终来源于数据库,并且可能会动态变化,所以标签集的选取关系到数据库的负载,进而一定程度上影响系统性能。在构造Prometheus远程写请求时每个监控值都需要附带标签信息,在数据流量很大时对标签信息的读取相应地也会非常频繁,如果每次都从数据库读取显然是不合适的,合适的选择是设计一个标签信息缓存。在标签信息的缓存设计中,该方案采用了以itemid为主键的哈希表结构,以达到稳定的查询效率,它不会因数据规模的增加而降低查询速度。缓存的淘汰策略为按照年龄淘汰,当超过一定时间长度没有访问时就淘汰。一般来说每个监控项的元数据都会按照一定的频率读取,长时间未读取往往意味着该监控项已经删除。

      在Zabbix访问Prometheus远程读写接口时,由于该接口只接受snappy压缩的ProtoBuf消息,所以每个请求都需要经过ProtoBuf消息的序列化以及随后的snappy压缩过程。虽然history syncer进程以批量方式将多个监控值打包成一个请求,但是在流量大时仍然会导致大量请求,这可能构成影响性能的一个重要因素。

      为了快速构造远程请求,我们创建了一个能够容纳1000个监控值的ProtoBuf消息数组作为对象池,每次构造请求都使用这个数组。其具体结构如图2所示,它由3段连续的内存区域构成,并且每一段的长度不变。该结构在进程启动时创建,并在整个生命周期中保持存活,这带来的好处是避免了频繁创建和销毁ProtoBuf消息对象。

图2. ProtoBuf消息对象数组结构

      在访问Prometheus远程API时,本方案利用了libcurl库所提供的连接池机制,重复利用连接,以避免频繁创建和销毁连接。最后,在整个改造过程中该方案保持了Zabbix系统的多进程扩展能力,必要时可以通过启动更多进程来提高性能。

        压测过程中,我们分别在10k和20k流量(NVPS,New Values Per Second)下对系统负载进行了观察。总体表现的情况如表1所示,可以看到在启动20个history syncer进程的情况下其繁忙率是很低的。无论是在10k还是20k的流量下,繁忙率均基本保持在5%以下。这里Prometheus的响应时间写的是100毫秒以下是因为它的最小统计口径就是100毫秒,实际的响应时间应该远小于这个值。此外,如果观察Zabbix的其他进程会发现,即使在20k流量的情况下Zabbix各进程的繁忙率也很低,相对高一点的是trapper进程和预处理manager进程,但是也不超过2%。

表1. 压测指标数据

3. 适用场景

该方案给用户带来两方面的收益:一方面实现了Zabbix和Prometheus监控数据的集中统一处理,从而能够降低监控数据处理系统的复杂度;另一方面能够提升Zabbix监控系统的数据处理能力。在这一架构下,Zabbix可以作为Prometheus的一个主动数据源而存在,相当于将Zabbix系统嵌入到了Prometheus中。这一方案适用于同时部署了Zabbix和Prometheus两种监控系统的用户。

4. 部署

      该方案所构建的系统本质上是对Zabbix监控系统的改造,使之能够使用Prometheus作为自己的远程存储。这相当于由Prometheus分担了Zabbix本地数据库的IO负载,从而大幅度降低了Zabbix原有数据库的压力,通过这一方式突破了Zabbix的数据处理能力瓶颈(Zabbix的数据处理能力瓶颈往往发生在数据库IO方面)。在进行系统部署时要求Zabbix节点能够访问Prometheus远程API。为了获得最佳性能表现,可以考虑将Prometheus API部署在Zabbix本地节点。

5. 注意事项

本方案表明,利用Prometheus TSDB来存储Zabbix系统的数值型监控数据是可行的,并且性能表现优异。不过,这一方案也搁置了一些问题没有处理,包括文本数据的存储,events数据的存储。

另外也没有存储trends数据,这是考虑到Prometheus可以通过recording规则对明细数据进行加工,并且Prometheus TSDB的空间占用很小,从而能够保存更长时间的明细数据。

  • 16
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值