【Elastic Engineering】Elasticsearch:管理 Elasticsearch 内存并进行故障排除

作者:刘晓国


随着 Elastic 扩展我们的 Elasticsearch Service Cloud 产品和自动上线,我们已经将 Elastic Stack 的受众范围从完整的运营团队扩展到了数据工程师,安全团队和顾问。作为 Elastic 支持团队的代表,我喜欢与更多用户背景甚至更广泛的用例进行交互。

在更广泛的听众中,我看到了更多有关管理资源分配的问题,尤其是神秘的 shard 堆比率和避免使用熔断器(circuit breaker)的问题。我完全理解!当我开始使用 Elastic Stack 时,我遇到了同样的问题。这是我关于 Java 堆和时间序列数据库分片以及扩展自己的基础结构的第一个介绍。

当我加入 Elastic 团队时,我很喜欢文档之外的内容,我们有博客和教程,因此我可以很快上手。但是后来我在第一个月就非常费劲地使我的理论知识与用户通过我的问题队列发送的错误相关联。最终,我发现像其他支持团队成员一样,许多报告的错误仅是分配问题的征兆,而相同的七个链接(在下面的理论部分可以看到)会带给用户加快成功管理其资源分配的速度。

作为支持团队的代表,在以下各节中,我将遍历我们向用户发送的最重要的分配管理理论链接,我们看到的最重要的症状以及我们指导用户更新其配置以解决其资源分配问题的地方。


理论


作为 Java 应用程序,Elasticsearch 需要从系统的物理内存中分配一些逻辑内存(堆)。 这应该最多是物理 RAM 的一半,上限为 32GB。 设置更高的堆使用率通常是为了响应昂贵的查询和更大的数据存储。 父级熔断器默认为95%,但是一旦持续达到85%,我们建议你扩展资源。

Elasticsearch包 含多个熔断器,这些熔断器用于防止操作引起 OutOfMemoryError。 每个断路器都指定了可以使用多少内存的限制。 此外,还有一个父级熔断器,用于指定可在所有断路器上使用的内存总量。

我强烈建议我们的团队提供这些概述文章,以获取更多信息:


配置


开箱即用,Elasticsearch 的默认设置会根据节点角色和总内存自动调整 JVM 堆的大小。 但是,根据需要,你可以通过以下三种方式直接对其进行配置:

1.直接在本地 Elasticsearch 文件的 config > jvm.options 文件中


1. ## JVM configuration 
2. ################################################################ 
3. ## IMPORTANT: JVM heap size 
4. ################################################################ 
5. … 
6. # Xms represents the initial size of total heap space 
7. # Xmx represents the maximum size of total heap space 
8. -Xms4g
9. -Xmx4g


2. 作为 docker-compose 中的 Elasticsearch 环境变量


1. version: '2.2'
2. services:
3.   es01:
4.     image: docker.elastic.co/elasticsearch/elasticsearch:7.12.0
5.     environment:
6.       - node.name=es01
7.       - cluster.name=es
8.       - bootstrap.memory_lock=true
9.       - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
10.       - discovery.type=single-node
11.     ulimits:
12.       memlock:
13.         soft: -1
14.         hard: -1
15.     ports:
16.       - 9200:9200


3.通过我们的 Elasticsearch Service > Deployment > Edit view。 注意:滑动条分配物理内存,大约一半将分配给堆。


【Elastic Engineering】Elasticsearch:管理 Elasticsearch 内存并进行故障排除


故障排除


如果您的群集当前遇到性能问题,则很可能归咎于通常的怀疑

  • 配置问题:分片,没有 ILM 策略
  • 引入的高体量:高请求速度/负载,重叠昂贵的查询/写入

所有以下所有 cURL / API请求都可以在 Elasticsearch Service > API 控制台中作为 Elasticsearch API 的 cURL 发出,或者在 Kibana> Dev Tools 下进行。


过度分片


数据索引存储在 sub-shards 中,这些 sub-shards 使用堆进行维护以及在搜索/写入请求期间使用。 shard 大小应限制为 50GB,数量应限制为通过以下公式确定的值:

