ELK 指南

之前写文章分别介绍过 Logstash 和 Elasticsearch,这里结合《ELKstack 中文指南》和自己的一些实战经验来具体介绍一下 ELK。


更新记录

  • 2016.07.26: 初稿
  • 2016.11.19: 更新通天塔之日志分析平台系列文章链接

通天塔之日志分析平台系列文章

简介

本日志中使用的 ELK 版本为:

  • Logstash - 2.3
  • Elasticsearch - 2.x
  • Kibana - 4.4

ELK Stack 的优点就直接复制书中的原话:

ELK Stack 在最近两年迅速崛起,成为机器数据分析,或者说实时日志处理领域,开源界的第一选择。和传统的日志处理方案相比,ELK Stack 具有如下几个优点:

  • 处理方式灵活。Elasticsearch 是实时全文索引,不需要像 storm 那样预先编程才能使用;
  • 配置简易上手。Elasticsearch 全部采用 JSON 接口,Logstash 是 Ruby DSL 设计,都是目前业界最通用的配置语法设计;
  • 检索性能高效。虽然每次查询都是实时计算,但是优秀的设计和实现基本可以达到全天数据查询的秒级响应;
  • 集群线性扩展。不管是 Elasticsearch 集群还是 Logstash 集群都是可以线性扩展的;
  • 前端操作炫丽。Kibana 界面上,只需要点击鼠标,就可以完成搜索、聚合功能,生成炫丽的仪表板。

总结一下,Logstash 收集数据,Elasticsearch 索引数据,Kibana 展示数据,ELK 套餐,就是这么简单。

安装

这里以 Ubuntu 16.04 系统为例(纯净安装),来简单介绍 ELK Stack 的安装:

  • 安装 Java 8
    • 添加源 sudo add-apt-repository -y ppa:webupd8team/java
    • 更新地址 sudo apt-get update
    • 安装 sudo apt-get -y install oracle-java8-installer
  • 添加 Elastic 公钥
    • 添加密钥 wget -qO - https://packages.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
    • Elasticsearch repo echo "deb https://packages.elastic.co/elasticsearch/2.x/debian stable main" | sudo tee -a /etc/apt/sources.list.d/elasticsearch-2.x.list
    • Logstash repo echo "deb https://packages.elastic.co/logstash/2.3/debian stable main" | sudo tee -a /etc/apt/sources.list
    • Kibana repo echo "deb http://packages.elastic.co/kibana/4.5/debian stable main" | sudo tee -a /etc/apt/sources.list
    • 更新地址 sudo apt-get update
  • 安装并配置 ELK
    • Elasticsearch 安装 sudo apt-get install elasticsearch
    • Elasticsearch 添加开机启动 sudo update-rc.d elasticsearch defaults 95 10
    • Logstash 安装 sudo apt-get install logstash
    • 把 Logstash 添加到环境变量中,方便执行
      • ~/.bashrc 中末尾添加一行 export PATH="$PATH:/opt/logstash/bin/"
      • 使配置生效 source ~/.bashrc
      • 这样直接输入 logstash即可执行
    • Kibana 安装 sudo apt-get install kibana
    • Kibana 添加开机启动 sudo update-rc.d kibana defaults 95 10

Logstash

Logstash 最打动我的是整个社区的风格,而这个风格和作者 Jordan Sissel 本人分不开,虽然现在最初的 Google groups 已经搬迁到 elastic 官方的论坛,但是还是能看到这么一句话:

Remember: if a new user has a bad time, it’s a bug in logstash

这是什么精神,这是白求恩精神,做一个高尚的人,一个纯粹的人,一个有道德的人,一个脱离了低级趣味的人,一个有益于人民的人。嗯,就是这样。

简单的入门可以参考我的 Logstash 入门指南,这里重点介绍一些中高级用法。

