ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Elasticsearch大数据检索实战:从原理、集群搭建到性能优化全解析

Elasticsearch大数据检索实战:从原理、集群搭建到性能优化全解析 搞大数据的人迟早会碰上一个叫 Elasticsearch 的东西。日志检索、订单搜索、用户标签查询凡是数据量一大还要求秒出结果的地方几乎都有它的影子。我最早接触 Elasticsearch是为了处理每天上亿条的访问日志当时用 MySQL 查一个接口要好几秒切成 ES 之后基本百毫秒内返回这个差距直接让我把它纳入了自己的大数据技术栈。今天这篇内容就是把我学习、搭建、调优 Elasticsearch、提升数据检索效率的完整过程摊开来讲适合刚入门大数据、或者已经在用 Hive/Spark 但觉得查询不够快的朋友。它和关系型数据库、Hive 这类离线数仓并不是替代关系而是互补关系。数据清洗、批量计算还是靠 Hive、Spark 完成但对外提供快速查询和检索的服务层Elasticsearch 是大数据架构里绕不开的一环。下面从原理、部署、集成、调优到真实案例一条线走下来。1. 为什么大数据场景要学 Elasticsearch1.1 大数据检索的痛点慢查询和模糊匹配做数据的人都有这种感觉数据量一旦大了查数就变得很别扭。MySQL 单表几百万行还顶得住到了千万、上亿级别一个带%关键词%的模糊查询能跑到几十秒业务人员在前台等结果接口直接超时。Hive 更不用说跑一次全量扫描要先提交任务、等资源是典型的分钟级延时。定时跑数没问题但要支撑在线业务它完全不合格。我最初遇到的场景是日志检索。线上服务每秒钟产生几千条请求日志需要按照用户 ID、接口路径、时间范围组合查询。用 MySQL 做了索引但一旦查询条件里加一个“接口路径的模糊匹配”索引就几乎失效整个表扫描一遍响应时间根本没法看。换成 Elasticsearch 后同样的数据量、同样的查询逻辑响应时间从秒级降到几十到一百毫秒而且集群只用了三个节点。这个反差让我意识到大数据领域的技术栈必须补上“检索”这一块。与其在关系型数据库里硬堆索引不如把全文检索、多维过滤这类工作交给专门干这件事的引擎。Elasticsearch 就是这类引擎里最主流的一个。还有一个容易被忽略的点Elasticsearch 的聚合能力很强。数仓里常用 Hive 做离线统计但很多临时分析场景不需要精确到每一条明细只要对最近一小时、最近一天的数据做维度聚合如果数据已经同步到 ES可以直接用它的聚合 API 在秒级出结果。这比每次拉回 Hive 跑 MapReduce 高效太多。1.2 Elasticsearch 在大数据生态里的位置常规的大数据数仓分 ODS、DWD、DWS、ADS 几层ETL 一般交给 Hive、Spark、Flink。处理完之后结果要用于展示、交互查询除了 Redis 和 MySQLES 是另一个重要出口。它在大数据链路里的典型角色有三个。第一检索服务层。把明细数据同步进去对外提供高性能的搜索和筛选接口。比如订单系统按条件查订单用户画像系统按标签组合筛选用户。第二日志分析平台。这就是大家熟悉的 ELK 技术栈Filebeat/Logstash 采集日志Kafka 做缓冲Logstash 清洗写入 ESKibana 做可视化。研发排查问题的时候输入一个关键词选一个时间范围秒级看到日志全文和上下文。第三实时分析底座。很多“大屏”项目里数据更新频繁查询条件又复杂Hive 出结果太慢MySQL 又顶不住高并发查询。ES 能同时承担写入和聚合大多数情况都不需要再套一层缓存。至于网上经常讨论的“大数据集群部署策略”其实和 ES 也强相关。ES 的分布式特性天生适合横向扩展节点可以按职责拆成 master、data、ingest 等角色可以跨机房部署也能在 Kubernetes 里用 Operator 管理。学习 ES 的过程本身就是在理解分布式存储中的分片、副本、脑裂、水平扩展这些问题。2. 先搞清楚 ES 的工作原理再动手2.1 倒排索引让搜索从“遍历”变成“查表”很多同学第一次看到 Elasticsearch 的文档被一堆名词劝退。但其实它最核心的东西就一个倒排索引。举一个生活化的例子。一本技术书正文是按章节顺序写的你想找“倒排索引”出现在哪几页如果从头翻到尾这就是“正排”效率很低。但书的最后通常有“索引”按关键词排序并标注了页码你直接查“倒排索引”就能得到页码列表。你查的是词得到的是文档 ID 列表这就是倒排索引的本质。Elasticsearch 会把文档分词比如“大数据检索效率”会被拆成“大数据”“检索”“效率”这样的词项然后维护一张表每个词项对应一组文档 ID。查询时先在词项字典里快速定位再合并文档 ID 列表比逐条扫描快得多。过程中要注意分词效果直接影响检索质量。中文不像英文有天然空格必须选对中文分词器比如 IK 分词器。否则默认的标准分词器会把“大数据”拆成“大”“数”“据”查询结果一点都不准。我见过很多同学在网上搜索“Elasticsearch 查不到数据”绝大多数不是数据没写进去而是字段的 mapping 把类型定成了 text又没配中文分词器导致分词不是预期效果。对比关系型数据库的 B 树索引两者解决的是不同的问题。B 树适合等值、范围查询但遇到“包含某个词”这种场景它只能靠前缀匹配甚至全表扫描倒排索引则是为“词项出现位置”而生不管这个词出现在文档的哪个位置都能通过词项直接定位。这也是 ES 在模糊检索、全文检索上碾压传统数据库的根本原因。2.2 分片、副本与集群数据大了怎么办单机 ES 能承载的数据量有限想扩展就必须利用分片。分片是 ES 数据分布的最小粒度一个索引可以被拆成多个主分片分散到集群的不同节点上。查询的时候协调节点把请求发给各个分片最后合并结果。这个概念类似于你要把一百本书的内容按章节拆到十个书架上。分片越多单分片压力越小但分片太多也会让集群管理成本上升查询时要广播给更多分片翻倒变慢。官方建议一般是一个分片控制在 20 到 40 GB 左右具体要看业务。副本的作用有两个一是高可用某个节点挂了副本可以直接顶上二是提升读性能多个副本可以分担查询压力。但副本不是越多越好每多一个副本就等于多一份磁盘占用写入数据时要同步的网络开销也会变大。对于大数据场景我建议在索引创建前把分片数想清楚因为 ES 不支持在创建后修改主分片数。如果想调整只能用_reindex把一个索引的数据搬到另一个新索引数据量大时非常耗时。常见策略是看数据总量比如单个索引可能要放 500 GB 数据单个分片控制在 30 GB 左右那么 16 个分片比较合适另外再配 1 个副本。如果未来数据增长明显就一次给到 24 或 32 个分片宁可前期多点也不要频繁 reindex。2.3 写入与查询路径为什么有时快有时慢理解写入路径你才能明白为什么 ES 不是实时写入立刻可查而是“近实时”。客户端发来一条文档先落到分片的主分片上写一份到 translog 防止宕机丢数据同时写入内存缓冲区。默认每隔一秒内存缓冲区的数据会生成一个分段打开查询可见性这个动作叫refresh。这就是为什么刚写入的数据可能要等 1 秒左右才能查到。如果你确实需要写入后立刻可查可以通过refreshtrue强制刷新但整体写入性能会下降不建议在高吞吐场景这么用。另一个重要概念是flush。translog积累到一定程度或触发条件后会把已经 refresh 过的段文件真正落盘清空 translog。这个动作受磁盘 IO 影响很大所以写入慢的时候不能只看 CPU要重点看磁盘。查询路径相对清晰。用户请求到达协调节点后先根据文档_id或查询条件路由到数据所在分片各分片并行执行查询返回命中文档的排序信息和部分字段协调节点再根据结果去各分片拉取完整数据。所以查询慢不一定是 ES 不行可能是聚合字段没优化、分页太深、返回字段太大或者直接就是分片在磁盘上发生了严重的段合并。理解这些原理之后再去看调优参数就不会是背命令而是知道每个参数在链路里影响哪个环节。3. 环境搭建从单机到集群的实操记录3.1 单机版快速起步不管是学习还是测试先跑一个单机 ES 是最快的方式。以 Elasticsearch 7.17 系列为例。确认机器安装了 JDKES 自带捆绑的 JDK但环境变量如果有其他 JDK可能会版本冲突启动报错。建议直接用解压包安装不额外配JAVA_HOME让它用自己的 JDK。Windows 下直接双击或执行bin\elasticsearch.bat。Linux 下先解压tar -xzf elasticsearch-7.17.20-linux-x86_64.tar.gz cd elasticsearch-7.17.20/bin ./elasticsearch默认监听 9200 端口如果只是本机测试直接访问curl http://localhost:9200能返回一个带cluster_name和版本的 JSON就说明启动成功。Linux 启动经常会碰到一个报错max virtual memory areas vm.max_map_count [65530] is too low。解决方法sudo sysctl -w vm.max_map_count262144想永久生效写入/etc/sysctl.conf。如果是 Elasticsearch 8.x默认开启了安全认证。第一次启动会打印初始密码需要保存好。测试环境如果不打算研究认证可以在elasticsearch.yml里改成xpack.security.enabled: false但生产环境千万不要关安全功能否则集群端口直接暴露在网络上风险很大。单机跑通后立刻做的事是创建一个测试索引确认写入和查询都正常curl -X PUT localhost:9200/test_index curl -X POST localhost:9200/test_index/_doc/1 -H Content-Type: application/json -d {title:大数据检索效率} curl localhost:9200/test_index/_search?qtitle:大数据3.2 多节点集群部署与关键参数单机学习可以但要真正体现 ES 的能力还是要搭多节点集群。最简单的三节点集群假设三台机器 IP 是192.168.1.10、192.168.1.11、192.168.1.12。每台机器的elasticsearch.yml配置类似cluster.name: bigdata-es node.name: node-1 node.roles: [master, data, ingest] network.host: 0.0.0.0 http.port: 9200 transport.port: 9300 discovery.seed_hosts: [192.168.1.10, 192.168.1.11, 192.168.1.12] cluster.initial_master_nodes: [node-1, node-2, node-3] discovery.min_master_nodes: 2 gateway.recover_after_nodes: 3第二、三台把node.name改成node-2、node-3即可。network.host设置为0.0.0.0后ES 会认为自己是生产模式如果没配置其他节点可能启动失败。这也是为什么必须配置好discovery.seed_hosts和cluster.initial_master_nodes。discovery.min_master_nodes: 2是防止脑裂的关键参数。它表示选举 master 至少要几个候选节点投票对于三节点集群设置为 2 可以避免网络分区时出现两个 master。启动三台后查看集群状态curl 192.168.1.10:9200/_cluster/health?pretty返回的status如果是green说明主分片和副本都分配正常。yellow说明副本缺失通常是数据节点不足或者磁盘泄露。节点角色上如果集群规模超过十个节点建议把 master、data、ingest 角色分离避免数据节点压力过大影响主节点稳定性。不过三到五个节点的中小集群混布角色问题不大重点是控制 JVM 堆内存统一设置为物理内存的一半且不超过 30 GB。3.3 在 Kubernetes 上用 Kubesphere 部署很多公司现在的集群环境已经容器化Kubesphere 这类平台可以把 ES 部署成 Kubernetes 工作负载。Kubesphere 中创建企业空间和项目后有几种方式部署 ES。一是通过 Helm 模板安装 Elastic 官方提供的elasticsearchchart二是在项目中直接导 YAML三是通过应用商店选择包。不管用哪种方式至少关注三件事存储ES 数据必须存到 PVCPod 重启后数据才不丢。内存限制需要在 YAML 或 helm values 里配置 JVM heap 大小不能只给容器内存不设置 ES 自己的-Xms和-Xmx。网络ES 节点之间通过transport.port通信Pod 间要能互通一般用 headless Service 或独立 StatefulSet。用 Helm 的示例参数文件replicas: 3 resources: requests: memory: 4Gi cpu: 1 limits: memory: 8Gi cpu: 2 volumeClaimTemplate: accessModes: [ReadWriteOnce] storageClassName: nfs-client resources: requests: storage: 200Gi esJavaOpts: -Xmx3g -Xms3g这里提醒一下容器规格给 8 Gi 内存esJavaOpts却不应该直接给到 6 Gi因为 Elasticsearch 还有大量堆外内存用于文件缓存给太小容易 OOM给太大又挤压系统缓存。一般建议容器 memory 限制和 JVM heap 之间留一半以上空间。比如容器 8 Gi堆内存 4 Gi 更稳。Kubernetes 部署的好处是扩缩容方便通过修改replicas就能增加节点但分片数设计仍然要在创建索引前敲定扩容节点解决的是吞吐和容量不是分片数不够的问题。4. 与大数据生态集成Hive、Spark、Spring Boot 怎么连4.1 把 Hive / 数仓数据同步到 ES大数据业务里最常用的是每天从数仓把结果导出到 ES。ES-Hadoop 是官方提供的集成库支持 Hive、Spark、MapReduce 直接读写 ES。以 Hive 表同步为例。先把elasticsearch-hadoop-*.jar添加到 Hive 的 classpathADD JAR /opt/bigdata/libs/elasticsearch-hadoop-7.17.20.jar;然后在 Hive 里创建一张指向 ES 索引的外部表CREATE EXTERNAL TABLE dim_order_es ( order_id STRING, city_id STRING, driver_id STRING, total_amount DOUBLE, create_time STRING ) STORED BY org.elasticsearch.hadoop.hive.EsStorageHandler TBLPROPERTIES ( es.resource dim_order/doc, es.nodes http://192.168.1.10:9200,http://192.168.1.11:9200, es.index.auto.create true );之后从临时表插入INSERT OVERWRITE TABLE dim_order_es SELECT order_id, city_id, driver_id, total_amount, create_time FROM dwd_order_info WHERE dt 2025-06-01;用 Spark 也一样引入 ES-Hadoop 包后可以用org.elasticsearch.spark.sql包直接创建 DataFrame 读写 ES。比如墨import org.elasticsearch.spark.sql._ val df spark.read.format(org.elasticsearch.spark.sql) .option(es.nodes, 192.168.1.10:9200) .option(es.resource, dim_order/doc) .load()同步逻辑里有一个容易踩的坑ES 的doc类型在 7.x 以后已经弱化但很多旧版本 ES-Hadoop 代码仍然指定/doc新版本直接写索引名就行写多了反而会提示类型异常。适配最新版时要去掉类型后缀。4.2 Spring Boot Elasticsearch 项目落地在线服务的同学更关心后端项目怎么接。以 Spring Boot 为例常见做法有两种一种是spring-boot-starter-data-elasticsearch另一种是直接用官方 RestHighLevelClient 或新的 ElasticsearchClient。Spring Data 的方式比较省事但一个老问题是版本绑定。Spring Boot 2.7 默认适配 Elasticsearch 7.17 附近的客户端如果你的 ES 是 8.x最好升级到 Spring Boot 3.x并确认依赖版本。简单示例先引入依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-elasticsearch/artifactId /dependency然后在application.yml里配置地址spring: elasticsearch: uris: http://192.168.1.10:9200,http://192.168.1.11:9200 connection-timeout: 3s socket-timeout: 10s写一个查询方法用ElasticsearchRestTemplateRepository public class OrderSearchRepository { Autowired private ElasticsearchRestTemplate template; public ListOrderDoc searchByCity(String cityId, int page, int size) { NativeSearchQuery query new NativeSearchQueryBuilder() .withFilter(QueryBuilders.termQuery(city_id, cityId)) .withPageable(PageRequest.of(page, size)) .build(); SearchHitsOrderDoc hits template.search(query, OrderDoc.class); return hits.stream().map(SearchHit::getContent).toList(); } }实际项目中建议少用match做精确筛选而是把精确值字段设置为keyword查询时用term或filter。这样既能走倒排索引又不会因为分词导致精确匹配出问题。4.3 JDBC 连接 ES 的版本坑不少人在用 DBeaver 或 Navicat 连接 ES 时会看到类似报错this version of the JDBC driver is only compatible with Elasticsearch version ...这个报错的原因基本只有一个JDBC 驱动版本和 ES 版本不匹配。ES 的 JDBC 驱动不是通用驱动它对版本很敏感。7.x 的驱动连 7.x 服务没问题去连 6.x 服务就可能报错8.x 服务也需要对应的驱动。我的经验是直接去 Elasticsearch 对应版本的发行包里找jdbc插件不要随便从网上下一个旧 jar。7.x 以后ES 的 SQL 功能已经内置在节点里客户端驱动通常是dependency groupIdorg.elasticsearch.plugin/groupId artifactIdx-pack-sql-jdbc/artifactId version7.17.20/version /dependency使用 DBeaver 时在驱动设置里把版本改成和集群一致然后 JDBC URL 写成类似jdbc:es://http://192.168.1.10:9200如果集群开了安全认证jdbc:es://http://192.168.1.10:9200?sslfalse再填账号密码。遇到driver version报错先别怀疑 ES 集群有毛病先查驱动版本是不是和curl localhost:9200返回的number一致。这个坑我遇到过两次每次都是因为本地驱动被 IDE 缓存了旧版本。5. 检索效率优化的核心指标5.1 慢查询日志与 profile APIES 的性能优化不能靠猜。第一步应该是开启慢查询日志。通过动态配置可以打开慢日志curl -X PUT localhost:9200/dim_order/_settings -H Content-Type: application/json -d { index.search.slowlog.threshold.query.warn: 5s, index.search.slowlog.threshold.query.info: 1s, index.search.slowlog.threshold.query.debug: 500ms, index.search.slowlog.threshold.fetch.info: 500ms }这样超过 1 秒的查询就会在日志里出现日志会记录查询的query_source、耗时、命中文档数等。再看具体的查询为什么慢可以用profile参数GET dim_order/_search?profiletrue { query: { term: { city_id: 110000 } } }返回结果里会显示每个分片在每个查询阶段花了多少毫秒。通常你会发现耗时大头不是query而是fetch或aggs。fetch大往往是你返回字段太多aggs大通常是聚合字段类型不对用了text字段而没有启用fielddata。做优化时我习惯先看三层是否命中缓存、是否扫了太多文档、是否对 text 字段做聚合。百分之八十的慢查询都能在这三个问题上找到答案。5.2 写入慢磁盘问题还是索引设计问题之前热搜词里有人问“Elasticsearch 怎么判断写入慢是磁盘有问题还是索引设计有问题”这个问题非常实际。先做一些基础排查。ES 数据节点有个核心状态接口可以看每个节点的索引耗时、刷新耗时、合并耗时curl localhost:9200/_nodes/stats?filter_pathnodes.*.indices.indexing,nodes.*.indices.refresh,nodes.*.indices.merges,nodes.*.fs这时候如果indexing.index_total很大且index_time_in_millis增长很快说明 CPU 都在处理索引写入看磁盘是否真正繁忙。磁盘层面用iostat看iostat -x 1关注几个指标指标含义危险值%util磁盘利用率长期大于 90awaitIO 请求平均等待时间大于 30 mssvctmIO 服务时间远小于 await 说明队列积压aqu-sz平均队列深度大于 2-4如果%util接近 100% 且await很高基本可以确定磁盘是瓶颈。此时靠调 ES 参数很难根治优先换 SSD、加节点分担分片或者减少副本数降低写入放大。如果磁盘指标正常再往索引设计方向排查refresh_interval是不是设得太小默认 1 秒意味着每秒都生成一个段后台段合并压力大。对于批量导数可以临时把它改成 30 秒甚至 -1禁用刷新导完再恢复。分片数是不是太多一个节点上几十个小分片各写各的每个分片都要维护自己的 translog 和段会造成 IO 争抢。批量请求体是不是太大单次 bulk 建议 5MB 到 15MB几百 MB 一个请求会让协调节点内存暴涨。是否在写入时做了复杂的 pipeline ingesttranslog.durability默认是request每次写入都 fsync非常慢。如果数据允许掉几秒可以设为async写入性能会有明显提升。磁盘和索引设计之间不是非此即彼的关系。很多情况是磁盘本来就不算快索引又乱两者同时背锅。我的判断顺序是先看iostat再关掉一个或几个索引设计因素比如临时调大refresh_interval如果吞吐没变化基本上问题在磁盘。5.3 常用性能指标与监控日常维护 ES下面几个指标我建议至少盯住集群健康状态green、yellow、red。节点堆内存使用_nodes/stats里jvm.heap.used_percent持续超过 85% 就要关注 GC。查询耗时分位数通过慢日志和 Kibana 监控看 p99。写入拒绝数如果大量es_rejected_execution_exception说明写入线程池已满通常需要扩容或调大thread_pool.write.size。段合并耗时indices.merges.total_time_in_millis增长过快说明段合并拖慢了整体索引速度。关注 GC 时不要只看堆大小也要看老年代 GC 频率。堆太大反而会导致 Full GC 时间过长这也是为什么官方建议单节点堆内存不超过 30 GB 的原因之一。6. 完整案例网约车订单数据检索6.1 数据形态与索引建模用一个网约车订单项目举例。原始订单明细存在 Hive 数仓里通过每天跑批写入 ES前端需要按城市、订单状态、时间范围、司机 ID 做组合筛选并统计订单量、平均金额。先设计索引 mapping。创建索引时不指定 mappingES 会自动推断字段类型但这往往不是最优的。例如订单状态这个字段只存精确值如果被推断成text类型查询时就可能因为分词导致状态过滤不准确。建议在第一次写数据前就显式创建 mappingPUT /order_info { settings: { number_of_shards: 3, number_of_replicas: 1, refresh_interval: 5s }, mappings: { properties: { order_id: { type: keyword }, city_id: { type: keyword }, driver_id: { type: keyword }, status: { type: keyword }, total_amount: { type: double }, create_time: { type: date, format: yyyy-MM-dd HH:mm:ss||epoch_millis }, remark: { type: text, analyzer: ik_max_word } } } }这里city_id、driver_id、status都用 keyword因为它们是精确匹配字段remark是备注信息需要全文检索才用 text 配合中文分词器。如果前期字段设计不合理后期要改 mapping 只能新建索引_reindex。所以建模阶段宁可多花十分钟也不要图省事直接开自动映射。6.2 索引生命周期管理订单数据每天增量写入如果全部放在一个索引里数据量再大就会失控。常见策略是按天建索引比如order_info_20250601、order_info_20250602。写进数据流的做法一般用索引别名curl -X PUT localhost:9200/order_info_20250601/_alias/order_info_write写入端只写order_info_write查询端可以查询order_info*的模式GET /order_info*/_search同时加 ILM 策略控制生命周期。先建策略PUT /_ilm/policy/order_policy { policy: { phases: { hot: { actions: { rollover: { max_size: 50GB, max_age: 1d } } }, warm: { actions: { forcemerge: 1 } }, delete: { min_age: 90d, actions: { delete: {} } } } } }然后把策略关联到索引模板。这样数据量达到 50 GB 或超过一天时自动滚动生成新索引90 天前的索引自动删除避免人工清理。这类设计对检索效率的影响很大。索引多了查询时如果没有按时间过滤会导致 ES 跨所有分片查询又慢又浪费资源。所以在查询语句里尽量带上时间范围让 ES 通过索引别名和filter提前排除老索引数据。6.3 查询调优过程业务需求查询某个城市最近一小时的订单并按状态统计数量。先写查询 DSLPOST /order_info*/_search { size: 0, query: { bool: { filter: [ { term: { city_id: 110000 } }, { term: { status: 已完成 } }, { range: { create_time: { gte: now-1h } } } ] } }, aggs: { status_cnt: { terms: { field: status, size: 10 } } } }注意这里用的是filter不是must。filter不参与相关性打分ES 会缓存过滤结果的 bit set速度更快。如果需求不关心“匹配度排名”一律优先用filter。优化过程中我发现了一个典型问题第一次查询除状态聚合外还加了total_amount的 percentiles 聚合响应时间从几十毫秒涨到几百毫秒。原因是聚合默认会对每一条命中文档执行脚本采样数据量大时很慢。后续先去掉不关键的高成本聚合并通过提前在地图页做一次“城市时间”维度的慢速缓存线上查询才稳定下来。如果要做深度分页不要用from size比如用户翻到第 10000 条后面每次都要重新扫描和排序。改用search_afterPOST /order_info*/_search { size: 100, sort: [ { create_time: desc }, { order_id: asc } ], search_after: [2025-06-01 12:00:00, xxxx] }这样性能稳定不受页码变深影响。业务想快速跳页常见的做法是把from size限制在一个很小的范围内再往上加一层预筛选。7. 入门阶段最容易踩的坑7.1 常见问题速查问题原因解决方向查不到数据字段类型是 text被默认分词拆了精确值改 keyword全文检索用正确分词器写入很慢刷新间隔太小、磁盘 IO 饱和、bulk 过大调大 refresh_interval换 SSD减小 bulk聚合结果不准确对 text 字段做了默认聚合改成 keyword 字段或开启 fielddata慎用集群变 yellow/red磁盘不足、节点下线、副本分配失败查看_cat/allocation释放磁盘或扩容查询超时分页太深、返回字段太多、没走 filter 缓存用 search_after限制字段把查询放 filterJDBC 连接失败驱动版本和集群版本不一致换对应版本的 x-pack-sql-jdbc节点 CPU 高段合并频繁、GC 频繁调大 refresh_interval、检查堆内存、分片数量还有一个容易忽视的坑很多人会用GET _all/_search这种把所有索引都查一遍的语句索引多了以后性能非常差。业务侧一定要限定索引名或别。7.2 几点入门建议从零开始学 Elasticsearch我不建议上来就读源码或者抄一堆调优参数。正确路线是先把单机跑起来建索引写几条数据理解倒排索引和分词然后搭一个三节点集群模拟节点挂掉看副本怎么恢复接着把 Hive 表同步到 ES写一个 Spring Boot 接口最后才是优化。调优参数不用背但要把_cat、_nodes/stats、_cluster/health这些接口当作手电筒遇到异常先照一照再动手。最后再分享一个我自己的习惯每次搭建集群我都会把所有节点的jvm.options、elasticsearch.yml和索引 mapping 全部用 git 管理起来。版本变更、参数调整都能回溯。这个习惯让我少加了很多班也避开了很多“明明改了配置却想不起来改了什么”的尴尬。
返回列表