1 前言

EFK是一套分布式日志服务解决方案,由各个组件构成。EFK分别是指:elasticsearch、filebeat、kibana。不过在真实的生产环境中,搭建日志服务可能还需要logstash来进行规制解析,使用kafka进行削峰填谷作为缓冲。在本文中,我主要介绍如何使用elasticsearch+filebeat+logstash+kibana来快速搭建一套分布式日志服务,来接入线上的多个产品线,并进行日志的统一管理。

2整体框架及各组件介绍

2.1 整体框架

日志系统elfk 日志 efk_大数据

2.2 各组件简介

filebeat:作为agent部署在需要收集日志的服务所在的机器上,进行日志的收集;
logstash:接收来自filebeat的日志流,进行规则解析,写入到es;
elasticsearch + searchguard:es用于日志的存储、查询;searchguard用于对es索引的安全防护;
kibana:进行日志查询的可视化界面。

3 日志收集&传输

3.1 logstash作为agent

在最初的ELK方案中,是将logstash作为agent部署在各个client上的进行日志的收集、解析直接写入到es中。但是在要接入的服务非常多、日质量不断增大的场景中,这种方式会造成以下影响:

  • logstash非常占用内存,会影响到部署到本机器上的线上服务
  • 直接写es会对es造成非常大的压力

filebeat使用go进行开发的,其轻量级特性非常适合作为agent进行部署。在本文的日志服务中,filebeat所扮演的角色,就是作为agent进行日志的收集,以及对于java异常日志multiline的处理。

3.2 filebeat作为agent

各公司都应该有自己的线上服务部署平台,由于要收集的服务是分布在许多不同的机器上的。建议将filebeat封装为一个服务,直接将二进制包打包到要部署服务的包中,根据不同的沙盒或者线上环境加载不同的filebeat.yml配置文件进行安装即可。

3.2.1 filebeat的日志收集文件说明

举例说明,我们要收集sonofelice模块的sonofelice.debug.log中的日志,针对这一个日志文件需要配置一个sonofelice_debug.yml日志收集文件,以便filebeat开启一个harvest通道开始日志收集。具体配置示例如下:

