【八股消消乐】Elasticsearch优化—检索Labubu

发布于:2025-06-22 ⋅ 阅读:(11) ⋅ 点赞:(0)

在这里插入图片描述

😊你好,我是小航,一个正在变秃、变强的文艺倾年。
🔔本专栏《八股消消乐》旨在记录个人所背的八股文,包括Java/Go开发、Vue开发、系统架构、大模型开发、具身智能、机器学习、深度学习、力扣算法等相关知识点,期待与你一同探索、学习、进步,一起卷起来叭!

题目

💬技术栈:Elasticsearch

🔍简历内容:熟悉Elasticsearch节点角色、索引与分片基本原理。

根据业务定制Elasticsearch插件,实现基于内存使用率和CPU 使用率限流;针对xx业务实时性不高,引入消息队列Kafka,通过监听binlog并将生成消息丢到Kafka中,实现削峰和限流;针对高并发业务设计策略保护协调节点;设计简易双集群方案来替换CCR方案,成本节约了近80%。

🚩面试问:主分片是由主节点选出来的,那么主节点自己又是怎么选出来的呢?


在这里插入图片描述

💡建议暂停思考10s,你有答案了嘛?如果你有不同题解,欢迎评论区留言、打卡。


答案

对于中间件,常见的两个问题:

  1. 中间件是如何做到高可用/高性能的?
  2. 你在实践中怎么做到高可用/高性能?

Elasticsearch 节点角色

Elasticsearch 的节点可以分成很多种角色,并且一个节点可以扮演多种角色。常见的有:

  • 候选主节点(Master-eligible Node):可以被选举为主节点的节点。主节点主要负责集群本身的管理,比如说创建索引。类似的还有仅投票节点(Voting-only Node),这类节点只参与主从选举,但是自身并不会被选举为主节点。
  • 协调节点(Coordinating Node):协调节点负责协调请求的处理过程。一个查询请求会被发送到协调节点上,协调节点确定数据节点,然后让数据节点执行查询,最后协调节点合并数据节点返回的结果集。大多数节点都会兼任这个角色。
  • 数据节点(Data Node):存储数据的节点。当协调节点发来查询请求的时候,也会执行查询并且把结果返回给协调节点。类似的还有热数据节点(Hot Data Node)、暖数据节点(Warm Data Node)、冷数据节点(Cold Data Node),你从名字就可以看出来,它们只是用于存储不同热度的数据。

在这里插入图片描述

写入数据

写入数据的整体流程如下:

在这里插入图片描述

  1. 文档首先被写入到 Buffer 里面,这个是 Elasticsearch 自己的 Buffer。
  2. 定时刷新到 Page Cache 里面。这个过程叫做 refresh,默认是 1 秒钟执行一次
  3. 刷新到磁盘中,这时候还会同步记录一个 Commit Point

数据迁移存在的问题:

  • 在写入到 Page Cache 之后会产生很多段(Segment),一个段里面包含了多个文档。文档只有写到了这里之后才可以被搜索到。
  • 不断写入会不断产生段,而每一个段都要消耗 CPU、内存和文件句柄,所以需要考虑合并。

整个过程:

  1. 已有的段不动
  2. 创建一个新的段,把已有段的数据写过去,标记为删除的文档就不会写到段里面。
  3. 告知查询使用新的段
  4. 等使用老的段的查询都结束了,直接删掉老的段。

在这里插入图片描述

查询怎么知道应该使用合并段了呢?

这都依赖于一个统一的机制,就是 Commit Point。你可以理解成,它里面记录了哪些段是可用的。所以当合并段之后,产生一个新的 Commit Point,里面有合并后的段,但是没有被合并的段,就相当于告知了查询使用新的段

Translog

Elasticsearch 在写入的时候,还要写入一个东西,也就是 Translog。如果宕机了,Elasticsearch 可以用 Translog 来恢复数据

对比一下 MySQL 的写入过程:

  • MySQL 写入的时候,其实只是修改了内存里的值,然后记录了日志,也就是 binlog、redo log 和 undo log
  • Elasticsearch写入的时候,也是写到了 Buffer 里,然后记录了 Translog

不同的是,Translog 是固定间隔刷新到磁盘上的,默认情况下是 5 秒

在这里插入图片描述

Elasticsearch 索引与分片

一个 Elasticsearch 的索引并不仅仅指倒排索引,还包括了对应的文档。这个和关系型数据库下的语义是不同的。Elasticsearch 的一个索引有多个分片,每个分片又有主从结构。

  • 一个索引就是一个逻辑表
  • 分片就是分库分表
  • 每个分片都有主从结构,在分库分表里面,一般也是用主从集群来存储数据。

在这里插入图片描述

简历准备

问题收集:

  • 你们公司有没有使用 Elasitcsearch?用来解决什么问题?
  • 你用的 Elasticsearch 的性能怎么样?读写流量多大?存储的数据量又有多大?
  • 你创建的索引有多大?多少个分片?你是怎么确定分片数量的?
  • 你们公司有没有使用一些措施来保证 Elasticsearch 的可用性?有没有用过 Elasticsearch 的网关?
  • 你们公司的 Elasticsearch 有没有出过问题?出了什么问题?最终又是怎么解决的?

Elasitcsearch 高可用的核心:

  • 分片,并且每个分片都有主从之分。万一主分片崩溃了,还可以使用从分片,从而保证了最基本的可用性。
  • Translog,类似于 MySQL 里的 redo log。后面 Elasticsearch 崩溃之后,可以利用 Translog 来恢复数据。Elasticsearch 在写入数据的过程中,为了保证高性能,都是写到自己的 Buffer 里面,后面再刷新到磁盘上。所以为了降低数据丢失的风险,Elasticsearch 还额外写了一个 Translog。

在 Elasticsearch 的基础上,还可以做一些额外的优化,来保证 Elasticsearch 的高可用。

限流保护节点

通过 Elasticsearch 的插件机制来实现自定义的限流策略,例如设计一个限流插件,根据 Elasticsearch 当前的内存使用率和 CPU 使用率来判断是否需要执行限流。不管是内存使用率还是 CPU 使用率,只要超过阈值一段时间,就触发限流。

也可以考虑其他两种策略,一种是在 Elasticsearch 之前加一个网关,查询经过网关的时候会被限流、熔断或者降级。当然,引代理也可以

在这里插入图片描述

这里客户端也可以进行限流,各个业务方需要限制住自己的查询频率,防止把整个 Elasticsearch 打崩,这种方式是最好落地的。

利用消息队列削峰

场景:数据实时性要求不高。

方案:在业务方和 Elasticsearch 中间加入一个消息队列。削峰和限流

优化前:双写,一方面写数据库,一方面写 Elasticsearch。那么在业务高峰期,Elasticsearch 就会有性能瓶颈。

优化后:引入了消息队列。业务方只是写入数据库就返回。然后我们监听 binlog,并且生成消息丢到 Kafka 上。在这种情况下,Elasticsearch 空闲的话,消费速率就高;如果 Elasticsearch 性能比较差,那么消费就比较慢。这样就起到了削峰和限流的效果。

在这里插入图片描述
在这个架构的基础上,还可以考虑引入降级,也就是在 Elasticsearch 真的有性能问题的时候,关闭一部分消费者。

我有两类消费者写入数据到 Elasticsearch。一类是核心数据消费者,一类是非核心数据消费者。如果我在监控到 Elasticsearch 性能已经比较差了,比如说写入的时候会遇到超时问题,那么我就把非核心数据消费者停下来。等 Elasticsearch 恢复过来再启动。

在这里插入图片描述
对于大促或者秒杀这种活动中,你可以把整个数据同步都停掉,让 Elasticsearch 只支持查询操作。如果你所在的业务是电商类的,那么你可以考虑使用这个策略。

保护协调节点

问题:突发大请求打崩协调节点。

