轻松筹监控系统实现方案

栏目: 服务器 · 发布时间: 7年前

内容简介:轻松筹监控系统实现方案

监控系统是服务管理最重要的组成部分之一,可以帮助开发人员更好的了解服务的运行状况,及时发现异常情况。虽然阿里提供收费的业务监控服务,但是监控有很多开源的解决方案,可以尝试自建监控系统,满足基本的监控需求,以后逐步完善优化。这样既可以更灵活的满足自身业务的监控需求,也可以为以后自建机房提供技术积累。通过以下7个方面来建设监控系统。

轻松筹监控系统实现方案

1.日志打印

完善的日志是实现监控的基础,如何打印日志关系到之后的日志过滤、存储以及分析。除了选择合适的日志库,还要满足一些日志打印的要求:

- 日志风格:以key-value的field形式输出结构化的日志。

- 输出时机: error日志一定都需要打印,info日志结合业务需求适当打印,日志只需要在业务层关注,model和util等不需要打印。

- 输出格式:线上以json的格式打印日志,方便解析日志。线下为了方便查看,可以用自定义的format打印日志,线上和线下的日志格式通过etcd来控制。

- 输出内容: 每一条日志都要携带logid、method、host和level,并且根据不同业务场景,需要携带不同业务的标识field,例如projectType、platform、payType等。

- 用context来传递不同goroutine之间的共享信息。

2.日志切分

日志切分是运维层面的东西,不应该由日志库来承担日志切分的事情,因为 Linux 在日志切分上有很成熟的工具,不需要自己写码去重复实现。

目前对日志切分的需求只有2个:按天切分和删除切出来的多余日志。logrotate就能很好的满足这些需求,logrotate是基于cron来运行的,其脚本是/etc/cron.daily/logrotate,默认放在/etc/cron.daily下,每天执行一次。

有的时候程序异常或者请求激增会导致日志量暴增,有可能在短时间内打满整个磁盘。可以在logrotate的配置文件里加上maxsize来限制日志文件的大小,并且将logrotate的执行频率调高至每小时甚至每分钟,及时切分并删除超过rotate数量的日志,来防止异常情况下磁盘被打满的情况发生。

样例配置如下所示:

// logrotate config of sample

// rotate every day, and keep for 3 days

/var/log/sample.log {

daily

rotate 3

maxsize 1G

missingok

sharedscripts

postrotate

    # 在切分时向程序发送SIGHUP信号

    killall -SIGHUP bin_sample

endscript

}

业务程序只需要负责监听SIGHUP信号,收到该信号时再重新打开日志文件。

3.日志采集

从监控系统的角度来说,日志收集有2种方式:主动采集和被动接收,两种方式各有利弊。

- 主动采集

优点:日志收集和业务程序分开,互不影响。

缺点:日志收集需要依赖额外的采集服务,过滤和存储可能还需要额外配置。

- 被动接收

优点:业务程序直接将日志发送至存储,灵活性强,存储内容可在业务代码里控制。

缺点:日志存储不稳定的话会影响业务程序的正常运行;反之,日志量大的话也会压垮日志存储。

但是在建设监控系统初期,日志存储还不是很稳定的情况下,还是用主动采集的方式比较稳妥,不影响服务稳定性为主。

轻松筹监控系统实现方案

Collectd功能确实很强大,它的tail插件也能满足从文件收集日志,但是tail插件配置比较复杂而且说明文档相较于Filebeat来说不是很详细。

Collectd的其他插件可以采集的数据确实很多,而且也有插件支持将数据发送到Logstash和InfluxDB,但是多数插件的功能我们用不到,而且Elastic Stack中的Beats也能够很好的收集系统参数等数据,而且跟ELK能很好的兼容。

所以在分别试用了Filebeat和Collectd这2个采集服务后,综合上述分析决定采用Filebeat来负责从日志文件中采集日志。如下所示,Filebeat的配置简单易懂:

filebeat:

spool_size: 1024                                    # 最大可以攒够 1024 条数据一起发送出去

idle_timeout: "5s"                                  # 否则每 5 秒钟也得发送一次

registry_file: "registry"                           # 文件读取位置记录文件,会放在当前工作目录下。

config_dir: "path/to/configs/contains/many/yaml"    # 如果配置过长,可以通过目录加载方式拆分配置