Logstash 支持的数据值类型有 bool, string, number, array 和 hash,和 Redis 一样,支持得不多,但是完全够用。支持的条件判断和表达式则比较丰富,如:

  • 基本条件判断 ==, !=, <, >, <=, >=
  • =~ 匹配正则, !~ 不匹配正则
  • in 包含, not in 不包含
  • and 与, or 或, nand 非与, xor 非或
  • () 复合表达式, !() 表达式结果取反

比方说我们有一个字段是 type,我们想要过滤一下做指定操作的话,可以

if "good" in [type] {
// do something
} else {
// do something
}

从 Logstash 5.0 开始,可以在 $LS_HOME/config/logstash.yml 文件进行所有的命令行参数配置,例如

pipeline:
workers: 24
batch:
size: 125
delay: 5

Plugin

使用之前我们先要安装一下 ruby,命令为 sudo apt install ruby,然后我们可以运行 logstash-plugin list 来看看本机中目前有多少插件可以用,这里会有一个警告,不过查阅 github issue 中说没有问题,那就暂时忽略。插件很多,这里就不一一介绍,简单贴一下 help 文档应该就一目了然了:

dawang@dawang-Parallels-Virtual-Platform:~$ logstash-plugin -h Usage: bin/logstash-plugin [OPTIONS] SUBCOMMAND [ARG] ... Parameters: SUBCOMMAND subcommand [ARG] ... subcommand arguments Subcommands: install Install a plugin uninstall Uninstall a plugin update Update a plugin pack Package currently installed plugins unpack Unpack packaged plugins list List all installed plugins Options: -h, --help print help

自动运行

通常来说,我们需要 logstash 在后台长期运行,否则每次需要去各台机器上手动操作,会很麻烦。

有两种方法,一种是配合 crontab,定期执行指定命令,另一种是让 logstash 以服务或者守护进程的形式运行,配合配置文件中的 schedule 即可。其中 crontab 的方法可以参阅 Crontab 指南,这里主要介绍另外四种方法。

方法一:标准的 service 方式

/etc/init.d/logstash 脚本中,会加载 /etc/init.d/functions 库文件,利用其中的 daemon 函数,将 logstash 进程作为后台程序运行。

我们要做的是把配置文件都放到 /etc/logstsh/ 目录下,必须以 .conf 结尾,然后我们执行 service logstash start 即可(注意要在配置文件中设定好 schedule,这样就可以按照要求自动执行了)

方法二:nohup 方式

简单来说,一句话就可以搞定,如果想让某命令在后台长期运行,需要在命令前加 nohup,后面加 &

方法三:用 tmux/screen

一般来说,如果我需要让服务器跑一堆命令又不想挂着 ssh 连接的话,直接用 tmux/screen 运行命令即可,这样即使退出,命令也依然在执行,具体的使用可以参考 tmux 指南

方法四:daemontools 方式

如果需要长期在后台运行大量程序,建议使用 daemontools 工具,可以通过配置文件来管理操作程序,类似于自动化的 tmux,比方说 python 实现的 supervisord,perl 实现的 ubic 或者 ruby 实现的 god,具体的用法之后会写日志进行说明

Input

我们的配置文件中一定需要有一个 input,如果没有的话,就会默认使用 input/stdin。这里只记录一些最常用和最基本的插件,更多的插件可以参考官方文档或参考链接中的教程。

  • 读取文件 File
  • 读取 Syslog 数据
  • 编码插件 Codec: JSON

Filter

这部分是 Logstash 最具特色和扩展性的部分(但并不一定是必须的),这里只记录一些最常用和最基本的插件,更多的插件可以参考官方文档或参考链接中的教程。

  • 时间处理 Date,包括 ISO8601, UNIX, UNIX_MS, TAI64NJoda-Time
  • 正则捕获 Grok,这个插件可以摆弄出非常多的黑魔法,可以考虑重点应用,记得使用 Grok Debugger 来调试 grok 表达式
  • GeoIP 地址查询,用于统计区域活着可视化地图
  • Mutate 数据修改,可以用来转换类型、处理字符串以及处理字段(重命名、更新、替换等)
  • split 拆分事件

