集群统计

集群统计 API 提供了和 节点统计 相似的输出。但有一个重要的区别:节点统计显示的是每个节点上的统计值,而 集群统计 展示的是对于单个指标,所有节点的总和值。

这里面提供一些很值得一看的统计值。比如说你可以看到,整个集群用了 50% 的堆内存,或者说过滤器缓存的驱逐情况不严重。这个接口主要用途是提供一个比 集群健康 更详细、但又没有 节点统计 那么详细的快速概览。对于非常大的集群来说也很有用,因为那时候 节点统计 的输出已经非常难于阅读了。

这个 API 可以像下面这样调用:

  1. GET _cluster/stats

索引统计

到目前为止,我们看到的都是以 节点为中心 的统计值:节点有多少内存?用了多少 CPU ?正在服务多少个搜索?

有时候从 索引为中心 的角度看统计值也很有用:这个索引 收到了多少个搜索请求?那个索引 获取文档耗费了多少时间?

要做到这点,选择你感兴趣的索引 ( 或者多个索引 )然后执行一个索引级别的 统计 API:

  1. GET my_index/_stats <1>
  2. GET my_index,another_index/_stats <2>
  3. GET _all/_stats <3>

<1> 统计 my_index 索引。

<2> 使用逗号分隔索引名可以请求多个索引统计值。

<3> 使用特定的 _all 可以请求全部索引的统计值

返回的统计信息和 节点统计 的输出很相似:searchfetchgetindexbulksegment counts 等等。

索引为中心的统计在有些时候很有用,比如辨别或验证集群中的 热门 索引,或者试图找出某些索引比其他索引更快或者更慢的原因。

实践中,节点为中心的统计还是显得更有用些。瓶颈往往是针对整个节点而言,而不是对于单个索引。因为索引一般是分布在多个节点上的,这导致以索引为中心的统计值通常不是很有用,因为它们是从不同环境的物理机器上汇聚的数据。

索引为中心的统计作为一个有用的工具可以保留在你的技能表里,但是通常它不会是第一个用的上的工具。

等待中的任务

有一些任务只能由主节点去处理,比如创建一个新的索引或者在集群中移动分片。由于一个集群中只能有一个主节点,所以只有这一节点可以处理集群级别的元数据变动。在 99.9999% 的时间里,这不会有什么问题。元数据变动的队列基本上保持为零。

在一些 罕见 的集群里,元数据变动的次数比主节点能处理的还快。这会导致等待中的操作会累积成队列。

等待中的任务 API 会给你展示队列中(如果有的话)等待的集群级别的元数据变更操作:

  1. GET _cluster/pending_tasks

通常,响应都是像这样的:

  1. {
  2. "tasks": []
  3. }

这意味着没有等待中的任务。如果你有一个罕见的集群在主节点出现瓶颈了,等待中的任务列表可能会像这样:

  1. {
  2. "tasks": [
  3. {
  4. "insert_order": 101,
  5. "priority": "URGENT",
  6. "source": "create-index [foo_9], cause [api]",
  7. "time_in_queue_millis": 86,
  8. "time_in_queue": "86ms"
  9. },
  10. {
  11. "insert_order": 46,
  12. "priority": "HIGH",
  13. "source": "shard-started ([foo_2][1], node[tMTocMvQQgGCkj7QDHl3OA], [P],
  14. s[INITIALIZING]), reason [after recovery from gateway]",
  15. "time_in_queue_millis": 842,
  16. "time_in_queue": "842ms"
  17. },
  18. {
  19. "insert_order": 45,
  20. "priority": "HIGH",
  21. "source": "shard-started ([foo_2][0], node[tMTocMvQQgGCkj7QDHl3OA], [P],
  22. s[INITIALIZING]), reason [after recovery from gateway]",
  23. "time_in_queue_millis": 858,
  24. "time_in_queue": "858ms"
  25. }
  26. ]
  27. }

可以看到任务都被指派了优先级( 比如说 URGENT 要比 HIGH 更早的处理 ),任务插入的次序、操作进入队列多久,以及打算处理什么。在上面的列表中,有一个 创建索引(create-index) 和两个 启动分片(shard-started) 的操作在等待。

什么时候应该担心等待中的任务?


就像曾经提到过的,主节点很少会成为集群的瓶颈。唯一可能成为瓶颈的是集群状态非常大 而且 更新频繁。

例如,如果你允许客户按照他们的意愿创建任意的动态字段,而且每个客户每天都有一个独立索引,那么你的集群状态会变得非常大。集群状态包括 ( 但不限于 ) 所有索引及其类型,以及每个索引的全部字段。

