我尝试同时使用监视系统Prometheus和TICK Stack
这篇文章是Nifty集团2018年Advent Calendar第21天的文章。
昨天是@megmism先生的“在移动设备环境下进行JavaScript注入”的主题。
首先
我们公司的服务器监控会针对不同的服务选择使用munin或zabbix等工具,但有一些系统监控已经使用了10年了。
为了替换这些系统,今年开始我们引入了Prometheus,并进行试运行。
由于我个人在家里使用TICK Stack来监视我的服务器,所以我想比较一下这两者。请注意,本文不会涉及详细的设置步骤,请参考其他文章。
简而言之
普罗米修斯

Prometheus是受到Google内部监控系统Borgmon的启发而开发的监控系统。
据说最初是由SoundCloud公司开发的,但到2018年12月,它已成为Cloud Native Computing Foundation的子项目。
成为核心的Prometheus服务器
-
- データ収集
-
- データ保存
-
- アラート発報
- クエリ応答
它担负着主要功能,并采用了从监控目标服务器上安装的代理(exporter)拉取数据的拉取模型。
蜘蛛栈

TICK Stack是一个以InfluxDB作为核心的时序数据库分析系统。它也被用于传感器数据的收集和分析等。虽然与Prometheus的架构相似,但在以下几个方面有所不同。
-
- エージェント(Telegraf)からInfluxDBにデータを送信するPush型
- アラートはデータ処理エージェント(Kapacitor)が全て担う
图表显示我们使用Chronograf,不过也可以使用Grafana。
查询和数据模型
我来获取一下 CPU 的值。
普罗米修斯(键值+自定义查询)
在Prometheus中收集的数据大致上是一个带有时间戳和标签的键值对模型。
在查询时,会使用以下类似的自定义查询语言(PromQL)进行计算。
# 1分間のCPU使用率(全コア平均)
1 - avg(rate(cpu_user_seconds_total{instance="hoge", mode="idle"}[1m]))
由于通常以累计值的形式呈现,因此在导出数据中,没有使用rate()函数无法得出使用率的差异。
仅仅计算CPU使用率就需要额外的计算,并且由于使用了专有查询语言,需要熟悉才能熟练应用。
而且由于在Grafana的图表定义中也使用了这个查询,所以每次显示都会进行计算。
因此,与TICK Stack相比,查询负载更高。
当在Grafana中扩大显示时间段时,CPU使用率有可能达到100%,给运营带来困扰。
这方面可能需要通过Recording Rules进行预先计算来进行调整。
TICK Stack translates to:
TICK 技术栈 (TICK
中央处理器
TICK Stack是类似于在关系数据库管理系统的表中添加了时间戳和标签的形式。与Prometheus不同的是,它返回的是CPU使用率的百分比值。
# 1分間のuser CPU使用率
SELECT 100 - mean(cpu_idle) FROM cpu WHERE host = "hoge" and cpu = "cpu-total" GROUP BY time(1m)
除了查询中出现time()以外,基本上就是SQL了。
根据到目前为止的观察,从可读性和需要计算的部分来看,TICK似乎更容易阅读,负载也较轻。
实际上,在监控5至6台服务器的家庭环境中,使用树莓派运行TICK Stack也完全没有问题。
警报
警报管理问题
在中国当地进行本地化翻译时,只需要一种选项:
对于监控的核心功能——警报功能,我们该怎么办呢?
我所在的团队处理大约500个虚拟机实例,并且在某些区域采用了100个实例规模的冗余配置。
因此,如果不适当地进行控制,有可能被警报的大雨淹没而错过所需的警报。
至少,以下功能似乎是必要的。
-
- 抑制第一次响起的警报
-
- 只有持续一段时间才会触发警报
-
- 根据警报的级别和服务类型来调整发送给特定的责任人
- 将同一服务的警报进行整合
普罗米修斯
- alert:
expr: 1 - avg by (instance) (rate(cpu_user_seconds_total{instance="hoge", mode="idle"}[1m])) * 100 > 90
for: 10m
labels:
serverity: critical
annotations:
identifier: '{{ $labels.host }}'
description: 'CPU usage over 90%'
Prometheus的警报触发条件会在配置文件(prometheus.yml)中进行设置。
在上述示例中,我们指定当每台主机的平均CPU使用率超过90%时,警报将触发。
通过设置for:10m,我们可以指定警报的持续时间,已满足第二个要求。
顺便一提,我们还创建了要显示在警报中的消息。
route:
group: wait: 1m // 初回アラートの待機時間
group_interval: 5m // (group_byした中で)状態変化があった場合の次回アラート待機時間
repeat_interval: 1d // (group_byした中で)状態変化がなかった場合の次回アラート待機時間
group_by: [ 'alertname', 'group' ]
receiver: team-default
routes:
- match:
group: frontend
receiver: team-frontend
- match:
group: backend
receiver: team-backend
receivers:
- name: team-default
slack_configs:
- channel: 'general'
- name: team-frontend
slack_configs:
- channel: 'team_frontend'
- name: team-backend
slack_configs:
- channel: 'team_backend'
在Prometheus中,AlertManager负责控制触发的警报。
通过设置group_by,可以将警报按特定的标签进行分组。
通过进行分组,可以将多个警报合并为一个警报。
即使每台服务器的警报触发时间存在偏差,也可以通过调整group_wait和group_interval的值来进行适应。
此外,在routes设置中,可以根据标签将警报目标进行分配。

这是一个在我们公司环境下投入Slack的警报示例。你可以看到多个警报被整理到一条消息中。
(Slack警报的模板是根据以下文章进行参考和部分修改的。另外,为了保密,我们屏蔽了主机名)
https://medium.com/quiq-blog/better-slack-alerts-from-prometheus-49125c8c672b
在Prometheus中,我们已经满足了必要的要求。
大数据技术栈
var base = stream
|from()
.measurement('cpu')
.groupBy('host')
base
|where(lambda: "group" == 'frontend')
|alert()
.id('{{ index .Tags "host" }}')
.crit(lambda: "usage_user" > 90)
.message('{{ .ID }} is {{ .Level }} host: {{{ index .Tags "host" }})
.stateChangesOnly()
.slack()
.channel('#team_frontend')
base
|where(lambda: "group" == 'backend')
|alert()
.id('{{ index .Tags "host" }}')
.crit(lambda: "usage_user" > 90)
.message('{{ .ID }} is {{ .Level }} host: {{{ index .Tags "host" }})
.stateChangesOnly()
.slack()
.channel('#team_backend')
在TICK Stack中,你可以在Chronograf的Web界面上定义流处理代理Kapacitor的处理内容。对于那些接触过Reactive Extensions或其他流处理系统的人来说,可能会更容易理解。
通过指定stateChangesOnly(),只有在警报级别发生变化时才会发送通知。
分配是通过在基本对象中共享设置,并通过where过滤器进行分配。
然而,由于警报条件和消息定义几乎完全相同,因此并不理想。
同时,无法编写符合2、4要求的脚本…
尽管没有像Prometheus那样的分组功能,但Slack警报是以以下方式提供的。

总结
在进行查询和可视化方面,TICK Stack更易于使用,但在具有多台服务器的环境下,Prometheus在警报管理方面更胜一筹。
当在规模达到数百台的环境中进行监视时,使用TICK Stack可能会变得困难。
然而,在台数较少的环境中,使用GUI轻松进行设置的TICK Stack更容易操作。
因此,公司将继续在公司使用Prometheus,在家中使用TICK Stack的环境。
明天会有@hicka04的”【Swift】利用UISplitViewController实现iPhone和iPad的共用UI代码”。敬请期待!