Elasticsearch架构与基本原理

Elasticsearch是一个分布式、近实时的搜索与数据分析引擎,采用面向文档的存储方式,支持分布式处理和水平扩展。文章介绍了其集群原理,包括主节点、数据节点和协调节点的角色,以及分片的概念和内部原理,如分段存储、延迟刷新、事务日志和段合并。此外,详细阐述了文档的索引、更新、删除和搜索过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 简介

Elasticsearch 是一个分布式、可扩展、实时的 搜索与数据分析引擎 。Elasticsearch 不仅仅只是全文搜索,还支持结构化搜索、数据分析、复杂的人类语言处理、地理位置和对象间关联关系等,天生具有良好的水平伸缩性。

Elasticsearch是一个 近实时 的搜索平台。这意味着,从索引一个文档直到这 个文档能够被搜索到有一个轻微的延迟(通常是1秒)

不同于关系型数据库的行和列存储,Elasticsearch 是 面向文档 的,不仅存储文档,而且 索引 每个文档的内容,使之可以被检索。

2. 集群原理

ElastiSearch天生就是 分布式的,主旨是随时可用和按需扩容。 扩容可以通过购买性能更强大( 垂直扩容 ) 或者数量更多( 水平扩容 )的服务器来实现。但是垂直扩容是有极限的。 真正的扩容能力是来自于水平扩容,将负载压力分散到这些节点中。

2.1 角色

主节点

主节点负责负责 管理集群 范围内的所有变更,例如增加、删除索引,或者增加、删除节点等。 主节点并 不涉及到文档级别的变更和搜索等操作 ,所以即使流量的增加它也不会成为瓶颈。

任何节点都可以成为主节点,主节点从候选主节点中选举产生。生产环境建议分离数据节点与主节点,即设置专用的候选主节点,避免因数据节点负载重导致主节点不响应。

数据节点

数据节点 保存数据并执行与数据相关的操作 ,例如CRUD,搜索和聚合。数据节点的负载较重,对CPU、内存、硬盘要求较高。

协调节点

协调节点 接收客户端请求 的节点。搜索、批量请求可能涉及到不同节点的数据,协调节点将请求分发到对应的数据节点(scatter阶段),将数据节点返回的结果集聚合处理后返回给客户端(gather阶段)。此外,协调节点还起到 负载均衡 的作用。

每个节点都是隐式的协调节点,由于gather阶段需要消耗较多的CPU和内存,建议指定专用协调节点。

2.2 分片

Elasticsearch 每个索引中的数据都被分发到多个分片之中,每个分片都保留全部数据的一部分。分片是数据的容器,文档保存在分片内,分片又被分配到集群内的各个节点里。 当集群规模扩大或者缩小时, Elasticsearch 会自动的在各节点中迁移分片,使得数据仍然均匀分布在集群里。每个分片都是一个 Lucene 的实例,本身就是一个完整的搜索引擎。

主分片

主分片响应索引请求,主分片的数量在创建索引时指定,决定着索引能够保存的最大数据量。因为如果数量变化了,那么所有之前路由的值都会无效,文档也再也找不到了。

当节点故障导致在索引丢失部分主分片时,Elasticsearch 会将副本分片提升为主分片。

副本分片

副本分片只是一个主分片的拷贝。副本分片作为冗余备份提供故障转移,并为搜索和返回文档等读操作提供服务。提高系统的可用性和搜索性能。

集群健康

  • green 所有的主分片和副本分片都正常运行。
  • yellow 所有的主分片都正常运行,但不是所有的副本分片都正常运行。
  • red 有主分片没能正常运行。

3. 分布式文档存取

3.1 路由

当索引一个文档的时候,文档会被存储到一个主分片中。Elasticsearch 通过路由规则决定文档应当存储在哪个分片中。

shard = hash(routing) % number_of_primary_shards

默认使用文档_id的哈希码对主分片数取余来路由文档。

3.2 索引、新建、删除文档

索引、新建、删除文档都是写操作,会现在主分片上完成之后再复制到相关的副本分片上。

新建、索引和删除单个文档

具体流程是:

  1. 客户端向协调节点发送写请求;
  2. 协调节点将请求路由到文档所属主分片的节点上;
  3. 目标节点在主分片上执行请求,并将请求并行转发到副本分片所处的节点上;
  4. 一旦所有副本分片都执行成功,主分片节点将向协调节点报告成功,协调节点向客户端报告成功。

所以当客户端收到成功响应时,文档变更在主副分片上均已执行成功。默认情况下,ES在半数以上的副本分片正常时,才会允许写操作,避免网络分区时产生不一致性。

3.3 获取文档

可以从主分片或者任意副本分片上获取文档。

取回单个文档

具体流程:

  1. 客户端向协调节点发送请求;
  2. 协调节点根据路由规则确定文档所属主分片,通过轮训算法将请求转发到主分片或者副本分片所处节点;
  3. 目标节点执行请求,通过协调节点将请求返回给客户端。

3.4 更新文档

ES中的文档都是不可变的,更新操作会首先读取原有文档,应用更新后,创建一个新的文档,并删除之前的文档。主分片更新完成后,会将完整的新文档并行复制到副本分片上。之所以采用基于文档的复制,而不是转发更新请求,是因为无法保证多个更新操作有序复制到副本分片。

ES使用_version 字段进行乐观的并发版本控制。UPDATE API在GET时会出发一次刷新,而UPDATE BY QUERY则直接从searcher里检索文档。

ES update_by_query 版本冲突_萝卜头柯克船长的博客-优快云博客)

3.5 搜索文档

搜索分为两个阶段:query then fetch

查询阶段:

  1. 协调节点接受客户端请求,并构建一个大小为from + size的优先级队列用于聚合搜索结果;随后协调节点会将查询请求广播到索引中每一个分片拷贝(主分片或者副本分片);
  2. 每个分片在本地执行搜索并将结果放入一个大小为from + size的优先队列。随后返回一个轻量级的结果集列表给协调节点,即优先级队列中所有文档的ID和排序值
  3. 协调节点将所有分片的结果合并到自己的优先级队列中,获得全局的搜索排序结果。

取回阶段:

  1. 协调节点确定要获取的文档并向执行查询的分片发送mutil-get请求;
  2. 每个分片将文档所需字段返回;
  3. 协调节点收集到所有文档后,将结果返回给客户端。

在全文搜索的下,Query then Fetch 会出现打分偏离的情形,Elasticsearch提供DFS Query then Fetch的搜索方式,使用预查询来计算整体文档的frequency等信息。

深度分页

协调节点需要根据 number_of_shards * (from + size) 排序文档,来找到被包含在 size 里的文档。from值若很大,将会给协调节点带来很高的负载,排序过程将会变得沉重。

ES的深度分页默认只支持到前1万条记录。

词项(词条)搜索

每个字段被分词后的单词称之为词项(term),当倒排索引中的词项数量很大时,顺序遍历的方式检索词项将会变得不可行。

Elasticsearch将词项排序后放入Term Dictionary中,利用跳表和二分查找来快速定位词项,其时间复杂度为O(lgN)。当词项很多时,将Term Dictionary全部放入内存有些不太现实,于是将Term Dictionary分块并利用Term Index和有限状态机(Trie前缀树)来定位词项所属的分块。

在多词项的联合查询中,Elasticsearch使用跳表或者位图(Roaring Bitmaps)完成多个搜索结果文档ID的快速与运算,实现联合查询。

4. 分片的内部原理

4.1 分段存储

Elasticsearch的全文搜索是基于倒排索引的:对字段分词后,建立词项到文档的索引,并根据相关性排序搜索结果。

索引数据是按段(Segment),每个段都是倒排索引的最小单位,分段存储的优点在于:

  1. 数据增加、变更时,无需全量更新倒排索引;
  2. 加上段的不变性,可以避免使用锁;

段具有不变性,一旦生成就不能被修改,不变性的有点在于:

  1. 不需要锁,没有对段进行修改也就不需要做并发控制;
  2. 缓存,可以直接利用文件系统缓存
  3. 其它缓存,比如Filter缓存在索引的生命周期内始终有效,不需要在数据改变时重建,因为段数据不会变化;
  4. 段可以被压缩存入磁盘;

由于段具有不变性,删除数据并不会将文档从段中移除,而是在.del文件中记录被删除的文档信息。文档仍然可以被搜索匹配到,只是会从结果集中删除。类似的,更新操作变成了:删除+新增两个操作的结合

不变性的缺点主要在于:存储空间占用大,旧数据只有在段合并(merge)期间才会被删除。倘若频繁更新数据,存储空间将会浪费更多。

4.2 延迟刷新

Elasticsearch的近实时搜索特性来源于延迟刷新策略。

当有新的文档写入时,先将其写入到JVM的内存中,当达到一定的时间或者缓存的数据达到一定量时,会触发一次刷新(refresh):将缓存的文档生成一个新的段,异步刷盘,首先写到文件系统的缓存上,稍后将刷新到磁盘上并生成一个提交点(commit point)。

只有文档以段的形式存在时才能被搜索到,也就是文档生成段并刷新到文件系统缓存,才能供搜索使用,但不需要等段被刷新到磁盘。

默认情况下,每个分片会每秒刷新一次。这Elasticsearch文档近实时搜索的原因,文档变化并不是立即对搜素可见,但是会在1秒之后变为可见。

段被写入磁盘后,会有一个提交点,一旦拥有提交点,段不可修改。

4.3 事务日志

延迟刷新和异步刷盘在提升了Elasticsearch写入能力的情况下,增大了数据丢失的风险。Elasticsearch引入了事务日志(Translog)来记录还没有持久化到磁盘的数据,是一种WAL(Write Ahead Log)策略,提供Crash-Safe能力。

引入事务日志后,文档的写入流程为:

  1. 文档首先被添加到缓存中,同时会在事务日志中追加一条记录;
  2. 当达到默认刷新时间或者缓存数据达到一定量时,触发刷新操作,生成新的段并写到文件系统缓存;
  3. 当日志文件达到一定量时或者超过一定时间时,触发一次Flush操作——将文件系统缓存中的数据落盘,生成一个commit point,然后清空日志文件。

4.4 段合并

Elasticsearch默认情况下,每秒就会生成一个段。段的数量太多时会带来较大的资源损耗:文件句柄、内存和CPU消耗等等;在搜索阶段,搜索请求需要检查每一个段,然后合并查询结果,段越多搜索速度越慢。

为此,Elasticsearch引入了段合并(Segment Merge)。段合并在后台定期进行,将多个大小相似的小段合并成一个大段,同时删除旧段,并将新段刷新到磁盘。

在段合并期间,Elasticsearch会将已被删除的旧文档作物理删除——删除文档不会被拷贝到新的大段中。

段合并的计算量较大,对磁盘IO消耗也较高,会影响正常的数据写入速率。

参考

ES分布式架构及底层原理

Elasticsearch: 权威指南 | Elastic

《Elasticsearch实战与原理解析》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值