GET _cluster/health
Elasticsearch 经常以多节点集群的方式部署。有多种 API 让你可以管理和监控集群本身,而不用和集群里存储的数据打交道。
和 Elasticsearch 里绝大多数功能一样,我们有一个总体的设计目标,即任务应该通过 API 执行,而不是通过修改静态的配置文件。这一点在你的集群扩容时尤为重要。即便通过配置管理系统(比如 Puppet,Chef 或者 Ansible),一个简单的 HTTP API 调用,也比往上百台物理设备上推送新配置文件简单多了。
因此,本章将介绍各种可以让你动态调整、调优和调配集群的 API。同时,还会介绍一系列提供集群自身统计数据的 API,你可以用这些接口来监控集群健康状态和性能。
Marvel 让你可以很简单的通过 Kibana 监控 Elasticsearch。你可以实时查看你的集群健康状态和性能,也可以分析过去的集群、索引和节点指标。
虽然你可以通过本章介绍的 API 查看大量的指标数据,但是它们展示的都是当前时间点的即时情况。了解这个瞬间的内存占用比当然很有用,但是了解内存占用比 随时间轴的趋势 更加有用。Marvel 会查询并聚合这些数据,你可以通过可视化效果看到自己集群随时间的变化,这样可以很容易的发现发展的趋势。
随着你集群规模的发展,统计 API 的输出内容会复杂得让人完全没法看。当你有一大把节点,比如说一百个,再阅读这个输出的 JSON 就非常乏味了。而 Marvel 可以让你交互式的探索这些数据,更容易于集中关注特定节点或者索引上发生了什么。
Marvel 使用公开的 API,和你自己能找到的一样 — 它没有暴露任何你通过 API 访问不到的统计信息。但是,Marvel 极大的简化了这些统计信息的采集和可视化工作。
Marvel 可以免费使用(包括生产环境上!),所以你现在就开始用起来吧!安装介绍,参阅 Marvel 入门。
一个 Elasticsearch 集群至少包括一个节点和一个索引。或者它可能有一百个数据节点、三个单独的主节点,以及一小打客户端节点——这些共同操作一千个索引(以及上万个分片)。
不管集群扩展到多大规模,你都会想要一个快速获取集群状态的途径。Cluster Health
API 充当的就是这个角色。你可以把它想象成是在一万英尺的高度鸟瞰集群。它可以告诉你安心吧一切都好,或者警告你集群某个地方有问题。
让我们执行一下 cluster-health
API 然后看看响应体是什么样子的:
GET _cluster/health
和 Elasticsearch 里其他 API 一样,cluster-health
会返回一个 JSON 响应。这对自动化和告警系统来说,非常便于解析。响应中包含了和你集群有关的一些关键信息:
{
"cluster_name": "elasticsearch_zach",
"status": "green",
"timed_out": false,
"number_of_nodes": 1,
"number_of_data_nodes": 1,
"active_primary_shards": 10,
"active_shards": 10,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0
}
响应信息中最重要的一块就是 status
字段。状态可能是下列三个值之一:
green
所有的主分片和副本分片都已分配。你的集群是 100% 可用的。
yellow
所有的主分片已经分片了,但至少还有一个副本是缺失的。不会有数据丢失,所以搜索结果依然是完整的。不过,你的高可用性在某种程度上被弱化。如果 更多的 分片消失,你就会丢数据了。把 yellow
想象成一个需要及时调查的警告。
red
至少一个主分片(以及它的全部副本)都在缺失中。这意味着你在缺少数据:搜索只能返回部分数据,而分配到这个分片上的写入请求会返回一个异常。
green
/yellow
/red
状态是一个概览你的集群并了解眼下正在发生什么的好办法。剩下来的指标给你列出来集群的状态概要:
number_of_nodes
和 number_of_data_nodes
这个命名完全是自描述的。
active_primary_shards
指出你集群中的主分片数量。这是涵盖了所有索引的汇总值。
active_shards
是涵盖了所有索引的_所有_分片的汇总值,即包括副本分片。
relocating_shards
显示当前正在从一个节点迁往其他节点的分片的数量。通常来说应该是 0,不过在 Elasticsearch 发现集群不太均衡时,该值会上涨。比如说:添加了一个新节点,或者下线了一个节点。
initializing_shards
是刚刚创建的分片的个数。比如,当你刚创建第一个索引,分片都会短暂的处于 initializing
状态。这通常会是一个临时事件,分片不应该长期停留在 initializing
状态。你还可能在节点刚重启的时候看到 initializing
分片:当分片从磁盘上加载后,它们会从 initializing
状态开始。
unassigned_shards
是已经在集群状态中存在的分片,但是实际在集群里又找不着。通常未分配分片的来源是未分配的副本。比如,一个有 5 分片和 1 副本的索引,在单节点集群上,就会有 5 个未分配副本分片。如果你的集群是 red
状态,也会长期保有未分配分片(因为缺少主分片)。
想象一下某天碰到问题了, 而你发现你的集群健康状态看起来像是这样:
{
"cluster_name": "elasticsearch_zach",
"status": "red",
"timed_out": false,
"number_of_nodes": 8,
"number_of_data_nodes": 8,
"active_primary_shards": 90,
"active_shards": 180,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 20
}
好了,从这个健康状态里我们能推断出什么来?嗯,我们集群是 red
,意味着我们缺数据(主分片 + 副本分片)了。我们知道我们集群原先有 10 个节点,但是在这个健康状态里列出来的只有 8 个数据节点。有两个数据节点不见了。我们看到有 20 个未分配分片。
这就是我们能收集到的全部信息。那些缺失分片的情况依然是个谜。我们是缺了 20 个索引,每个索引里少 1 个主分片?还是缺 1 个索引里的 20 个主分片?还是 10 个索引里的各 1 主 1 副本分片?具体是哪个索引?
要回答这个问题,我们需要使用 level
参数让 cluster-health
答出更多一点的信息:
GET _cluster/health?level=indices
这个参数会让 cluster-health
API 在我们的集群信息里添加一个索引清单,以及有关每个索引的细节(状态、分片数、未分配分片数等等):
{
"cluster_name": "elasticsearch_zach",
"status": "red",
"timed_out": false,
"number_of_nodes": 8,
"number_of_data_nodes": 8,
"active_primary_shards": 90,
"active_shards": 180,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 20
"indices": {
"v1": {
"status": "green",
"number_of_shards": 10,
"number_of_replicas": 1,
"active_primary_shards": 10,
"active_shards": 20,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0
},
"v2": {
"status": "red", (1)
"number_of_shards": 10,
"number_of_replicas": 1,
"active_primary_shards": 0,
"active_shards": 0,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 20 (2)
},
"v3": {
"status": "green",
"number_of_shards": 10,
"number_of_replicas": 1,
"active_primary_shards": 10,
"active_shards": 20,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0
},
....
}
}
我们可以看到 v2
索引就是让集群变 red
的那个索引。
由此明确了,20 个缺失分片全部来自这个索引。
一旦我们询问要索引的输出,哪个索引有问题立马就很清楚了:v2
索引。我们还可以看到这个索引曾经有 10 个主分片和一个副本,而现在这 20 个分片全不见了。可以推测,这 20 个索引就是位于从我们集群里不见了的那两个节点上。
level
参数还可以接受其他更多选项:
GET _cluster/health?level=shards
shards
选项会提供一个详细得多的输出,列出每个索引里每个分片的状态和位置。这个输出有时候很有用,但是由于太过详细会比较难用。如果你知道哪个索引有问题了,本章讨论的其他 API 显得更加有用一点。
当构建单元和集成测试时,或者实现和 Elasticsearch 相关的自动化脚本时,cluster-health
API 还有另一个小技巧非常有用。你可以指定一个 wait_for_status
参数,它只有在状态达标之后才会返回。比如:
GET _cluster/health?wait_for_status=green
这个调用会 阻塞 (不给你的程序返回控制权)住直到 cluster-health
变成 green
,也就是说所有主分片和副本分片都分配下去了。这对自动化脚本和测试非常重要。
如果你创建一个索引,Elasticsearch 必须在集群状态中向所有节点广播这个变更。那些节点必须初始化这些新分片,然后响应给主节点说这些分片已经 Started
。这个过程很快,但是因为网络延迟,可能要花 10–20ms。
如果你有个自动化脚本是 (a) 创建一个索引然后 (b) 立刻写入一个文档,这个操作会失败。因为索引还没完全初始化完成。在 (a) 和 (b) 两步之间的时间可能不到 1ms —— 对网络延迟来说这可不够。
比起使用 sleep
命令,直接让你的脚本或者测试使用 wait_for_status
参数调用 cluster-health
更好。当索引完全创建好,cluster-health
就会变成 green
,然后这个调用就会把控制权交还给你的脚本,然后你就可以开始写入了。
有效的选项是: green
、 yellow
和 red
。这个调回会在达到你要求(或者『更高』)的状态时返回。比如,如果你要求的是 yellow
,状态变成 yellow
或者 green
都会打开调用。
集群健康
就像是光谱的一端——对集群的所有信息进行高度概述。而 节点统计值
API 则是在另一端。它提供一个让人眼花缭乱的统计数据的数组,包含集群的每一个节点统计值。
节点统计值
提供的统计值如此之多,在完全熟悉它之前,你可能都搞不清楚哪些指标是最值得关注的。我们将会高亮那些最重要的监控指标(但是我们鼓励你记录接口提供的所有指标——或者用 Marvel ——因为你永远不知道何时需要某个或者另一个值)。
节点统计值
API 可以通过如下命令执行:
GET _nodes/stats
在输出内容的开头,我们可以看到集群名称和我们的第一个节点:
{
"cluster_name": "elasticsearch_zach",
"nodes": {
"UNr6ZMf5Qk-YCPA_L18BOQ": {
"timestamp": 1408474151742,
"name": "Zach",
"transport_address": "inet[zacharys-air/192.168.1.131:9300]",
"host": "zacharys-air",
"ip": [
"inet[zacharys-air/192.168.1.131:9300]",
"NONE"
],
...
节点是排列在一个哈希里,以节点的 UUID 作为键名。还显示了节点网络属性的一些信息(比如传输层地址和主机名)。这些值对调试诸如节点未加入集群这类自动发现问题很有用。通常你会发现是端口用错了,或者节点绑定在错误的 IP 地址/网络接口上了。
索引(indices)
部分列出了这个节点上所有索引的聚合过的统计值:
"indices": {
"docs": {
"count": 6163666,
"deleted": 0
},
"store": {
"size_in_bytes": 2301398179,
"throttle_time_in_millis": 122850
},
返回的统计值被归入以下部分:
docs
展示节点内存有多少文档,包括还没有从段里清除的已删除文档数量。
store
部分显示节点耗用了多少物理存储。这个指标包括主分片和副本分片在内。如果限流时间很大,那可能表明你的磁盘限流设置得过低(在段和合并里讨论过)。
"indexing": {
"index_total": 803441,
"index_time_in_millis": 367654,
"index_current": 99,
"delete_total": 0,
"delete_time_in_millis": 0,
"delete_current": 0
},
"get": {
"total": 6,
"time_in_millis": 2,
"exists_total": 5,
"exists_time_in_millis": 2,
"missing_total": 1,
"missing_time_in_millis": 0,
"current": 0
},
"search": {
"open_contexts": 0,
"query_total": 123,
"query_time_in_millis": 531,
"query_current": 0,
"fetch_total": 3,
"fetch_time_in_millis": 55,
"fetch_current": 0
},
"merges": {
"current": 0,
"current_docs": 0,
"current_size_in_bytes": 0,
"total": 1128,
"total_time_in_millis": 21338523,
"total_docs": 7241313,
"total_size_in_bytes": 5724869463
},
indexing
显示已经索引了多少文档。这个值是一个累加计数器。在文档被删除的时候,数值不会下降。还要注意的是,在发生内部 索引 操作的时候,这个值也会增加,比如说文档更新。
还列出了索引操作耗费的时间,正在索引的文档数量,以及删除操作的类似统计值。
get
显示通过 ID 获取文档的接口相关的统计值。包括对单个文档的 GET
和 HEAD
请求。
search
描述在活跃中的搜索( open_contexts
)数量、查询的总数量、以及自节点启动以来在查询上消耗的总时间。用 query_time_in_millis / query_total
计算的比值,可以用来粗略的评价你的查询有多高效。比值越大,每个查询花费的时间越多,你应该要考虑调优了。
fetch 统计值展示了查询处理的后一半流程(query-then-fetch 里的 fetch )。如果 fetch 耗时比 query 还多,说明磁盘较慢,或者获取了太多文档,或者可能搜索请求设置了太大的分页(比如, size: 10000
)。
merges
包括了 Lucene 段合并相关的信息。它会告诉你目前在运行几个合并,合并涉及的文档数量,正在合并的段的总大小,以及在合并操作上消耗的总时间。
在你的集群写入压力很大时,合并统计值非常重要。合并要消耗大量的磁盘 I/O 和 CPU 资源。如果你的索引有大量的写入,同时又发现大量的合并数,一定要去阅读索引性能技巧。
注意:文档更新和删除也会导致大量的合并数,因为它们会产生最终需要被合并的段 碎片 。
"filter_cache": {
"memory_size_in_bytes": 48,
"evictions": 0
},
"fielddata": {
"memory_size_in_bytes": 0,
"evictions": 0
},
"segments": {
"count": 319,
"memory_in_bytes": 65812120
},
...
filter_cache
展示了已缓存的过滤器位集合所用的内存数量,以及过滤器被驱逐出内存的次数。过多的驱逐数 可能 说明你需要加大过滤器缓存的大小,或者你的过滤器不太适合缓存(比如它们因为高基数而在大量产生,就像是缓存一个 now
时间表达式)。
不过,驱逐数是一个很难评定的指标。过滤器是在每个段的基础上缓存的,而从一个小的段里驱逐过滤器,代价比从一个大的段里要廉价的多。有可能你有很大的驱逐数,但是它们都发生在小段上,也就意味着这些对查询性能只有很小的影响。
把驱逐数指标作为一个粗略的参考。如果你看到数字很大,检查一下你的过滤器,确保他们都是正常缓存的。不断驱逐着的过滤器,哪怕都发生在很小的段上,效果也比正确缓存住了的过滤器差很多。
field_data
显示 fielddata 使用的内存,用以聚合、排序等等。这里也有一个驱逐计数。和 filter_cache
不同的是,这里的驱逐计数是很有用的:这个数应该或者至少是接近于 0。因为 fielddata 不是缓存,任何驱逐都消耗巨大,应该避免掉。如果你在这里看到驱逐数,你需要重新评估你的内存情况,fielddata 限制,请求语句,或者这三者。
segments
会展示这个节点目前正在服务中的 Lucene 段的数量。这是一个重要的数字。大多数索引会有大概 50–150 个段,哪怕它们存有 TB 级别的数十亿条文档。段数量过大表明合并出现了问题(比如,合并速度跟不上段的创建)。注意这个统计值是节点上所有索引的汇聚总数。记住这点。
memory
统计值展示了 Lucene 段自己用掉的内存大小。这里包括底层数据结构,比如倒排表,字典,和布隆过滤器等。太大的段数量会增加这些数据结构带来的开销,这个内存使用量就是一个方便用来衡量开销的度量值。
OS
和 Process
部分基本是自描述的,不会在细节中展开讲解。它们列出来基础的资源统计值,比如 CPU 和负载。OS
部分描述了整个操作系统,而 Process
部分只显示 Elasticsearch 的 JVM 进程使用的资源情况。
这些都是非常有用的指标,不过通常在你的监控技术栈里已经都测量好了。统计值包括下面这些:
CPU
负载
内存使用率
Swap 使用率
打开的文件描述符
jvm
部分包括了运行 Elasticsearch 的 JVM 进程一些很关键的信息。最重要的,它包括了垃圾回收的细节,这对你的 Elasticsearch 集群的稳定性有着重大影响。
因为垃圾回收对 Elasticsearch 是如此重要,你应该非常熟悉 node-stats
API 里的这部分内容:
"jvm": {
"timestamp": 1408556438203,
"uptime_in_millis": 14457,
"mem": {
"heap_used_in_bytes": 457252160,
"heap_used_percent": 44,
"heap_committed_in_bytes": 1038876672,
"heap_max_in_bytes": 1038876672,
"non_heap_used_in_bytes": 38680680,
"non_heap_committed_in_bytes": 38993920,
jvm
部分首先列出一些和 heap 内存使用有关的常见统计值。你可以看到有多少 heap 被使用了,多少被指派了(当前被分配给进程的),以及 heap 被允许分配的最大值。理想情况下,heap_committed_in_bytes
应该等于 heap_max_in_bytes
。如果指派的大小更小,JVM 最终会被迫调整 heap 大小——这是一个非常昂贵的操作。如果你的数字不相等,阅读 堆内存:大小和交换 学习如何正确的配置它。
heap_used_percent
指标是值得关注的一个数字。Elasticsearch 被配置为当 heap 达到 75% 的时候开始 GC。如果你的节点一直 >= 75%,你的节点正处于 内存压力 状态。这是个危险信号,不远的未来可能就有慢 GC 要出现了。
如果 heap 使用率一直 >=85%,你就麻烦了。Heap 在 90–95% 之间,则面临可怕的性能风险,此时最好的情况是长达 10–30s 的 GC,最差的情况就是内存溢出(OOM)异常。
"pools": {
"young": {
"used_in_bytes": 138467752,
"max_in_bytes": 279183360,
"peak_used_in_bytes": 279183360,
"peak_max_in_bytes": 279183360
},
"survivor": {
"used_in_bytes": 34865152,
"max_in_bytes": 34865152,
"peak_used_in_bytes": 34865152,
"peak_max_in_bytes": 34865152
},
"old": {
"used_in_bytes": 283919256,
"max_in_bytes": 724828160,
"peak_used_in_bytes": 283919256,
"peak_max_in_bytes": 724828160
}
}
},
新生代(young)
、 幸存区(survivor)
和 老生代(old)
部分分别展示 GC 中每一个代的内存使用情况。这些统计值很方便观察其相对大小,但是在调试问题的时候,通常并不怎么重要。
"gc": {
"collectors": {
"young": {
"collection_count": 13,
"collection_time_in_millis": 923
},
"old": {
"collection_count": 0,
"collection_time_in_millis": 0
}
}
}
gc
部分显示新生代和老生代的垃圾回收次数和累积时间。大多数时候你可以忽略掉新生代的次数:这个数字通常都很大。这是正常的。
与之相反,老生代的次数应该很小,而且 collection_time_in_millis
也应该很小。这些是累积值,所以很难给出一个阈值表示你要开始操心了(比如,一个跑了一整年的节点,即使很健康,也会有一个比较大的计数)。这就是像 Marvel 这类工具很有用的一个原因。GC 计数的 时间趋势 是个重要的考虑因素。
GC 花费的时间也很重要。比如,在索引文档时,一系列垃圾生成了。这是很常见的情况,每时每刻都会导致 GC。这些 GC 绝大多数时候都很快,对节点影响很小:新生代一般就花一两毫秒,老生代花一百多毫秒。这些跟 10 秒级别的 GC 是很不一样的。
我们的最佳建议是定期收集 GC 计数和时长(或者使用 Marvel)然后观察 GC 频率。你也可以开启慢 GC 日志记录,在 日志记录 小节已经讨论过。
Elasticsearch 在内部维护了线程池。这些线程池相互协作完成任务,有必要的话相互间还会传递任务。通常来说,你不需要配置或者调优线程池,不过查看它们的统计值有时候还是有用的,可以洞察你的集群表现如何。
这有一系列的线程池,但以相同的格式输出:
"index": {
"threads": 1,
"queue": 0,
"active": 0,
"rejected": 0,
"largest": 1,
"completed": 1
}
每个线程池会列出已配置的线程数量( threads
),当前在处理任务的线程数量( active
),以及在队列中等待处理的任务单元数量( queue
)。
如果队列中任务单元数达到了极限,新的任务单元会开始被拒绝,你会在 rejected
统计值上看到它反映出来。这通常是你的集群在某些资源上碰到瓶颈的信号。因为队列满意味着你的节点或集群在用最高速度运行,但依然跟不上工作的蜂拥而入。
这里的一系列的线程池,大多数你可以忽略,但是有一小部分还是值得关注的:
indexing
普通的索引请求的线程池
bulk
批量请求,和单条的索引请求不同的线程池
get
Get-by-ID 操作
search
所有的搜索和查询请求
merging
专用于管理 Lucene 合并的线程池
继续向下阅读 node-stats
API,你会看到一串和你的文件系统相关的统计值:可用空间,数据目录路径,磁盘 I/O 统计值,等等。如果你没有监控磁盘可用空间的话,可以从这里获取这些统计值。磁盘 I/O 统计值也很方便,不过通常那些更专门的命令行工具(比如 iostat
)会更有用些。
显然,Elasticsearch 在磁盘空间满的时候很难运行——所以请确保不会这样。
还有两个跟网络统计值相关的部分:
"transport": {
"server_open": 13,
"rx_count": 11696,
"rx_size_in_bytes": 1525774,
"tx_count": 10282,
"tx_size_in_bytes": 1440101928
},
"http": {
"current_open": 4,
"total_opened": 23
},
transport
显示和 传输地址 相关的一些基础统计值。包括节点间的通信(通常是 9300 端口)以及任意传输客户端或者节点客户端的连接。如果看到这里有很多连接数不要担心;Elasticsearch 在节点之间维护了大量的连接。
http
显示 HTTP 端口(通常是 9200)的统计值。如果你看到 total_opened
数很大而且还在一直上涨,这是一个明确信号,说明你的 HTTP 客户端里有没启用 keep-alive 长连接的。持续的 keep-alive 长连接对性能很重要,因为连接、断开套接字是很昂贵的(而且浪费文件描述符)。请确认你的客户端都配置正确。
终于,我们到了最后一段:跟 fielddata 断路器(在 断路器 介绍过)相关的统计值:
"fielddata_breaker": {
"maximum_size_in_bytes": 623326003,
"maximum_size": "594.4mb",
"estimated_size_in_bytes": 0,
"estimated_size": "0b",
"overhead": 1.03,
"tripped": 0
}
这里你可以看到断路器的最大值(比如,一个请求申请更多的内存时会触发断路器)。这个部分还会让你知道断路器被触发了多少次,以及当前配置的间接开销。间接开销用来铺垫评估,因为有些请求比其他请求更难评估。
主要需要关注的是 tripped
指标。如果这个数字很大或者持续上涨,这是一个信号,说明你的请求需要优化,或者你需要添加更多内存(单机上添加,或者通过添加新节点的方式)。
集群统计
API 提供了和 节点统计
相似的输出。 但有一个重要的区别:节点统计显示的是每个节点上的统计值,而 集群统计
展示的是对于单个指标,所有节点的总和值。
这里面提供一些很值得一看的统计值。比如说你可以看到,整个集群用了 50% 的堆内存,或者说过滤器缓存的驱逐情况不严重。这个接口主要用途是提供一个比 集群健康
更详细、但又没有 节点统计
那么详细的快速概览。对于非常大的集群来说也很有用,因为那时候 节点统计
的输出已经非常难于阅读了。
这个 API 可以像下面这样调用:
GET _cluster/stats
到目前为止,我们看到的都是以 节点为中心 的统计值: 节点有多少内存?用了多少 CPU ?正在服务多少个搜索?
有时候从 索引为中心 的角度看统计值也很有用:这个索引 收到了多少个搜索请求?那个索引 获取文档耗费了多少时间?
要做到这点,选择你感兴趣的索引 ( 或者多个索引 )然后执行一个索引级别的 统计
API:
GET my_index/_stats (1)
GET my_index,another_index/_stats (2)
GET _all/_stats (3)
统计 my_index
索引。
使用逗号分隔索引名可以请求多个索引统计值。
使用特定的 _all
可以请求全部索引的统计值
返回的统计信息和 节点统计
的输出很相似:search
、 fetch
、 get
、 index
、 bulk
、 segment counts
等等。
索引为中心的统计在有些时候很有用,比如辨别或验证集群中的 热门 索引,或者试图找出某些索引比其他索引更快或者更慢的原因。
实践中,节点为中心的统计还是显得更有用些。瓶颈往往是针对整个节点而言,而不是对于单个索引。因为索引一般是分布在多个节点上的,这导致以索引为中心的统计值通常不是很有用,因为它们是从不同环境的物理机器上汇聚的数据。
索引为中心的统计作为一个有用的工具可以保留在你的技能表里,但是通常它不会是第一个用的上的工具。
有一些任务只能由主节点去处理,比如创建一个新的索引或者在集群中移动分片。由于一个集群中只能有一个主节点,所以只有这一节点可以处理集群级别的元数据变动。在 99.9999% 的时间里,这不会有什么问题。元数据变动的队列基本上保持为零。
在一些 罕见
的集群里,元数据变动的次数比主节点能处理的还快。这会导致等待中的操作会累积成队列。
等待中的任务
API 会给你展示队列中(如果有的话)等待的集群级别的元数据变更操作:
GET _cluster/pending_tasks
通常,响应都是像这样的:
{
"tasks": []
}
这意味着没有等待中的任务。如果你有一个罕见的集群在主节点出现瓶颈了,等待中的任务列表可能会像这样:
{
"tasks": [
{
"insert_order": 101,
"priority": "URGENT",
"source": "create-index [foo_9], cause [api]",
"time_in_queue_millis": 86,
"time_in_queue": "86ms"
},
{
"insert_order": 46,
"priority": "HIGH",
"source": "shard-started ([foo_2][1], node[tMTocMvQQgGCkj7QDHl3OA], [P],
s[INITIALIZING]), reason [after recovery from gateway]",
"time_in_queue_millis": 842,
"time_in_queue": "842ms"
},
{
"insert_order": 45,
"priority": "HIGH",
"source": "shard-started ([foo_2][0], node[tMTocMvQQgGCkj7QDHl3OA], [P],
s[INITIALIZING]), reason [after recovery from gateway]",
"time_in_queue_millis": 858,
"time_in_queue": "858ms"
}
]
}
可以看到任务都被指派了优先级( 比如说 URGENT
要比 HIGH
更早的处理 ),任务插入的次序、操作进入队列多久,以及打算处理什么。在上面的列表中,有一个 创建索引(create-index)
和两个 启动分片(shard-started)
的操作在等待。
如果经常在命令行环境下工作,cat
API 对你会非常有用。用 Linux 的 cat
命令命名,这些 API 也就设计成像 *nix 命令行工具一样工作了。
他们提供的统计和前面已经讨论过的 API ( 健康、节点统计
等等 ) 是一样的。但是输出以表格的形式提供,而不是 JSON。对于系统管理员来说这是 非常 方便的,你仅仅想浏览一遍集群或者找出内存使用偏高的节点而已。
通过 GET
请求发送 cat
命名可以列出所有可用的 API:
GET /_cat
=^.^=
/_cat/allocation
/_cat/shards
/_cat/shards/{index}
/_cat/master
/_cat/nodes
/_cat/indices
/_cat/indices/{index}
/_cat/segments
/_cat/segments/{index}
/_cat/count
/_cat/count/{index}
/_cat/recovery
/_cat/recovery/{index}
/_cat/health
/_cat/pending_tasks
/_cat/aliases
/_cat/aliases/{alias}
/_cat/thread_pool
/_cat/plugins
/_cat/fielddata
/_cat/fielddata/{fields}
许多 API 看起来很熟悉了 ( 是的,顶上还有一只猫:) )。让我们看看 cat
的健康检查 API:
GET /_cat/health
1408723713 12:08:33 elasticsearch_zach yellow 1 1 114 114 0 0 114
首先你会注意到的是响应是表格样式的纯文本,而不是 JSON。其次你会注意到各列默认是没有表头的。这都是模仿 *nix 工具设计的,因为它假设一旦你对输出熟悉了,你就再也不想看见表头了。
要启用表头,添加 ?v
参数即可:
GET /_cat/health?v
epoch time cluster status node.total node.data shards pri relo init
1408[..] 12[..] el[..] 1 1 114 114 0 0 114
unassign
嗯,好多了。我们现在看到 时间戳、集群名称、状态、集群中节点的数量等等—所有信息和 集群健康
API 返回的都一样。
让我们再看看 cat
API 里面的 节点统计
:
GET /_cat/nodes?v
host ip heap.percent ram.percent load node.role master name
zacharys-air 192.168.1.131 45 72 1.85 d * Zach
我们看到集群里节点的一些统计,不过和完整的 节点统计
输出相比而言是非常基础的。你可以包含更多的指标,但是比起查阅文档,让我们直接问 cat
API 有哪些可用的吧。
你可以过对任意 API 添加 ?help
参数来做到这点:
GET /_cat/nodes?help
id | id,nodeId | unique node id
pid | p | process id
host | h | host name
ip | i | ip address
port | po | bound transport port
version | v | es version
build | b | es build hash
jdk | j | jdk version
disk.avail | d,disk,diskAvail | available disk space
heap.percent | hp,heapPercent | used heap ratio
heap.max | hm,heapMax | max configured heap
ram.percent | rp,ramPercent | used machine memory ratio
ram.max | rm,ramMax | total machine memory
load | l | most recent load avg
uptime | u | node uptime
node.role | r,role,dc,nodeRole | d:data node, c:client node
master | m | m:master-eligible, *:current master
...
...
( 注意这个输出为了页面简洁而被截断了 )。
第一列显示完整的名称,第二列显示缩写,第三列提供了关于这个参数的简介。现在我们知道了一些列名了,我们可以用 ?h
参数来明确指定显示这些指标:
GET /_cat/nodes?v&h=ip,port,heapPercent,heapMax
ip port heapPercent heapMax
192.168.1.131 9300 53 990.7mb
因为 cat
API 试图像 *nix 工具一样工作,你可以使用管道命令将结果传递给其他工具,比如 sort
、 grep
或者 awk
。例如,通过以下方式可以找到集群中最大的索引:
% curl 'localhost:9200/_cat/indices?bytes=b' | sort -rnk8
yellow test_names 5 1 3476004 0 376324705 376324705
yellow .marvel-2014.08.19 1 1 263878 0 160777194 160777194
yellow .marvel-2014.08.15 1 1 234482 0 143020770 143020770
yellow .marvel-2014.08.09 1 1 222532 0 138177271 138177271
yellow .marvel-2014.08.18 1 1 225921 0 138116185 138116185
yellow .marvel-2014.07.26 1 1 173423 0 132031505 132031505
yellow .marvel-2014.08.21 1 1 219857 0 128414798 128414798
yellow .marvel-2014.07.27 1 1 75202 0 56320862 56320862
yellow wavelet 5 1 5979 0 54815185 54815185
yellow .marvel-2014.07.28 1 1 57483 0 43006141 43006141
yellow .marvel-2014.07.21 1 1 31134 0 27558507 27558507
yellow .marvel-2014.08.01 1 1 41100 0 27000476 27000476
yellow kibana-int 5 1 2 0 17791 17791
yellow t 5 1 7 0 15280 15280
yellow website 5 1 12 0 12631 12631
yellow agg_analysis 5 1 5 0 5804 5804
yellow v2 5 1 2 0 5410 5410
yellow v1 5 1 2 0 5367 5367
yellow bank 1 1 16 0 4303 4303
yellow v 5 1 1 0 2954 2954
yellow p 5 1 2 0 2939 2939
yellow b0001_072320141238 5 1 1 0 2923 2923
yellow ipaddr 5 1 1 0 2917 2917
yellow v2a 5 1 1 0 2895 2895
yellow movies 5 1 1 0 2738 2738
yellow cars 5 1 0 0 1249 1249
yellow wavelet2 5 1 0 0 615 615
通过添加 ?bytes=b
,我们关闭了人类可读的数字格式化,强制它们以字节数输出。随后通过管道命令将输出传递给 sort
让索引按大小( 第八列 )排序
不幸的是,你会注意到 Marval 索引也出现在结果中,但是我们目前并不真正在意这些索引。让我们把结果传递给 grep
命令来移除提到 Marval 的数据:
% curl 'localhost:9200/_cat/indices?bytes=b' | sort -rnk8 | grep -v marvel
yellow test_names 5 1 3476004 0 376324705 376324705
yellow wavelet 5 1 5979 0 54815185 54815185
yellow kibana-int 5 1 2 0 17791 17791
yellow t 5 1 7 0 15280 15280
yellow website 5 1 12 0 12631 12631
yellow agg_analysis 5 1 5 0 5804 5804
yellow v2 5 1 2 0 5410 5410
yellow v1 5 1 2 0 5367 5367
yellow bank 1 1 16 0 4303 4303
yellow v 5 1 1 0 2954 2954
yellow p 5 1 2 0 2939 2939
yellow b0001_072320141238 5 1 1 0 2923 2923
yellow ipaddr 5 1 1 0 2917 2917
yellow v2a 5 1 1 0 2895 2895
yellow movies 5 1 1 0 2738 2738
yellow cars 5 1 0 0 1249 1249
yellow wavelet2 5 1 0 0 615 615
瞧!在传递给 grep
( 通过 -v
来过滤掉不需要匹配的数据 ) 之后,我们得到了一个没有 Marval 混杂的索引排序列表了。
这只是命令行上 cat
的灵活性的一个简单示例。一旦你习惯了使用 cat
,你会发现它和其他所有 *nix 工具一样并且开始疯狂的使用管道、排序和过滤。如果你是一个系统管理员并且永远都是 SSH 登录到设备上,那么当然要花些时间来熟悉 cat
API 了。