当 Elasticsearch 各节点之间的资源使用分布不均时,可能出现热点。短暂峰值通常不是问题,但如果某些节点持续表现出明显异常的资源占用,就可能形成集群瓶颈,需要进一步检查。
这段视频 演示了热点问题的排查过程。
通过 AutoOps 检测并解决问题:AutoOps 是一种监控工具,可实时检测 Elasticsearch 集群问题,并建议如何解决问题、改善性能。详情见 AutoOps 介绍。
发现热点
可以同时观察实时利用率和历史节点统计信息。
实时状态
热点最常见的表现是:cat nodes 报告部分节点的 disk.percent、heap.percent 或 cpu 明显升高。单次峰值不一定有问题,但如果利用率反复冲高,或持续很长时间处于高位,例如超过 30 秒,就可能存在需要处理的热点。
下面用 cat nodes 展示两个不同的潜在问题:
GET _cat/nodes?v&s=master,name&h=name,master,node.role,heap.percent,disk.used_percent,cpu
假设在五分钟内的两次查询,都得到相同输出:
name master node.role heap.percent disk.used_percent cpu
node_1 * hirstm 24 20 95
node_2 - hirstm 23 18 18
node_3 - hirstmv 25 90 10
其中有两个显著异常:主节点的 CPU 为 95,而另一个热层节点的磁盘使用率为 90%。这说明两个节点都在发生热点,但不一定具有相同根因。
历史状态
还可以轮询节点统计 API,查看与索引有关的性能指标,从而发现热点逐渐形成的迹象:
GET _nodes/stats?pretty=true&filter_path=nodes.*.name,nodes.*.roles,nodes.*.indices
该请求返回查询、刷新、索引等操作指标,可用于衡量每个节点尝试执行的事件总数,以及每类事件的平均处理时间。
这些指标在各节点的运行期间累计。为了便于阅读,可以使用 JQ 等第三方工具解析响应:
cat nodes_stats.json | jq -rc '.nodes[]|.name as $n|.roles as $r|.indices|to_entries[]|.key as $m|.value|select(.total and .total_time_in_millis)|select(.total>0)|{node:$n, roles:$r, metric:$m, total:.total, avg_millis:(.total_time_in_millis?/.total|round)}'
如果多个主要操作在各节点上都表现不佳,集群很可能配置不足。如果某一种操作或某个节点特别突出,则可能存在分片分布问题,可以结合索引统计进行对比:
GET /_stats?level=shards&human&expand_wildcards=all&ignore_unavailable=true
这些指标按每个分片的历史累计。可以用 JQ 等工具解析响应,并与前面的性能数据比较:
cat indices_stats.json | jq -rc '.indices|to_entries[]|.key as $i|.value.shards[]|to_entries[]|.key as $sh|.value|.routing.primary as $p|.routing.node[:4] as $n|to_entries[]|.key as $m|.value|select(.total and .total_time_in_millis)|select(.total>0)|{index:$i, shard:$sh, primary:$p, node:$n, metric:$m, total:.total, avg_millis:(.total_time_in_millis/.total|round)}'
原因
从以往情况看,集群热点主要与硬件、分片分布和/或任务负载有关。对用户而言,它可能表现为搜索变慢、索引延迟、摄入积压,或查询和批量操作超时。下面按照潜在影响范围依次讨论。
硬件
以下不合适的硬件配置可能导致热点:
- 资源分配不一致。例如,某个热层节点的 CPU 只有其他节点的一半。Elasticsearch 预期同一数据层中的节点具有相同硬件配置或规格。可以通过 cat nodes API 查看:
GET _cat/nodes?v=true&s=name&h=name,role,disk.total,heap.max,allocated_processors
- 同一宿主机上的其他服务占用了资源,包括其他 Elasticsearch 节点。请参阅 专用主机建议。
- 网络或磁盘吞吐量不同。例如,某个节点的 I/O 吞吐量低于其他节点。请参阅 使用更快的硬件。
- JVM 堆配置超过
31GB。请参阅 设置 JVM 堆大小。 - 有问题的节点单独出现了内存交换现象。
分片分布
Elasticsearch 索引被划分为一个或多个分片,有时它们的分布并不合理。Elasticsearch 通过平衡数据节点上的分片数量处理这一问题。从 8.6 版本开始,还默认启用“期望平衡(desired balancing)”,将摄入负载纳入考量。不过,写入密集型索引,或者节点承载的整体分片负载,仍然可能导致热点。
节点层面
可以通过 cat allocation 查看分片平衡情况。不过,从 8.6 版本开始,期望平衡不再一定以分片数量完全相等为目标。集群不稳定时,这两种观察方式都可能暂时显示出不平衡。
下面用 cat allocation 展示两个潜在问题:
GET _cat/allocation?v&s=node&h=node,shards,disk.percent,disk.indices,disk.used
可能返回:
node shards disk.percent disk.indices disk.used
node_1 446 19 154.8gb 173.1gb
node_2 31 52 44.6gb 372.7gb
node_3 445 43 271.5gb 289.4gb
这里有两个显著不同的情况。node_2 最近重启过,因此分片数量远少于其他节点。分片仍在恢复时,disk.indices 也明显小于 disk.used,恢复过程可通过 cat recovery 观察。尽管 node_2 分片数量少,持续的 ILM rollover 仍可能让它成为写入热点,这是下一节将讨论的常见根因。
第二个情况是:node_3 与 node_1 分片数量接近,但 disk.percent 更高。原因可能是分片大小不均,或存在大量空索引。分片大小建议见 将分片控制在最多 2 亿文档,或 10GB 至 50GB 大小。
基于期望平衡的集群再平衡承担了避免热点的大部分工作。但它可能受到磁盘水位限制,也可能因为某个写入密集型索引的分片总数远少于接收写入的节点数而受到限制。磁盘问题见 修复磁盘水位错误。
可以通过节点统计 API 确认热点节点。与只查询一次并读取节点整个运行期间的统计相比,间隔一段时间查询两次、只比较差值,通常更便于观察。例如,查看所有节点的索引统计:
GET _nodes/stats?human&filter_path=nodes.*.name,nodes.*.indices.indexing
索引层面
热点节点经常会通过 cat thread pool 中 write 和 search 队列的积压暴露出来:
GET _cat/thread_pool/write,search?v=true&s=n,nn&h=n,nn,q,a,r,c
可能返回:
n nn q a r c
search node_1 3 1 0 1287
search node_2 0 2 0 1159
search node_3 0 1 0 1302
write node_1 100 3 0 4259
write node_2 0 4 0 980
write node_3 1 5 0 8714
这里同样有两个明显情况。首先,node_1 的写入队列相较其他节点严重积压。其次,node_3 历史完成的写入数约为其他任一节点的两倍。这通常是写入密集型索引分布不均,或者多个写入密集型索引被分配到了同一节点所致。
主分片和副本的写入给集群带来的工作量大致相同,因此通常建议先使索引分片数量与节点总数相适配,再设置 index.routing.allocation.total_shards_per_node,强制将索引分散到不同节点。
持续监控数据摄入流程的变化非常重要,因为突然增加或转移的流量会引发 CPU 使用率升高和摄入延迟。根据集群架构,优化主分片数量可以显著提高摄入性能。详情见 集群、节点和分片。
通常建议为写入密集型索引配置足够的主分片 number_of_shards 与副本 number_of_replicas,使负载均匀分散到索引节点。也可以将分片重新路由到较空闲的节点,减轻写入热点。
如果无法直接判断哪些索引有问题,可以进一步调用索引统计 API:
GET _stats?level=shards&human&expand_wildcards=all&filter_path=indices.*.total.indexing.index_total
更深入的分析可以轮询分片级统计,从而结合索引与节点层面的数据进行比较。这种分析没有考虑节点重启和/或分片重新路由,但可以作为总体观察:
GET _stats/indexing,search?level=shards&human&expand_wildcards=all
例如,可以使用第三方 JQ 工具处理保存为 indices_stats.json 的输出:
cat indices_stats.json | jq -rc ['.indices|to_entries[]|.key as $i|.value.shards|to_entries[]|.key as $s|.value[]|{node:.routing.node[:4], index:$i, shard:$s, primary:.routing.primary, size:.store.size, total_indexing:.indexing.index_total, time_indexing:.indexing.index_time_in_millis, total_query:.search.query_total, time_query:.search.query_time_in_millis } | .+{ avg_indexing: (if .total_indexing>0 then (.time_indexing/.total_indexing|round) else 0 end), avg_search: (if .total_search>0 then (.time_search/.total_search|round) else 0 end) }'] > shard_stats.json
# show top written-to shard simplified stats which contain their index and node references
cat shard_stats.json | jq -rc 'sort_by(-.avg_indexing)[]' | head
任务负载
分片分布问题往往会表现为任务负载问题,如前面的线程池示例所示。任务本身也可能导致某个节点出现热点:单个任务执行成本很高,或总体流量很大,都可能造成任务积压。
原文:Hot spotting。作者/维护者:Elastic 文档团队。本文为原文的中文译文;代码保留原文内容。











暂无评论内容