所以如果你有 100000 客户,然后每个客户平均有 1000 个字段,而且数据有 90 天的保留期—这就有九十亿个字段需要保存在集群状态中。不管它何时发生变更,所有的节点都需要被通知。

主节点必须处理这些变动,这需要不小的 CPU 开销,加上推送更新的集群状态到所有节点的网络开销。

这就是那些可以看到集群状态操作队列上涨的集群。没有简单的办法可以解决这个问题,不过你有三个选择:

  • 使用一个更强大的主节点。不幸的是,这种垂直扩展只是延迟这种必然结果出现而已。
  • 通过某些方式限定文档的动态性质来限制集群状态的大小。
  • 到达某个阈值后组建另外一个集群。

cat API

如果经常在命令行环境下工作,cat API 对你会非常有用。用 Linux 的 cat 命令命名,这些 API 也就设计成像 *nix 命令行工具一样工作了。

他们提供的统计和前面已经讨论过的 API ( 健康、节点统计 等等 ) 是一样的。但是输出以表格的形式提供,而不是 JSON。对于系统管理员来说这是 非常 方便的,你仅仅想浏览一遍集群或者找出内存使用偏高的节点而已。

通过 GET 请求发送 cat 命名可以列出所有可用的 API:

  1. GET /_cat
  2. =^.^=
  3. /_cat/allocation
  4. /_cat/shards
  5. /_cat/shards/{index}
  6. /_cat/master
  7. /_cat/nodes
  8. /_cat/indices
  9. /_cat/indices/{index}
  10. /_cat/segments
  11. /_cat/segments/{index}
  12. /_cat/count
  13. /_cat/count/{index}
  14. /_cat/recovery
  15. /_cat/recovery/{index}
  16. /_cat/health
  17. /_cat/pending_tasks
  18. /_cat/aliases
  19. /_cat/aliases/{alias}
  20. /_cat/thread_pool
  21. /_cat/plugins
  22. /_cat/fielddata
  23. /_cat/fielddata/{fields}

许多 API 看起来很熟悉了 ( 是的,顶上还有一只猫:) )。让我们看看 cat 的健康检查 API:

  1. GET /_cat/health
  2. 1408723713 12:08:33 elasticsearch_zach yellow 1 1 114 114 0 0 114

首先你会注意到的是响应是表格样式的纯文本,而不是 JSON。其次你会注意到各列默认是没有表头的。这都是模仿 *nix 工具设计的,因为它假设一旦你对输出熟悉了,你就再也不想看见表头了。

要启用表头,添加 ?v 参数即可:

  1. GET /_cat/health?v
  2. epoch time cluster status node.total node.data shards pri relo init
  3. 1408[..] 12[..] el[..] 1 1 114 114 0 0 114
  4. unassign

嗯,好多了。我们现在看到 时间戳、集群名称、状态、集群中节点的数量等等—所有信息和 集群健康 API 返回的都一样。

让我们再看看 cat API 里面的 节点统计

  1. GET /_cat/nodes?v
  2. host ip heap.percent ram.percent load node.role master name
  3. zacharys-air 192.168.1.131 45 72 1.85 d * Zach

我们看到集群里节点的一些统计,不过和完整的 节点统计 输出相比而言是非常基础的。你可以包含更多的指标,但是比起查阅文档,让我们直接问 cat API 有哪些可用的吧。

你可以过对任意 API 添加 ?help 参数来做到这点:

  1. GET /_cat/nodes?help
  2. id | id,nodeId | unique node id
  3. pid | p | process id
  4. host | h | host name
  5. ip | i | ip address
  6. port | po | bound transport port
  7. version | v | es version
  8. build | b | es build hash
  9. jdk | j | jdk version
  10. disk.avail | d,disk,diskAvail | available disk space
  11. heap.percent | hp,heapPercent | used heap ratio
  12. heap.max | hm,heapMax | max configured heap
  13. ram.percent | rp,ramPercent | used machine memory ratio
  14. ram.max | rm,ramMax | total machine memory
  15. load | l | most recent load avg
  16. uptime | u | node uptime
  17. node.role | r,role,dc,nodeRole | d:data node, c:client node
  18. master | m | m:master-eligible, *:current master
  19. ...
  20. ...

( 注意这个输出为了页面简洁而被截断了 )。

