ELK是Elasticsearch、Logstash与Kibana三个组件的首字母的缩写,三个开源组件组合在一起就构成了一个完整的日志采集、处理与查询解决方案,下图是Elastic公司给出的ELK方案架构图。
最底层是Beats与Logstash,Beats是一个数据迁移工具可以将各种数据源如文件、网路数据包、Syslog等数据做简单解析后写入Logstash做进一步处理或直接写入Elasticsearch;Logstash与Beats功能稍有重合,它可以接收Beats发送出来的数据或者直接读取本地文件,他注重的主要是数据的预处理,本文也将对Logstash做比较详细的介绍;中间层是Elasticsearch,主要负责数据的持久化与分析,是ELK Stack的核心;最上层是Kibana,主要负责对Elasticsearch中的数据进行可视化展示。
Logstash由两个必要组件:INPUT与OUTPUT,一个可选组件FILTER组成,INPUT组件主要负责数据读取(如Beats、本地文件、syslog等),FILTER组件负责数据的预处理,OUTPUT组件负责数据输出(如Elasticsearch、Kafka、本地文件等)。
本节将详细介绍Filebeat读取本地apache日志作为输入、Elasticsearch作为输出的ELK Stack日志解决方案。
标准apache日志日志示例:
86.1.76.62 - - [04/Jan/2015:05:30:37 +0000] "GET /projects/xdotool/ HTTP/1.1" 200 12292 "http://www.haskell.org/haskellwiki/Xmonad/Frequently_asked_questions" "Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20140205 Firefox/24.0 Iceweasel/24.3.0" 86.1.76.62 - - [04/Jan/2015:05:30:37 +0000] "GET /reset.css HTTP/1.1" 200 1015 "http://www.semicomplete.com/projects/xdotool/" "Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20140205 Firefox/24.0 Iceweasel/24.3.0" 86.1.76.62 - - [04/Jan/2015:05:30:37 +0000] "GET /style2.css HTTP/1.1" 200 4877 "http://www.semicomplete.com/projects/xdotool/" "Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20140205 Firefox/24.0 Iceweasel/24.3.0"
Filebeats负责将本地的日志文件解析后交于Logstash做进一步的处理,其配置如下:
filebeat.prospectors: - type: log paths: - /path/to/file/logstash-tutorial.log output.logstash: hosts: ["localhost:5044"]
5044埠是Logstash配置的beats监听埠
Logstash配置:
input { beats { port => "5044" # 输入为beats,监听埠5044 } } filter { grok { match => { "message" => "%{COMBINEDAPACHELOG}"} # grok插件 } geoip { source => "clientip" # geoip插件 } } output { elasticsearch { hosts => ["localhost:9200"] index => "apache_log-%{+YYYY.MM.dd}" } }
配置文件由三部分组成:input、filter、output
对于日志数据,由於单个索引的存储量的瓶颈,ES一般推荐使用时间作为后缀为同一份日志数据创建多个索引,而用户则通过一个定时器来定时删除过期的索引。ES在6.6之后,在x-pack中推出了索引生命周期管理相关的API来简化与增强类似日志数据索引的管理。该方案基于时间将索引数据分为四个阶段:Hot、Warm、Cold、Delete,这四个阶段分别有如下的定义:
对于这四种并给不同的数据阶段,ES也给出了不同的数据处理方式如下,更加详细的文档可以看这里。
PUT _ilm/policy/apache_log_policy { "policy": { "phases": { "hot": { "actions": { // 该阶段索引需要执行的Action "rollover": { "max_size": "50KB", // 单个索引超过50KB或者存在时间超过1分钟后进行Rollover "max_age": "1m" } } }, "warm" : { "min_age": "10m", // 索引创建10分钟后进入warm阶段 "actions": { "forcemerge" : { // 强制执行Merge,每个Shard最多1个Segment "max_num_segments": 1 } } }, "delete": { "min_age": "60m", // 索引创建60分钟后进入delete阶段 "actions": { "delete": {} // 删除索引 } } } } }
这边创建了一个名为apache_log_policy的索引生命周期管理规则,总共有三个阶段:Hot、Warm和Delete,在Hot阶段单个索引大于50KB或者创建时间超过1分钟将会Rollover。Hot索引创建时间超过10分钟后,索引进入Warm阶段,在该阶段,索引将会被执行force_merge,每个Shard最多一个Segment。Warm阶段的索引再创建60分钟后将会被删除。
PUT /_template/apache_log_template { "index_patterns": ["apache_log-*"], "settings": { "number_of_shards": 1, "number_of_replicas": 1, "index.lifecycle.name": "apache_log_policy", // 关联的索引生命周期规则 "index.lifecycle.rollover_alias": "apache_log" // 索引生命周期管理所用的索引别名 } }
PUT apache_log-000001 // 索引名称必须以数字结尾,方便规则进行Rollover { "aliases": { "apache_log": { "is_write_index": true } } }
当索引创建后,由于索引名满足了上述索引模板,所以该索引会被索引生命周期所管理。这边要注意的是,索引的名称必须以数字结尾以便于规则对索引进行Rollover。
为了让这些被管理的索引堆外暴露时看上去是一个索引,这边给了该索引一个别名:apache_log,并打开了is_write_index,is_write_index配置会被生命周期管理规则在Rollover是赋给新的索引。
GET apache_log-*/_ilm/explain
响应示例
{ "indices" : { "apache_log-000008" : { "index" : "apache_log-000008", // 索引名称 "managed" : true, // 是否被规则管理 "policy" : "apache_log_policy", // 规则名称 "lifecycle_date_millis" : 1554118764383, "phase" : "warm", // 当前阶段 "phase_time_millis" : 1554119964175, "action" : "complete", "action_time_millis" : 1554120564177, "step" : "complete", "step_time_millis" : 1554120564177, "phase_execution" : { // 改阶段需要执行的Action "policy" : "apache_log_policy", "phase_definition" : { "min_age" : "10m", "actions" : { "forcemerge" : { "max_num_segments" : 1 } } }, "version" : 4, "modified_date_in_millis" : 1554117414882 } }, "apache_log-000007" : { "index" : "apache_log-000007", "managed" : true, "policy" : "apache_log_policy", "lifecycle_date_millis" : 1554117564136, "phase" : "warm", "phase_time_millis" : 1554118164176, "action" : "complete", "action_time_millis" : 1554118764177, "step" : "complete", "step_time_millis" : 1554118764177, "phase_execution" : { "policy" : "apache_log_policy", "phase_definition" : { "min_age" : "10m", "actions" : { "forcemerge" : { "max_num_segments" : 1 } } }, "version" : 4, "modified_date_in_millis" : 1554117414882 } }, "apache_log-000009" : { "index" : "apache_log-000009", "managed" : true, "policy" : "apache_log_policy", "lifecycle_date_millis" : 1554119964235, "phase" : "warm", "phase_time_millis" : 1554120564291, "action" : "forcemerge", "action_time_millis" : 1554120564291, "step" : "segment-count", "step_time_millis" : 1554120564350, "phase_execution" : { "policy" : "apache_log_policy", "phase_definition" : { "min_age" : "10m", "actions" : { "forcemerge" : { "max_num_segments" : 1 } } }, "version" : 4, "modified_date_in_millis" : 1554117414882 } }, "apache_log-000010" : { "index" : "apache_log-000010", "managed" : true, "policy" : "apache_log_policy", "lifecycle_date_millis" : 1554119964245, "phase" : "hot", "phase_time_millis" : 1554119964364, "action" : "rollover", "action_time_millis" : 1554119964364, "step" : "check-rollover-ready", "step_time_millis" : 1554119964364, "phase_execution" : { "policy" : "apache_log_policy", "phase_definition" : { "min_age" : "0ms", "actions" : { "rollover" : { "max_size" : "50kb", "max_age" : "10m" } } }, "version" : 4, "modified_date_in_millis" : 1554117414882 } } } }
基于ES提供的索引生命周期管理,我们可以很方便地实现日志数据的管理,Logstash的ES输出插件也支持了索引生命周期管理规则所管理的索引,具体配置如下:
output { elasticsearch { hosts => ["localhost:9200"] ilm_enabled => true ilm_rollover_alias => "apache_log" ilm_pattern => "000001" ilm_policy => "apache_log_policy" } }
推荐阅读: