集中式日志分析平台
介绍
为什么要分析日志.
传统的Web开发中,日志可能并不被重视,只有应用出现问题后,才会适时性的去看一眼。而且日志的储存方式也很简单,直接写入一个文本文件或者扔到数据库中就了事了。这样对于单机应用来说没有什么不可以的,可是当系统架构分布式后,官网、论坛、社交、交易等各个大大小小的子系统越来越多,再加上操作系统、应用服务、业务逻辑等等,日志的管理与查看就越发的麻烦,面对大量的日志数据而且又是分布在各个不同的机器甚至不同的机房,如果我们还是按照传统的方式登录到某一台机器上去查看日志,然后再汇总起来,再做个跨机房的排序,那这样感觉就太糟糕了。所以一套集中式的实时日志分析平台就显得非常重要了,而一套日志分析平台至少要包括一下几个特点:
-
收集, 可以收集不同来源的日志,包括Web日志,请求日志,本地机器,跨机房机器等
-
存储,稳定的存储日志信息并索引起来
-
分析,支持各种层面的分析,而且可以以UI展示出来
-
警告,根据日志内容进行不同错误级别的报警
ELK 协议栈
其实市面上的日志分析产品很多,简单的 Rsyslog,商业化的 Splunk,开源的 Scribe,Apache 的 Flume,Cloudera 的 ELK。这里采用的是 ELK 这个体系架构,ELK(Elasticsearch, Logstash, Kibana) 经过这么多年的发展,一直到现在的 6.0.0 版本。能够发展这么快,其中肯定有他的原因所在。简单介绍一下这三个软件的特点:
-
Elasticsearch 高可用性,实时索引,拓展简单,接口友好
-
Logstash 是一个具有实时的数据收集引擎,几乎可以收集所有的数据
-
Kibana 提供分析和可视化的 Web 平台,用来查询分析以及生成各种报表
通过架构图可以看到,整体日志平台的原理其实并不难,日志的生产者作为 Shipper 产生各种各样的日志,然后传输到 Kafka 中,这里传输也是从生产者中读取然后传输通过 Logstash 到 Kafka, 再者 Logstash 通过读取 Kafka 中的日志数据,储存到 ElasticSearch。只在中间再增加了 Kafka 做为缓冲层,因为 Logstash 会同步把日志传输到 Elasticsearch,一旦 ElasticSearch 挂掉数据就有可能会丢失。于是,我们考虑利用 Kafka 作为缓冲区。
这里选择 Kafka 的原因是因为与大多数消息系统比较, Kafka 有更好的吞吐量,内置分区,副本和故障转移,这有利于处理大规模的消息,因为互联网应用日志基本上都是海量的。
基于 Docker
Docker 算是云计算时代拥有划时代意义的项目了,关于 Docker 的介绍与资料非常多。特别是 docker-compose 相当于给 Docker 插上了翅膀。Docker 相对于传统的虚拟化技术,Docker 应用运行于宿主内核,无需启动完整的操作系统,可以做到秒级、甚至毫秒级的启动时间,大大的节约了开发、测试、部署的时间。并且确保了运行环境的一致,「这段代码在我机器上没问题啊」这一些的问题再也不会出现。
环境搭建
基于 Docker 的好处还有一个就是不用去考虑环境的搭建,直接一个 Dockerfile 就可以直接搞定了,而且现在的热门开源软件,都有官方维护的镜像。这里基于docker-elk和docker-kafka这两个基础镜像制作。前者是在对 x-Pack 的支持上有问题,配置文件不足而且错误,这里进行了一些修改和调整。
x-Pack 是一个对 ELK 的补充,可以进行监控与报警功能
Docker 安装
Docker 的安装网上资源非常多,这里简单介绍一些,并且把踩过的坑填补了。Docker 的安装方式有很多种,这里建议使用官方的一键安装脚本来,避免一系列繁琐的操作。
1. 下载安装
curl -fsSLget.docker.com -oget-docker.sh
然后安装,并且选择从阿里镜像源下载:
sudo shget-docker.sh --mirrorAliyun
2. 基本配置
其实安装后基本上就可以使用了,主要是配置一些镜像源和用户组。配置镜像源的目的不多说,用户组主要是为了再使用的时候不用使用超级管理员权限即可运行。
-
加入用户组
sudo usermod -aG docker $USER
PS. 配置用户组后,可能还是会出现还是提示没有权限的情况,这时重启机器即可
-
配置镜像源
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://be62qq2e.mirror.aliyuncs.com"]
}
EOF
PS. 这里的镜像源是我自己阿里云的,同学们可以自行去阿里云获取专有镜像源地址
-
重启
sudo systemctl daemon-reload
sudo systemctl restart docker
3. 安装docker-compose
docker-compose 类似一个包管理工具,方便我们管理镜像。
curl -L https://github.com/docker/compose/releases/download/1.17.1/run.sh > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
ELK 搭建
直接从docker-elk克隆下来之后,切换到目录下,需要修改下 Kafka 的一个配置 KAFKAADVERTISEDHOST_NAME 改为你的机器IP,然后执行以下命令,漫长等待即可。
docker-compose up -d
等待提示启动完成后,访问 http://localhost:5601
,如果能够进入 Kibana 的登录界面就表示没问题了。输入帐号密码登录即可。默认帐号是 elastic 密码是 changeme 。
PS: 如果到了登录界面发现无法输入帐号密码(表单处于 disabled 状态),那么打开浏览器的开发者工具,手动把表单和提交按钮的 disable 状态去掉再输入密码即可。官方给的解决办法是在 Kibana 的配置文件中写入 Elasticsearch 的帐号密码,这样第一次可以登录,第二次又会不行。这是个神坑,在 ELK6.0.0 版本非常多人遇见,目前无解。
Docker 常用操作
贴一些 Docker 的常用操作,方便各位同学学习。
docker-compose stop 停止所有容器
docker-compose stop kafka 停止指定容器
docker-compose up -d 启动容器后台运行
docker-compose ps 查看当前容器
docker-compose logs kafka 查看指定容器日志
快速入门
Zookeeper
对于 Zookeeper 我们用一条简单的命令来测试一下:
echo ruok|nc localhost2181
你应该可以看到:
imok
Kafka
Kafka 是由 Linked 开发并且开源的一套分布式的流平台,它类似于一个消息队列。 Kafka 的优势就是适合构建实时的流数据管道,并且可靠地获取系统和应用程序之间的数据, 还可以实时的对数据流进行转换。Kafka 的使用场景很多, 特别是在需要高吞吐量的系统上。首先来理解一下 Kafka 的几个基本的概念:
-
Topic, Kafka 将消息进行分类,每一类的消息称之为一个主题(Topic).
-
Producer, 发布消息的对象称之为主题生产者(Producer)
-
Consumer, 订阅消息并处理消息的对象称之为主题消费者(Consumers)
-
Broker, 已发布的消息保存在一组服务器中,称之为Kafka集群。集群中的每一个服务器都是一个代理(Broker)。 消费者可以订阅一个或多个主题(topic),并从Broker拉数据,从而消费这些已发布的消息。
1. 创建一个主题
我们可以登录到 Kafka 容器中,做一些简单的小测试,登录到容器中的命令:
docker-composeexeckafka bash
首先来创建一个名为test的 Topic ,只有一个分区和一个备份:
kafka-topics.sh--create--zookeeper zookeeper:2181--replication-factor1--partitions1--topic test
创建好之后,可以通过运行以下命令,查看topic信息:
kafka-topics.sh--list--zookeeper zookeeper:2181
2. 发送消息
Kafka 默认有提供了一个命令行的工具用来发送消息,一行是一条消息,运行 Producer 然后输入一些信息:
kafka-console-producer.sh--broker-list localhost:9092--topic test
3. 消费消息
Kafka 也提供了一个消费消息的命令行工具,将存储的信息输出出来。
kafka-console-consumer.sh--zookeeper zookeeper:2181--topic test--from-beginning
Elasticsearch
ElasticStack 技术栈包括的三个软件,而且一开始就是 5.0 的大版本,主要目的是为了让其他的软件版本号一致,方便各个软件的对应。不过到现在已经发展到了 6.0 的版本了,我们这次就是用这个版本。具体的更新详细可以查看这里[Elasticsearch][4],这里只说说基本的概念。
Elasticsearch 之所以可以方便的进行查询过滤排序是因为和 MongoDB 一样存储的是整个文档,然后还会根据文档的内容进行索引,而且文档的格式用的还是很友好的 JSON,比如一个简单的用户对象可以这么表示:
{
"name":"Xiao Ming",
"phone":"10086",
"age":"25",
"info":{
"site":"https://sunnyshift.com"
"likes":["games","music"]
}
}
在 Elasticsearch 中有四个名词,索引(idnex)、类型(type)、文档(document)、字段(field),这四个字段类似于数据库中的数据库(database), 表(table), 行(row), 列(column), Elasticsearch 可以包含多个索引,每个索引可以包含多个类型,每个类型可以包含多个文档,每个文档可以包含多个字段,把他想成数据库就行了。
我们来简单操作一下,先来创建一个索引,并且插入几条数据:
PUT/banji/xuesheng/1
{
"name":"Xiao Ming",
"age":"12"
}
PUT/banji/xuesheng/2
{
"name":"Xiao Hong",
"age":"16"
}
具体操作可以使用 Kibana 上面的 Dev Tools 来运行命令:
有了数据之后就可以来简单的检索一下:
这里只是介绍了一下简单的入门使用,之后可以像一些其他的操作比如过滤、组合、全文、啥的都不在话下,甚至还可以高亮搜索结果。
Logstash
Logstash 是一个日志收集器,支持非常多的输入源和输出源。我们简单的整合一下 ElasticStack 这个技术栈,这里用 Nginx 的访问日志来测试一下。Logstash 最新的是有一个 Beats 的组件来收集数据,这里先不考虑而是使用传统的配置文件,我们会直接把配置写到配置文件中。
Logstash 使用一个名叫 FileWatch 的 Ruby Gem 库来监听文件变化。这个库支持 glob 展开文件路径,而且会记录一个叫 .sincedb 的数据库文件来跟踪被监听的日志文件的当前读取位置。
使用 Dcoker 后配置文件路径在 logstash/config
下,可以在该目录下放置多个配置文件,最后 Logstash 会帮我们合并成一个。先来定义一个读取 Nginx 访问日志的配置:
input{
file{
path=>["/var/log/nginx/access.log"]
type=>"accesslog"
}
}
output{
# 输出到 elasticsearch,索引名为 access-log
elasticsearch{
hosts=>"localhost:9200"
index=>"access-log"
user=>"elastic"
password=>"changeme"
}
}
要注意的是这里写的 Nginx 的路径是相对于 Logstash 容器的,所以要把该路径挂载到容器中。然后重启 Logstash 就可以去 Kibana 中查看日志了, 附上 Logstash 重启命令。如果一切正常,那么就可以去 Kibana 中日志了。
docker-compose stop logstash
docker-compose up-d logstash
Kibana
Kibana 是一个可视化的 UI 界面,并且可以检索聚合分词搜索在 Elasticsearch 中的数据,并且还可以以非常精美的图标来展示统计数据。我们需要在 Management 页面中告诉 Kibana 我们刚才创建的 access-log 索引。
到这里就完成了收集 Nginx 系统日志并展示出来,对于 Kibana 还有很多用法,就不一一撰述了。
Kafka缓冲区
在上一篇中我们基本上完成了 ELK 和 Kafka 环境的安装,并且也通过几个简单的例子入门。现在我们就把搭建好的架构中加入 Kakfa 作为缓冲区。再来说一下,首先 Logstash 从日志源读取日志并且存储到 Kafka,然后 Logstash 再从 Kafka 中读取日志存储到 Elasticsearch。所以我们需要两步骤。
Logstash -> Kafka
Logstash 会直接把日志发送给 Elasticsearch,再由 Kibana 进行展示。因为因为 Logstash 会同步把日志传输到 Elasticsearch ,一旦 ElasticSearch 挂掉数据就有可能会丢失。于是,我们考虑利用 Kafka 作为缓冲区,让 Logstash 不受 Elasticsearch 的影响,第一步就是让 Logstash 把日志发送到 Kafka,这里 Logstash 相当于 Producer。直接来看看 Logstash 的配置文件:
input{
file{
path=>["/var/log/laravel/storage/logs/*.log"]
}
}
filter{
grok{
match=>{
"message"=>"\[%{TIMESTAMP_ISO8601:logtime}\] %{WORD:env}\.%{LOGLEVEL:level}\: %{GREEDYDATA:msg}"
}
}
}
output{
kafka{
bootstrap_servers=>"kafka:9092"
topic_id=>"laravellog"
}
}
这里是用来读取 Laravel 项目的日志文件,我们在 input 和 output 中间加入了一个 filter,这是 Logstash的插件,用户格式化读取进来的数据。一般情况下,Laravel的日志文件大概是这样:
[2017-12-0517:45:07]production.ERROR:报错接口{"api":"/admin/sales"}
分为几个部分,分别是日志的记录时间,产生日志的环境,日志的级别,日志的信息以及额外数据。所以我们进行了一个格式化,最后可以让他以 JSON 的形式存储到 Elasticsearch,默认没有 filter 的情况是直接一行存储进去。格式化后的数据就是这样的(部分):
{
"msg":"接口参数 {\"params\":[]} ",
"path":"/var/log/fenyong/storage/logs/laravel-2017-12-05.log",
"level":"ERROR",
"env":"local",
"logtime":"2017-12-05 17:54:50"
}
Kafka -> Elasticsearch
利用 Logstash 从 Kafka 读取数据然后存储到 Elasticsearch,这里 Logstash 作为 Consumer,唯一需要注意的地方是要保证 Topic 的名称一致。
input{
kafka{
bootstrap_servers=>"kafka:9092"
topics=>["laravellog"]
}
}
output{
elasticsearch{
hosts=>"elasticsearch:9200"
index=>"laravellog"
user=>"elastic"
password=>"changeme"
}
}
这样我们就完成了从 Logstash 到 Kafka 再到 Elasticsearch 的日志存储,接下来就可以用 Kibana 来展示数据了。
至此,我们就成功把 Kafka 加入到日志分析平台的架构中。
监控与报警
X-Pack 简介
在 ElasticStack 出5.0之前,对于 ELK 的监控有着五花八门的解决方案,官方的插件也是各种变化,不仅名字乱而且还要一个个安装。当然,官方也考虑到了大家的疾苦,于是推出了 X-Pack 这个套件专门用来做监测。总共包含:安全,警报,监控,监控,报告,图表这五个功能,这里简单介绍下安全监控与报警。
如果是单独安装 ELK 的话是需要额外再安装X-Pack的
安全
在没有安装 X-Pack 的时候登录 Kibana 是不需要输入账号密码的。登录之后就可以看到侧边栏有一个新的 Management 菜单,点进去后有一个关于 Elasticsearch 的栏目,可以进行角色和权限的设定。
监控
监控在侧边栏的 Monitoring 面板,可以看到关于 ELasticsearch 和 Kibana 具体的信息和运行状态:
点击进去还可以通过很霸气的折线图来查看:
总共有4个标签页,其中 Indices 可以查看当前的索引情况:
报警
在 Elasticsearch 中需要我们自己设定一系列的条件,当条件满足的时候会触发相应的动作,而且还要设定监测的频率。我们这里设定一个每 10 分钟循环监测发现日志中出现 5 次数 ERROR 的情况则触发相应的动作。需要设定以下四个:
-
Trigger: 设定循环执行的时间间隔
-
Input: 设定监测的索引以及触发数据
-
Condition: 如果出现 ERROR 的次数超过 5 次,则认为触发了条件
-
Actions: 执行具体的操作
PUT _xpack/watcher/watch/log_errors
{
"metadata":{
"color":"red"
},
"trigger":{
"schedule":{
"interval":"10m"
}
},
"input":{
"search":{
"request":{
"indices":"access-log",
"body":{
"size":0,
"query":{"match":{"level":"ERROR"}}
}
}
}
},
"condition":{
"compare":{"ctx.payload.hits.total":{"gt":5}}
},
"actions":{
"email_administrator":{
"email":{
"to":"[email protected]",
"subject":"Encountered {{ctx.payload.hits.total}} errors",
"body":"Find five errors in the system",
"priority":"high"
}
}
}
}
到这里日志平台就基本搭建完成了,接下来有机会会讲讲从单机到集群的部署方式以及需要注意的地方。