Output

我们的配置文件中一定需要有一个 input,如果没有的话,就会默认使用 output/stdout。这里只记录一些最常用和最基本的插件,更多的插件可以参考官方文档或参考链接中的教程。

  • 保存到 Elasticsearch 中,注意几个参数: flush_size 是攒够这个大小才写入,idle_flush_time 是隔这么多时间写入一次,这俩都会影响 ES 的写入性能
  • 发邮件 Email
  • 调用命令执行 exec,比方说可以发短信,最好只用于少量的信息处理场景
  • 保存成文件 file
  • 发送到 HDFS 可以使用 hadoop_webhdfs 插件

监控 API

从 Logstash 5.0 开始提供了监控 API,就不再像以前那样比较黑盒了,具体有

  • events curl -s localhost:9600/_node/stats/events?pretty=true
  • jvm curl -s localhost:9600/_node/stats/jvm?pretty=true
  • process curl -s localhost:9600/_node/stats/process?pretty=true
  • 热线程统计 curl -s localhost:9600/_node/stats/hot_threads?human=true

扩展

可以考虑的思路:

  • 利用 Redis
  • 利用 Kafka
  • 利用 rsyslog

Elasticsearch

配置文件在 /etc/elasticsearch/elasticsearch.yml,重启命令 sudo service elasticsearch restart

基本原理

这部分内容虽然不一定对工程有立竿见影的帮助,但是知其然还知其所以然,才是高手的做事风格。那么问题来了

写入的数据是如何变成 Elasticsearch 里可以被检索和聚合的索引内容的?

关键在于『倒排索引』,新收到的数据会被写入到内存的 buffer 中,然后在一定的时间间隔后刷到磁盘中,成为一个新的 segment,然后另外使用一个 commit 文件来记录所有的 segment,数据只有在成为 segment 之后才能被检索。默认的从 buffer 到 segment 的时间间隔是 1 秒,基本已经是『实时』了,如果需要更改,也可以调用 /_refresh 接口。不过很多时候我们不需要这么『实时』,所以可以加大这个时间间隔,以获得更快的写入性能。导入历史数据时甚至可以关闭,导入完成再重新开启。

为了保证数据从 buffer 到 segment 的一致性,Elasticsearch 还会有一个名为 Translog 的记录,至于 Translog 的一致性则是通过定期保存到磁盘中来实现的

前面说过 Lucene 会不断开新文件,这样磁盘上就会有一堆小文件,所以 ES 会在后台把这些零散的 segment 做数据归并,归并完成后就可以把小的 segment 删掉,也就减少了 segment 的数量了。为了不影响 IO 和 CPU,会对归并线程做一定的限制,我们可以根据硬件的不同来调整 indices.store.throttle.max_bytes_per_sec 来提高性能。与此同时,我们也有不同的归并策略,不过总体来说就是让我们加大 flush 的间隔,尽量让每次新生成的 segment 本身就比较大。

ES 的分布式处理主要是通过 sharding 机制,也会保留副本进行冗余备份,具体采用的是 gossip 协议,配置也不算复杂,这里就不赘述,如果有机会专门写一篇实例教程。

增删改查

ES 虽然不是数据库,不过其特性决定了,这就是一个很好的 NoSQL 数据库嘛,因为 ELK stack 的缘故,写入由 Logstash 负责,查询由 Kibana 负责,不过修改和删除就有些无能为力了(毕竟为什么要简单修改和删除日志?),可是修改和删除是数据库必须的功能,好在 ES 提供了 RESTful 接口来处理 JSON 请求,最简单的用 curl 就可以完成各类操作。这里推荐一个 Chrome 的插件 Postman,可以很方便进行各类测试。具体如何发送请求请参考文档,这里不赘述了。

搜索

前面的增删改查针对的是单条记录,ES 中更重要的是搜索。这里回顾一下:刚写入的数据,可以通过 translog 立刻获取;但是直到其成为一个 segment 之后,才能被搜索到

