MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

ElasticSearch可选参数对性能的影响分析

2023-05-082.2k 阅读

ElasticSearch 可选参数基础介绍

ElasticSearch 是一个分布式的搜索和分析引擎,在实际应用中,通过合理配置其可选参数,能够显著提升性能。首先,我们来了解一些常见的可选参数及其基本概念。

索引相关参数

  1. number_of_shards:该参数决定了一个索引被分成多少个分片。分片是 ElasticSearch 进行水平分割数据的最小单位,每个分片本质上是一个独立的 Lucene 索引。例如,创建一个新索引时,可以这样设置:
CreateIndexRequest createIndexRequest = new CreateIndexRequest("my_index");
createIndexRequest.settings(Settings.builder()
      .put("index.number_of_shards", 3));
IndexResponse indexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);

如果设置的分片数量过多,会增加管理开销,每个分片都需要占用一定的系统资源(如文件句柄、内存等);若分片数量过少,在数据量增大时可能无法充分利用集群的并行处理能力,影响查询性能。

  1. number_of_replicas:定义了每个分片的副本数量。副本主要用于提高系统的高可用性和读性能。比如:
createIndexRequest.settings(Settings.builder()
      .put("index.number_of_shards", 3)
      .put("index.number_of_replicas", 2));

增加副本数量可以提升读操作的并发能力,因为多个副本可以同时响应读请求。但过多的副本会占用大量的磁盘空间,并且在数据写入时,需要同步更新到所有副本,可能会降低写性能。

查询相关参数

  1. timeout:设置查询的超时时间。在执行查询时,如果超过这个时间还未返回结果,查询将被终止并返回错误。例如,在 Java 客户端中:
SearchRequest searchRequest = new SearchRequest("my_index");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
searchSourceBuilder.timeout(new TimeValue(10, TimeUnit.SECONDS));
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

合理设置超时时间可以避免长时间等待无效的查询结果,提高用户体验。但如果设置得过短,可能会导致一些复杂但必要的查询被过早终止。

  1. size:用于指定查询返回的文档数量。默认情况下,ElasticSearch 返回前 10 个匹配的文档。若需要获取更多文档,可以调整该参数:
searchSourceBuilder.size(50);

然而,返回大量文档会增加网络传输开销和内存消耗,特别是在查询结果集较大时,可能导致性能问题。

索引参数对性能的深入影响分析

number_of_shards 的性能影响

  1. 存储性能
    • 从存储角度来看,每个分片都有自己的文件系统占用。如果number_of_shards设置过大,会造成大量的小文件,增加文件系统的元数据管理负担。例如,在一个磁盘 I/O 性能有限的系统中,过多的小文件会导致磁盘寻道时间增加,降低数据读写速度。假设每个分片平均占用 100MB 数据,一个索引设置了 1000 个分片,相比设置 100 个分片,文件系统需要管理的文件数量大幅增加,在进行数据存储和检索时,磁盘 I/O 性能会受到明显影响。
    • 另一方面,如果分片数量过少,单个分片的数据量会过大。当单个分片数据量超过一定阈值(如几十 GB 甚至上百 GB),在进行数据恢复或重新分配时,所需的时间会显著增加。比如在集群节点故障后,需要重新分配数据,大分片的数据恢复时间会比小分片长得多,影响系统的可用性。
  2. 查询性能
    • 在查询时,ElasticSearch 会并行地在各个分片上执行查询操作。适当增加分片数量可以提高查询的并行度,从而加快查询速度。例如,对于一个包含大量文档的索引,设置 5 个分片的查询性能可能优于设置 1 个分片,因为多个分片可以同时处理查询请求,减少了整体的查询时间。但是,如果分片数量过多,查询时的协调开销会增大。每个分片查询完成后,需要将结果汇总,过多的分片会增加这个汇总过程的时间和资源消耗,最终可能导致查询性能不升反降。
    • 以搜索一篇长文章中的关键词为例,如果索引被分成多个合理数量的分片,每个分片可以独立地搜索关键词,然后将结果合并。但如果分片数量不合理,比如设置了 1000 个分片,在合并结果时,可能会花费大量时间在网络传输和数据整合上,降低了查询效率。