prospectors:                                        # 有相同配置参数的可以归类为一个 prospector

    -

        fields:

            log_source: "sample"                    # 类似 logstash 的 add_fields,此处的"log_source"用来标识该日志来源于哪个项目

        paths:

            - /var/log/system.log                   # 指明读取文件的位置

            - /var/log/wifi.log

        include_lines: ["^ERR", "^WARN"]            # 只发送包含这些字样的日志

        exclude_lines: ["^OK"]                      # 不发送包含这些字样的日志

    -

        document_type: "apache"                     # 定义写入 ES 时的 _type 值

        ignore_older: "24h"                         # 超过 24 小时没更新内容的文件不再监听。

        scan_frequency: "10s"                       # 每 10 秒钟扫描一次目录,更新通配符匹配上的文件列表

        tail_files: false                           # 是否从文件末尾开始读取

        harvester_buffer_size: 16384                # 实际读取文件时,每次读取 16384 字节

        backoff: "1s"                               # 每 1 秒检测一次文件是否有新的一行内容需要读取

        paths:

            - "/var/log/apache/*"                   # 可以使用通配符

        exclude_files: ["/var/log/apache/error.log"]

    -

        input_type: "stdin"                         # 除了 "log",还有 "stdin"

        multiline:                                  # 多行合并

            pattern: '^[[:space:]]'

            negate: false

            match: after

output:

logstash:

hosts: ["localhost:5044"]                          # The Logstash hosts

Filebeat 发送的日志,会包含以下字段:

beat.hostname beat 运行的主机名

beat.name shipper 配置段设置的 name,如果没设置,等于 beat.hostname

@timestamp 读取到该行内容的时间

type 通过 document_type 设定的内容

input_type 来自 "log" 还是 "stdin"

source 具体的文件名全路径

offset 该行日志的起始偏移量

message 日志内容

fields 添加的其他固定字段都存在这个对象里面

4.日志过滤

轻松筹监控系统实现方案

Logstash 自2009年诞生经过多年发展,已经是很成熟并且流行的日志处理框架。Logstash使用管道方式进行日志的搜集处理和输出。有点类似*NIX系统的管道命令 input | filter | output,input 执行完了会执行 filter,然后执行 output。在 Logstash 中,包括了三个阶段:输入input → 处理filter(不是必须的)→ 输出output。每个阶段都由很多的插件配合工作,比如 file、elasticsearch、 redis 等等。每个阶段也可以指定多种方式,比如输出既可以输出到elasticsearch中,也可以指定到stdout在控制台打印。

Codec 是 Logstash 从 1.3.0 版开始新引入的概念(Codec 来自 Coder/decoder两个单词的首字母缩写)。在此之前,Logstash 只支持纯文本形式输入,然后以过滤器处理它。但现在,我们可以在输入 期处理不同类型的数据,这全是因为有 Codec 设置。所以,这里需要纠正之前的一个概念。Logstash 不只是一个 input | filter | output 的数据流,而是一个 input | decode | filter | encode | output 的数据流!Codec 就是用来 decode、encode 事件的。Codec 的引入,使得 Logstash 可以更好更方便的与其他有自定义数据格式的运维产品共存,比如 graphite、fluent、netflow、collectd,以及使用msgpack、json、edn 等通用数据格式的其他产品等。

Logstash 提供了非常多的插件(Input plugins、Output plugins、Filter plugins、Codec plugins),可以根据需求自行组合。其中 Filter 插件 Grok 是 Logstash 最重要的插件。Grok 通过正则表达式匹配日志内容,并将日志结构化,所以理论上只要正则掌握的够娴熟,就能解析任何形式的日志,非常适合用来解析第三方服务产生的非结构化日志。但是如果是自己写的服务,就没必要将日志输出成非结构的,增加写正则的负担,所以在上述日志打印一节中才规定线上的日志输出成json形式,方便 Logstash 解析,Logstash 提供 json 的 Filter 插件。

Logstash 的配置文件默认放在 /etc/logstash/conf.d 目录下,如果需要采集多个项目的日志,每个项目的 Logstash 配置可能不一样,那就会在 conf.d 里存放多个配置文件,以每个项目命名方便管理。但是这样会带来一个问题,因为 Logstash 会将所有配置文件合并为一个,即一条日志通过input进入到Logstash后,会经过每个配置文件里的filter和output插件,造成对日志错误的处理和输出。解决方式是在Filebeat的fileds配置项里增加区分不同项目的field,如果日志路径就能区分不同项目的话也可以不用额外加field,用 Filebeat 自带的source字段就可以,然后在每个项目对应的 Logstash 配置文件里通过IF标识项目,项目各自的日志进各自的配置,互不干扰。

下列配置示例是对一个sample服务产生的json日志,通过Filebeat采集,用json的Filter插件进行解析,并将结果输出到标准输出。

input {

beats {

    port => "5044"

}

}

// The filter part of this file is commented out to indicate that it is

// optional.

filter {

if [beat] and [source] =~ "sample" {

    json {

        source => "message"

    }

    ruby {

        code => "event.set('time',(Time.parse(event.get('time')).to_f*1000000).to_i)"

    }

}

}

output {

if [beat] and [source] =~ "sample" {

    stdout { codec => rubydebug }

}

}

5.日志存储