第一列显示完整的名称,第二列显示缩写,第三列提供了关于这个参数的简介。现在我们知道了一些列名了,我们可以用 ?h 参数来明确指定显示这些指标:

  1. GET /_cat/nodes?v&h=ip,port,heapPercent,heapMax
  2. ip port heapPercent heapMax
  3. 192.168.1.131 9300 53 990.7mb

因为 cat API 试图像 *nix 工具一样工作,你可以使用管道命令将结果传递给其他工具,比如 sortgrep 或者 awk 。例如,通过以下方式可以找到集群中最大的索引:

  1. % curl 'localhost:9200/_cat/indices?bytes=b' | sort -rnk8
  2. yellow test_names 5 1 3476004 0 376324705 376324705
  3. yellow .marvel-2014.08.19 1 1 263878 0 160777194 160777194
  4. yellow .marvel-2014.08.15 1 1 234482 0 143020770 143020770
  5. yellow .marvel-2014.08.09 1 1 222532 0 138177271 138177271
  6. yellow .marvel-2014.08.18 1 1 225921 0 138116185 138116185
  7. yellow .marvel-2014.07.26 1 1 173423 0 132031505 132031505
  8. yellow .marvel-2014.08.21 1 1 219857 0 128414798 128414798
  9. yellow .marvel-2014.07.27 1 1 75202 0 56320862 56320862
  10. yellow wavelet 5 1 5979 0 54815185 54815185
  11. yellow .marvel-2014.07.28 1 1 57483 0 43006141 43006141
  12. yellow .marvel-2014.07.21 1 1 31134 0 27558507 27558507
  13. yellow .marvel-2014.08.01 1 1 41100 0 27000476 27000476
  14. yellow kibana-int 5 1 2 0 17791 17791
  15. yellow t 5 1 7 0 15280 15280
  16. yellow website 5 1 12 0 12631 12631
  17. yellow agg_analysis 5 1 5 0 5804 5804
  18. yellow v2 5 1 2 0 5410 5410
  19. yellow v1 5 1 2 0 5367 5367
  20. yellow bank 1 1 16 0 4303 4303
  21. yellow v 5 1 1 0 2954 2954
  22. yellow p 5 1 2 0 2939 2939
  23. yellow b0001_072320141238 5 1 1 0 2923 2923
  24. yellow ipaddr 5 1 1 0 2917 2917
  25. yellow v2a 5 1 1 0 2895 2895
  26. yellow movies 5 1 1 0 2738 2738
  27. yellow cars 5 1 0 0 1249 1249
  28. yellow wavelet2 5 1 0 0 615 615

通过添加 ?bytes=b ,我们关闭了人类可读的数字格式化,强制它们以字节数输出。随后通过管道命令将输出传递给 sort 让索引按大小( 第八列 )排序

不幸的是,你会注意到 Marval 索引也出现在结果中,但是我们目前并不真正在意这些索引。让我们把结果传递给 grep 命令来移除提到 Marval 的数据:

  1. % curl 'localhost:9200/_cat/indices?bytes=b' | sort -rnk8 | grep -v marvel
  2. yellow test_names 5 1 3476004 0 376324705 376324705
  3. yellow wavelet 5 1 5979 0 54815185 54815185
  4. yellow kibana-int 5 1 2 0 17791 17791
  5. yellow t 5 1 7 0 15280 15280
  6. yellow website 5 1 12 0 12631 12631
  7. yellow agg_analysis 5 1 5 0 5804 5804
  8. yellow v2 5 1 2 0 5410 5410
  9. yellow v1 5 1 2 0 5367 5367
  10. yellow bank 1 1 16 0 4303 4303
  11. yellow v 5 1 1 0 2954 2954
  12. yellow p 5 1 2 0 2939 2939
  13. yellow b0001_072320141238 5 1 1 0 2923 2923
  14. yellow ipaddr 5 1 1 0 2917 2917
  15. yellow v2a 5 1 1 0 2895 2895
  16. yellow movies 5 1 1 0 2738 2738
  17. yellow cars 5 1 0 0 1249 1249
  18. yellow wavelet2 5 1 0 0 615 615

瞧!在传递给 grep ( 通过 -v 来过滤掉不需要匹配的数据 ) 之后,我们得到了一个没有 Marval 混杂的索引排序列表了。

这只是命令行上 cat 的灵活性的一个简单示例。一旦你习惯了使用 cat ,你会发现它和其他所有 *nix 工具一样并且开始疯狂的使用管道、排序和过滤。如果你是一个系统管理员并且永远都是 SSH 登录到设备上,那么当然要花些时间来熟悉 cat API 了。