之前学习了通过 ELK 进行 Nginx 的日志收集与分析,有了日志之后我们就可以通过解析日志近实时的监控服务器的访问状态了。通常 Nginx 都是作为代理服务器进行使用的,当我们的应用服务因为某些原因挂掉时,Nginx 访问就会出现频繁 502 的情况,基于这一场景我们可以进行报警来及时提醒我们去解决问题。

本篇文章主要简单介绍下基于 ELK 实现监控的过程。

一. ELK 的安装

首先是 ELK 的搭建,这里不再赘述,可以参考写过一篇文章 快速搭建一个ELK日志分析平台。

二. ElastAlert 安装与配置

1. 安装

报警组件使用的是 ElastAlert。这里 Yelp 公司使用 Python 写的一个开源组件。地址在这: ElastAlert.其可以通过两种方式安装:

  • pip 直接安装
pip install elastalert
  • 源码下载安装
git clone https://github.com/Yelp/elastalert.git
pip install "setuptools>=11.3"
python setup.py install

这里更推荐源码下载的方式安装吧,因为其源码中有各种示例代码,可以很方便的在本地参考调式。

另外为了与 ES 进行交互需要安装 elasticsearch 的包:

pip install "elasticsearch>=5.0.0"
  • 创建 ElastAlert 所需的索引

每次执行监控报警时,ElastAlert 都会生成一些元信息存储到 ES 中,这里我们手动创建索引,执行命令

elastalert-create-index

执行完该命令,会在 ES 中创建如下几个索引:

  • elastalert_status_status: 记录每次根据 rule 的查询结果,包括查询的时间段、查询结果等
  • elastalert_status: 记录告警信息,当查询完毕达到告警条件需要报警时,其报警相关的信息会存储到这里。
  • elastalert_status_error: 记录 ElastAlert 出现的错误
  • elastalert_status_silence: 表示被忽略的报警,某些报警可能和之前重复或者人为忽略后将不会实际执行的报警会被记录于此。
2. config.yaml 配置文件。

安装完成使用前首先要修改配置文件。在这里可以配置 ES 的地址,报警规则文件路径等基本的配置,下面是几个最基本的配置

# 报警规则文件夹,存放自定义的 rule 文件
rules_folder: /usr/local/elastalert/my_alert_rules

# 查询频率,这里表示每分钟查询一次 ES 索引
run_every:
  minutes: 1

# 指定 ES 主机地址
es_host: localhost

# 指定 ES 端口
es_port: 9200
3. rule 文件配置

一个 rule 文件表示一个查询报警规则。ElastAlert 支持多个 rule 文件,其将会找到 config.yaml 中配置的 rules_folder 然后执行其中的每一个 rule 文件,进行查询与报警。

【1】. 基本配置

rule 文件用来配置监控与报警规则,首先要指明对应的索引、名称、类型。

# 规则名称,每个 rule 都要执行一个名称,并且是唯一的
name: test_502_alert

# 索引名,指定要查询的索引,可以通过正则匹配
index: nginx_log_*

# 类型,frequency 表示按出现频率查询
type: frequency

# 次数,达到时报警
num_events: 50

# 时间频率,表示在一段时间内的。结合 num_events 表示在最近一分钟内如果出现超过 50 次错误则报警
timeframe:
  minutes: 1

这里采用的是 frequency 按出现次数进行查询。ElastAlert 还提供了其他查询方式,简要介绍如下:

  • any: 任何匹配都将会触发报警
  • blacklist: 黑名单,通过指定 compare_key 字段,将该字段的值与黑名单中的值比较,如果存在则触发报警
  • whitelist: 与白名单相反,其通过 compare_key 字段与白名单中的值进行比较,如果不存在和触发报警
  • change: 指定 compare_key 字段进行监控,如果该字段的值发生变化则触发报警
  • frequency: 按频率报警,当在 timeframe 时间内匹配结果出现次数达到 num_events 时则触发报警
  • flatline: 直译为水平线,其实就是这只一个 threshold 阈值,在 timeframe 是时间段内如果匹配次数达到 threshold 则触发报警
  • new_term: 当指定的 fields 中的某一个字段有新的值时就会触发报警

以上是主要的几种规则类型,更详细的内容可以参阅官方文档

对于 frequency 查询这里多说一点,因为在实际情况中我需要对多台服务器进行监控,此时必须按服务器进行次数的统计,当某一台服务器的错误频率超过 num_events 时则进行报警,这里可以通过 query_key 配置来指定

这里指定的 query_key 为 server_name.keyword。其会针对每一台服务器出现 502 的情况进行计数,当某台服务器达标时就会触发报警。
query_key: server_name.keyword
【2】匹配规则配置

基本配置完成后,就要配置查询规则了。ElastAlert 根据配置的查询规则向 ES 查询数据,如果查到的结果达到 num_events 则发送告警。

基本示例如下:

filter:
  - terms: # 多个值匹配,表示 server_name 服务器名为 ['server01', 'server02'] 之一
      server_name: ['server01', 'server02']
  - term: # 精确匹配,查询 response_code 为 502 的情况
      response_code: 502