number_of_replicas 的性能影响

  1. 读性能
    • 副本的主要作用之一是提升读性能。当有读请求时,ElasticSearch 可以从多个副本中选择一个响应,从而分散读负载。例如,在一个读操作频繁的系统中,将number_of_replicas设置为 3 相比设置为 1,可以使更多的读请求同时得到处理,提高系统的并发读能力。假设系统每秒有 100 个读请求,只有 1 个副本时,可能会出现排队等待的情况;而有 3 个副本时,这些请求可以更均匀地分配到各个副本上,减少响应时间。
    • 然而,读性能的提升并非与副本数量成线性关系。随着副本数量的不断增加,副本之间的数据同步开销也会增大。当一个文档更新时,需要同步更新到所有副本,这会占用一定的网络带宽和节点资源。如果副本数量过多,同步开销可能会抵消读性能提升带来的优势。
  2. 写性能
    • 对于写操作,增加副本数量会降低写性能。因为每次写入都需要同步到所有副本,这增加了写入操作的时间。例如,当向一个设置了 3 个副本的索引写入数据时,数据需要同时被写入到 1 个主分片和 3 个副本分片,相比没有副本的情况,写入时间会明显增加。在高并发写入场景下,这种性能下降会更加显著。如果系统的写入负载很高,过多的副本可能会导致写入队列积压,进一步降低系统的整体性能。

查询参数对性能的深入影响分析

timeout 的性能影响

  1. 用户体验角度
    • 设置合适的timeout参数对用户体验至关重要。在一个实时性要求较高的搜索应用中,如果查询长时间没有响应,用户可能会认为系统出现故障或反应迟钝。例如,一个电商搜索页面,用户期望在几秒钟内看到搜索结果。如果timeout设置为 30 秒,而一个复杂查询实际需要 20 秒才能完成,虽然查询最终能返回结果,但用户可能已经失去耐心离开页面。相反,如果timeout设置为 2 秒,而大多数查询在 3 秒左右才能完成,那么大量查询会因为超时被终止,用户得不到完整的结果,同样影响体验。
  2. 系统资源管理角度
    • 从系统资源管理方面来看,timeout可以避免查询长时间占用资源。一些复杂的查询可能会因为各种原因(如数据量巨大、查询条件复杂等)执行时间过长,如果没有timeout限制,这些查询会一直占用系统资源,如内存、CPU 等,影响其他查询的执行。例如,一个占用大量内存的聚合查询,如果没有设置timeout,可能会导致系统内存不足,使其他查询无法正常运行。通过合理设置timeout,可以及时释放资源,保证系统的整体稳定性和可用性。

size 的性能影响

  1. 网络传输性能
    • size参数直接影响网络传输的数据量。当size设置较大时,需要从 ElasticSearch 集群传输大量的文档数据到客户端。例如,将size设置为 1000,相比设置为 10,传输的数据量可能会增加几十倍甚至上百倍。在网络带宽有限的情况下,这会导致网络拥塞,增加数据传输时间。如果客户端和 ElasticSearch 集群之间的网络连接不稳定,大量数据传输还可能导致数据丢失或重传,进一步降低性能。
  2. 内存消耗
    • ElasticSearch 在处理查询时,会在内存中构建查询结果集。当size较大时,需要更多的内存来存储这些结果。如果系统内存不足,可能会导致频繁的磁盘交换,严重影响性能。例如,一个查询请求返回 10000 个文档,每个文档占用 1KB 内存,那么仅查询结果集就需要 10MB 内存。如果系统的可用内存有限,无法满足这个需求,就会出现性能问题。而且,在客户端接收大量数据时,也需要足够的内存来处理和显示这些数据,否则客户端也可能出现卡顿甚至崩溃。

优化策略与综合考量

索引参数优化策略

  1. 确定合适的 number_of_shards
    • 在创建索引时,应根据预估的数据量和查询模式来确定number_of_shards。对于数据量较小且查询相对简单的应用场景,如小型企业内部的文档搜索,每个索引设置 1 - 3 个分片可能就足够了。而对于大规模数据存储和复杂查询的场景,如电商的商品索引,可能需要根据数据量进行更细致的估算。一般来说,可以按照每个分片 15GB - 50GB 的数据量来估算。例如,如果预计索引的数据量为 500GB,可以设置 10 - 30 个分片。同时,需要在测试环境中进行性能测试,观察不同分片数量下的查询和写入性能,找到最优值。
  2. 合理调整 number_of_replicas
    • 如果系统以读操作为主,如新闻网站的搜索功能,可以适当增加副本数量来提高读性能。例如,设置 2 - 3 个副本。但如果写操作也很频繁,如社交平台的动态发布,副本数量应相对减少,以避免过多的同步开销影响写性能,通常可以设置 1 个副本。在系统运行过程中,还可以根据实际的读写负载情况动态调整副本数量。通过 ElasticSearch 的 API,可以在不重启服务的情况下修改副本数量:
IndicesOptions indicesOptions = IndicesOptions.fromOptions(true, true, true, true);
UpdateSettingsRequest updateSettingsRequest = new UpdateSettingsRequest("my_index");
updateSettingsRequest.settings(Settings.builder()
      .put("index.number_of_replicas", 2));
