😊你好,我是小航,一个正在变秃、变强的文艺倾年。
🔔本专栏《八股消消乐》旨在记录个人所背的八股文,包括Java/Go开发、Vue开发、系统架构、大模型开发、具身智能、机器学习、深度学习、力扣算法
等相关知识点,期待与你一同探索、学习、进步,一起卷起来叭!
目录
- 题目
- 答案
- Elasticsearch 节点角色
- 写入数据
- Translog
- Elasticsearch 索引与分片
- 简历准备
- 限流保护节点
- 利用消息队列削峰
- 保护协调节点
- 双集群
题目
💬技术栈:Elasticsearch
🔍简历内容:熟悉Elasticsearch节点角色、索引与分片基本原理。
根据业务定制Elasticsearch插件,实现基于内存使用率和CPU 使用率限流;针对xx业务实时性不高,引入消息队列Kafka,通过监听binlog并将生成消息丢到Kafka中,实现削峰和限流;针对高并发业务设计策略保护协调节点;设计简易双集群方案来替换CCR方案,成本节约了近80%。
🚩面试问:主分片是由主节点选出来的,那么主节点自己又是怎么选出来的呢?
💡建议暂停思考10s,你有答案了嘛?如果你有不同题解,欢迎评论区留言、打卡。
答案
对于中间件,常见的两个问题:
- 中间件是如何做到高可用/高性能的?
- 你在实践中怎么做到高可用/高性能?
Elasticsearch 节点角色
Elasticsearch 的节点可以分成很多种角色,并且一个节点可以扮演多种角色。常见的有:
候选主节点(Master-eligible Node)
:可以被选举为主节点的节点。主节点主要负责集群本身的管理,比如说创建索引
。类似的还有仅投票节点(Voting-only Node)
,这类节点只参与主从选举,但是自身并不会被选举为主节点。协调节点(Coordinating Node)
:协调节点负责协调请求的处理过程。一个查询请求会被发送到协调节点上,协调节点确定数据节点,然后让数据节点执行查询,最后协调节点合并数据节点返回的结果集。大多数节点都会兼任这个角色。数据节点(Data Node)
:存储数据的节点。当协调节点发来查询请求的时候,也会执行查询并且把结果返回给协调节点。类似的还有热数据节点(Hot Data Node)、暖数据节点(Warm Data Node)、冷数据节点(Cold Data Node)
,你从名字就可以看出来,它们只是用于存储不同热度的数据。
写入数据
写入数据的整体流程如下:
- 文档首先被写入到 Buffer 里面,这个是 Elasticsearch 自己的 Buffer。
定时刷新到 Page Cache 里面
。这个过程叫做 refresh,默认是 1 秒钟执行一次
。- 刷新到磁盘中,这时候还会
同步记录一个 Commit Point
。
数据迁移存在的问题:
- 在写入到 Page Cache 之后会产生很多段(Segment),
一个段里面包含了多个文档
。文档只有写到了这里之后才可以被搜索到。 不断写入会不断产生段,而每一个段都要消耗 CPU、内存和文件句柄
,所以需要考虑合并。
整个过程:
已有的段不动
。创建一个新的段,把已有段的数据写过去
,标记为删除的文档就不会写到段里面。告知查询使用新的段
。- 等使用老的段的查询都结束了,直接删掉老的段。
查询怎么知道应该使用合并段了呢?
这都依赖于一个统一的机制,就是 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
❌ [ 勘误 ] /* 暂无 */
📜 [ 声明 ] 由于作者水平有限,本文有错误和不准确之处在所难免,本人也很想知道这些错误,恳望读者批评指正!