可以利用 /_search?q= 这种 querystring 的简单语法,或者发送完整的 json 来进行查询。具体可以依据版本查阅文档,这里不赘述。

另外,聚合、管道聚合

其他功能

Elasticsearch 目前已经可以和 Hadoop, HDFS, Spark Streaming 等大数据工具连接使用。如果需要配置权限,可以使用 Elastic 官方的 Shield,如果想用开源的话,可以使用 search-guard,这样不同的用户可以访问不同的索引,达到权限控制。

监控集群健康状态也可以通过接口访问,比如 curl -XGET 127.0.0.1:9200/_cluster/health?pretty,更多监控信息请参阅文档,这里不赘述。

需要提的一点就是 GC 是非常影响性能的,所以我们来简单介绍一下 JVM 的机制。启动 JVM 虚拟机的时候,会分配固定大小的内存块,也就是堆 heap。堆又分成两组,Young 组是为新实例化的对象所分配的空间,比较小,一般来说几百 MB,Young 组内又分为两个 survivor 空间。Young 空间满了后,就垃圾回收一次,还存活的对象放到幸存空间中,失效的就被移除。Old 组就是保存那些重启存活且一段时间不会变化的内容,对于 ES 来说可能有 30 GB 内存是 Old 组,同样,满了之后就垃圾回收。

垃圾回收的时候,JVM 采用的是 STW(Stop The World) 机制,Young 组比较小还好,但是 Old 组可能需要几秒十几秒,那就是服务器无响应啊!所以我们必须非常关注 GC 性能。

如果 ES 集群中经常有很耗时的 GC,说明内存不足,如果影响集群之间 ping 的话,就会退出集群,然后因为分片缘故导致更大的影响。我们可以在节点状态中的 jvm 部分查看对应的数值,最重要是 heap_used_percent,如果大于 75,那么就要垃圾回收了,如果长期在 75 以上,那就是内存不足。

注:节点状态可以通过 curl -XGET http://127.0.0.1:9200/_nodes/stats 查看,下面是一个例子(省略了部分内容):

