Table of Contents

1. 前言

之前做了Prometheus和Jaeger相关的调研工作,这两者虽然也涉及到日志聚合相关的技术或是类似的技术,但毕竟不是通用的日志聚合系统。通用的日志聚合系统需要能接受任何类型的日志,并将其索引入库以备后续的查询。市面上这方面的产品现在基本上是Elasticsearch为主要选择,已经可以说是很成熟了。所以这块需求我这里也是以ELK为第一备选进行相关的调研。

后续的调研内容版本如下:

elasticsearch 7.0.0
elastic/filebeat 7.0.0
kibana 7.0.0

在提到Elasticsearch的时候我们一般不会只说Elasticsearch本身,而是会提到ELK这个词,这里说的其实就是从日志采集、清洗、转换、分发、到最后入库的整个流程,以及查询用的面板包含在内的一整套生态。因此下面行文会从:日志采集、日志存储、日志查询三方面着手。

官方文档:

2. Log Shipper

日志是在各个应用程序中生产的,此外也包括了操作系统级别的日志生产。因此日志的产生这个行为是分散在各个节点上的,日志的收集就是从分散的节点采集数据汇集到中心存储的一个过程,这也是所谓的聚合。而从分散的节点上采集数据,我们需要Agent(Log Shipper)来执行这个操作。

经典的ELK中,L代表的就是日志采集Agent:Logstash。当然,市面上也有非常多的其他选择,可以做到和Logstash类似的功能。从系统设计上来说,ELK三者本身是完全解耦分离的,所以所谓的ELK堆栈,只是一种经过验证的实践方案,其实中间除了E之外,L和K都是可以自由更换的。

2.1 横向比较 & 选择

关于日志采集组件的备选有大量横向比较,推荐阅读:5 Logstash Alternatives。这篇的时间还算比较新2018-10-09,讲解也非常到位,基本上看这篇就OK了。

此外,StevenACoffman/fluent-filebeat-comparison.md也可以看下。

排除比较年轻的项目,以及资历不太雄厚的项目,剩下的主要选项有三个:

  • Logstash
    • 优势:功能强大;经过实践检验
    • 劣势:资源占用过大;JVM
  • Filebeat
    • 优势:Go语言;部署简单;资源占用极小
    • 劣势:功能相对简单
  • Fluentd
    • 优势:CNCF孵化项目
    • 劣势:Ruby语言实现

Log Shipper作为每个应用程序都需要附加的边车组件其中之一,Logstash的内存和CPU消耗在某些情况下是完全不能接受的(1GB内存,开玩笑)。JVM众所周知是比较难搞的虚拟机,如果要用好,调优需要有非常专门的知识,所以算是一个减分项。但放在Elasticsearch堆栈上来说,倒也不是那么严重,因为你无论如何都需要JVM知识来调优Elasticsearch本身。功能强大是Logstash的最大优势,能满足基本上所有的应用场景,在某些架构上,即便使用了Filebeat等高效轻量级的Log Shipper,在进入Elasticsearch入库之前仍旧需要一个Logstash来进行转换等工作。

Filebeat基本上没有缺点,如果它的功能能满足你的需求的话。如果不能满足,那么最新的Kafka输出能解决你的问题。使用Filebeat作为边车的Log Shipper,输出到Kafka,然后使用Logstash或者自己编写的组件来消费Kafka里的日志,最终入库到Elasticsearch。

Fluentd的最大优势在于CNCF的加持(背书)。但基于我多年的编程经验,ruby的性能一般来说是不可靠的,甚至使用JVM的Logstash都已经为性能付出了过大的代价,我又有什么理由要去相信口碑一直不怎么样的ruby呢。Logstash至少使用的JVM还和Elasticsearch本身是一个技术栈的,Fluentd会引入一个完全新的ruby虚拟机,就更加增加系统复杂度了。甚至,我在调研的初期就随手找到了:Fluentd retains excessive amounts of memory after handling traffic peaks #16572017年的BUG,到现在还是Open状态

综上所述,任何情况下都应该使用Filebeat作为边车的Log Shipper。Filebeat能满足需求的直接入库到Elasticsearch,不能满足需求的日志进Kafka,然后使用Logstash或其他Consumer来进行转换,最终入库到Elasticsearch。

2.2 架构设计

Architecture

图中的Logstash部分可以替换成自编写的轻量级Consumer。

3. Filebeat

非常细节的使用及配置,可以查看这篇中文的博客:Filebeat 模块与配置

3.1 设计 & 基础概念

Architecture

这张图看看就好,意义不大。

Filebeat是一种Elastic Beat,其实现基于libbeat框架,更多的可以查看:Beats Platform Reference

工作流:

  • 输入:从指定的文件进行监控日志增加行为,并触发读取发送
  • 输出:可直接向Elasticsearch集群发送日志,也可以将日志输出到外部的消息队列(Kafka)里
  • 模块:对某些日志进行的采集行为及Elasticsearch集群对这些日志进行分析的配置化和固化
  • 消费:Elasticsearch集群解析日志入库,或从Kafka读取日志然后解析入库

3.2 使用

部分说明文档:

3.3 模块

官方文档:Modules overview

Elasticsearch Ingest Node pipeline definition, which is used to parse the log lines.

首先明确一点,Filebeat的模块并不是一般意义上的功能模块。按软件设计思维来说,模块意味着功能的拓展,意味着根据模块设计的要求(框架)可以将软件本身能做的事情大幅拓展。而Filebeat的模块则不是,在Filebeat里,模块意味着一系列既有行为的组合:

  • Nginx有两个日志:access和error
  • Nginx在Elasticsearch上处理的Ingest Pipeline是XXX
  • Nginx的日志格式是XXX,Elasticsearch里对应的字段是XXX
  • Nginx日志对应的Kibana面板有XXX,可以看到XXX数据

从上面的例子可见:Filebeat本身并没有做什么,它做的仍旧只是采集日志,发送出去,没了。只不过指定了Elasticsearch集群中处理这个日志的Ingest Pipeline是谁,日志应该怎么入库(事情是在Elasticsearch集群上完成的)。因此Filebeat是不可能替代Logstash的,它的定位看来永远只能当做一个轻量级的应用端Log Shipper。

部分文档:

docker run --rm --name filebeat elastic/filebeat:7.0.0 modules list

3.4 过滤和丰富

Filebeat可以在配置中指定一些受限的过滤和清洗功能:Filter and enhance the exported data

可选的processor清单有:Processors

触发的条件:Conditions

3.5 文件状态记录 & 投递保证

Filebeat对于输入的日志文件,会制作一个本地的注册文件,将状态都保存下来,因此在重启或者挂掉重新拉起来之后,Filebeat总是能知道之前发送到哪里。

Filebeat会保证本地的日志文件至少被输出一次,如果在输出的结果返回之前Filebeat就挂掉的话,在下次Filebeat启动之后,它还会将之前最后的日志再投递一次(对于Filebeat来说,它并不知道自己死前已经投递过一次,并被输出方接收到了)。因此,收取数据的服务端可能在某些情况下收到重复的数据

4. Elasticsearch

2套电子书非常不错:

对于作为Elasticsearch底层的Lucene有兴趣的,可以查看这篇:Lucene 查询原理及解析

4.1 知识点

这一节基本上都是简单的知识点和概念罗列,主要阐明:”这是什么”。详细的内容会在后续的章节里分析。

4.1.1 基础概念

官方文档:Basic Concepts

提到了几点:

  • Near Realtime (NRT)
  • Cluster
  • Node
  • Index
  • Document
  • Shards & Replicas

4.1.2 安装 & 配置

后面三条对生产环境影响比较大,需要仔细阅读。

4.1.3 API

Elasticsearch的API文档相当散,主要是以下几项:

4.1.4 Query DSL

官方文档:Query DSL

了解Elasticsearch的人肯定会问:Query DSL和Elasticsearch的基础Lucene之间是什么关系。关于这个知识点可以查看:What is the difference between Lucene and Elasticsearch

Elasticsearch is a JSON Based, Distributed, web server build over Lucene. Though it’s Lucene who is doing the actual work beneath, Elasticsearch provides us a convenient layer over Lucene. Each shard that gets created in Elasticsearch is a separate Lucene instance.

Lucene是底层,Elasticsearch是基于Lucene之上的富集开发,而QueryDSL则是用户和Elasticsearch之间交互的桥梁。

4.1.5 SQL

Elasticsearch还可以使用SQL进行查询:SQL access

4.1.6 Ingest节点

在整个Elasticsearch集群中,有一部分节点是用来进行日志过滤、清洗、丰富化的,这些工作在这个设计出现之前是只能在Agent上实现的,一般来说就是Logstash,而现在在服务器节点上也可以处理相对应的工作了。

官方文档:Ingest Node

通过定义Processors来进行日志的解析和处理:Processors

初步了解下来功能应该还算强大,可以使用脚本化代码进行功能拓展:

此外还有插件机制:Ingest Plugins

4.2 文档数据库 & 索引

Elasticsearch是一个文档数据库,从本质上来看,它和Mongo其实相当类似。和传统RDBMS比较起来:

Relational DB -> Databases -> Tables  -> Rows      -> Columns
Elasticsearch -> DEFAULT   -> Indices -> Documents -> Fields

举个例子: PUT /employee/1

Index:employee
Document:

{
    "first_name" : "John",
    "last_name" :  "Smith",
    "age" :        25,
    "about" :      "I love to go rock climbing",
    "interests": [ "sports", "music" ]
}

Fields:

  • first_name
  • last_name
  • age
  • about
  • interests

索引非常重要,在集群模式(cluster)中,索引是用来进行分区的唯一指标。Elasticsearch会根据Index来决定当前数据落到哪台实际的存储服务器上。

关于索引的细节,以及一些集群相关的索引知识,可以查看:Index API

4.3 存储

在官方手册文档中,并没有关于存储相关的设计及实现的详细内容。在Blog中找到一篇:A Dive into the Elasticsearch Storage,不过时间也稍微有点久,但还算可以用来一窥存储相关的技术点。

此外,shards:Lucene segments

Each Elasticsearch index is divided into shards. Shards are both logical and physical division of an index. Each Elasticsearch shard is a Lucene index. The maximum number of documents you can have in a Lucene index is 2,147,483,519. The Lucene index is divided into smaller files called segments. A segment is a small Lucene index. Lucene searches in all segments sequentially.

elk_shards

4.4 集群

关于架构和集群的基础概念可以阅读官方的一份PPT:Elasticsearch Best Practice Architecture

主要是了解下Elasticsearch集群的节点分类:

elk_node_types

然后看下之前提到过的ELK整体集群拓扑:

elk_arch

此外推荐一篇:Designing the Perfect Elasticsearch Cluster: the (almost) Definitive Guide

在官方的文档库中我并没有找到比较新版本的文档有讲解到分布式和高可用之类的架构设计内容,大部分的文档都是各种API和各种细节。在老的版本中倒是找到一点信息:

此外,中文书里的内容也可以阅读:集群内部工作方式,注意这本中文书的版本已经相当老了,里面的内容有部分和现在的版本明显不同。

几点整理:

  • replica与数据主节点并不一定是1:1的关系(并不一定一个master拖一个slave这样的设计),主节点的数据是完全分散到其他各个replica节点上的,这个replica节点数量是可设置的
  • 当你的replica设置越多,写入速度就越慢(参与的节点多),主节点写入完毕之后还要让所有的replica写入,全部都完成才会返回客户端完成
  • 当你的replica设置越多,查询(读取)速度就越快(参与的节点多)
  • 当发生查询请求时,查询请求是会落到所有的shard上的,所以集群shards做的越多,整个集群的查询性能开销就越大,这里就有一个平衡的问题

4.5 监控 & 高可用

4.5.1 监控

对于Elasticsearch的监控,官方有一套解决方案(Elasticsearch算是一个生态了,在上游和下游都有完整的处理)。可以查阅下官方文档:

当然也可以选用Prometheus作为监控:

4.5.2 高可用

数据节点数量选择

可恢复的集群最低配置

  • 3 locations to host your nodes. 2 locations to run half of your cluster, and one for the backup master node.
  • 3 master nodes. You need an odd number of eligible master nodes to avoid split brains when you lose a whole data center. Put one master node in each location so you hopefully never lose the quorum.
  • 2 http nodes, one in each primary data center.
  • As many data nodes as you need, split evenly between both main locations.

故障恢复

Elasticsearch在集群中分主节点shard和复制节点replica,当集群的设置足够多(数据冗余充分)的情况下,当某个物理节点不可用时,Elasticsearch会自动进行选举,将丢失的主节点shard的replica节点设置成主节点,并重新对集群进行平衡。举个例子:

事故发生前:

  • 一共有3个物理节点
  • 一共有3个主节点shard
  • 每个主节点shard有2个复制节点replica
  • 当前物理节点1是作为整个集群的master节点进行服务的
  • 后续事故会发生在物理节点1,这个节点会下线

Before

事故发生后:

  • master节点下线了,因此集群重新开始选取master节点,设定为物理节点2
  • 0号主节点shard(P0)本来就在物理节点3上,因此不受影响
  • 1号和2号主节点shard之前在物理节点1上,全部丢失,集群将物理节点2上的2号shard的replica(R2)提升为主节点shard(P2),并将物理节点3上的1号shard的replica(R1)提升为主节点shard(P1)
  • 此时所有的主节点shard都已恢复,且各主节点shard都存在一份replica
  • 后续集群会继续为各主节点shard复制缺失的一份replica

After

4.6 性能调优

Ebay有一篇非常细节非常棒的设计及性能优化分析博文:Elasticsearch Performance Tuning Practice at eBay。从时间上来看,这篇文章也比较近:2018-01-08。

这篇博文分析了大规模Elasticsearch集群会面临的挑战,以及解决方案,还按实际的应用Scenario进行了问题分析以及给出了解决范例,很棒。

5. UI

Kibana这块相对来说比较简单(?),这里就只做简单的尝试。下面会列一些关键文档位置:

6. 实践范例

和之前做Prometheus实验的时候一样,因为需要把握一些细节,所以实验使用的还是下载下来的Elasticsearch、Kibana以及Filebeat。作为配角的Nginx使用的则是镜像版本。

范例代码可以在Github查看:dist-system-practice/experiment/elasticsearch/

7. TODO

  • Elasticsearch集群及一些基本观察用的API熟悉
  • Elasticsearch JVM相关参数和实践研究
  • Elasticsearch reshard的策略,最佳实践
  • Elasticsearch reshard时候的CPU、磁盘、内存,还有特别是网络的影响
  • Elasticsearch reshard在各种集群规模下的耗时
  • Elasticsearch的性能指标研究
  • Elasticsearch性能测试
  • Kibana使用深入
  • 添加Logstash部分内容,这块由于时间问题暂时不准备展开

资料

链接

EOF