《ElsticSearch - CURD是如何实现的?》
一:前言
- 真是好几个月没有在更新博客了,主要是啊.......
- 这个排版啊,真是不好搞...... 印象笔记真香。
- 基本
- Es 的数据是以 Index 区分的。
- 其架构本身是分布式的(类似kafka),一个 Index(索引) 有多个 share(分片) 部署在 多个 Broker(机器) 上。
二:ElastciSearch 是如何完成插入文档的?
- 流程
- 当用户向一个节点提交了一个索引新文档的请求
- 1. 节点会计算新文档应该加入到哪个分片(shard),协调节点会将请求发送给对应的节点。
- 2. 注意这个请求会发送给主分片,等主分片完成索引,会并行将请求发送到其所有副本分片,保证每个分片都持有最新数据。
- 每次写入新文档时,都会先写入内存中,并将这一操作写入translog文件(transaction log)中,
- 此时如果执行搜索操作,这个新文档还不能被索引到。
- ES会每隔1秒时间(这个时间可以修改)进行一次刷新操作(refresh)。
- 此时写入内存的新文档都会被写入一个文件系统缓存(filesystem cache)中,并构成一个分段(segment)。
- 此时这个segment里的文档可以被搜索到,但是尚未写入硬盘,即如果此时发生断电,则这些文档可能会丢失
- 3. 之后不断会有文件写入, 每隔一秒将生成一个新的segment,每隔30分/translog文件变得很大,则执行一次fsync操作。
- 此时所有在文件系统缓存中的segment将被写入磁盘。
- 而translog将被删除(此后会生成新的translog)。
- 总结
- ES 的更新其实是和数据库(Mysql)类型的原理类似
- 通过translog(Mysql的redolog)提升效率。
- 符合条件自动合并Segment(Mysql的刷脏页)
- translog 提供了 crash-safe 的能力。
二: ElasticSearch 是如何完成查询的?
- 核心
- 查询的过程大体上分为查询(query)和取回(fetch)两个阶段。
- 这个节点的任务是广播查询请求到所有相关分片,并将它们的响应整合成全局排序后的结果集合,这个结果集合会返回给客户端。
- 流程
- Query
- 应为本身是分布式模型,所以在节点收到请求后,会以Coordinating身份,在分片中随机选择一个(可能是主分片,也可能是副本分片)进行查询。
- 选中分片进行查询,排序,返回 文档ID+排序值 (From + Size 条数据)
- Fetch
- 收到每个分片的数据,在重新排序,选择对应的ID
- 在以 Multi 方式,去对应分片获取信息
- 实例
- _doc 有三个分片 share1,share2,share3 (各有一个副本),部署在 Broker1,Broker2,Broker3 上
- 执行查询{}
- Query
- 请求发送到了 Broker2 上,则 Broker2 为协调节点,向 share1,share3,share2(自己本身)发送查询请求
- share1 返回了[ID:1, 排序值:3][ID:4, 排序值:8][ID:7, 排序值:200]
- share2 返回了[ID:2, 排序值:5][ID:5, 排序值:6][ID:8, 排序值:30]
- share3 返回了[ID:3, 排序值:5][ID:6, 排序值:6][ID:9, 排序值:30]
- 至此 borker2拿到了所有节点返回的数据
- Featch
- 协调节点重新排序(获取Size个数据)
- 根据排序结果需要获取前两个IDs[1,2]
- 在根据ID去对应分片获取结果
- 分布式查询所带来的问题
- 每个分片都需要查 From + Size
- 协调节点需要处理 分片数 * (From + Size) 个数据
三: ElasticSearch 是如何完成更新/删除的?
- 核心
- ES的索引是不能修改的,因此更新和删除操作并不是直接在原索引上直接执行。
- 每一个磁盘上的segment都会维护一个del文件,用来记录被删除的文件。
- 每当用户提出一个删除请求,文档并没有被真正删除,索引也没有发生改变,而是在del文件中标记该文档已被删除。
- 因此,被删除的文档依然可以被检索到,只是在返回检索结果时被过滤掉了。
- 每次在启动segment合并工作时,那些被标记为删除的文档才会被真正删除。
- 流程
- 1.更新文档会首先查找原文档,得到该文档的版本号。
- 2.将修改后的文档写入内存,此过程与写入一个新文档相同。
- 3.旧版本文档被标记为删除,同理,该文档可以被搜索到,只是最终被过滤掉。