{
"cluster_name" : "wdxtub",
"nodes" : {
"M-OzSwFBTc6uU8ndWU1SFw" : {
"timestamp" : 1470310258934,
"name" : "Kleinstocks",
"transport_address" : "127.0.0.1:9302",
"host" : "127.0.0.1",
"ip" : [ "127.0.0.1:9302", "NONE" ],
"indices" : {
"docs" : {
"count" : 7240861,
"deleted" : 257
},
"store" : {
"size_in_bytes" : 1836976476,
"throttle_time_in_millis" : 0
},
"indexing" : {
"index_total" : 17746868,
"index_time_in_millis" : 5340065,
"index_current" : 2,
"index_failed" : 0,
"delete_total" : 418,
"delete_time_in_millis" : 70,
"delete_current" : 0,
"noop_update_total" : 0,
"is_throttled" : false,
"throttle_time_in_millis" : 0
},
"get" : {
"total" : 351,
"time_in_millis" : 146,
"exists_total" : 240,
"exists_time_in_millis" : 104,
"missing_total" : 111,
"missing_time_in_millis" : 42,
"current" : 0
},
"search" : {
"open_contexts" : 0,
"query_total" : 2408275,
"query_time_in_millis" : 5930419,
"query_current" : 0,
"fetch_total" : 474268,
"fetch_time_in_millis" : 2706552,
"fetch_current" : 0,
"scroll_total" : 80,
"scroll_time_in_millis" : 158449847,
"scroll_current" : 0
},
"merges" : {
"current" : 0,
"current_docs" : 0,
"current_size_in_bytes" : 0,
"total" : 85947,
"total_time_in_millis" : 30458385,
"total_docs" : 876375857,
"total_size_in_bytes" : 256573193466,
"total_stopped_time_in_millis" : 0,
"total_throttled_time_in_millis" : 348966,
"total_auto_throttle_in_bytes" : 65901809302
},
"refresh" : {
"total" : 833546,
"total_time_in_millis" : 7243577
},
"flush" : {
"total" : 4038,
"total_time_in_millis" : 58670
},
"warmer" : {
"current" : 0,
"total" : 309738,
"total_time_in_millis" : 102270
},
"query_cache" : {
"memory_size_in_bytes" : 588080,
"total_count" : 47737532,
"hit_count" : 66843,
"miss_count" : 47670689,
"cache_size" : 408,
"cache_count" : 1687,
"evictions" : 1279
},
"fielddata" : {
"memory_size_in_bytes" : 16791680,
"evictions" : 0
},
"percolate" : {
"total" : 0,
"time_in_millis" : 0,
"current" : 0,
"memory_size_in_bytes" : -1,
"memory_size" : "-1b",
"queries" : 0
},
"completion" : {
"size_in_bytes" : 0
},
"segments" : {
"count" : 14771,
"memory_in_bytes" : 162052342,
"terms_memory_in_bytes" : 101949950,
"stored_fields_memory_in_bytes" : 4785984,
"term_vectors_memory_in_bytes" : 0,
"norms_memory_in_bytes" : 77376,
"doc_values_memory_in_bytes" : 55239032,
"index_writer_memory_in_bytes" : 0,
"index_writer_max_memory_in_bytes" : 1583616000,
"version_map_memory_in_bytes" : 0,
"fixed_bit_set_memory_in_bytes" : 0
},
"translog" : {
"operations" : 0,
"size_in_bytes" : 132999
},
"suggest" : {
"total" : 0,
"time_in_millis" : 0,
"current" : 0
},
"request_cache" : {
"memory_size_in_bytes" : 0,
"evictions" : 0,
"hit_count" : 0,
"miss_count" : 0
},
"recovery" : {
"current_as_source" : 0,
"current_as_target" : 0,
"throttle_time_in_millis" : 0
}
},
"os" : {
"timestamp" : 1470310262865,
"cpu_percent" : 56,
"load_average" : 2.04,
"mem" : {
"total_in_bytes" : 16827527168,
"free_in_bytes" : 761749504,
"used_in_bytes" : 16065777664,
"free_percent" : 5,
"used_percent" : 95
},
"swap" : {
"total_in_bytes" : 0,
"free_in_bytes" : 0,
"used_in_bytes" : 0
}
},
"process" : {
"timestamp" : 1470310262865,
"open_file_descriptors" : 26370,
"max_file_descriptors" : 65535,
"cpu" : {
"percent" : 30,
"total_in_millis" : 1508401460
},
"mem" : {
"total_virtual_in_bytes" : 7386607616
}
},
"jvm" : {
"timestamp" : 1470310262874,
"uptime_in_millis" : 1237196806,
"mem" : {
"heap_used_in_bytes" : 2868003728,
"heap_used_percent" : 67,
"heap_committed_in_bytes" : 4260102144,
"heap_max_in_bytes" : 4260102144,
"non_heap_used_in_bytes" : 75855480,
"non_heap_committed_in_bytes" : 109502464,
"pools" : {
"young" : {
"used_in_bytes" : 193899664,
"max_in_bytes" : 279183360,
"peak_used_in_bytes" : 279183360,
"peak_max_in_bytes" : 279183360
},
"survivor" : {
"used_in_bytes" : 29947264,
"max_in_bytes" : 34865152,
"peak_used_in_bytes" : 34865152,
"peak_max_in_bytes" : 34865152
},
"old" : {
"used_in_bytes" : 2644156800,
"max_in_bytes" : 3946053632,
"peak_used_in_bytes" : 3916390728,
"peak_max_in_bytes" : 3946053632
}
}
},
"threads" : {
"count" : 78,
"peak_count" : 88
},
"gc" : {
"collectors" : {
"young" : {
"collection_count" : 764634,
"collection_time_in_millis" : 25826848
},
"old" : {
"collection_count" : 500,
"collection_time_in_millis" : 56557
}
}
}
},
"thread_pool" : {
"bulk" : {
"threads" : 4,
"queue" : 0,
"active" : 0,
"rejected" : 0,
"largest" : 4,
"completed" : 877671
},
"fetch_shard_started" : {
"threads" : 8,
"queue" : 0,
"active" : 0,
"rejected" : 0,
"largest" : 8,
"completed" : 17037949
},
"fetch_shard_store" : {
"threads" : 0,
"queue" : 0,
"active" : 0,
"rejected" : 0,
"largest" : 0,
"completed" : 0
},
"flush" : {
"threads" : 1,
"queue" : 0,
"active" : 0,
"rejected" : 0,
"largest" : 2,
"completed" : 10416
},
"force_merge" : {
"threads" : 0,
"queue" : 0,
"active" : 0,
"rejected" : 0,
"largest" : 0,
"completed" : 0
},
"generic" : {
"threads" : 4,
"queue" : 0,
"active" : 0,
"rejected" : 0,
"largest" : 5,
"completed" : 17161902
},
"get" : {
"threads" : 4,
"queue" : 0,
"active" : 0,
"rejected" : 0,
"largest" : 4,
"completed" : 351
},
"index" : {
"threads" : 4,
"queue" : 0,
"active" : 0,
"rejected" : 0,
"largest" : 4,
"completed" : 302497
},
"listener" : {
"threads" : 2,
"queue" : 0,
"active" : 0,
"rejected" : 0,
"largest" : 2,
"completed" : 457516
},
"management" : {
"threads" : 5,
"queue" : 0,
"active" : 1,
"rejected" : 0,
"largest" : 5,
"completed" : 838887
},
"percolate" : {
"threads" : 0,
"queue" : 0,
"active" : 0,
"rejected" : 0,
"largest" : 0,
"completed" : 0
},
"refresh" : {
"threads" : 1,
"queue" : 0,
"active" : 0,
"rejected" : 0,
"largest" : 2,
"completed" : 833549
},
"search" : {
"threads" : 7,
"queue" : 0,
"active" : 0,
"rejected" : 105785,
"largest" : 7,
"completed" : 2930414
},
"snapshot" : {
"threads" : 0,
"queue" : 0,
"active" : 0,
"rejected" : 0,
"largest" : 0,
"completed" : 0
},
"suggest" : {
"threads" : 0,
"queue" : 0,
"active" : 0,
"rejected" : 0,
"largest" : 0,
"completed" : 0
},
"warmer" : {
"threads" : 1,
"queue" : 0,
"active" : 0,
"rejected" : 0,
"largest" : 2,
"completed" : 864039
}
},
"fs" : {
"timestamp" : 1470310262388,
"total" : {
"total_in_bytes" : 316934193152,
"free_in_bytes" : 32878755840,
"available_in_bytes" : 16755851264
},
"data" : [ {
"path" : "/data2/active2/dji-active/nodes/0",
"mount" : "/data2 (/dev/xvdf)",
"type" : "ext4",
"total_in_bytes" : 316934193152,
"free_in_bytes" : 32878755840,
"available_in_bytes" : 16755851264,
"spins" : "false"
} ]
},
"transport" : {
"server_open" : 0,
"rx_count" : 30,
"rx_size_in_bytes" : 8193,
"tx_count" : 36,
"tx_size_in_bytes" : 13202
}
}
}
}

