做为中国最大的在线教育站点,目前沪江日志服务的用户包含沪江网校,交易,金融,CCtalk(直播平台) 等多个部门的多个产品的日志搜索分析业务,每日产生的各种日志有好十几种,天天处理约10亿条(1TB)日志,热数据保留最近7天数据,冷数据永久保存。html
首先,什么是日志? 日志就是程序产生的,遵循必定格式(一般包含时间戳)的文本数据node
一般日志由服务器生成,输出到不一样的文件中,通常会有系统日志、 应用日志、安全日志。这些日志分散地存储在不一样的机器上。nginx
一般当系统发生故障时,工程师须要登陆到各个服务器上,使用 grep / sed / awk 等 Linux 脚本工具去日志里查找故障缘由。在没有日志系统的状况下,首先须要定位处理请求的服务器,若是这台服务器部署了多个实例,则须要去每一个应用实例的日志目录下去找日志文件。每一个应用实例还会设置日志滚动策略(如:天天生成一个文件),还有日志压缩归档策略等。json
这样一系列流程下来,对于咱们排查故障以及及时找到故障缘由,形成了比较大的麻烦。所以,若是咱们能把这些日志集中管理,并提供集中检索功能,不只能够提升诊断的效率,同时对系统状况有个全面的理解,避免过后救火的被动。浏览器
我认为,日志数据在如下几方面具备很是重要的做用:安全
针对这些问题,为了提供分布式的实时日志搜集和分析的监控系统,咱们采用了业界通用的日志数据管理解决方案 - 它主要包括 Elasticsearch 、 Logstash 和 Kibana 三个系统。一般,业界把这套方案简称为ELK,取三个系统的首字母,可是咱们实践以后将其进一步优化为EFK,F表明Filebeat,用以解决Logstash致使的问题。下面,咱们展开详细介绍。服务器
文中涉及的 ELK stack 版本是:网络
Elasticsearch 5.2.2 Logstash 5.2.2 Kibana 5.2.2 Filebeat 5.2.2 Kafka 2.10
Logstash :数据收集处理引擎。支持动态的从各类数据源搜集数据,并对数据进行过滤、分析、丰富、统一格式等操做,而后存储以供后续使用。架构
Kibana :可视化化平台。它可以搜索、展现存储在 Elasticsearch 中索引数据。使用它能够很方便的用图表、表格、地图展现和分析数据。并发
Elasticsearch :分布式搜索引擎。具备高可伸缩、高可靠、易管理等特色。能够用于全文检索、结构化检索和分析,并能将这三者结合起来。Elasticsearch 基于 Lucene 开发,如今使用最广的开源搜索引擎之一,Wikipedia 、StackOverflow、Github 等都基于它来构建本身的搜索引擎。
Filebeat :轻量级数据收集引擎。基于原先 Logstash-fowarder 的源码改造出来。换句话说:Filebeat就是新版的 Logstash-fowarder,也会是 ELK Stack 在 shipper 端的第一选择。
既然要谈 ELK 在沪江系统中的应用,那么 ELK 架构就不得不谈。本次分享主要列举咱们曾经用过的 ELK 架构,并讨论各类架构所适合的场景和优劣供你们参考
这种架构下咱们把 Logstash 实例与 Elasticsearch 实例直接相连。Logstash 实例直接经过 Input 插件读取数据源数据(好比 Java 日志, Nginx 日志等),通过 Filter 插件进行过滤日志,最后经过 Output 插件将数据写入到 ElasticSearch 实例中。
这个阶段,日志的收集、过滤、输出等功能,主要由这三个核心组件组成 Input 、Filter、Output
Input:输入,输入数据能够是 File 、 Stdin(直接从控制台输入) 、TCP、Syslog 、Redis 、Collectd 等
Filter:过滤,将日志输出成咱们想要的格式。Logstash 存在丰富的过滤插件:Grok 正则捕获、时间处理、JSON 编解码、数据修改 Mutate 。Grok 是 Logstash 中最重要的插件,强烈建议每一个人都要使用 Grok Debugger 来调试本身的 Grok 表达式
grok { match => ["message", "(?m)\[%{LOGLEVEL:level}\] \[%{TIMESTAMP_ISO8601:timestamp}\] \[%{DATA:logger}\] \[%{DATA:threadId}\] \[%{DATA:requestId}\] %{GREEDYDATA:msgRawData}"] }
Output:输出,输出目标能够是 Stdout (直接从控制台输出)、Elasticsearch 、Redis 、TCP 、File 等
这是最简单的一种ELK架构方式,Logstash 实例直接与 Elasticsearch 实例链接。优势是搭建简单,易于上手。建议供初学者学习与参考,不能用于线上的环境。
这种架构下咱们采用多个 Elasticsearch 节点组成 Elasticsearch 集群,因为 Logstash 与 Elasticsearch 采用集群模式运行,集群模式能够避免单实例压力太重的问题,同时在线上各个服务器上部署 Logstash Agent,来知足数据量不大且可靠性不强的场景。
数据收集端:每台服务器上面部署 Logstash Shipper Agent 来收集当前服务器上日志,日志通过 Logstash Shipper 中 Input插件、Filter插件、Output 插件传输到 Elasticsearch 集群
数据存储与搜索:Elasticsearch 配置默认便可知足,同时咱们看数据重要性来决定是否添加副本,若是须要的话,最多一个副本便可
数据展现:Kibana 能够根据 Elasticsearch 的数据来作各类各样的图表来直观的展现业务实时情况
这种架构使用场景很是有限,主要存在如下两个问题
这个架构相对上个版本略微复杂,不过维护起来一样比较方便,同时能够知足数据量不大且可靠性不强的业务使用。
该场景下面,多个数据首先经过 Lostash Shipper Agent 来收集数据,而后通过 Output 插件将数据投递到 Kafka 集群中,这样当遇到 Logstash 接收数据的能力超过 Elasticsearch 集群处理能力的时候,就能够经过队列就能起到削峰填谷的做用, Elasticsearch 集群就不存在丢失数据的问题。
目前业界在日志服务场景中,使用比较多的两种消息队列为 :Kafka VS Redis。尽管 ELK Stack 官网建议使用 Redis 来作消息队列,可是咱们建议采用 Kafka 。主要从下面两个方面考虑:
数据丢失:Redis 队列多用于实时性较高的消息推送,并不保证可靠。Kafka保证可靠但有点延时。
数据堆积:Redis 队列容量取决于机器内存大小,若是超过设置的Max memory,数据就会抛弃。Kafka 的堆积能力取决于机器硬盘大小。
综合上述的理由,咱们决定采用 Kafka 来缓冲队列。不过在这种架构下仍然存在一系列问题
这种架构适合较大集群的应用部署,经过消息队列解决了消息丢失、网络堵塞的问题。
随着沪江业务的飞速增加,单机房的架构已经不能知足需求。不可避免的,沪江的业务须要分布到不一样机房中,对于日志服务来讲也是不小的挑战。固然业界也有很多成熟的方法,好比阿里的单元化、腾讯的 SET 方案等等。单元化在这边不详细展开,你们能够参考微博的【单元化架构】。
最终咱们决定采用单元化部署的方式来解决 ELK 多机房中遇到的问题(延时、专线流量过大等),从日志的产生、收集、传输、存储、展现都是在同机房里面闭环消化,不存在跨机房传输与调用的问题。由于交互紧密的应用尽可能部署在同机房,因此这种方案并不会给业务查询形成困扰。
Logstash、Elasticsearch、Kafka、Kibana 四个集群都部署到同一机房中,每一个机房都要每一个机房本身的日志服务集群,好比A机房业务的日志只能传输给本机房 Kafka ,而A机房 Indexer 集群消费并写入到A机房 Elasticsearch 集群中,并由A机房 Kibana 集群展现,中间任何一个步骤不依赖B机房任何服务。
Filebeat 是基于原先 logstash-forwarder 的源码改造出来的,无需依赖 Java 环境就能运行,安装包10M不到。
若是日志的量很大,Logstash 会遇到资源占用高的问题,为解决这个问题,咱们引入了Filebeat。Filebeat 是基于 logstash-forwarder 的源码改造而成,用 Golang 编写,无需依赖 Java 环境,效率高,占用内存和 CPU 比较少,很是适合做为 Agent 跑在服务器上。
下面看看Filebeat的基本用法。编写配置文件,从 Nginx access.log 中解析日志数据:
# filebeat.yml filebeat.prospectors: - input_type: log paths: /var/log/nginx/access.log json.message_key: output.elasticsearch: hosts: ["localhost"] index: "filebeat-nginx-%{+yyyy.MM.dd}"
咱们来看看压测数据:
Logstash / Filebeat 读取 350W 条日志 到 console,单行数据 580B,8个进程写入采集文件
项目 | workers | cpu usr | 总共耗时 | 收集速度 |
---|---|---|---|---|
Logstash | 8 | 53.7% | 210s | 1.6w line/s |
Filebeat | 8 | 38.0% | 30s | 11w line/s |
Filebeat 所消耗的CPU只有 Logstash 的70%,但收集速度为 Logstash 的7倍。从咱们的应用实践来看,Filebeat 确实用较低的成本和稳定的服务质量,解决了 Logstash 的资源消耗问题。
最后,分享给你们一些血泪教训,但愿你们以我为鉴。
忽然有一天监控发现日志不消费了,排查下来发现消费 Kafka 数据的 indexer 挂掉了。因此,Indexer 进程也是须要用 supervisor 来监控的,保证它时刻都在运行。
开始咱们在经过 grok 切割日志的时候,发现 Java 的 Exception 日志输出以后,会出现换行的问题。后来使用 Logstash codec/multiline 插件来解决。
input { stdin { codec => multiline { pattern => "^\[" negate => true what => "previous" } } }
Logstash 2.3版本 date插件配置以下,查看解析结果发现@timestamp比中国时间早了8小时。
解决方案 Kibana 读取浏览器的当前时区,而后在页面上转换时间内容的显示
date { match => [ "log_timestamp", "YYYY-MM-dd HH:mm:ss.SSS" ] target => "@timestamp" }
4.Grok parse failure
咱们遇到线上 node 日志忽然有几天日志查看不出来。后来拉出原始日志对比才发现生成出来的日志格式不正确,同时包含 JSON 格式和非 JSON 格式的日志。可是咱们用grok解析的时候采用是 json 格式。建议你们输出日志保证格式一致同时不要出现空格等异常字符,可使用在线 grok debug (http://grokdebug.herokuapp.com/) 来调试正则。
基于 ELK stack 的日志解决方案的优点主要体现于: