Elasticsearch是一个开源的搜索引擎和分析存储,被各种应用所使用,从电子商务商店的搜索,到使用ELK栈的内部日志管理工具("Elasticsearch, Logstash, Kibana "的缩写)。作为一个分布式数据库,你的数据被分割成 "分片",然后被分配到一个或多个服务器。
由于这种分片,对Elasticsearch集群的读或写请求需要在多个节点之间进行协调,因为在单个服务器上没有你数据的 "全局视图"。虽然这使得Elasticsearch具有高度的可扩展性,但也使得它的设置和调整比其他流行的数据库如MongoDB或PostgresSQL要复杂得多,后者可以在单台服务器上运行。
当可靠性问题出现时,如果你的Elasticsearch设置是错误的或不稳定的,消防工作会很有压力。你的事件可能会影响到客户,这可能会对收入和你的企业声誉产生负面影响。快速的补救措施是很重要的,然而在事故或中断期间,花大量的时间在网上研究解决方案并不是大多数工程师所能做到的。本指南旨在为工程师运行中可能导致Elasticsearch问题的常见问题以及需要注意的事项提供一个小抄。
作为一个通用的工具,Elasticsearch有成千上万种不同的配置,这使它能够适应各种不同的工作负载。即使是在网上发布的,对某家公司有效的数据模型或配置也不一定适合你。让Elasticsearch扩展并没有什么灵丹妙药,需要勤奋的性能测试和试验/错误。
无响应的Elasticsearch集群问题
集群的稳定性问题是最难调试的,尤其是当你的数据量或代码库没有任何变化的时候。
检查集群状态的大小
它的作用是什么?
- Elasticsearch集群状态跟踪我们集群的整体状态,是控制流量和集群的核心。集群状态包括集群中节点的元数据、分片的状态以及它们如何被映射到节点、索引映射(即模式)等。
- 集群状态通常不会经常改变。然而,某些操作,如在索引映射中添加一个新字段,会触发更新。
- 因为集群更新会广播给集群中的所有节点,所以它应该是小的(<100MB)。
- 一个大的集群状态会很快使集群不稳定。这种情况发生的常见方式是通过映射爆炸(索引中太多的键)或太多的索引。
要寻找的东西
- 使用下面的命令下载集群状态,看看返回的JSON的大小。
curl -XGET 'http://localhost:9200/_cluster/state'
如何修复
- 看一下数据是如何被索引的。一个常见的映射爆炸发生的方式是当高cardinality标识符被用作JSON键。每次看到一个新的键,如 "4 "和 "5",集群的状态就会被更新。例如,下面的JSON将很快导致Elasticsearch的稳定性问题,因为每个键都被添加到全局状态中。
{
"1": {
"status": "ACTIVE"
},
"2": {
"status": "ACTIVE"
},
"3": {
"status": "DISABLED"
}
}
要解决这个问题,请将你的数据扁平化为对Elasticsearch友好的东西。
{
[ { "id": "1", "status": "ACTIVE" }, { "id": "2", "status": "ACTIVE" }, { "id": "3", "status": "DISABLED" } ]
}
检查Elasticsearch的任务队列
它是做什么的?
- 当对Elasticsearch提出请求时(索引操作、查询操作等),它首先被插入到任务队列中,直到有工作线程可以接替它。
- 一旦工作者池有了空闲的线程,它就会从任务队列中拿起一个任务并进行处理。
- 这些操作通常是由你通过HTTP请求在
:9200和:9300端口进行的,但它们也可以是内部的,以处理索引的维护任务 - 在一个特定的时间,可能有成百上千的飞行操作,但应该很快完成(如微秒或毫秒)。
要寻找的东西
-
运行下面的命令,寻找那些卡住运行很长时间的任务,如几分钟或几小时。
-
这意味着有什么东西在饿着集群,阻止它取得进展。
-
对于某些长期运行的任务,如移动索引,需要很长的时间,这是可以的。然而,正常的查询和索引操作应该是快速的。
curl -XGET 'http://localhost:9200/_cat/tasks?detailed' -
通过
?detailed参数,你可以获得更多关于目标索引和查询的信息。 -
找出哪些任务一直在列表的顶部的模式。它是同一个索引吗?是同一个节点吗?
-
如果是的话,也许是该索引的数据出了问题,或者该节点超载了。
如何修复
- 如果请求量高于正常值,那么看看如何优化请求(如使用批量API或更有效的查询/写入)。
- 如果请求量没有变化并且看起来是随机的,这意味着有其他东西拖慢了集群。任务的备份只是一个更大问题的症状。
- 如果你不知道这些请求来自哪里,可以在Elasticsearch客户端上添加
X-Opaque-Id头,以识别哪些客户端在触发查询。
检查Elasticsearch挂起的任务
它的作用是什么?
- 待定任务是对集群状态的待定更新,如创建一个新的索引或更新其映射。
- 与之前的任务队列不同,待定更新需要一个多步骤的握手来向集群中的所有节点广播更新,这可能需要一些时间。
- 在给定的时间内,飞行中的任务应该几乎为零。请记住,像快照恢复这样昂贵的操作可能会导致这个数字暂时飙升。
需要注意的是
-
运行该命令,确保没有或很少有飞行中的任务。
curl curl curl -XGET 'http://localhost:9200/_cat/pending_tasks' -
如果它看起来是一个持续的集群更新流,并迅速完成,看看什么可能会触发它们。是映射爆炸还是创建了太多的索引?
-
如果只是几个,但它们似乎被卡住了,看看主节点的日志和指标,看看是否有任何问题。例如,主节点是否遇到了内存或网络问题,以至于它无法处理集群更新?
热线程
它是做什么的?
- 热线程API是一个有价值的内置剖析器,可以告诉你Elasticseach在哪里花费了最多的时间。
- 这可以提供一些洞察力,比如Elasticsearch是否在索引刷新上花费了太多时间,或者执行了昂贵的查询。
要找的东西
-
对热线程API进行调用。为了提高准确性,建议使用
?snapshots参数捕获许多快照。curl -XGET 'http://localhost:9200/_nodes/hot_threads?snapshots=1000' -
这将返回快照拍摄时的堆栈痕迹。
-
在许多不同的快照中寻找相同的堆栈。例如,你可能会看到这样的文字:
5/10 snapshots sharing following 20 elements。这意味着一个线程在5个快照期间在代码的那个区域花费了时间。 -
你还应该看一下CPU%。如果一个区域的代码既有高的快照共享,也有高的CPU%,这就是一个热门的代码路径。
-
通过查看代码模块,拆解Elasticseach在做什么。
-
如果你看到等待或停车状态,这通常是可以的。
如何修复
- 如果大量的CPU时间花在索引刷新上,那么尝试增加刷新间隔,超过默认的1秒。
- 如果你在缓存中看到大量的数据,也许你的默认缓存设置是次优的,导致严重的错过。
内存问题
检查Elasticsearch Heap/Garbage Collection
它是做什么的?
- 作为一个JVM进程,堆是存储大量Elasticsearch数据结构的内存区域,需要垃圾收集周期来修剪旧对象。
- 对于典型的生产设置,Elasticsearch在启动时使用
mlockall锁定所有的内存,并禁止交换。如果你没有这样做,现在就做吧。 - 如果一个节点的Heap持续高于85%或90%,这意味着我们已经接近于没有内存了。
要寻找的东西
- 在Elasticsearch日志中搜索
collecting in the last。如果出现这些情况,这意味着Elasticsearch在垃圾收集上花费了更多的开销(这占用了其他生产任务的时间)。 - 只要Elasticsearch没有把大部分的CPU周期花在垃圾收集上,偶尔出现一些这样的情况是可以的(计算花在收集上的时间相对于整个时间的百分比)。
- 一个在垃圾收集上花费100%时间的节点是停滞不前的,无法取得进展。
- 看起来有超时等网络问题的节点,实际上可能是由于内存问题。这是因为在垃圾收集周期中,节点无法响应传入的请求。
如何修复
-
最简单的方法是添加更多的节点来增加集群的可用堆。然而,Elasticsearch需要时间来重新平衡分片到空节点上。
-
如果只有一小部分节点有很高的堆使用率,你可能需要更好地平衡你的客户。例如,如果你的分片大小差异很大,或者有不同的查询/索引带宽,你可能为同一组节点分配了太多的热分片。要移动一个分片,请使用重新路由API。只要调整分片意识的灵敏度,以确保它不会被移回。
curl -XPOST -H "Content-Type: application/json" localhost:9200/_cluster/reroute -d ' { "commands": [ { "move": { "index": "test", "shard": 0, "from_node": "node1", "to_node": "node2" } } ] }' -
如果你正在向Elasticsearch发送大量的请求,试着减少批处理的大小,使每个批处理在100MB以下。虽然较大的批次有助于减少网络开销,但它们需要分配更多的内存来缓冲请求,而这些内存在请求完成后和下一个GC周期才会被释放。
检查Elasticsearch的旧内存压力
它的作用是什么?
- 旧内存池包含了那些已经在多个垃圾收集周期中存活下来的对象,是长寿的对象。
- 如果旧内存超过75%,你可能要注意它。当它填满超过85%时,更多的GC循环将发生,但这些对象无法被清理掉。
需要注意的是
- 看一下旧池使用量/旧池最大值。如果它超过了85%,那就值得注意了。
如何解决
- 你是否急于加载大量的Fieldddata?这些数据会在内存中停留很长时间。
- 你是否在执行许多长期运行的分析任务?某些任务应该被卸载到分布式计算框架中,比如Apache Spark,用于地图/还原操作。
检查Elasticsearch字段数据大小
它是做什么的?
- FieldData用于计算一个字段的聚合,如
terms聚合 - 通常情况下,一个字段的fielddata不会被加载到内存中,直到第一次对其进行聚合时。
- 然而,如果设置了
eager_load_ordinals,这也可以在索引刷新时预先计算。
要看什么
-
像这样看一个索引或所有索引的字段数据大小。
curl -XGET 'http://localhost:9200/index_1/_stats/fielddata' -
如果我们在错误的数据类型上使用一个索引,它可能有非常大的字段数据结构。你是否在非常高cardinality的字段上执行聚合,如UUID或跟踪ID?Fielddata不适合用于非常高cardinality的字段,因为它们会产生大量的fielddata结构。
-
你是否有很多设置了
eager_load_ordinals的字段,或者为fielddata缓存分配了大量的内容?这将导致在刷新时间与查询时间产生的fielddata。虽然它可以加速聚合,但如果你在索引刷新时计算许多字段的fielddata,并且在查询中从不消耗它,那就不是最佳选择。
如何修复
- 对你的查询或映射进行调整,不要在非常高的cardinality key上聚合。
- 审核你的映射,以减少设置为 "true "的数量,
eager_load_ordinals。
Elasticsearch网络问题
节点离开或节点断开连接
它的作用是什么?
- 如果一个节点不响应请求,它最终会被从集群中删除。
- 这使得碎片可以被复制到其他节点上,以满足复制因素,并确保高可用性,即使一个节点被移除。
要看什么
- 看一下主节点的日志。即使有多个主节点,你也应该看一下当前当选的主节点。你可以使用节点的API或者像Cerebro这样的工具来做这件事。
- 看看是否有一个一致的节点超时或有问题。例如,你可以通过在主节点的日志中寻找短语
pending nodes,看看哪些节点还在等待集群更新。 - 如果你看到同一个节点不断被添加,但又被删除,这可能意味着该节点过载或无响应。
- 如果你不能从你的主节点到达该节点,这可能意味着一个网络问题。你也可能是遇到了网卡或CPU带宽的限制。
如何修复
- 在设置
transport.compression为真时进行测试。这将压缩节点之间的流量(比如从摄取节点到数据节点),减少网络带宽,牺牲CPU带宽。 - 注意:早期的版本把这个设置称为
transport.tcp.compression。 - 如果你也有内存问题,试着增加内存。一个节点可能会因为在垃圾收集上花费大量时间而变得没有反应。
没有足够的主节点问题
它是做什么的?
需要注意的是
-
启用跟踪记录以审查与发现有关的活动。
curl -XPUT -H "Content-Type: application/json" localhost:9200/_cluster/_settings -d ' { "transient": {"logger.discovery.zen":"TRACE"} }' -
查看配置,如
minimum_master_nodes(如果比6.x老)。 -
查看初始主节点列表中的所有主节点是否可以相互ping。
-
审查你是否有法定人数,这应该是
number of master nodes / 2 +1。如果你少于法定人数,将不会发生集群状态的更新以保护数据的完整性。
如何修复
- 有时网络或DNS问题会导致原始主节点无法到达。
- 检查你是否有至少
number of master nodes / 2 +1主节点目前正在运行。
分区分配错误
Elasticsearch处于黄色或红色状态(未分配的分片)。
它是做什么的?
- 当一个节点重启或集群恢复开始时,分片不会立即可用。
- 恢复是节制的,以确保集群不会被淹没。
- 黄色状态意味着主索引已被分配,但二级(副本)分片尚未被分配。虽然黄色索引既可读又可写,但可用性会下降。黄色状态通常是可以自我修复的,因为集群会复制分片。
- 红色索引意味着主要分片没有被分配。这可能是短暂的,如在快照恢复操作期间,但也可能意味着重大问题,如丢失数据。
要寻找的东西
-
看看为什么停止分配的原因。
curl -XGET 'http://localhost:9200/_cluster/allocation/explain' curl -XGET 'http://localhost:9200/_cat/shards?h=index,shard,prirep,state,unassigned.reason' -
获取红色索引的列表,了解哪些索引导致了红色状态。只要至少有一个索引是红色的,集群状态就会处于红色状态。
curl -XGET 'http:localhost:9200/_cat/indices' | grep red -
对于单个索引的更多细节,你可以看到违规索引的恢复状态。
curl -XGET 'http:localhost:9200/index_1/_recovery'
如何修复
-
如果你看到
max_retries(也许集群在分配过程中很忙)的超时,你可以暂时增加断路器阈值(默认是5)。一旦数字高于断路器,Elasticsearch将开始初始化未分配的分片。curl -XPUT -H "Content-Type: application/json" localhost:9200/index1,index2/_settings -d ' { "index.allocation.max_retries": 7 }'
Elasticsearch磁盘问题
索引是只读的
它是做什么的?
- Elasticsearch有三个基于磁盘的水印,影响分片分配。
cluster.routing.allocation.disk.watermark.low水印可以防止新的分片被分配到磁盘已满的节点上。默认情况下,这是85%的磁盘使用量。 cluster.routing.allocation.disk.watermark.high水印将迫使集群开始将分片从该节点转移到其他节点。默认情况下,这是90%。这将开始移动数据,直到低于高水印。如果Elasticsearch磁盘超过洪水阶段的水印cluster.routing.allocation.disk.watermark.flood_stage,这时磁盘就会变得非常满,在磁盘耗尽空间之前,移动速度可能不够快。当达到时,索引被置于只读状态,以避免数据损坏。
需要注意的是
-
看看你的每个节点的磁盘空间。
-
查看节点的日志,看是否有类似下面的信息。
high disk watermark [90%] exceeded on XXXXXXXX free: 5.9gb[9.5%], shards will be relocated away from this node -
一旦达到洪水阶段,你会看到像这样的日志。
flood stage disk watermark [95%] exceeded on XXXXXXXX free: 1.6gb[2.6%], all indices on this node will be marked read-only -
一旦发生这种情况,该节点上的索引是只读的。
-
为了确认,看看哪些索引的
read_only_allow_delete设置为真。curl -XGET 'http://localhost:9200/_all/_settings?pretty' | grep read_only
如何修复
-
首先,清理磁盘空间,如删除本地日志或临时文件。
-
要删除这个只读块,要做命令。
curl -XPUT -H "Content-Type: application/json" localhost:9200/_all/_settings -d ' { "index.blocks.read_only_allow_delete": null }'
结论
解决稳定性和性能问题可能是一个挑战。找到根本原因的最好方法是使用假设的科学方法,并证明其正确或不正确。使用这些工具和Elasticsearch管理API,你可以深入了解Elasticsearch的性能以及问题可能出现的地方。