状态比较多,这里挑几个说一下,首先是 gc 部分,显示的是 young 和 old gc 的耗时,一般来说 young 会比较大,这是正常的。一次 young gc 大概在 1-2ms,old gc 在 100 ms 左右,如果有量级上的差距,建议打开 slow-gc 日志,具体研究原因。

thread_pool 是线程池信息,我们主要看 rejected 的数据,如果这个数值很大,就说明 ES 忙不过来了。

其他的基本就是系统和文件系统的数据如果 fielddata_breaker.tripped 数值太高,那么就需要优化了。

其他一些监控接口

  • hot_threads 状态 curl -XGET 'http://127.0.0.1:9200/_nodes/_local/hot_threads?interval=60s'
  • 等待执行的任务列表 curl -XGET http://127.0.0.1:9200/_cluster/pending_tasks{ "tasks": [] }
  • 可以用 /_cat 接口,具体参考文档
    • 集群状态 curl -XGET http://127.0.0.1:9200/_cat/health?v
    • 节点状态 curl -XGET http://127.0.0.1:9200/_cat/nodes?v

Elasticsearch 的日志在 $ES_HOME/logs/ 中,或者可以使用 官方自己的监控工具 - marvel。如果在生产环境中,最好使用 nagios, zabbix, ganglia, collectd 这类监控系统。

