Prometheus VS InfluxDB

前言

除了传统的监控系统如 Nagios,Zabbix,Sensu 以外,基于时间序列数据库的监控系统随着微服务的兴起越来越受欢迎,比如 Prometheus,比如 InfluxDB。gtt 也尝试了一下这两个系统,希望能找到两者的差别,为以后选型提供一些帮助。

首先,说道时间序列数据库不得不说老牌的 rrdtools 和 graphite,这些经典老系统工作的非常好,除了有人嫌弃它们在巨大规模情景下不 scale,嫌弃它们部署不方便外。于是有了 OpenTSDB,Prometheus,InfluxDB 等这些后起之秀。

监控系统

OpenTSDB

OpenTSDB:基于 Hadoop and HBase 的时间序列数据库,它最先提出了为 metric 增加 tag(key-value 键值对) 的方法来实现更方便和强大的查询语法,InfluxDB 的设计和查询语法受它的启发很大。OpenTSDB 基于 Hadoop 和 HBase 的实现了变态的横向扩展能力,但是也因为这两个依赖,对于不熟悉 Hadoop 这套系统的团队来说,OpenTSDB 的维护成本很高,于是有人搞出了 InfluxDB。

InfluxDB

InfluxDB:InfluxData 公司使用 golang 实现的时间序列数据库,InfluxDB 的口号之一就是:From the ground up,没有任何外部依赖,就一个可执行文件,丢到服务器上就可以运行,对运维非常之友好。语法的设计很大程度受到 OpenTSDB 的启发。虽然项目初期标榜了自带集群功能,可以非常轻松地实现横向扩展,但是在在 InfluxDB 1.0 之后集群功能被删除,取而代之的是通过 Relay 模式实现高可用,官方文档上挂出如下说明,但是0.9版本的集群使用说明在官网上仍然能访问到,估计未来被删除的可能性非常大

Note: Clustering is now a commerial product called InfluxEnterprise. More information can be found here.

Prometheus

Prometheus:SoundCloud 开源的监控系统,已经提交给开源社区独立运营。并且和 k8s 一样都为Cloud Native Computing Foundation 的成员,虽然目前这个 Foundation 只有 k8s 和 Prometheus 两个项目。Prometheus 和上面两者最大的区别可以理解成:上面两者仅仅是数据库,而 Prometheus 是一个监控系统,它不仅仅包含了时间序列数据库,还有全套的抓取、检索、绘图、报警的功能。官方也对这种区别做了详细的描述

它很大程度收到了 Google 内部的 Borgmon 系统的启发,基于拉(pull)模式实现的监控系统。在《Site Reliability Engineering》一书中有这句话提到 Prometheus,当然我不会告诉你原文其实还提到了 Bosun 和 Riemann 这两个监控系统,这是为什么这面这句话末尾有个省略号:

Even though Borgmon remains internal to Google, the idea of treating time-series data as a data source for generating alerts is now accessible to everyone through those open source tools like Prometheus […]»
— Site Reliability Engineering: How Google Runs Production Systems (O’Reilly Media)

不过 InfluxData 公司也推出了整套的围绕时间序列数据库的解决方案:TICK,功能覆盖了数据获取(Telegraf )、存储和查询(InfluxDB)、图表绘制(Chronograf )、报警(Kapacitor )。这套解决方案和 Elastic 公司的做法特别像:围绕着 ElasticSearch 核心功能,收购了 Logstash,Kibana,又搞出了了 Beat、Watcher 等外围服务打造完整的功能完备的全文检索解决方案。

扯得有点远,回到文章的核心内容:InfluxDB 和 Prometheus 的区别是啥。目前主要区别在于:前者仅仅是一个数据库,它被动的接受客户的数据插入和查询请求。而后者是完整的监控系统,能抓取数据、查询数据、报警等功能。

Push vs Pull

到此,我们知道 Prometheus 是基于 pull 的,InfluxDB 是基于 push 的。关于 push 和 pull 之前写过 ansible 和 puppet 的对比,但是在监控系统上,又有了微妙的差别。

首先,Push 和 Pull 描述的是数据传输的方式,它不影响传输的内容。换言之,只要是 push 能够携带的信息,pull 肯定也能携带同样的信息,比如 ”CPU 利用率 30%“ 这样的监控数据,不管是 pull 还是 push,传输的内容还是这些,不会因为传输模式改变导致消息体积暴长,因此两种方式消耗的网络带宽不会差别很大。

gtt 认为 Push 和 Pull 的主要区别在:

发起者不同

pull 的发起人是监控系统,它依次轮询被监控目标,所以如果目标在防火墙内或者 NAT 之后,则 Pull 方式行不通。并且,对于批处理(batch)类型的任务,因为可能整个处理时间小于轮询的间隔时间,因此监控系统会捕捉不到这类任务的数据。

为了解决这两个问题 Prometheus 提供了 pushgateway_exporter 组件来支持 push 模式的监控需求。

push 要求发起人是被监控目标,所以它可以突破防火墙限制,即使目标躲在 NAT 之后,仍然能顺利将数据推送出来,对于批处理类型的任务也能比较从容的发出数据。

