ELK介绍和部署

为什么用到ELK

介绍参考:https://www.cnblogs.com/aresxin/p/8035137.html

一般我们通过日志排除,发现问题根源解决问题:如果1台或者几台服务器,我们可以通过 linux命令,tail、cat,通过grep、awk等过滤去查询定位日志查问题。但在规模较大的场景中,此方法效率低下,面临问题包括日志量太大如何归档、文本搜索太慢怎么办、如何多维度查询。需要集中化的日志管理,所有服务器上的日志收集汇总。常见解决思路是建立集中式日志收集系统,将所有节点上的日志统一收集,管理,访问。

一般大型系统是一个分布式部署的架构,不同的服务模块部署在不同的服务器上,问题出现时,大部分情况需要根据问题暴露的关键信息,定位到具体的服务器和服务模块,构建一套集中式日志系统,可以提高定位问题的效率。

一个完整的集中式日志系统,需要包含以下几个主要特点:

  • 收集-能够采集多种来源的日志数据
  • 传输-能够稳定的把日志数据传输到中央系统
  • 存储-如何存储日志数据
  • 分析-可以支持 UI 分析
  • 警告-能够提供错误报告,监控机制

ELK提供了一整套解决方案,并且都是开源软件,之间互相配合使用,完美衔接,高效的满足了很多场合的应用。目前主流的一种日志系统。

ELK简介

ELK是三个开源软件的缩写,分别表示:Elasticsearch , Logstash, Kibana , 它们都是开源软件。新增了一个FileBeat,它是一个轻量级的日志收集处理工具(Agent),Filebeat占用资源少,适合于在各个服务器上搜集日志后传输给Logstash,官方也推荐此工具。

Elasticsearch是个开源分布式搜索引擎,提供搜集、分析、存储数据三大功能。它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful风格接口,多数据源,自动搜索负载等。

Logstash 主要是用来日志的搜集、分析、过滤日志的工具,支持大量的数据获取方式。一般工作方式为c/s架构,client端安装在需要收集日志的主机上,server端负责将收到的各节点日志进行过滤、修改等操作在一并发往elasticsearch上去。

Kibana 也是一个开源和免费的工具,Kibana可以为 Logstash 和 ElasticSearch 提供的日志分析友好的 Web 界面,可以帮助汇总、分析和搜索重要数据日志。

Filebeat隶属于Beats。目前Beats包含四种工具:

    1. Packetbeat(搜集网络流量数据)
    2. Topbeat(搜集系统、进程和文件系统级别的 CPU 和内存使用情况等数据)
    3. Filebeat(搜集文件数据)
    4. Winlogbeat(搜集 Windows 事件日志数据)

官网地址:https://www.elastic.co/cn/

官网权威指南:https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html

Elasticsearch:
https://www.elastic.co/cn/products/elasticsearch
https://www.elastic.co/guide/en/elasticsearch/reference/5.6/index.html

elasticsearch中文社区:
https://elasticsearch.cn/

Logstash:
https://www.elastic.co/cn/products/logstash
https://www.elastic.co/guide/en/logstash/5.6/index.html

Kibana:

https://www.elastic.co/cn/products/kibana

https://www.elastic.co/guide/en/kibana/5.5/index.html

Filebeat:

https://www.elastic.co/cn/products/beats/filebeat
https://www.elastic.co/guide/en/beats/filebeat/5.6/index.html

ELK架构图

架构图一

这是最简单的一种ELK架构方式。优点是搭建简单,易于上手。缺点是Logstash耗资源较大,运行占用CPU和内存高。另外没有消息队列缓存,存在数据丢失隐患

架构图二

此种架构引入了消息队列机制,位于各个节点上的Logstash Agent先将数据/日志传递给Kafka(或者Redis),并将队列中消息或数据间接传递给Logstash,Logstash过滤、分析后将数据传递给Elasticsearch存储。最后由Kibana将日志和数据呈现给用户。因为引入了Kafka(或者Redis),所以即使远端Logstash server因故障停止运行,数据将会先被存储下来,从而避免数据丢失。

架构图三

此种架构将收集端logstash替换为beats,更灵活,消耗资源更少,扩展性更强。同时可配置Logstash 和Elasticsearch 集群用于支持大集群系统的运维日志数据监控和查询。

Filebeat工作原理

