ELK组件

什么是ELK?

ELK是Elasticsearch、Logstash与Kibana三个组件的首字母的缩写,三个开源组件组合在一起就构成了一个完整的日志采集、处理与查询解决方案,下图是Elastic公司给出的ELK方案架构图。

最底层是Beats与Logstash,Beats是一个数据迁移工具可以将各种数据源如文件、网路数据包、Syslog等数据做简单解析后写入Logstash做进一步处理或直接写入Elasticsearch;Logstash与Beats功能稍有重合,它可以接收Beats发送出来的数据或者直接读取本地文件,他注重的主要是数据的预处理,本文也将对Logstash做比较详细的介绍;中间层是Elasticsearch,主要负责数据的持久化与分析,是ELK Stack的核心;最上层是Kibana,主要负责对Elasticsearch中的数据进行可视化展示。

Logstash

Logstash由两个必要组件:INPUT与OUTPUT,一个可选组件FILTER组成,INPUT组件主要负责数据读取(如Beats、本地文件、syslog等),FILTER组件负责数据的预处理,OUTPUT组件负责数据输出(如Elasticsearch、Kafka、本地文件等)。

本节将详细介绍Filebeat读取本地apache日志作为输入、Elasticsearch作为输出的ELK Stack日志解决方案。

配置Filebeats

标准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

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

  • input:input为beats,无需关心底层beats的实现,仅需要将埠暴露给beats即可
  • filter:本示例给出了两个filter:
    • grok:这边使用了COMBINEDAPACHELOG,用于解析apache日志
    • geoip:为grok输出的结构话日志添加ip的地理位置信息 *
  • output:输出部分为elasticsearch,这边设置的索引名为apache_log-%{+YYYY.MM.dd},这边使用了时间占位符,数据写入ES会根据系统时间将数据投入对应的索引中。这种索引管理方式虽然简单,但是无法实现冷热数据分离、数据归档等功能,所以在ES6.6之后又推出了索引生命周期管理,这将在下一节做详细介绍。

索引生命周期管理

对于日志数据,由於单个索引的存储量的瓶颈,ES一般推荐使用时间作为后缀为同一份日志数据创建多个索引,而用户则通过一个定时器来定时删除过期的索引。ES在6.6之后,在x-pack中推出了索引生命周期管理相关的API来简化与增强类似日志数据索引的管理。该方案基于时间将索引数据分为四个阶段:Hot、Warm、Cold、Delete,这四个阶段分别有如下的定义:

  • Hot:索引数据被大量更新与新增,并且用户对处于该阶段的索引由很强的查询需求(热数据)
  • Warm:索引数据不再被更新,单用户对处于该阶段的索引任有查询需求
  • Cold:索引数据不再被更新,用户对这个阶段的索引查询需求较低并且可以容忍较大的查询延迟
  • Delete:数据不再需要,索引可被删除

对于这四种并给不同的数据阶段,ES也给出了不同的数据处理方式如下,更加详细的文档可以看这里。

  • Hot
    • 基于时间、大小对索引进行Rollover
  • Warm
    • 指定数据所在的节点,可用作冷热数据分层
    • 设置只读
    • 强制Merge
    • 索引Shrink(减少Shard数)
  • Cold:
    • 设置数据所在节点,可用作冷热数据分层
    • 冻结索引(freeze,6.6之后再x-pack中提供,默认对此种索引的搜索请求返回0条数据,并且搜索请求会在search_throttled线程池中执行)
  • Delete:
    • 删除索引

入门

创建生命周期规则

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
}
}
}
}

回到Logstash

基于ES提供的索引生命周期管理,我们可以很方便地实现日志数据的管理,Logstash的ES输出插件也支持了索引生命周期管理规则所管理的索引,具体配置如下:

output {
elasticsearch {
hosts => ["localhost:9200"]
ilm_enabled => true
ilm_rollover_alias => "apache_log"
ilm_pattern => "000001"
ilm_policy => "apache_log_policy"
}
}

推荐阅读:

相关文章