另外,有人说“push 模式下监控系统是单点,会有单点故障和性能瓶颈而 pull 模式则没有。”

这里 gtt 不同意,因为 pull 解决单点故障的方法是增加另外一个监控系统,本质上是是通过数据冗余提高可靠性,那么 push 为什么不能推送到两个监控系统上呢,这样也能做到数据冗余。

对于性能瓶颈,这点更不成立,因为不管是 push 还是 pull,影响的只是传输方式,对传输的数据内容没有影响,占用的带宽是一样的。那么唯一区别是并发度可能不一样,push 模式下,目标服务可能在某个时间内集中向监控系统推送数据,导致瞬间并发请求很大,类似 DDos 攻击。相反地,pull 以此轮询目标服务,能够按照自己能够承受的并发度处理监控数据,避免了监控数据短时间内爆发的情况。但解决办法也有,在 push 模式下,给监控服务加上请求处理队列,超过监控系统负载的请求暂存在队列中,这样监控系统就能按照自己的节奏来处理数据,防止被队友给DDos。

所以单点问题、性能问题不是两种模式的本质区别。

逻辑架构不同

push 要求被监控目标知道监控系统的地址(IP或者域名),所以这部分信息需要设置在目标服务中,换言之,目标服务依赖监控系统。监控系统如果地址改变,所有目标服务都需要做相应的改动。而一旦产生依赖意味着监控系统故障,可能会影响到目标服务正常运行,当然在编程时可以做一些规避,但是逻辑上仍然是目标服务依赖监控系统。架构图下图所示:

监控系统

pull 要求监控系统知道所有目标服务的地址,目标服务对监控系统是不知情的。所以监控系统依赖目标服务,每次新增加一个目标服务,对监控系统做配置修改。从这点区别上看,pull 模式更加符合逻辑架构。为了自动化处理目标服务的增加和删除,Prometheus 支持从服务发现系统中动态获取目标服务的地址,省去了大规划微服务部署情况下复杂的配置需求。逻辑架构如下图所示:

监控系统 (2)

鸡贼的人应该发现了,那岂不是服务发现系统被所有目标服务依赖了?是的,服务发现系统和监控系统在逻辑架构上处于不同地位,在有服务发现的架构中,如果目标服务没有被“发现”,它实际上是不能正常提供服务的,所以必须依赖服务发现系统,而相反,目标服务在没有监控系统的情况下仍然可以正常运行。逻辑架构如下图所示:

监控系统 (3)

因为不依赖监控系统,即使没有部署监控服务,人工判断目标服务是否正常也非常容易,只要模拟监控系统访问目标服务的某个接口即可,所以 pull 模式下的监控更向白盒,你可以很轻松的获取到所有信息。相反的,push 模式依赖于一个成型的监控服务,没有监控服务就完全不知道目标服务运行状况如何,这点比较让人难以接受。

查询语法

到此,我们知道 Prometheus 是基于 pull 模式获取数据,InfluxDB 是基于 push 模式获取数据。现在关注两者在数据查询上的区别。

比如获取磁盘 IO 时间的数据:

时间戳           metric: 值  tag
1475216224 disk_io_time:10  type="sda" 
1475216224 disk_io_time: 30 type="sdb"
1475216224 disk_io_time: 11 type="sdc"
1475216224 disk_io_time: 18 type="sde"

基本查询

作为基本的时间序列数据库,两者对数据的基本获取都很简单。

InfluxDB:

SELECT mean("value") FROM "disk_io_time" WHERE $timeFilter GROUP BY time($interval), "instance" fill(null)

Prometheus:

disk_io_time

基本的算数计算

两者的差别也不大:

InfluxDB:

SELECT mean("value") *1024 FROM "disk_io_time" WHERE $timeFilter GROUP BY time($interval), "instance" fill(null)

Prometheus:

disk_io_time*1024

计算速度

InfluxDB:

SELECT derivative(mean("value"), 10s) *1024 FROM "disk_io_time" WHERE $timeFilter GROUP BY time($interval), "instance" fill(null)

Prometheus:

rate(disk_io_time)*1024

维度之间的计算

这点是目前为止 gtt 发现的两者最大区别。比如我需要 sda 和 sdc 的 io 时间相加,InfluxDB 还不支持这样的语法,不过社区已经在讨论相关的实现了:[feature request] Mathematics across measurements #3552

而 Prometheus 能够完成这个任务:

rate(disk_io_time{type="sda"}) + rate(disk_io_time{type="sdc"})

总结

整体比较下来,Prometheus 是一个靠谱的监控系统,它的设计深受到 Google 内部 Borgmon 系统的启发,并且有着优雅的查询语法,不过是基于拉(pull)模式的,需要在具体业务中做抉择。而 InfluxDB 仅仅是时间序列数据库,没有其他监控相关的功能,不过 InfluxData 公司还提供了配套的其他组件可供选择。于 Prometheus 相比,它的查询语法更加复杂,并且不支持维度之间的计算。

发表评论

电子邮件地址不会被公开。 必填项已用*标注