其主要查询方式有如下几种:

query string

模糊匹配

filter:
- query:
    # 查询 username 中包含 bob 的文档
    query_string:
      query: "username: bob"
- query:
    # 查询 name 包含 tom 与 address 包含 USA 的文档
    query_string:
       query: "name: tom AND address: USA"

term

精确匹配,这里必须字段的值等于给定的值才会被查询出来。

filter:
  - term: # 精确匹配,response_code 必须为 502 的情况
      response_code: 502

也可以通过 terms 来匹配多个值。

filter:
  - terms: # name 的值为其中任何一个即可满足条件
      name: [Faker, Mlxg, Uzi]

wildcard
通配符匹配

filter:
- query:
    wildcard: # 查询 filenae 以 ngxin 开头、log 结尾的文件名
      filename: "nginx_*_log"

range

范围查询,

filter:
- range:
    status_code: # 查询状态码在 500 ~ 599 之前的文档,可以监听所有的服务器错情况
      from: 500
      to: 599

ElastAlert 的查询规则是基于 ES 的 DSL 确定的,不熟悉的同学查询 ES 的文档

【3】. 配置告警方式

ElastAlert 提供了非常多的告警方式,可以通过 email 邮件、slack、http post 请求等方式进行报警信息的发送。并且可以同时可以指定多个告警方式。这里我们指定报警方式为 email 和 post。

# 同时指定多种告警方式
alert:
 - "email"
 - "post"

指定完了告警方式,就要对各个告警方式作针对性的配置了。首先是针对 email 的配置,我们需要指明邮件服务器、收件人、邮件内容等。

# 指定邮件服务器地址和端口,
smtp_host: "smtp.sina.cn"
smtp_port: 25
# 这里是邮件服务器的校验文件,我使用是自己的新浪邮箱作为服务器,因此这里配置的是我的新浪邮箱用户名和密码
smtp_auth_file: "/usr/local/elastalert/sina_auth.yaml"

# sina_auth.yaml 文件中的配置
# user: "my@sina.cn"
# password: "mypassword"

# 邮件文本内容,参数可以用数字表示
alert_text: |
    In the past 1 minute, Cloud Application have been more than 50 times 502 exceptions on the {0} machine. Please pay attention to the status of the server in time.
    "timestamp": {1}
alert_text_args: ["host.name.keyword", "@timestamp"] # 参数值,根据索引与 text 中的参数进行匹配
alert_text_type: alert_text_only # 声明文本类型,

# 指定发件人
from_addr: "my@sina.cn"

# 指定收件人,可以指定多个
email:
  - "first@qq.com"
  - "second@gmail.com"

其次是 post 请求的配置,我这里将 post 指向了一个短信服务,每次报警都会收到短信。

# 指定请求链接
http_post_url: "http://mysite.alert.cn/api/v2/alert/"
# 指定 post 参数,这里匹配的是 ES 索引中的值
http_post_payload:
  server: host.name.keyword
  num_hits: num_hits

# 指定静态参数。
http_post_static_payload:
  response_code: 502
  service_name: mysite

这里两点需要注意下:

  • http_post_payload: 其发送的是 ES 中 elastalert_status 索引的字段值,如果没有字段则值为 None
  • http_post_static_payload: 发送的自己额外需要的不在 ES 索引中的静态参数

配置完成后,可以直接通过 python 命令运行

python -m elastalert.elastalert --verbose --rule example_rules/test.yaml
INFO:elastalert:Starting up
INFO:elastalert:Queried rule test_502_alert from 2018-08-22 13:30 UTC to 2018-08-22 13:30 UTC: 0 buckets
INFO:elastalert:Ran test_502_alert from 2018-08-22 13:30 UTC to 2018-08-22 13:30 UTC: 0 query hits (0 already seen), 0 matches, 0 alerts sent
INFO:elastalert:Sleeping for 59.794757 seconds

通过 python 命令执行有几个参数需要注意下:

  • –verbose 输出调试信息
  • –debug 只输出调试,不触发报警
  • –config 指定配置文件
  • –rule 指定规则文件

除此之外,当调试完成作为服务开始运行时,我们可以使用 Supervisor 进行服务的管理,配置文件如下:

[program:elastalert]
# workon elastalert 如果是在虚拟环境中设置则执行该命令
# running globally
user=dev
command=sudo elastalert --config /usr/local/elastalert/config.yaml
autorestart=true
startsecs=15
stderr_logfile=/var/log/supervisor/elastalert.log
stdout_logfile=/var/log/supervisor/elastalert.log

以上就是整个监控报警系统的简要搭建过程,就结果来看,在监控 20 台机器,每当某台机器在一分钟内超过 50 次 502 请求时都会在一分钟内收到报警短信,当然问题的定位还是需要自己来进行。如果可以根据错误提示做进一步的运维处理,比如自动扩容,更改机器负载将有问题的机器屏蔽等,从现在处理方式出发,想法是在对应的 post 请求中进行相应的处理,欢迎有其他建议和有兴趣的同学交流指正。