InfluxDB vs. Elasticsearch

根据 DB-ENGINES 的排名,InfluxDB和Elasticsearch在各自专攻的领域都是NO.1,InfluxDB统治Time Series DBMS,Elasticsearch制霸Search engine,关于它们的原理和使用,各自都有非常详细的文档和资料,这里就不再赘述。

在时序数据方面,InfluxDB表现强劲,Elasticsearch在主要的指标上均远落于下风:

数据写入:同时起4个进程写入8百64万条数据,Elasticsearch平均为 115,422 条/秒,InfluxDB平均 926,389 条/秒,写入速度是Elasticsearch的8倍。这种写入速度的差距随着数据量的增大保持相对一致。

轻松筹监控系统实现方案

磁盘存储:存储相同的8百64万条数据,使用默认配置的Elasticsearch需要2.1G,使用针对时序数据配置的Elasticsearch需要517MB,而InfluxDB只需要127MB,压缩率分别是前两者的16倍和4倍。

轻松筹监控系统实现方案

数据查询:在24h的数据集(8百64万条数据)里随机查询1个小时内的数据,按1分钟的时间间隔聚合,Elasticsearch和InfluxDB分别单进程执行1000次这种查询,算耗时的平均值。Elasticsearch耗时4.98ms(201次查询/秒),InfluxDB耗时1.26ms(794次查询/秒),查询速度是Elasticsearch的4倍。随着数据集的增大,查询速度之间的差距逐渐拉大,最大相差10倍之多。而且随着执行查询的进程数增加,InfluxDB的查询速度增幅显著,而且在不同数据集之间的查询速度基本一致,但是Elasticsearch增幅就不大,而且随着数据集的增大查询速度是递减的。

轻松筹监控系统实现方案

轻松筹监控系统实现方案

详细的比较说明参见 InfluxDB Markedly Outperforms Elasticsearch in Time-Series Data & Metrics Benchmark

Elasticsearch强在全文搜索,InfluxDB擅长时序数据,所以还是具体需求具体分析。如果需要保存日志并经常查询的,Elasticsearch比较合适;如果只依赖日志做状态展示,偶尔查询,InfluxDB比较合适。

轻松筹的业务各有特点,单一选择Elasticsearch或者InfluxDB都不能很好的查询日志和指标展示,所以有必要InfluxDB和Elasticsearch共存。在 Logstash 里配置2个输出,同一条日志输出2份,一份保留全部字段输出至 Elasticsearch;另一份过滤文本性的字段保留指标性的字段,然后输出至 InfluxDB。

InfluxDB如果作为Logstash的输出,有个坑需要注意,就是Logstash的InfluxDB插件支持的时间戳精度太粗,不能精确到纳秒,会导致同一个值的时间戳在插入InfluxDB的时候出现异常。因为InfluxDB用measurement名、tag集和时间戳来唯一标识一条记录。如果插入InfluxDB的一条记录与已经存在的一条记录measurement名、tag集和时间戳都相同,那么filed会是新老两条记录的集合,相同field的值会被新记录覆盖。 解决方式有2种,一种是增加一个tag来标识新记录。另一种是手动提升时间戳的精度,提升至微秒,理论上每天可以支持86,400,000,000条不重复的日志,可以很大程度避免时间戳的重叠,配置如下所示:

// 业务日志输出时时间戳格式化到微秒:2006-01-02T15:04:05.999999Z07:00



// Logstash的filter根据时间戳转换

filter {

ruby {

    code => "event.set('time',(Time.parse(event.get('time')).to_f*1000000).to_i)"

}

}

6.数据展示

Grafana vs. Kibana

轻松筹监控系统实现方案

比较Kibana和Grafana,Kibana在图表展示上没有Grafana美观,而且Grafana的配置更加简单灵活。既然在日志存储中决定InfluxDB和Elasticsearch共存,展示上就也需要Kibana和Grafana共同协作,Kibana从Elasticsearch中检索日志,Grafana从InfluxDB和Elasticsearch中获取展示数据。下面2张图片展示了Grafana在轻松筹业务监控上的应用:

轻松筹监控系统实现方案

轻松筹监控系统实现方案

7.异常报警

即使上述6个环节都建立了,如果没有报警一切都是没有意义的,因为不可能每时每刻都盯着曲线看,所以需要设置异常阈值,让监控系统定时检查,发现异常立即发送报警通知。

报警的服务有很多,但是数据展示的Grafana自带报警功能,功能也能满足我们的报警需求,而且配置简单,所以规则简单的报警可以采用Grafana的报警服务。不过Grafana的报警只支持部分数据库,分别是Graphite, Prometheus, InfluxDB 和 OpenTSDB,所以在Elasticsearch中的日志报警还需要Elastic Stack的X-Pack。

Condition

轻松筹监控系统实现方案