shards <= sum(nodes.max_heap) * 20

以上面的 Elasticsearch Service 为例,在两个区域中具有 8GB 的物理内存(这将总共分配两个节点)

1. # node.max_heap 
2. 8GB of physical memory / 2 = 4GB of heap  
3. # sum(nodes.max_heap) 
4. 4GB of heap * 2 nodes = 8GB 
5. # max shards 
6. 8GB * 20
7. 160

然后将其与 _cat /allocation 进行交叉比较

1. GET /_cat/allocation?v=true&h=shards,node
2. shards node
3. 41 instance-0000000001
4. 41 instance-0000000000

或者使用 _cluster/health

1. GET /_cluster/health?filter_path=status,*_shards
2. {
3. "status": "green",
4. "unassigned_shards": 0,
5. "initializing_shards": 0,
6. "active_primary_shards": 41,
7. "relocating_shards": 0,
8. "active_shards": 82,
9. "delayed_unassigned_shards": 0
10. }

因此,此部署具有最多160个建议的82个分片。 如果计数高于建议值,则可能在接下来的两个部分中出现症状(请参阅下文)。

如果有任何 shard 报告(除 active_shards 或 active_primary_shards)之外的数字 > 0,则表明你已确定导致性能问题的主要原因。

最常见的情况是,如果报告了问题,则其值为 unassigned_shards > 0。 如果这些 shard 是主要分片,则群集将报告为状态:红色;如果仅副本,它将报告为状态:黄色。 (这就是在索引上设置副本很重要的原因,这样,如果群集遇到问题,它可以恢复而不是遭受数据丢失。)

假设我们有一个状态:黄色,带有一个未分配的分片。 为了进行调查,我们将通过 _cat /shards 来查看哪个索引分片遇到问题

1. GET _cat/shards?v=true&s=state
2. index                                     shard prirep state        docs   store ip           node
3. logs                                      0     p      STARTED         2  10.1kb 10.42.255.40 instance-0000000001
4. logs                                      0     r      UNASSIGNED
5. kibana_sample_data_logs                   0     p      STARTED     14074  10.6mb 10.42.255.40 instance-0000000001
6. .kibana_1                                 0     p      STARTED      2261   3.8mb 10.42.255.40 instance-0000000001

因此,这将用于我们的非系统索引日志,该日志具有未分配的副本分片。 让我们看看通过运行 _cluster/allocation/explain 是什么造成这个原因(专业提示:当你向我们发送问题以提供支持时,这正是我们的工作)

