You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

226 lines
14 KiB
Markdown

2 years ago
# 15 | 如何搭建一个可靠的监控系统?
[专栏第7期](http://time.geekbang.org/column/article/15109)我给你讲解了监控系统的实现原理,先来简单回顾一下,一个监控系统的组成主要涉及四个环节:数据收集、数据传输、数据处理和数据展示。不同的监控系统实现方案,在这四个环节所使用的技术方案不同,适合的业务场景也不一样。
目前,比较流行的开源监控系统实现方案主要有两种:以[ELK](https://www.elastic.co/cn/)为代表的集中式日志解决方案,以及[Graphite](http://graphite.readthedocs.io/en/latest/index.html)、[TICK](https://www.influxdata.com/time-series-platform/)和[Prometheus](https://prometheus.io/)等为代表的时序数据库解决方案。接下来我就以这几个常见的监控系统实现方案,谈谈它们的实现原理,分别适用于什么场景,以及具体该如何做技术选型。
## ELK
ELK是Elasticsearch、Logstash、Kibana三个开源软件产品首字母的缩写它们三个通常配合使用所以被称为ELK Stack它的架构可以用下面的图片来描述。
![](https://static001.geekbang.org/resource/image/cd/9a/cd8d76c0ab3a17bf16c19f973e92bb9a.png)
(图片来源:[https://cdn-images-1.medium.com/max/1600/1\*mwSvtVy\_qGz0nTjaYbvwpw.png](https://cdn-images-1.medium.com/max/1600/1*mwSvtVy_qGz0nTjaYbvwpw.png)
这三个软件的功能也各不相同。
* Logstash负责数据收集和传输它支持动态地从各种数据源收集数据并对数据进行过滤、分析、格式化等然后存储到指定的位置。
* Elasticsearch负责数据处理它是一个开源分布式搜索和分析引擎具有可伸缩、高可靠和易管理等特点基于Apache Lucene构建能对大容量的数据进行接近实时的存储、搜索和分析操作通常被用作基础搜索引擎。
* Kibana负责数据展示也是一个开源和免费的工具通常和Elasticsearch搭配使用对其中的数据进行搜索、分析并且以图表的方式展示。
这种架构因为需要在各个服务器上部署Logstash来从不同的数据源收集数据所以比较消耗CPU和内存资源容易造成服务器性能下降因此后来又在Elasticsearch、Logstash、Kibana之外引入了Beats作为数据收集器。相比于LogstashBeats所占系统的CPU和内存几乎可以忽略不计可以安装在每台服务器上做轻量型代理从成百上千或成千上万台机器向Logstash或者直接向Elasticsearch发送数据。
其中Beats支持多种数据源主要包括
* Packetbeat用来收集网络流量数据。
* Topbeat用来收集系统、进程的CPU和内存使用情况等数据。
* Filebeat用来收集文件数据。
* Winlogbeat用来收集Windows事件日志收据。
Beats将收集到的数据发送到Logstash经过Logstash解析、过滤后再将数据发送到Elasticsearch最后由Kibana展示架构就变成下面这张图里描述的了。
![](https://static001.geekbang.org/resource/image/e6/ef/e6ebce07db63a7f0d6e4c03cb458eaef.png)
(图片来源:[https://logz.io/wp-content/uploads/2018/08/image21-1024x328.png](https://logz.io/wp-content/uploads/2018/08/image21-1024x328.png)
## Graphite
Graphite的组成主要包括三部分Carbon、Whisper、Graphite-Web它的架构可以用下图来描述。
* Carbon主要作用是接收被监控节点的连接收集各个指标的数据将这些数据写入carbon-cache并最终持久化到Whisper存储文件中去。
* Whisper一个简单的时序数据库主要作用是存储时间序列数据可以按照不同的时间粒度来存储数据比如1分钟1个点、5分钟1个点、15分钟1个点三个精度来存储监控数据。
* Graphite-Web一个Web App其主要功能绘制报表与展示即数据展示。为了保证Graphite-Web能及时绘制出图形Carbon在将数据写入Whisper存储的同时会在carbon-cache中同时写入一份数据Graphite-Web会先查询carbon-cache如果没有再查询Whisper存储。
![](https://static001.geekbang.org/resource/image/fc/11/fc78b78efe3c2cb52f478e61a9ebbc11.png)
(图片来源:[https://graphiteapp.org/img/architecture\_diagram.png](https://graphiteapp.org/img/architecture_diagram.png)
也就是说Carbon负责数据处理Whisper负责数据存储Graphite-Web负责数据展示可见Graphite自身并不包含数据采集组件但可以接入[StatsD](https://github.com/etsy/statsd)等开源数据采集组件来采集数据再传送给Carbon。
其中Carbon对写入的数据格式有一定的要求比如
```
servers.www01.cpuUsage 42 1286269200
products.snake-oil.salesPerMinute 123 1286269200
[one minute passes]
servers.www01.cpuUsageUser 44 1286269260
products.snake-oil.salesPerMinute 119 1286269260
```
其中“servers.www01.cpuUsage 42 1286269200”是“key” + 空格分隔符 + “value + 时间戳”的数据格式“servers.www01.cpuUsage”是以“.”分割的key代表具体的路径信息“42”是具体的值“1286269200”是当前的Unix时间戳。
Graphite-Web对外提供了HTTP API可以查询某个key的数据以绘图展示查询方式如下。
```
http://graphite.example.com/render?target=servers.www01.cpuUsage&
width=500&height=300&from=-24h
```
这个HTTP请求意思是查询key“servers.www01.cpuUsage”在过去24小时的数据并且要求返回500\*300大小的数据图。
除此之外Graphite-Web还支持丰富的函数比如
```
target=sumSeries(products.*.salesPerMinute)
```
代表了查询匹配规则“products.\*.salesPerMinute”的所有key的数据之和。
## TICK
TICK是Telegraf、InfluxDB、Chronograf、Kapacitor四个软件首字母的缩写是由InfluxData开发的一套开源监控工具栈因此也叫作TICK Stack它的架构可以看用下面这张图来描述。
![](https://static001.geekbang.org/resource/image/6e/35/6e5c85e68f0eff409f70f17f846d5335.png)
(图片来源:[https://2bjee8bvp8y263sjpl3xui1a-wpengine.netdna-ssl.com/wp-content/uploads/Tick-Stack-Complete.png](https://2bjee8bvp8y263sjpl3xui1a-wpengine.netdna-ssl.com/wp-content/uploads/Tick-Stack-Complete.png)
从这张图可以看出其中Telegraf负责数据收集InfluxDB负责数据存储Chronograf负责数据展示Kapacitor负责数据告警。
这里面InfluxDB对写入的数据格式要求如下。
```
<measurement>[,<tag-key>=<tag-value>...] <field-key>=<field-value>[,<field2-key>=<field2-value>...] [unix-nano-timestamp]
```
下面我用一个具体示例来说明它的格式。
```
cpu,host=serverA,region=us_west value=0.64 1434067467100293230
```
其中“cpu,host=serverA,region=us\_west value=0.64 1434067467100293230”代表了host为serverA、region为us\_west的服务器CPU的值是0.64时间戳是1434067467100293230时间精确到nano。
## Prometheus
还有一种比较有名的时间序数据库解决方案Prometheus它是一套开源的系统监控报警框架受Google的集群监控系统Borgmon启发由工作在SoundCloud的Google前员工在2012年创建后来作为社区开源项目进行开发并于2015年正式发布2016年正式加入CNCFCloud Native Computing Foundation成为受欢迎程度仅次于Kubernetes的项目它的架构可以用下图来描述。
![](https://static001.geekbang.org/resource/image/a4/71/a42d15cb006b41fecc82575b566dbc71.png)
(图片来源:[https://prometheus.io/assets/architecture.png](https://prometheus.io/assets/architecture.png)
从这张图可以看出Prometheus主要包含下面几个组件
* Prometheus Server用于拉取metrics信息并将数据存储在时间序列数据库。
* Jobs/exporters用于暴露已有的第三方服务的metrics给Prometheus Server比如StatsD、Graphite等负责数据收集。
* Pushgateway主要用于短期jobs由于这类jobs存在时间短可能在Prometheus Server来拉取metrics信息之前就消失了所以这类的jobs可以直接向Prometheus Server推送它们的metrics信息。
* Alertmanager用于数据报警。
* Prometheus web UI负责数据展示。
它的工作流程大致是:
* Prometheus Server定期从配置好的jobs或者exporters中拉取metrics信息或者接收来自Pushgateway发过来的metrics信息。
* Prometheus Server把收集到的metrics信息存储到时间序列数据库中并运行已经定义好的alert.rules向Alertmanager推送警报。
* Alertmanager根据配置文件对接收的警报进行处理发出告警。
* 通过Prometheus web UI进行可视化展示。
Prometheus存储数据也是用的时间序列数据库格式如下。
```
<metric name>{<label name>=<label value>, …}
```
比如下面这段代码代表了位于集群cluster 1上节点IP为1.1.1.1端口为80访问路径为“/a”的http请求的总数为100。
```
http_requests_total{instance="1.1.1.1:80",job="cluster1",location="/a"} 100
```
讲到这里,四种监控系统的解决方案都已经介绍完了,接下来我们对比一下这四种方案,看看如何选型。
## 选型对比
我们从监控系统的四个环节来分别对比。
**1\. 数据收集**
ELK是通过在每台服务器上部署Beats代理来采集数据Graphite本身没有收据采集组件需要配合使用开源收据采集组件比如StatsDTICK使用了Telegraf作为数据采集组件Prometheus通过jobs/exporters组件来获取StatsD等采集过来的metrics信息。
**2\. 数据传输**
ELK是Beats采集的数据传输给Logstash经过Logstash清洗后再传输给ElasticsearchGraphite是通过第三方采集组件采集的数据传输给CarbonTICK是Telegraf采集的数据传输给InfluxDB而Prometheus是Prometheus Server隔一段时间定期去从jobs/exporters拉取数据。可见前三种都是采用“推数据”的方式而Prometheus是采取拉数据的方式因此Prometheus的解决方案对服务端的侵入最小不需要在服务端部署数据采集代理。
**3\. 数据处理**
ELK可以对日志的任意字段索引适合多维度的数据查询在存储时间序列数据方面与时间序列数据库相比会有额外的性能和存储开销。除此之外时间序列数据库的几种解决方案都支持多种功能的数据查询处理功能也更强大。
* Graphite通过Graphite-Web支持正则表达式匹配、sumSeries求和、alias给监控项重新命名等函数功能同时还支持这些功能的组合比如下面这个表达式的意思是要查询所有匹配路径“stats.open.profile.\*.API.\_comments\_flow”的监控项之和并且把监控项重命名为Total QPS。
```
alias(sumSeries(stats.openapi.profile.*.API._comments_flow.total_count,"Total QPS")
```
* InfluxDB通过类似SQL语言的InfluxQL能对监控数据进行复杂操作比如查询一分钟CPU的使用率用InfluxDB实现的示例是
```
SELECT 100 - usage_idel FROM "autogen"."cpu" WHERE time > now() - 1m and "cpu"='cpu0'
```
* Prometheus通过私有的PromQL查询语言如果要和上面InfluxDB实现同样的功能PromQL语句如下看起来更加简洁。
```
100 - (node_cpu{job="node",mode="idle"}[1m])
```
**4\. 数据展示**
Graphite、TICK和Prometheus自带的展示功能都比较弱界面也不好看不过好在它们都支持[Grafana](https://grafana.com/)来做数据展示。Grafana是一个开源的仪表盘工具它支持多种数据源比如Graphite、InfluxDB、Prometheus以及Elasticsearch等。ELK采用了Kibana做数据展示Kibana包含的数据展示功能比较强大但只支持Elasticsearch而且界面展示UI效果不如Grafana美观。
## 总结
以上几种监控系统实现方式,所采用的技术均为开源的,其中:
* ELK的技术栈比较成熟应用范围也比较广除了可用作监控系统外还可以用作日志查询和分析。
* Graphite是基于时间序列数据库存储的监控系统并且提供了功能强大的各种聚合函数比如sum、average、top5等可用于监控分析而且对外提供了API也可以接入其他图形化监控系统如Grafana。
* TICK的核心在于其时间序列数据库InfluxDB的存储功能强大且支持类似SQL语言的复杂数据处理操作。
* Prometheus的独特之处在于它采用了拉数据的方式对业务影响较小同时也采用了时间序列数据库存储而且支持独有的PromQL查询语言功能强大而且简洁。
从对实时性要求角度考虑时间序列数据库的实时性要好于ELK通常可以做到10s级别内的延迟如果对实时性敏感的话建议选择时间序列数据库解决方案。
从使用的灵活性角度考虑几种时间序列数据库的监控处理功能都要比ELK更加丰富使用更灵活也更现代化。
所以如果要搭建一套新的监控系统我建议可以考虑采用Graphite、TICK或者Prometheus其中之一。不过Graphite还需要搭配数据采集系统比如StatsD或者Collectd使用而且界面展示建议使用Grafana接入Graphite的数据源它的效果要比Graphite Web本身提供的界面美观很多。TICK提供了完整的监控系统框架包括从数据采集、数据传输、数据处理再到数据展示不过在数据展示方面同样也建议用Grafana替换掉TICK默认的数据展示组件Chronograf这样展示效果更好。Prometheus因为采用拉数据的方式所以对业务的侵入性最小比较适合Docker封装好的云原生应用比如Kubernetes默认就采用了Prometheus作为监控系统。
## 思考题
通过我今天的讲解你应该知道了Graphite、TICK以及Prometheus存储监控数据都采用了时间序列数据库它们在存储和性能上有什么不同之处吗
欢迎你在留言区写下自己的思考,与我一起讨论。