如上图所示,可以设置报警检查的频率,报警条件是最近的5分钟内指定指标的平均值是否大于70,如果这个条件为True则触发报警。这种报警条件还比较单一,像错误数在十分钟内超过几次才报警,当前订单数与昨天同一时间的订单数比较跌了超过百分之几就报警,控制报警通知发送的频率,等等,Grafana就不能满足了,针对这种报警规则我们自己实现了一个报警引擎,用来满足这些比较复杂的报警规则。

Notification

Grafana的报警通知只有在状态转换时才会触发,即报警状态的时候会发送告警通知,如果到恢复之前的一段时间里条件一直是满足报警条件的,Grafana不会一直发送通知,直到恢复的时候再发送一次恢复的通知。如果触发报警,Grafana支持4中通知方式:Email、Slack、Webhook 和 PagerDuty。其中Slack是国外的一种协作工具,类似钉钉,PagerDuty是一个收费的告警平台,所以可选的只剩下Email和Webhook了。下面简单的介绍如何配置Email和Webhook

Email

Grafana的邮件配置很简单,可以利用QQ企业邮箱的smtp服务来发送报警邮件,邮件内容是配置的报警,配置比较简单:

[smtp]

enabled = true

host = smtp.exmail.qq.com:465

user = alert@qingsongchou.com

password = ********

from_address = alert@qingsongchou.com

from_user = Grafana

Webhook

Webhook 就是在触发报警时,Grafana主动调用配置的http服务,以POST或者PUT方式传递json数据。这样就可以在我们自己开发的http服务里增加额外的通知方式,例如短信、微信甚至电话。

Reception

配置了报警通知,不接收不去看也是白搭。一方面我们尽量实现多种通知途径,比如邮件、微信和短信。另一方面需要项目负责人接到报警及时响应,查看问题。

Q&A

Q:针对grafana不支持的报警,你们自己实现的报警引擎是直接在grafana的基础上修改的么,还是独立于grafana呢?

A:我们用 Go 自己实现的一个报警引擎,独立于Grafana

Q:能否谈谈整个日志系统架构演变过程和走过的坑

A:这个问题个人觉得有大,不过上述分享里已经记录了一些坑,现在这个也比较初期,以后需求复杂了,遇到的问题多了,自然会促进演变了

Q:logstash 你们遇到过收集慢和丢日志的情况吗?现在你们logstash收集日志到什么规模了?

A:我们目前的日质量大概每天2亿条,高峰时候每小时2000万条左右。Logstash运行的还可以,如果后期遇到手机慢,做简单的方式是扩机器,先解决问题,再想更好的优化策略

Q:如果类似于nginx,mysql这种日志,类型增加需要解析每增加一个就要去改logstash的grok吗

A:针对常用的服务,grok已经提供了一些正则的pattern,例如你提到的nginx,mysql。目前是每增加一个就需要修改grok,后期可以实现一个ui来提高修改效率。

Q:各种服务的日志格式也不一样! 前面说是用 logstash正则匹配,为了减轻负担采用json标准,如何实现 服务的标准化日式输出?如:系统日志 nginx apache 等服务器日志!

A:Logstash的Grok插件

Q:这个lostash 日志格式转换 怎么学习

A:Logstash有很完善的文档,感兴趣的话可以参考 https://www.elastic.co/guide/e ... .html

Q:据说 logstash 比较吃内存,fluentd 作为EFK组合也经常出现,请问你们有没有做过选型呢?

A:当时选择了ELK,就没有做太多的选型了,Logstash吃内存的问题现在还不是太突出

Q:json标准结构化日志,建议是自己预先写好生成格式,那么有没有 介绍结构化日志的文章那?有没有简单易用的方式?

A:不好意思,介绍结构化日志的文章有哪些具体我也没搜集过,也不是很清楚。以前是为了查问题打日志,如果基于日志做分析,就需要根据统计的需求来决定打印哪些field

Q:日志的完整性怎么保证的?怎么知道没丢日志,或丢失了多少日志

A:Filebeat和Logstash的输出插件都有一些重试的策略,但是也免不了日志丢失。日志的完整性确实和保证日志不丢也是我们目前在尝试解决的问题

Q:请问监控系统需要考虑高可用吗?

A:肯定是要考虑高可用,当后期更多的业务依赖监控系统后,就要保证监控系统不挂,查询要快,实时监控,报警准确等


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Cypherpunks

Cypherpunks

Julian Assange、Jacob Appelbaum、Andy Müller-Maguhn、Jérémie Zimmermann / OR Books / 2012-11 / GBP 8.99

Cypherpunks are activists who advocate the widespread use of strong cryptography (writing in code) as a route to progressive change. Julian Assange, the editor-in-chief of and visionary behind WikiLea......一起来看看 《Cypherpunks》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具