Filebeat由两个主要组件组成:prospectors 和 harvesters。这两个组件协同工作将文件变动发送到指定的输出中。

Harvester(收割机):负责读取单个文件内容。每个文件会启动一个Harvester,每个Harvester会逐行读取各个文件,并将文件内容发送到制定输出中。

Harvester负责打开和关闭文件,意味在Harvester运行的时候,文件描述符处于打开状态,如果文件在收集中被重命名或者被删除,Filebeat会继续读取此文件。所以在Harvester关闭之前,磁盘不会被释放。默认情况filebeat会保持文件打开的状态,直到达到close_inactive(如果此选项开启,filebeat会在指定时间内将不再更新的文件句柄关闭,时间从harvester读取最后一行的时间开始计时。若文件句柄被关闭后,文件发生变化,则会启动一个新的harvester。关闭文件句柄的时间不取决于文件的修改时间,若此参数配置不当,则可能发生日志不实时的情况,由scan_frequency参数决定,默认10s。Harvester使用内部时间戳来记录文件最后被收集的时间。例如:设置5m,则在Harvester读取文件的最后一行之后,开始倒计时5分钟,若5分钟内文件无变化,则关闭文件句柄。默认5m)。

Prospector(勘测者):负责管理Harvester并找到所有读取源

filebeat.prospectors:
- input_type: log
  paths:
    - /apps/logs/*/info.log

Prospector会找到/apps/logs/*目录下的所有info.log文件,并为每个文件启动一个Harvester。Prospector会检查每个文件,看Harvester是否已经启动,是否需要启动,或者文件是否可以忽略。若Harvester关闭,只有在文件大小发生变化的时候Prospector才会执行检查。只能检测本地的文件。

Filebeat如何记录文件状态:

将文件状态记录在文件中(默认在/var/lib/filebeat/registry)。此状态可以记住Harvester收集文件的偏移量。若连接不上输出设备,如ES等,filebeat会记录发送前的最后一行,并再可以连接的时候继续发送。Filebeat在运行的时候,Prospector状态会被记录在内存中。Filebeat重启的时候,利用registry记录的状态来进行重建,用来还原到重启之前的状态。每个Prospector会为每个找到的文件记录一个状态,对于每个文件,Filebeat存储唯一标识符以检测文件是否先前被收集。

Filebeat如何保证事件至少被输出一次:

Filebeat之所以能保证事件至少被传递到配置的输出一次,没有数据丢失,是因为filebeat将每个事件的传递状态保存在文件中。在未得到输出方确认时,filebeat会尝试一直发送,直到得到回应。若filebeat在传输过程中被关闭,则不会再关闭之前确认所有时事件。任何在filebeat关闭之前为确认的时间,都会在filebeat重启之后重新发送。这可确保至少发送一次,但有可能会重复。可通过设置shutdown_timeout 参数来设置关闭之前的等待事件回应的时间(默认禁用)。

Logstash工作原理

Logstash事件处理有三个阶段:inputs → filters → outputs。是一个接收,处理,转发日志的工具。支持系统日志,webserver日志,错误日志,应用日志,总之包括所有可以抛出来的日志类型。

Input:输入数据到logstash。

一些常用的输入为:

file:从文件系统的文件中读取,类似于tail -f命令

syslog:在514端口上监听系统日志消息,并根据RFC3164标准进行解析

redis:从redis service中读取

beats:从filebeat中读取

Filters:数据中间处理,对数据进行操作。

一些常用的过滤器为:

grok:解析任意文本数据,Grok 是 Logstash 最重要的插件。它的主要作用就是将文本格式的字符串,转换成为具体的结构化的数据,配合正则表达式使用。内置120多个解析语法。

官方提供的grok表达式:https://github.com/logstash-plugins/logstash-patterns-core/tree/master/patterns
grok在线调试:https://grokdebug.herokuapp.com/

mutate:对字段进行转换。例如对字段进行删除、替换、修改、重命名等。

drop:丢弃一部分events不进行处理。

clone:拷贝 event,这个过程中也可以添加或移除字段。

geoip:添加地理信息(为前台kibana图形化展示使用)

Outputs:outputs是logstash处理管道的最末端组件。一个event可以在处理过程中经过多重输出,但是一旦所有的outputs都执行结束,这个event也就完成生命周期。

一些常见的outputs为:

elasticsearch:可以高效的保存数据,并且能够方便和简单的进行查询。

file:将event数据保存到文件中。

graphite:将event数据发送到图形化组件中,一个很流行的开源存储图形化展示的组件。

Codecs:codecs 是基于数据流的过滤器,它可以作为input,output的一部分配置。Codecs可以帮助你轻松的分割发送过来已经被序列化的数据。

一些常见的codecs:

json:使用json格式对数据进行编码/解码。

multiline:将汇多个事件中数据汇总为一个单一的行。比如:java异常信息和堆栈信息。

Elasticsearch部署

配置说明

es版本:7.8.1

安装路径:/home/rndii/projects/es/elasticsearch-7.8.1

服务器:10.0.1.104,10.0.1.117,10.0.1.127

jdk :/home/rndii/projects/es/elasticsearch-7.8.1/jdk

jdk-version:14.0.1(需要java-jdk,前置条件)

ES不能用root用户启动,必须使用普通用户安装启动

设置sudo权限:visudo(三台机器使用root用户执行visudo命令为普通用户添加权限)

配置文件

现阶段基本为默认配置,注意新建index时的分片与备份

# 找到配置文件中的cluster.name,打开该配置并设置集群名称
cluster.name: wisefly-test-es
# 找到配置文件中的node.name,打开该配置并设置节点名称
node.name: es-104
# 修改data存放的路径
path.data: /home/rndii/projects/es/elasticsearch-7.8.1/data
# 修改logs日志的路径
path.logs: /home/rndii/projects/es/elasticsearch-7.8.1/logs
# 监听的网络地址
network.host: 10.0.1.104
# 开启监听的端口
http.port: 9200
# 注册到注册中心
discovery.seed_hosts: ["10.0.1.104", "10.0.1.117", "10.0.1.127"]
cluster.initial_master_nodes: ["es-104"]
# 开启跨域,增加新的参数,这样head插件可以访问es
http.cors.enabled: true
http.cors.allow-origin: "*"

如果没有配置java的全局环境变量,需要在bin/elasticsearch 增加JAVA_HOME=/home/rndii/projects/es/elasticsearch-7.8.1/jdk

安装ik分词器

https://github.com/medcl/elasticsearch-analysis-ik
https://github.com/medcl/elasticsearch-analysis-ik/releases

在以上路径中找到对应版本的ik分词器,解压到 /home/rndii/projects/es/elasticsearch-7.8.1/plugins/ik/下

IK分词器动态扩容

修改 /home/rndii/projects/es/elasticsearch-7.8.1/plugins/ik/config/IKAnalyzer.cfg.xml 文件

把自己需要的词加到字典中,再在下边添加自己的拓展词典和停用词词典:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
        <comment>IK Analyzer 扩展配置</comment>
        <!--用户可以在这里配置自己的扩展字典 -->
        <entry key="ext_dict"></entry>
         <!--用户可以在这里配置自己的扩展停止词字典-->
        <entry key="ext_stopwords"></entry>
        <!--用户可以在这里配置远程扩展字典 -->
        <entry key="remote_ext_dict">http://10.0.1.117:19200/dynamic.txt</entry>
        <!--用户可以在这里配置远程扩展停止词字典-->
        <entry key="remote_ext_stopwords">http://10.0.1.117:19200/stop.txt</entry> 
</properties>

如果配置完重启es报错的话,重启Kibana

启动命令,-d表示后台运行

bin/elasticsearch -d

遇到的问题

普通用户打开文件的最大数限制

普通用户启动线程数限制

普通用户调大虚拟内存

查看es集群相关信息

查看集群健康状态
http://10.0.1.104:9200/_cluster/health?pretty=true

查看集群状态
http://10.0.1.104:9200/_cluster/stats?pretty

查看节点总体情况
http://10.0.1.104:9200/_nodes/process?pretty

查看某个节点的情况
http://10.0.1.104:9200/_nodes/es-104/process?pretty

ElasticSearch-Head
http://10.0.1.104:9100/

Kibana部署

1.下载:到elasticsearch官网下载7.8.1版本

2.解压后进入config目录

3.编辑kibana.yml

#外网访问
server.host: "0.0.0.0"

#配置es集群地址
elasticsearch.hosts: ["http://10.0.1.104:9200", "http://10.0.1.117:9200", "http://10.0.1.127:9200"]

#7.x后自带中文包,使用中文包
i18n.locale: "zh-CN"

4.进入bin,后台启动nohup

./kibana > runlog.log 2> & 1&

2>&1 & 中,最后一个&表示把条命令放到后台执行,含义:将标准错误输出重定向到标准输出

整句语句的意思就是将标准错误输出和标准输出都定向到runlog.log中。

5.kibana访问界面:http://10.0.1.127:5601/app/kibana

公司内网,外边进不去

6.索引模板

由于每天生成索引日志,并且日志索引分片为1,副本分片也为1,logstash在向es中添加数据时会自动创建索引,所以我们可以在es中创建索引模板,规范以logstash开头的索引名的数据类型,索引等生成规则。而不是默认生成!!!!

下列为索引生成规则及请求参数:

1)template指定的”searchlog-*”表示该template将应用于searchlog-开头的索引的创建,并与order参数一起决定哪个模板生效(同名称规则的order更大的模板生效);

2)setting节点下refresh_interval参数表示数据自动刷新的频率(默认1s),由于日志文件实时性要求并不是特别高,因此这里可以酌情降低频率以提高索引的写入性能;

#查询索引
GET /_cat/indices?v
#模糊查询索引
GET _cat/indices/log*

DELETE loginfo-2021-01-07

#查询索引下所有数据
GET loginfo-2021-01-07/_search?pretty
{
  "query": {
    "match_all": {}
  }
}

#获取文档
GET loginfo-2021-01-04/_doc/b18izXYBqI-k2LwG7vaq?pretty
#获取模板
GET _template/loginfo
#删除模板
DELETE _template/loginfo
#添加模板
PUT _template/loginfo
{

  "order": 1,
  "index_patterns" : ["loginfo*"],
  "settings": {
    "index": {
      "number_of_shards": "1",
      "number_of_replicas": "1",
      "max_result_window": 2147483647,
      "refresh_interval": "10s",
      "store": {
        "type": "fs"
      }
    }
  },
  "mappings": {
            "properties": {
                "@timestamp": {
                    "type": "date"
                },
                "@version": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "dateTime": {
          "format": "yyyy-MM-dd HH:mm:ss.SSS",
          "type": "date"
        },
        "level": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "thread": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "class": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "ip": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "port": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "applicationName": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "traceId": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "spanId": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "method": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "message": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                }
            },
            "dynamic_templates": [{
                "longs": {
                    "match_mapping_type": "string",
                    "match": "l_*",
                    "unmatch": "*_text",
                    "mapping": {
                        "type": "long"
                    }
                }
            }, {
                "shorts": {
                    "match_mapping_type": "string",
                    "match": "s_*",
                    "unmatch": "*_text",
                    "mapping": {
                        "type": "short"
                    }
                }
            }]
  },
  "aliases": {
    "display_es": {}
  }
}

Logstash部署

1.elasticsearch官网下载7.8.1logstash

2.解压后进入config

3.增加配置文件logstash-es.conf

4.增加内容

input {

    kafka {

        type => "loginfo"

        bootstrap_servers => ["10.0.1.104:9092,10.0.1.117:9092,10.0.1.127:9092"]

        group_id => "loginfo"

        topics => ["loginfo"]

        consumer_threads => 1

        decorate_events => true

        }

}

#过滤器,去除换行符,将消息以json格式解析

filter {
   multiline {
        pattern => "^\d{4}-\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2}:\d{1,2}"
        negate => true  
        what => "previous" 
    }   
    mutate {
        gsub => ["message","
    ",""]
        gsub => ["message","[\u0000-\u000A]",""] 
        gsub => ["message","\r",""]
    }

    json{
        source => "message"
    }
}

#消息输出到es集群,根据时间建立不同索引loginfo-%{+yyyy-MM-dd}

output {

        if[type] == "loginfo" {

                elasticsearch {

                        hosts => ["10.0.1.104:9200","10.0.1.117:9200","10.0.1.127:9200"]

                        #index => "log-service" 

                        #codec => "json" 这里写好像没用,还没测试,暂时注释

                        index => "loginfo-%{+yyyy-MM-dd}"  #使用自定义名称                       

                }

        }
       stdout { 
        codec => json
           }

}


   转载规则


《ELK介绍和部署》 锦泉 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录