1. GET _cluster/allocation/explain?pretty&filter_path=index,node_allocation_decisions.node_name,node_allocation_decisions.deciders.*
2. { "index": "logs",
3. "node_allocation_decisions": [{
4. "node_name": "instance-0000000005",
5. "deciders": [{
6. "decider": "data_tier",
7. "decision": "NO",
8. "explanation": "node does not match any index setting

此错误消息指向 data_hot,它是索引生命周期管理(ILM)策略的一部分,并指示我们的 ILM 策略与我们当前的索引设置不一致。 在这种情况下,此错误的原因是由于没有指定 hot-warm 节点而设置了 hot-warm ILM 策略。

仅供参考,如果你在没有任何 unsigned shards 的情况下运行此命令,则会出现 400 错误,提示找不到任何未分配的分片进行解释,因为没有错误要报告。

如果你遇到非逻辑原因(例如,临时网络错误,例如分配期间节点离开群集),则可以使用 Elastic 方便的 _cluster/reroute。

POST /_cluster/reroute

无需定制的此请求将启动一个异步后台进程,该进程尝试分配所有当前状态:UNASSIGNED shards。 


熔断器


最大化堆分配会导致对集群的请求超时或错误,并且经常会导致集群遇到熔断器异常。 熔断器会导致类似的 elasticsearch.log 事件:

Caused by: org.elasticsearch.common.breaker.CircuitBreakingException: [parent] Data too large, data for [] would be [num/numGB], which is larger than the limit of [num/numGB], usages [request=0/0b, fielddata=num/numKB, in_flight_requests=num/numGB, accounting=num/numGB]

要进行调查,请查看你的 heap.percent,方法是查看 _cat/nodes:

1. GET /_cat/nodes?v=true&h=name,node*,heap*
2. # heap = JVM (logical memory reserved for heap)
3. # ram  = physical memory
4. name                                node.role heap.current heap.percent heap.max
5. tiebreaker-0000000002 mv             119.8mb           23    508mb
6. instance-0000000001   himrst           1.8gb           48    3.9gb
7. instance-0000000000   himrst           2.8gb           73    3.9gb

或者,如果你先前已启用它,请导航至 Kibana > Stack Monitoring。

【Elastic Engineering】Elasticsearch:管理 Elasticsearch 内存并进行故障排除

如果你确定正被击中内存熔断器,则可以考虑暂时增加堆容量,为自己腾出空间进行调查。 在调查根本原因时,请通过群集代理日志或 elasticsearch.log 查找先前的连续事件。 你将寻找

  • 昂贵的查询,尤其是:
    • 高桶聚合
      •   当我发现搜索在根据搜索大小或存储桶尺寸运行查询之前临时分配堆的某个端口时,我感到非常傻,因此设置 10,000,000 确实让我的运营团队感到非常沮丧。
    • 非优化映射
      • 感到愚蠢的第二个原因是,当我认为进行分层报告会比扁平化的数据更好(不是)。
  • 请求量/速度:通常是批量或异步查询


是时间该扩容


如果这不是你第一次接触熔断器,或者你怀疑这将是一个持续存在的问题(例如,持续击中85%,那么该是时候考虑扩展资源了),那么你需要仔细研究一下 JVM 内存压力作为你的长期堆指标。 你可以在 Elasticsearch Service > Deployment 中进行检查

【Elastic Engineering】Elasticsearch:管理 Elasticsearch 内存并进行故障排除

或者你可以根据 _nodes/stats 信息进行计算:

1. GET /_nodes/stats?filter_path=nodes.*.jvm.mem.pools.old
2. {"nodes": { "node_id": { "jvm": { "mem": { "pools": { "old": {
3. "max_in_bytes": 532676608,
4. "peak_max_in_bytes": 532676608,
5. "peak_used_in_bytes": 104465408,
6. "used_in_bytes": 104465408
7. }}}}}}}

这里:

JVM Memory Pressure = used_in_bytes / max_in_bytes

潜在的症状是 elasticsearch.log 中的垃圾收集器(gc)事件发生的频率高且持续时间长

[timestamp_short_interval_from_last][INFO ][o.e.m.j.JvmGcMonitorService] [node_id] [gc][number] overhead, spent [21s] collecting in the last [40s]

如果你确认了这种情况,则需要研究扩展集群或减少达到集群的需求。 你需要调查/考虑:

  • 增加堆资源(堆/节点,节点数)
  • 减少分片(删除不必要的/旧的数据,使用 ILM 将数据放入温/冷存储中,以便你可以缩小数据,关闭不需要的数据的副本,以防丢失)


结论


喔! 从我在 Elastic Support 中看到的情况来看,这是最常见的用户问题的缩影:未分配的分片 (unassigned shards),不平衡的分片堆,熔断器,大量垃圾收集和分配错误。 所有这些都是核心资源分配管理对话的症状。 希望你现在也了解理论和解决步骤。

不过,如果你现在仍无法解决问题,请随时与我们联系。 我们在这里,乐意为你服务! 你可以通过 Elastic DiscussElastic Community Slack 咨询,培训和支持与我们联系。

为我们将 Elastic Stack 的资源分配作为非运维(也喜欢运维)进行自管的能力感到高兴!


参考:

【1】https://www.elastic.co/blog/managing-and-troubleshooting-elasticsearch-memory

上一篇:继续完成昨天的第一个点:更改DJANGO的ADMIN后台的表单显示


下一篇:【Android 安全】DEX 加密 ( Proguard keep 用法 | Proguard 默认混淆结果 | 保留类及成员混淆结果 | 保留注解以及被注解修饰的类/成员/方法 )