AckedResponse response = client.indices().updateSettings(updateSettingsRequest, RequestOptions.DEFAULT);

查询参数优化策略

  1. 精准设置 timeout
    • 为了设置合适的timeout,需要对系统中的查询类型和平均执行时间有深入了解。对于简单的关键词查询,通常可以设置较短的timeout,如 5 - 10 秒。而对于复杂的聚合查询或涉及大量数据的跨索引查询,可能需要设置较长的timeout,如 30 秒甚至 1 分钟。可以通过在生产环境中记录查询的执行时间,分析查询的时间分布,来确定一个合理的timeout值。同时,在设置timeout时,要考虑到系统的负载情况。在负载高峰期,查询执行时间可能会变长,此时可以适当增加timeout的值。
  2. 谨慎使用 size
    • 如果只需要获取部分文档摘要信息,应尽量将size设置为较小的值。例如,在搜索结果列表页面,只需要显示前 10 - 20 条结果。如果确实需要获取大量文档,可以采用分页的方式,每次获取少量数据。在 ElasticSearch 中,可以通过fromsize参数结合实现分页:
searchSourceBuilder.from(0).size(20);

这样可以减少单次网络传输的数据量和内存消耗。同时,要注意在分页时,随着from值的增大,查询性能会逐渐下降,因为 ElasticSearch 需要跳过前面的大量文档来获取指定页的数据。对于深度分页场景,可以考虑使用 Scroll API 来提高性能。

不同场景下的参数配置案例分析

日志分析场景

  1. 索引参数配置
    • 在日志分析场景中,数据量通常较大且增长迅速。对于number_of_shards,可以根据预估的每日日志生成量来设置。假设每天生成 100GB 的日志数据,按照每个分片 30GB 左右的标准,可以设置 4 - 5 个分片。对于number_of_replicas,由于日志数据主要用于查询分析,读操作频繁,而写操作相对集中在日志采集阶段,可以设置 2 - 3 个副本,以提高读性能。
    • 例如,在创建日志索引时:
CreateIndexRequest createIndexRequest = new CreateIndexRequest("log_index");
createIndexRequest.settings(Settings.builder()
      .put("index.number_of_shards", 4)
      .put("index.number_of_replicas", 2));
IndexResponse indexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
  1. 查询参数配置
    • 在日志查询时,timeout可以设置稍长一些,如 20 - 30 秒,因为日志查询可能涉及到复杂的时间范围过滤和聚合操作。size则根据实际需求来设置,如果只是查看最近的几条日志,设置为 10 - 20 即可;如果需要导出一段时间内的所有日志,可能需要结合分页或 Scroll API 来处理。
SearchRequest searchRequest = new SearchRequest("log_index");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.rangeQuery("@timestamp").gte("now - 1d").lte("now"));
searchSourceBuilder.timeout(new TimeValue(30, TimeUnit.SECONDS));
searchSourceBuilder.size(20);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

电商搜索场景

  1. 索引参数配置
    • 电商平台的商品数据量较大且变化频繁。对于number_of_shards,可以根据商品数量和增长趋势来设置。假设平台有 100 万种商品,预计未来会增长到 500 万种,每个分片存储 50 万种商品左右比较合适,那么可以设置 2 - 10 个分片。由于电商搜索读操作远远多于写操作,number_of_replicas可以设置为 3 - 5 个,以提高读性能。
    • 如下是创建商品索引的代码示例:
CreateIndexRequest createIndexRequest = new CreateIndexRequest("product_index");
createIndexRequest.settings(Settings.builder()
      .put("index.number_of_shards", 5)
      .put("index.number_of_replicas", 4));
IndexResponse indexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
  1. 查询参数配置
    • 在电商搜索中,用户对响应时间要求较高,timeout一般设置在 5 - 10 秒。size通常根据搜索结果展示页面的需求来设置,如每页显示 10 - 20 个商品。
SearchRequest searchRequest = new SearchRequest("product_index");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchQuery("product_name", "手机"));
searchSourceBuilder.timeout(new TimeValue(8, TimeUnit.SECONDS));
searchSourceBuilder.size(10);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

总结不同参数对 ElasticSearch 性能的综合影响

通过以上对 ElasticSearch 可选参数的分析,我们可以看到不同参数从多个方面影响着系统的性能。索引参数number_of_shardsnumber_of_replicas主要影响存储、读写性能以及系统的可用性;查询参数timeoutsize则对查询的响应时间、资源管理以及用户体验有着重要作用。在实际应用中,需要根据具体的业务场景和需求,综合考虑这些参数的配置,通过不断的测试和优化,找到最适合的参数组合,以提升 ElasticSearch 系统的整体性能和稳定性,满足业务对搜索和分析功能的要求。