Loading... 以阿里云Elasticsearch6.7为例,记录一些常见问题 ## 一、数据迁移与同步 ### 1、跨集群数据迁移 (1)**跨集群复制CCR**(Cross Cluster Replication),简单来说是索引级别的多向多集群复制,适合高吞吐的容灾备份。使用CCR功能,需要准备两种类型的集群。一个是远程集群,即提供源数据(Leader index)的集群;一个是本地集群,即订阅数据(Follower index)的集群。该功能为被动复制,即所有复制任务都是由本地集群执行。 CCR一般用于长期的批量实时迁移数据做容灾备份,且复制的索引为只读,需要再转换为普通索引,不建议作为集群迁移方案(比方案二操作复杂且耗时久) 文档:https://help.aliyun.com/document_detail/175973.html (2)配置同一网络下的阿里云Logstash管道,保存后将重启实例部署。 文档:https://help.aliyun.com/document_detail/142425.html?spm=a2c4g.176854.0.0.34f65abazCcTTL 两者的迁移步骤大致如下: 1. 开发:系统中依据时间节点切割数据,切割点之后的数据暂存于缓存or队列中 2. 运维:配置Logstash/CCR迁移旧集群数据到新集群(全量+增量) 3. 开发:验证新旧集群数据量是否一致,待一致后关闭线上消费 4. 开发:通知人员停止数据操作(强一致性下保障) 5. 开发:更改ES配置,并重启系统生效 6. 运维:关闭Logstash/CCR配置,若为CCR需要将新集群的只读索引转为普通索引 7. 开发:开启线上消费,待消费稳定后开启暂存数据 8. 开发:通知人员恢复数据操作 ### 2、集群中数据迁移(重新分片、索引重建) 阿里云的 `reindex API`虽然支持跨集群数据迁移,但仅限于新旧集群都在旧网络架构下。更多的是用来做重新分片于重建索引Mapping(同集群下需要更改索引名,且涉及代码改动,设计时需要谨慎)。 ```json POST _reindex { "source": { "remote": {// remote在跨集群中使用 "host": "http://otherhost:9200", "socket_timeout": "1m", "connect_timeout": "10s" }, "index": "source", "query": { "match": { "test": "data" } } }, "dest": { "index": "dest" } } ``` 线上数据600w,耗时20min。 文档:https://help.aliyun.com/document_detail/176854.html?spm=a2c4g.148115.0.0.1b9e484dMXME8D ### 3、重启实例 ES的重启只能在阿里云的ElasticSearch控制面板上执行,每次重启时间耗时较久,在面板上有预估时间;开关公网访问、修改集群密码均不会引发重启;对于没有副本的索引,可能会导致重启过程中无法对外持续提供服务(如访问超时) ## 二、集群负载或状态异常 ### 1、ES集群状态yellow/red 当设置的索引副本数大于当前节点数减1时,会导致集群处于yellow状态。 可以通过 `GET _cat/indices?v`命令查看索引分片的分布情况,定位yellow状态的索引,并将其副本分片数设置为0。等待集群恢复正常后,再将对应索引的副本分片数设置为原来的值。 ```json PUT test/_settings { "index" : { "number_of_replicas":"0" } } ``` > 将副本分片数设置为0后,当节点掉线时,可能会导致数据丢失,需谨慎操作。待集群恢复正常后(大约1分钟),需尽快将副本分片数恢复到原来的值。 > > **索引的副本至少都要为1,防止节点不稳定导致索引为red状态从而影响到系统。** 分片负载不均导致资源不足、集群中包含过多以.monitor开头的索引监控索引数据(通过[kibna修改配置](https://help.aliyun.com/document_detail/68017.htm?spm=a2c4g.164513.0.0.4e048d66aY4Cf5#task-2458007))、分片未分配(通过 `GET /_cluster/allocation/explain?pretty`命令查看分片未分配的原因。处理后,可通过 `POST /_cluster/reroute?retry_failed=true`命令,重新分配分片。)、缓存导致资源占用(使用 `POST /<索引名>/_cache/clear?fielddata=true`命令清理缓存)、升配集群、磁盘水位超过85%都可能导致状态为Red ### 2、集群CPU占比过高 **(1)读写QPS增加导致CPU上涨** 一般不是主因。可以降低并发读写,读操作问题可以开启AliES内核的[慢查询隔离池](https://help.aliyun.com/document_detail/189717.html?spm=a2c4g.171548.0.0.6e015ed79kIJIL) **(2)索引缓存占用资源** ES缓存包括了节点查询缓存(node query cache)、字段数据缓存(field data cache)、分配请求缓存(share request cache)、索引缓存(indexing buffer),主要清理的为field data chache:`POST /索引名/_cache/clear?fielddata=true` **节点查询缓存(node query cache)**:`GET /_nodes/stats?pretty`中的query_cache 对于TermQuery、MatchAllDocsQuery不会缓存,而对于消耗较高的Query2次就能缓存,BooleanQuery和DisjunctionMaxQuery为4次,其它默认5次 ```json { "memory_size_in_bytes":1544022265,//1.5G "total_count":894457986, "hit_count":248356418, "miss_count":646101568, "cache_size":2917, "cache_count":7617608, "evictions":7614691 } ``` 上述生产中evictions缓存驱逐次数是cache_size的2600倍,如果filter查询较多可以适当调大 `indeces.querise.cache.size`(用于此缓存的 Java 堆的百分比,默认为 10%) **字段数据缓存(field data cache)**:主要用于sort和aggs的字段 ```json # 获取占用fielddata内存占用高的字段 GET _cat/fielddata?v&s=size:desc # 根据索引查看 GET /_stats/fielddata?fields=* # 根据节点查看 GET /_nodes/stats/indices/fielddata?fields=* ``` 对于差异较大的数据如 `contentKeywordEnc`fielddata的缓存相比于其他字段开销较大,平均每个node达到了170MB(不包括副本情况下),可以使用 `POST /索引名/_cache/clear?fielddata=true`命令,清理缓存。正常来说不是到达GB级别的影响不大。 **分配请求缓存(share request cache)**:主要缓存size=0的请求,如:aggs、suggestion、hits.tota。缓存采用LRU淘汰策略,当refresh时缓存清除,同时缓存是根据请求的JSON作为key进行存储,当含义相同但写法不同时无法识别缓存,默认缓存大小为1%。 **索引缓存(indexing buffer)**:用于缓存新索引的数据,当空间满了后就将数据写到磁盘上形成新的段。大小为分配给节点的堆总量的10%(`indices.memory.index_buffer_size`),一般不需要调整。 **(3)单节点CPU高,负载不均** 优先排查CPU与磁盘使用率是否差异较大,常用的指标含义与异常处理建议可以点[这里](https://help.aliyun.com/document_detail/137967.htm?spm=a2c4g.160455.0.0.22c4538aqKyTBN#concept-2151173); 主要是由于**shard设置不合理**或者**segment大小不均**导致,可以看下阿里的[集群负载不均问的分析方法及解决方案](https://help.aliyun.com/document_detail/160455.htm?spm=a2c4g.164513.0.0.2a666bbd8WEFni#section-04v-cpj-g6v)里面的分析步骤。一般的排查思路: 1. 查看CPU、TCP 2. 查看主日志、es慢searching日志、`GET /_nodes/hot_threads?pretty`查看热点线程、`GET_tasks/isolator?detailed=true`查看慢查询隔离池中的查询请求列表 3. 查询body中添加 `"profile": true`查看耗时,再分别指定 `preference=_primary`和 `preference=_replica`查看主副shard查询消耗的时间 4. `GET _cat/shards?v`查看分片、`GET /_cat/segments?v=true`查看segment 5. `GET _cat/indices?v`查看索引信息 **(4)单节点CPU高,负载均匀,协调节点查询CPU过高** 当一个搜索请求被发往一个节点时,该节点就变成了协调节点(Coordinating Node),但是在实际中发现每次协调节点都是同一台服务器(连接时ip直连、长链接问题),导致这个node的cpu暴涨。 PS:系统会与集群中的某个主节点建联,该节点主要就是维护两者的正常通信。而系统中某个主节点(包括建联的该主节点)会被推举成为协调节点,默认情况下协调节点有且仅有一个,且只要该协调节点不出现故障、维护时,就会一直是它 ### 3、shard分配不均 建议重新分配并合理规划shard,确保主shard数与副shard数之和是集群**数据节点**的整数倍。如:主节点数3、数据节点数6,那么最好就是主分片6个,副本1份;对于数据量小的可以主分片3个,副本1份。对于长期索引,建议在业务低峰期reindex,而按月分表的修改一下后续的index setting就好了。 ### 4、磁盘使用率过高 - 超过85%:导致新的分片无法分配。 - 超过90%:ES会尝试将对应节点中的分片迁移到其他磁盘使用率比较低的数据节点中。 - 超过95%:系统会对Elasticsearch集群中的每个索引强制设置**read_only_allow_delete**属性,此时索引将无法写入数据,只能读取和删除对应索引。 1. 优先考虑删除无用索引,再看看以.monitor开头的索引监控索引数据占比,可通过[kibna修改配置](https://help.aliyun.com/document_detail/68017.htm?spm=a2c4g.164513.0.0.4e048d66aY4Cf5#task-2458007)。 若磁盘使用率平均达到75+就需要升配集群了,若是单节点磁盘使用率高则排查shard分配不均。后续需要合理评估索引存储周期。 2. 若索引仍为 `read_only`状态,手动执行修改 ``` PUT _settings { "index.blocks.read_only_allow_delete": null } ``` 3. 若集群仍为 `Red`状态,使用 `_cat/allocation?v`命令查看集群中是否存在未分配的分片。 若存在未分配,执行 `GET _cluster/allocation/explain`命令查看未分配分片的原因。 若出现 `[[Lucene commit failed], failure IOException[No space left on device]]`,执行 `POST /_cluster/reroute?retry_failed=true`命令。 ### 5、ES内存占比过高 **(1)集群缓存占用内存** 索引缓存问题会导致内存、cpu都过高。短期通过 `POST /索引名/_cache/clear?fielddata=true`命令清理缓存;长期就需要考虑升配集群了。 **(2)读写过高** 可以开启[aliyun-qos插件的限流](https://help.aliyun.com/document_detail/156622.htm?spm=a2c4g.164513.0.0.4e048d66aY4Cf5#section-d9k-cc5-30s)功能,但要先提交工单让阿里云技术人员升级插件为最新版。 **(3)无用索引占用** 无用索引对磁盘、内存都有一定影响,需要删除无用索引、定义合理存储周期、合理配置.monitor系统索引。 **(4)单节点内存高,分片不均** 重新分配并合理规划shard,确保主shard数与副shard数之和是集群**数据节点**的整数倍。 **(5)跑资源消耗高的脚本任务** 通过 `GET _cat/tasks?v`命令获取耗时查询任务ID,并通过 `GET _tasks?detailed=true&actions=*read/search*`命令获取详细的查询语句并保存分析。 ### 6、JVM相关大小 默认为集群内存的一半,且不允许修改。可通过 `GET _nodes/stats/jvm?pretty`命令查看。 ### 7、队列、线程池大小查看与调整 一般除了偶发的业务性高峰的write队列写入失败,否则不建议调整,常态优先考虑升配或者写入调优。 可以通过修改yml配置调整: ```json thread_pool.write.queue_size: 200 //文档写入队列大小 thread_pool.search.queue_size: 1000// 文档搜索队列大小 ``` 线程池大小非必要不修改,修改必须同时满足[官方定义配置](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-threadpool.html)。 ```json # 查看线程池运行情况 GET /_cat/thread_pool?v&h=id,name,type,active,size,queue,queue_size,rejected,largest,completed,min,max,keep_alive id name type active size queue queue_size rejected largest completed min max keep_alive xxxxxxxxxxxxxxxxxxxxxx analyze fixed 0 0 0 16 0 0 0 1 1 ``` ### 8、FullGC FullGC(清理整个堆空间)是否存在问题,需要通过业务延时,以及对比历史和现在的状况来分析。CMS回收器在内存为75%就会开始回收,需要留一点空间以应付突增流量。 ``` [o.e.m.j.JvmGcMonitorService] [xxx] [gc][4385224] overhead, spent [547ms] collecting in the last [1s] [gc][这是第4385224次GC检查] 在最近547m 内花了1s用来做垃圾收集 ``` 默认花费时间占用50%就会警告,可以通过yml配置 `monitor.jvm.gc.overhead.warn: 85`变更。 ### 9、集群分片健康不为100%(存在未分配分片) **现象**: 存在 `unassigned shards`为分配分片,集群green但是存在索引状态为yellow。 **排查**: 通过 `GET _cluster/health`查看集群健康状态,发现存在 `relocating_shards`和 `unassigned_shards`问题: ```json { "cluster_name" : "es-cn-zvp2op13q000uocn6", "status" : "green",// 集群健康状态:green、yellow、red "timed_out" : false, "number_of_nodes" : 9, "number_of_data_nodes" : 6, "active_primary_shards" : 337,// 活跃主分片数 "active_shards" : 644,// 活跃分片数 "relocating_shards" : 2,// 迁移节点的分片数 "initializing_shards" : 0,// 初始化分片数 "unassigned_shards" : 12,// 未分配分片数 "delayed_unassigned_shards" : 0,// 延迟分配分片数 "number_of_pending_tasks" : 0,// 主节点创建索引并分配shards等任务,如果该指标数值一直未减小代表集群存在不稳定因素 "number_of_in_flight_fetch" : 0,// 未fetch操作数 "task_max_waiting_in_queue_millis" : 0,// 任务最大等待时长 "active_shards_percent_as_number" : 96.0// 集群分片健康值,活跃分片数占总分片数比例。 } ``` 再通过 `GET /_cat/indices?v`查看存在索引为yellow,且都为新建索引。接着从 `GET /_cluster/allocation/explain?pretty`查看索引未分配原因: ``` there are too many copies of the shard allocated to nodes with attribute [zone_id], there are [2] total configured shard copies for this shard id and [2] total attribute values, expected the allocated shard count per attribute [2] to be less than or equal to the upper bound of the required number of shards per attribute [1] ``` **结论**: 删除索引导致节点分片迁移重新平衡,刚好有新建索引操作,触发新索引延迟分配,集群分片健康值不为100%,触发告警,通过等待后自愈。 **unassigned shards出现原因:** (1)shard allocation触发延迟机制  (2)nodes数小于分片副本数 (3)`cluster.routing.allocation.enable`被关闭,默认 `all`开启 (4)磁盘超过85% ## 三、集群查询与写入问题 ### 1、search limit 10000 ES默认的**index.max_result_window**(分页查询时查询的最大文档数量)参数值为10000(from+size),查询时超过该值将报错 `Result window is too large, from + size must be less than or equal to: [10000]`。 ```json PUT /my_index/_settings { "index": { "max_result_window": 50000 } } ``` 当查询召回结果过多,不推荐使用from+size做深分页,否则会消耗大量的CPU和内存资源。深度分页场景建议使用scroll或search after。 ### 2、写入时报错forbids automatic creation of the index 未开启自动创建索引。建议测试环境开启,线上只允许自动创建系统索引: ``` # 允许自动创建所有索引 PUT /_cluster/settings { "persistent": { "action": { "auto_create_index": "true" } } } # 仅允许自动创建系统索引 PUT /_cluster/settings { "persistent": { "action": { "auto_create_index": "+.*,-*" } } } ``` ## 四、集群配置与变更问题 ### 1、es磁盘容量、集群规格、shard大小评估 **磁盘容量:** ``` 磁盘总大小 = 源数据 *(1 + 副本数量)* 索引开销 /(1 - 操作系统预留空间)/(1 - Elasticsearch内部开销)/(1 - 安全阈值) = 源数据 *(1 + 副本数量)* 1.7 = 源数据 * 3.4 ``` **集群规格:** | 规格 | 最大节点数 | 单节点磁盘最大容量(查询) | 单节点磁盘最大容量(日志) | 单节点磁盘最大容量(通常) | | -------- | ---------- | ------------------------- | ------------------------- | ------------------------- | | 16核32GB | 16*5=80 | 32GB*10=320GB | 32GB*50=1.5TB | 32GB*30=960GB | **Shard评估:** 1. 建议一个shard的存储量保持在30 GB以内(最优),特殊情况下,可以提升到50 GB以内。 2. 对于日志分析或者超大索引场景,建议单个shard大小不要超过100 GB。 3. 建议shard的个数(包括副本)要尽可能等于数据节点数,或者是数据节点数的整数倍。 4. 主分片不是越多越好,因为主分片越多,Elasticsearch性能开销也会越大。 建议单个节点上同一索引的shard个数不要超5个。 单个数据节点的shard数量 = 当前节点的内存大小 * 30~50。 Last modification:February 21, 2024 © Allow specification reprint Like 0 喵ฅฅ