惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
F
Fortinet All Blogs
云风的 BLOG
云风的 BLOG
MyScale Blog
MyScale Blog
D
DataBreaches.Net
Stack Overflow Blog
Stack Overflow Blog
A
About on SuperTechFans
Google DeepMind News
Google DeepMind News
Microsoft Security Blog
Microsoft Security Blog
腾讯CDC
The GitHub Blog
The GitHub Blog
Jina AI
Jina AI
B
Blog RSS Feed
I
InfoQ
N
Netflix TechBlog - Medium
T
The Blog of Author Tim Ferriss
Microsoft Azure Blog
Microsoft Azure Blog
Recent Announcements
Recent Announcements
GbyAI
GbyAI
H
Help Net Security
L
LangChain Blog
M
MIT News - Artificial intelligence
Y
Y Combinator Blog
aimingoo的专栏
aimingoo的专栏

浮华生

舆情监控系统综述 - 浮华生 2024 半年度总结 - 浮华生 2023 年终总结 - 浮华生 异地机器组网方案 - 浮华生 Kubernetes 部署 Elasticsearch 和 Kibana - 浮华生 2022 年终总结 - 浮华生 RabbitMQ connection channel 的关系 - 浮华生 Kafka Java 客户端 Producer 原理分析 - 浮华生 RabbitMQ 和 Kafka 应用原理简单对比 - 浮华生 阿里云 OpenSearch 介绍 - 浮华生 Golang Array 和 Slice 区别 - 浮华生 Mac OS 下打造 golang nvim 编程环境之基础配置 - 浮华生 电商搜索技术总结 - 浮华生 电商搜索业务总结 - 浮华生 2021 年终总结 - 浮华生 Cypress 实践总结 - 浮华生 年终总结 - 浮华生 关于我 - 浮华生 使用 cucumber 进行行为驱动开发(BDD) - 浮华生 微服务应用集成 SpringCloud 步骤 - 浮华生 电商搜索数据同步方案 - 浮华生 通过一道数值转换题重温计算机补码 - 浮华生 macOS 系统推荐的一些软件 - 浮华生 DevOps 实施规划(持续更新) - 浮华生 rabbitmq 如何提高可靠性并保证消费端幂等 - 浮华生 AMQ Model总结 - 浮华生 结对编程 - 浮华生 RSocket 介绍 - 浮华生 面向对象的理解 - 浮华生 企业平台技术框架 - 浮华生
Elasticsearch 检索性能优化 - 浮华生
浮华生 · 2024-12-20 · via 浮华生

前言

ElasticSearch 是当前使用场景比较多的全文检索数据库,可以用到搜广推业务、日志监控、数据可视化等。既然是数据库就无法避免的会遇到查询性能问题,本篇文章主要介绍从索引设计、集群配置、查询三个方面进行优化。

索引优化

设置 index:false

适用场景:对没有检索和过滤需求的并且后续不会更新的字段,这个设置只是不建立索引,实际数据还是会进行存储,在查询时可以通过 _source 进行返回。

设置 shard 数

基础概念可以参考之前的文章

简单讲一下 shard 的开销,shard 分为主分片和副本分片两种,那如果 shard 数越多,需要的同步时间就会越久,检索时会发生数据短暂不一致情况,并且同步的成本及稳定性也会受影响;shard 越多需要分配的内存和 CPU 也就越多,如果并发量大的话会将 node 的线程池耗尽,从而降低吞吐量。

官方推荐,理论上一个 shard 可以存储 20 亿文档,或者 10G-50G 之间的数据,如果你的数据在这两个范围内,可以直接使用一个 shard 进行检索。

设置副本数

这个副本数是和主 shard 一一对应的,也就是现在有三个 primary shard,如果副本数设置为 1,那么会出现三个 replica shard,确保每个主分片都有对应的副本,如果副本数不够分配,集群状态就会变成黄色。在生产环境至少要配置 1 个分片,在本地开发可以设置为 0。

举例:如果数据预估是 1T,shard 分片大小为 50 G,那就需要 20 个 primary shard,如果副本数设置为 1,那么也会存在 20 个 replica shard,一共是 40 个 shard。

禁用 Dynamic Mapping

使用确定的映射,不要让 ES 自己推断,这个在日常设计中都会注意。

慎用复杂结构

官方指出,nested 结构查询会让搜索慢几倍,而 parent-child 会让搜索慢上百倍!

如果要存储简单的键值对,并且后期只会用到简单的查询聚合场景,可以将字段设置为flattened类型,它不会单独维护一个子文档

使用 copy_to

把经常要组合搜索的放到同一个字段中,比如要同时在文章标题、正文中查找,那可以做如下设置:

{
  "mappings": {
    "properties": {
      "full-text": { // 只需要用这个字段进行搜索
        "type": "text"
      },
      "title": {
        "type": "text",
        "copy_to": "name_and_plot"
      },
      "content": {
        "type": "text",
        "copy_to": "name_and_plot"
      }
    }
  }
}

数据预处理

比如日期,2024-12-22 10:00:00,我们可以拆成多个字段进行存储