- type: log
  enabled: true
  paths:
    - /home/work/logs/sonofelice/debug/sonofelice.debug.log
    - /home/work/logs/sonofelice/debug/sonofelice.debug.log*/*.debug.log
  ignore_older: 72h
  close_inactive: 1h
  multiline:
    pattern: '^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d'
    negate: true
    match: after
  fields:
    productline: test
    module: sonofelice
    submodule: api
    type: debug
    language: java
    logpattern: java-std
    region: bj

在上述配置中,必选项及解释可以参考博客:...上述配置中的各个字段会对应为es中的具体的document中的field。

3.2.2 filebeat.yml文件说明

在本文示例中通过filebeat写入的logstash,因此只需要配置如下几个部分即可。

  • Filebeat modules模块用于配置3.2.1中对于每个日志文件配置的日志收集文件所在的路径。
  • Logstash output部分用于配置要写入的logstash的各节点服务地址,以及证书相关信息
#============================= Filebeat modules ===============================
filebeat.config.modules:
  # Glob pattern for configuration loading
  path: ${path.config}/modules.d/*.yml
  # Set to true to enable config reloading
  reload.enabled: true
  # Period on which files under path should be checked for changes
  reload.period: 10s
path.data: /home/filebeat/data
filebeat.shutdown_timeout: 300s
filebeat.config.inputs:
  enabled: true
  path: inputs/*.yml
  reload.enabled: true
  reload.period: 10s
queue.mem:
  events: 4096
  flush.min_events: 512
  flush.timeout: 1s
#output.console:
#  pretty: true
#----------------------------- Logstash output --------------------------------
output.logstash:
  # The Logstash hosts
  hosts: ["logstash-hosts1:5044", "logstash-hosts2:5044", "logstash-hosts3:5044"]
  loadbalance: true
  # Optional SSL. By default is off.
  # List of root certificates for HTTPS server verifications
  ssl.certificate_authorities: ['${FILEBEAT_ROOT_CA_PATH}']
  # Certificate for SSL client authentication
  ssl.certificate: '${FILEBEAT_CRT_PEM_PATH}'
  # Client Certificate Key
  ssl.key: '${FILEBEAT_KEY_PEM_PATH}'

为了确保安全性,我们开启了证书访问,关于证书的生成部分,另有相关文章介绍,此处不再赘述。

如果希望将filebeat的相关监控信息写入到es,可以启用xpack monitoring,配置如下:

#============================== Xpack Monitoring ===============================
# filebeat can export internal metrics to a central Elasticsearch monitoring
# cluster.  This requires xpack monitoring to be enabled in Elasticsearch.  The
# reporting is disabled by default.

# Set to true to enable the monitoring reporter.
xpack.monitoring.enabled: true

# Uncomment to send the metrics to Elasticsearch. Most settings from the
# Elasticsearch output are accepted here as well. Any setting that is not set is
# automatically inherited from the Elasticsearch output configuration, so if you
# have the Elasticsearch output configured, you can simply uncomment the
# following line.
xpack.monitoring.elasticsearch:
  hosts: ["es-host1:9920","es-host2:9920","es-host3:9920"]
  protocol: "https"
  username: "filebeat_system"
  password: "abcdefg"
  ssl.enabled: true
  ssl.verification_mode: full
  ssl.certificate_authorities: ['${FILEBEAT_ROOT_CA_PATH}']

# metric http server
http.enabled: true
http.host: localhost
http.port: 5066

4 日志规则解析

Logstash 是一款强大的数据处理工具,它可以实现数据传输,格式处理,格式化输出,还有强大的插件功能,常用于日志处理。对于logstash的详细介绍可以参考:...本文介绍的日志服务中,logstash的作用主要是接收来自filebeat收集上来的日志,匹配不同的规则,写入到不同的es索引中。
同filebeat一样,也非常建议将logstash封装为可以直接部署的服务。我们重点介绍logstash的基础配置,以及pipelines的配置。

4.1 logstash.yml配置解析

pipeline.batch.size: 500
pipeline.batch.delay: 100
config.reload.automatic: true
config.reload.interval: 30s
queue.type: persisted
path.queue: /home/logstash/data/queue
queue.max_bytes: 4gb
queue.checkpoint.writes: 256
dead_letter_queue.enable: true
dead_letter_queue.max_bytes: 100gb
path.dead_letter_queue: /home/logstash/data/dead_letter_queue
http.host: "127.0.0.1"
http.port: 5044
# ------------ X-Pack Settings (not applicable for OSS build)--------------
#
# X-Pack Monitoring
# https://www.elastic.co/guide/en/logstash/current/monitoring-logstash.html
xpack.monitoring.enabled: true
xpack.monitoring.elasticsearch.username: logstash_system
xpack.monitoring.elasticsearch.password: kdhlr953
xpack.monitoring.elasticsearch.url: ["https://es-host1:9920","https://es-host2:9920","https://es-host3:9920"]
xpack.monitoring.elasticsearch.ssl.truststore.path: /home/work/certificate/truststore.jks
xpack.monitoring.elasticsearch.ssl.truststore.password: sjaifdakdjf
xpack.monitoring.elasticsearch.ssl.verification_mode: certificate
xpack.monitoring.elasticsearch.sniffing: false
xpack.monitoring.collection.interval: 10s
xpack.monitoring.collection.pipeline.details.enabled: true

跟filebeat一样,我们开启了证书访问,因此也需要证书相关的支持。更多配置相关的介绍可以自行百度。后续也会有文章进行详细介绍。

4.2 pipelines配置解析

pipelines.yml文件主要配置logstash需要加载的pipelines的相关路径:

- pipeline.id: filebeat-log
  path.config: "pipelines/filebeat-log/*.conf"

4.3 pipelines热加载

pipelines主要分为三部分:input、fileter、output,这三部分可以配置到三个不同的配置文件中。
这三个配置文件的改动是热加载的。logstash会定期进行检测。

4.3.1 input.conf

主要是filter-beats插件的配置,配置示例如下:

input {
    beats {
        port => 5044
        client_inactivity_timeout => 600
        ssl => true
        ssl_certificate_authorities => ["/home/work/certificate/chain-ca.pem"]
        ssl_certificate => "/home/work/certificate/server.crt.pem"
        ssl_key => "/home/work/certificate/server.key.pem"
        ssl_verify_mode => "force_peer"
    }
}

4.3.2 filter.conf

最挑战的就是fileter的配置部分。强烈推荐定义规则时先使用grok调试器进行在线调试后再加载到logstash中。https://grokdebug.herokuapp.com/配置参考如下:

filter {
    # 备份一下事件时间,@timestamp在后面的日志处理过程中会被替换成日志内容中的时间
    mutate {
        copy => {
            "@timestamp" => "event_timestamp"
        }
    }
    if [fields][language] == "go" and [fields][type] == "info" {
        grok {
            match => {
                "message" => "^\[%{GO_TIMESTAMP:[@metadata][log_timestamp]}\]\s+\[%{DATA:log_level}\]"
            }
            pattern_definitions => {
                "GO_TIMESTAMP" => "%{YEAR}/%{MONTHNUM}/%{MONTHDAY} %{HOUR}:%{MINUTE}:%{SECOND} %{TZ}"
            }
        }
        date {
            match => ["[@metadata][log_timestamp]", "yyyy/MM/dd HH:mm:ss z"]
            timezone => "Asia/Shanghai"
        }
    }
    if ![@metadata][index_name] {
        mutate {
            add_field => {"[@metadata][index_name]" => "%{[fields][productline]}-%{[fields][logpattern]}-%{[fields][type]}"}
        }
    }
    if ![@metadata][document_id] {
        mutate {
            add_field => {"[@metadata][document_id]" => "%{[@timestamp]}%{[offset]}%{[host][name]}"}
        }
        mutate {
            gsub => ["[@metadata][document_id]", "[.:TZ-]", ""]
        }
    }
}

4.3.3 output.conf

output {
    if "_grokparsefailure" in [tags] or "_jsonparsefailure" in [tags] {
        file {
            path => "/home/work/logstash/failure_output/failure-%{+YYYY-MM-dd}.log"
        }
    } else {
        elasticsearch {
            hosts => ["https://es-host1:9920","https://es-host2:9920","https://es-host3:9920"]
            index => "logstash-%{[@metadata][index_name]}-%{+YYYY.MM.dd}"
            document_id => "%{[@metadata][document_id]}"
            ssl => true
            ssl_certificate_verification => true
            truststore => "/home/work/certificate/truststore.jks"
            truststore_password => "adofkoe"
            user => "logstash"
            password => "dafodmfkamkefadfg"
        }
    }
}

如果filebeat收集的日志不满足fileter.conf中配置的grok表达式,会统一写入到failure文件中,方便问题排查。

5 日志存储查询

5.1 elasticsearch

elasticsearch是一个全文检索引擎,在本文中的日志服务中主要用于日志的结构化存储和查询。
为了将不同产品线的访问权限进行隔离,我们需要在es安装时加载search-guard插件。
在第一次部署es启动前需要进行系统配置更新(使用root权限),修改/etc/security/limit.conf,保存后logout然后再login一遍系统

  • hard nofile 65536
  • soft nofile 65536 work hard nofile 65536 work soft nofile 65536
  • soft nproc 4096
  • hard nproc 4096 work soft nproc 4096 work hard nproc 4096 work soft memlock unlimited work hard memlock unlimited

在/etc/sysctl.conf加入 vm.max_map_count=262144 保存后执行sysctl -p
对于search-guard插件,可以将es封装为可独立部署的线上服务,在部署脚本中加载search-guard插件。关于插件的安装在本文中先不进行过多介绍,重点介绍一下search-guard插件的账号体系配置。
sgconfig中的用户密码需要通过执行es节点部署路径中plugin/search-guard-6/tools/hash.sh脚本来生成hash值。 执行命令为bash hash.sh -p $PASSWORD 然后将生成的hash填入sg_internal_users.yml中,并执行bin/sg_update.sh脚本

具体执行步骤如下:

第一步: 在es节点部署路径中,执行以下命令,得到一个哈希值

bash plugins/search-guard-6/tools/hash.sh -p tsdb123

第二步: 将第一步中的哈希值写入到sgconfig目录下的sg_internal_users.yml文件中

#password is: tsdb123
tsdb:
  hash: $2y$12$nRgsuDYm36ZKCTjPf3/CeusU9BSGNDCOGOC.JKT7lhj9tVE.nVtS2
  roles:
    - tsdb

此处填写的roles: -tsdb角色需要在

第三步: 在sg_roles_mapping.yml文件中添加角色映射

sg_tsdb:
  readonly: true
  backendroles:
    - tsdb

第四步: 在sg_roles.yml文件中添加索引控制。此处添加kibana是为了让用户可以有kibana的访问权限,否则是无法通过kibana进行查询的。

sg_tsdb:
  readonly: true
  cluster:
    - CLUSTER_COMPOSITE_OPS_RO
  indices:
    'logstash-tsdb-*':
      '*':
        - READ
    '?kibana*':
      '*':
        - READ

第五步: 生效配置,执行以下命令:

sh bin/sg_update.sh sgconfig/

其中sg_update.sh脚本可以自行编写,主要用于加载sg的各个配置文件。

5.2 kibana

kibana用于进行日志的查询、报表展示,可以理解为es的一个可视化操作界面。
kibana同上述的所有服务,也可以封装为单独的服务包进行安装部署,其最主要的就是kibana.yml的配置。主要配置kibana的端口,es的地址,访问es需要的用户名、密码,证书的地址等信息。
使用5,1中分配的账号进行kibana登录即可查看对应索引的相关信息。

总结

至此,搭建完上述的各个组件,依次检查filebeat的日志是否能够正确收集到对应的日志文件、logstash能否正确接收到filebeat传输过来的信息并且正确解析,检查es是否能够生成索引,kibana是否能够进行不同账号的登录以及对应es索引的日志查询。没有问题之后,分布式日志服务就搭建完毕了。