Kibana

Kibana3 和 Kibana4 基本还处于并行的状态(想到了 Python),这里主要介绍 Kibana4(因为主要在用这个版本)

任何需要展示的数据都需要现在 Settings 中进行索引配置,注意可以选择配置时间索引,这样在 Discover 页面会多出来时间的选项。默认情况下,Discover 页面会显示匹配搜索条件的前 500 个文档。Visualization 用来为搜索结果做可视化。每个可视化都是跟一个搜索关联着的。Dashboard 可以创建定值自己的仪表盘。

要应用到生产环境的话,具体对于 Nginx, shield 和 SSL 的配置请参考官方文档。使用 Shield 的话,可以做到索引级别的访问控制,这对多团队管理很有帮助。

Discover

Discover 标签用于交互式探索数据。基本上常用的功能应有尽有,具体就要自己慢慢摸索。

  • 右上角的时间过滤器、中间的直方图都可以选择时间范围
  • 搜索的时候可以使用 Lucene 查询语法,可以用完整的基于 JSON 的 Elasticsearch 查询 DSL
  • 按字段过滤包含正反两种过滤器,尝试一下即可
  • JSON 中可以灵活应用 bool query 组合中各种 should, must, must not 条件
  • 可以使用任何已建立索引的字段排序文档表哥中的数据。如果当前索引模式配置了时间字段,默认会使用该字段倒序排列文档

Visualize

几个不同的大类

  • Area chart: 用区块图来可视化多个不同序列的总体共享
  • Data table: 用数据表来显示聚合的原始数据。其他可视化可以通过点击底部的方式显示数据表
  • Line char: 用折线图来比较不同序列
  • Markdown widget: 用 Markdown 显示自定义格式的信息或和仪表盘有关的用法说明
  • Metric: 用指标在仪表盘上显示单个数字
  • Pie char: 用饼图来显示每个来源对总体的贡献
  • Tile map: 用瓦片地图将聚合结果和经纬度联系起来
  • Vertical bar chart: 用垂直条形图作为一个通用图形

Y 轴的数值维度有以下聚合:

  • Count 原始计数
  • Average 平均值
  • Sum 总和
  • Min 最小值
  • Max 最大值
  • Unique Count 不重复的值
  • Standard Deviation 标准差
  • Percentile 百分比
  • Percentile Rank 百分比排名

配置

Kibana 服务器在启动的时候会从 kibana.yml 文件读取属性。常见的属性有

  • port
  • host
  • elasticsearch_url
  • kibana_index
  • default_app_id
  • request_timeout
  • shard_timeout
  • verify_ssl
  • ca
  • ssl_key_file
  • ssl_cert_file
  • pid_file

总结

ELK Stack 更应该用于实时监控和细节分析,总体来说搭建起来不算特别费劲。但是因为具体涉及的东西比较多,熟练掌握还是需要很多时间的,建议运维的同学好好往深挖。就我自己的感受来说,在配置机器和集群上花费的诸多时间着实让我痛苦(因为错了也不知道如何办),直接看文档的性价比也很低。不过对于日志监控的免费解决方案来说,ELK Stack 已经非常不错了。

参考链接

捧个钱场?