场景:你有一个查询命中了十个分片,并且每个分片都返回了几万条数据,那么协调节点本身的资源使用量一下就会上去,甚至出现 CPU 100% 或者 OOM 等问题。

解决方案:如果公司内部资源比较多,那么可以考虑 部署纯粹的协调节点。比如说专门部署一批节点,只扮演协调节点的角色。

在这里插入图片描述

如果客户端能够判定自己是大请求,就将请求发送到纯粹的协调节点上,否则发送到其他兼任的协调节点上。

好处:大请求即便把协调节点打崩了,也只会影响到其他大请求。但是占据绝大多数的普通请求,并不会受到影响。

在这里插入图片描述

对 Elasticsearch 进行二次开发,可以修改协调节点的逻辑,让协调节点在资源快不足的时候,直接拒绝这种大请求。

双集群

钞能力方案:直接使用付费的 CCR 跨集群复制。

简单方案:假设有A、B两个集群。

  • 使用消息队列来保持双写。写入的时候并不是直接写入到 Elasticsearch,而是写入到消息队列,而后启动两个消费者,分别消费消息,然后写到两个集群 AB 里面。
  • 在查询的时候,优先使用 A 集群,当确认 A 集群出了问题的时候,切换到 B 集群。

在这里插入图片描述
如何实现自动切换:对 Elasticsearch 的客户端进行了二次封装。在封装之后,正常情况下,会访问集群 A。同时客户端监控集群 A 的响应时间。如果响应时间超出预期,又或者返回了比较多超时响应,客户端就会自动切换到集群 B 上。

在这里插入图片描述


往期精彩专栏内容,欢迎订阅:

🔗【八股消消乐】20250619:构建微服务架构体系—保证服务高可用
🔗【八股消消乐】20250615:构建微服务架构体系—链路超时控制
🔗【八股消消乐】20250614:构建微服务架构体系—实现制作库与线上库分离
🔗【八股消消乐】20250612:构建微服务架构体系—限流算法优化
🔗【八股消消乐】20250611:构建微服务架构体系—降级策略全总结
🔗【八股消消乐】20250610:构建微服务架构体系—熔断恢复抖动优化
🔗【八股消消乐】20250609:构建微服务架构体系—负载均衡算法如何优化
🔗【八股消消乐】20250608:构建微服务架构体系—服务注册与发现
🔗【八股消消乐】20250607:MySQL存储引擎InnoDB知识点汇总
🔗【八股消消乐】20250606:MySQL参数优化大汇总
🔗【八股消消乐】20250605:端午节产生的消费数据,如何分表分库?
🔗【八股消消乐】20250604:如何解决SQL线上死锁事故
🔗【八股消消乐】20250603:索引失效与优化方法总结
🔗【八股消消乐】20250512:慢SQL优化手段总结
🔗【八股消消乐】20250511:项目中如何排查内存持续上升问题
🔗【八股消消乐】20250510:项目中如何优化JVM内存分配?
🔗【八股消消乐】20250509:你在项目中如何优化垃圾回收机制?
🔗【八股消消乐】20250508:Java编译优化技术在项目中的应用
🔗【八股消消乐】20250507:你了解JVM内存模型吗?
🔗【八股消消乐】20250506:你是如何设置线程池大小?
🔗【八股消消乐】20250430:十分钟带背Duubo中大厂经典面试题
🔗【八股消消乐】20250429:你是如何在项目场景中选取最优并发容器?
🔗【八股消消乐】20250428:你是项目中如何优化多线程上下文切换?
🔗【八股消消乐】20250427:发送请求有遇到服务不可用吗?如何解决?

📌 [ 笔者 ]   文艺倾年
📃 [ 更新 ]   2025.6.20
❌ [ 勘误 ]   /* 暂无 */
📜 [ 声明 ]   由于作者水平有限,本文有错误和不准确之处在所难免,
              本人也很想知道这些错误,恳望读者批评指正!

在这里插入图片描述