{
  "mappings": {
    "properties": {
      "published": { 
        "type": "date"
      },
      "year": { 
        "type": "keyword"
      },
      "month": {
        "type": "keyword",
        
      },
      "day": {
        "type": "keyword",
      }
    }
  }
}

优先使用 Keyword

对于不需要范围查询的,比如身份证号、ISBN 这种,要使用 Keyword 类型存储,因为 keyword 查询要比数值类型的速度快。

段合并

此操作对经常变更的索引没有太大帮助,但是如果已经不会再变的数据,比如昨日索引的数据,使用段合并能提高查询效率。

集群配置

合理设置 node 的角色

ES 中的 node 分为

  • Master Node:负责管理集群的元数据和控制集群的状态,例如索引创建、分片分配等(保证集群高可用和稳定性,不存储数据)
  • Data Node:存储实际的数据和实际的查询请求(存储和计算)
  • Coordinating:协调节点,负责搜索和聚合的请求分发和结果合并,不存储数据,类似于微服务中的服务编排。
  • Ingest:数据预处理节点,如果数据处理操作在代码中完成,这个可以不设计。
  1. 在生产和测试环境要显式设置集群角色,不要混用,配置项:node.roles
  2. 对于 Master 角色,设置奇数个,避免脑裂问题

合理分配 node 的资源

Master 节点

master 只负责集群的管理,所以不需要太多的资源

# JVM 堆内存配置
-Xms4g
-Xmx4g

# 系统配置
CPU: 4-8 核
内存: 8GB
磁盘: 普通 SATA 即可,100GB

原因:

  • 主要处理集群状态管理,不需要太大内存
  • 集群元数据相对较小
  • 需要稳定的 CPU 处理能力
  • 磁盘 I/O 要求不高

Data 节点

数据节点要重点关照

# JVM 堆内存配置
-Xms31g
-Xmx31g  # 保持在32GB以下,避免指针压缩失效

# 系统配置
*CPU: 8-32 核
*内存: 64GB+
**磁盘: SSD,500GB+

原因:

  • 需要大内存做缓存
  • 需要留足够系统内存给 Lucene 文件系统缓存
  • 多核 CPU 有利于并行处理
  • SSD 提高随机 I/O 性能

指针压缩会降低存储成本,能够让 CPU 加载更多的对象引用,提高 CPU 缓存命中率。最新的 JDK 24 版本中对此做了优化 文章地址

堆内存的大小不要超过物理内存的 50%,剩下空间的主要给 Lucene 用来做缓存。也就是说 JVM 配置了 31 G,那么物理内存至少是 64 G。

Coordinating 节点

# JVM 堆内存配置
-Xms16g
-Xmx16g

# 系统配置
*CPU: 8-16 核
*内存: 32GB
磁盘: 普通 SATA,200GB

原因:

  • 需要足够内存做查询缓存
  • 需要较强 CPU 处理聚合计算
  • 磁盘要求不高

查询优化

显式设置返回字段

对应业务无关的数据可以在查询时使用 _source 进行设置

"_source": {
  "includes": ["field1", "field2"]
}

使用 filter 查询

对于复杂的查询条件并且不需要排序的场景,要使用 filter+bool 的方式

{
  "query": {
    "bool": {
      "filter": [
        {"term": {"userLevel": "PGC"}}
      ]
    }
  }
}

不要一次性返回大集合

如果需要数据导出可以使用 Scroll 或者 SearchAfter,每次条数可以根据实际的文档大小进行设置,要权衡吞吐量和服务稳定性。

高亮后置处理

在程序代码中进行筛选和飘红处理,简单讲就是将查询 keyword 分词,然后遍历返回内容,如果匹配到就飘红处理。

慎用 Script

脚本查询虽然使用灵活,但是因为需要动态计算,会降低整体的性能

聚合显式设置 collect_mode

在使用聚合统计时,有一个collect_mode 参数可以设置,它有两种值:

  • BFS:广度优先,第一步先将顶层 bucket 计算完,再计算里面的子集,在 bucket 数量比较小的时候使用,如统计男女数量、正负面等。
  • DFS:深度优先,计算出一个顶层 bucket后计算这个 bucket 的子集,在 bucket 数量很大的时候使用,如统计价格分布数量、互动量等。

默认情况下,ES 会自动推断,但是如果明确聚合 bucket 数量大小时,建议手动设置。

总结

ES 性能优化是一个非常复杂的事情,需要从物理字段、JVM、索引、查询等方面进行综合考虑,上面给出只是优化的一些手段和建议,在实战时还需要具体问题具体分析。在做方案设计时早期要考虑的详细一些,确定集群的规格参数,因为后期物理层面的成本会很大。

参考文章

https://www.elastic.co/guide/en/elasticsearch/reference/8.17/size-your-shards.html#each-shard-has-overhead

https://www.elastic.co/guide/en/elasticsearch/reference/8.17/tune-for-search-speed.html

https://www.elastic.co/guide/en/elasticsearch/reference/current/flattened.html