概述
文章目录
- 1. 简介
- 2. 数据结构
- 3. 基本概念
- 3.1 节点与集群
- 3.2 分片
- 3.3 术语
- 4. 主节点选举
- 4.1 选举流程
- 4.2 缺陷
- 4.2.1 主节点假死
- 4.2.2 脑裂
- 5. 增删改查流程
- 5.1 新增
- 5.2 更新和删除
- 5.3 查询
- 6. 乐观并发控制
- 7. 分页
- 7.1 from size
- 7.2 scroll
- 7.3 search_after
- 8. 调优
1. 简介
Elasticsearch 是一个分布式存储、搜索、分析的引擎。它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。底层是开源库 Lucene,是对 Lucene 的封装,提供了 REST API 的操作接口,开箱即用。
2. 数据结构
ES为实现快速的“模糊匹配”/“相关性查询”,会将写入的数据进行分词,再通过倒排索引查找记录。
正向索引:文档ID作为索引,文档内容作为记录
倒排索引:文档内容作为索引,文档ID作为记录,方便地通过内容查找到其所在的文档。
ES会对文本进行分词,分词的集合叫做Term Dictionary,会进行排序,查询时使用二分查找。分词对应的文档ID叫做Posting List,使用FST(Finite State Transducers)进行压缩,节省硬盘空间,使用Roaring Bitmaps求出文档ID的交并集。由于Term Dictionary的词量太大,不能全部装入到内存中,抽象了一层词前缀为Term Index。Term Index以FST数把结构来保存词的前缀,节省内存且查找速度快。
3. 基本概念
3.1 节点与集群
单个ES实例称为节点(Node),多个节点组成集群(Cluster)。
主节点
节点是一主多从的关系。
主节点,负责维护索引元数据、负责切换主分片和副本分片等。如果主节点挂了,会再选举出一个新的主节点。
3.2 分片
分片是单个 Lucene 实例。
当有大量的文档时,由于内存的限制、磁盘处理能力不足、无法足够快的响应客户端的请求等,一个节点可能不够。所以将数据分为多个分片,每个分片放到不同的服务器上。多个分片,在写入或查询的时候就可以并行操作,从各个节点中读写数据,提高吞吐量。
主副分片
分片分为主分片和副本分片。副本分片增强了高可用性,实现了故障转移,也提高了性能。索引需要多少个主分片和副本分片是通过配置决定的。
数据写入时,先写入到主分片,然后再复制到副本分片;数据读取时,主分片和副本分片都可以读取。如果某个节点挂了,主节点就会把对应的副本分片提升为主分片。这样即便节点挂了,数据就不会丢失。
3.3 术语
关系型数据库 | Elasticsearch |
---|---|
Database/Table | Index |
Row | Doucument,索引中的单条记录。 |
Column | Field,索引的字段。 |
Schema | Mapping,索引映射,即索引的定义。 |
SQL | DSL |
4. 主节点选举
选举时间
- 新节点加入集群或某个节点从宕机中恢复
- 集群中的某个节点发现到主节点崩溃
4.1 选举流程
基于 Bully 选举算法,每个节点都有一个编号,只有编号最大的存活节点才能成为主节点。
当节点发现主节点不响应请求时,它发起一次选举:
- 当前节点向所有编号比自己大的节点发送一个选举消息;
- 如果没有其他节点响应,则自动成为主节点;
- 如果编号比它大的节点响应了,则有响应的节点接管选举工作。
任何一个时刻,节点只能从编号比它小的节点接收选举消息,当消息到达时,接收者发送OK消息给发送者,表明它在运行,之后接管工作。最终的那个节点就成为主节点,将消息发送给其他节点,通知它们新的主节点。
编号比较
- ClusterState版本号:版本号越大优先级越高。ClusterState是主节点向集群中各个节点发送的集群状态,这个状态有一个版本号,如果集群状态发生了变化,如集群新增节点或有节点成员退出,那么这个版本号就会加一。
- 节点id:id越小优先级越高。
4.2 缺陷
4.2.1 主节点假死
假死是主节点承担的职责负载过重的情况下,可能无法即时对其他节点作出响应。例如当前主节点为P6假死,于是P5成为了主节点,当P6负载减轻后,P6又对集群内节点作出响应,P6又会称为主节点。如此反复,使整个集群状态就会非常不可靠。
解决
在ES中,当主节点无法假死时,当前节点会请求其他节点判断直接点是否存活,如果有1/2以上节点都认定主节点存活,那么当前节点就会放弃发起选举。
4.2.2 脑裂
脑裂指的是一个集群中出现了两个及以上的主节点节点,可能是路由器短时故障造成不能相互通信,导致集群节点分成了两部分,例如一部分包含P3、P5、P6节点,另一部分包含P1、P2、P4节点。
解决
配置 discovery.zen.minimum_master_nodes
决定了在选主过程中需要有多少个节点通信,默认是1,设置的原则就是设置为 N/2+1
个。如果集群是六个节点,那么该参数就是 6/2+1=4
个。分区后两边都不满足,所以导致ES不可用。
如果产生了脑裂情况,为了避免脑裂的主节点生成错误数据对整个集群产生影响。主节点更新集群状态时还作出了如下防护,主节点有两种指令,一种是send指令,另一种是commit指令。
主节点使用send指令将最新集群状态推送给其它节点的时候,主节点进入等待响应状态,其它节点并不会立刻应用该集群状态,而是首先会响应主节点表示它已经收到集群状态更新,同时等待主节点的commit指令。如果主节点在 discovery.zen.commit_timeout
配置时间内都没有收到 discovery.zen.minimum_master_nodes
个数的节点响应,那么主节点就不会向其它节点发送commit指令。如果主节点收到了足够数量的响应,那么主节点会向集群发出提交状态的指令,之后其它节点应用集群最新状态,主节点再次等待所有节点响应,等待时间为 discovery.zen.publish_timeout
,如果任何一个节点没有发出提交响应,主节点再次更新整个集群状态更新。
5. 增删改查流程
5.1 新增
集群上的每个节点都是协调节点(Coordinating Node),协调节点表明这个节点可以做路由。协调节点通过hash算法计算出文档ID是在哪个主分片上,然后再路由到对应的节点 shard = hash(document_id) % (num_of_primary_shards)
。
路由到对应的节点和对应的主分片
- 先将数据写到内存缓存区;
- 再写到 translog 缓存区;
- 每秒将数据从内存缓存区中 refresh 到 FileSystemCache 中,生成段(segment)文件;
- refresh完,清空内存缓存区;
- 每隔5s中,将 translog 从缓存区 flush 到磁盘;
- 定期/定量结合 FileSystemCache 和 translog 将数据 flush 到磁盘。
ES会把数据先写入内存缓冲区,然后每秒刷新到 FileSystemCache。当数据被刷新到 FileSystemCache 后,数据才可以被检索到。为了防止节点宕机导致内存中的数据丢失,ES还会写到日志文件 translog 中。translog 会先写到缓冲区,再每隔5s将缓冲区的数据 flush 到磁盘中。所以ES某个节点如果挂了,可能会造成有5s的数据丢失。等到磁盘上的 translog 文件大到一定程度或者超过了30分钟,会触发 commit 操作,结合 FileSystemCache 和 translog 将数据 flush 到磁盘,完成持久化操作。
如果主分片成功后,主分片所在的节点会将请求并行转发到副本节点上。一旦所有的副本分片都报告成功,它会向协调节点报告成功,协调节点向客户端报告成功,完成写入。
5.2 更新和删除
段文件是不可改变的,通过 .del
标识来确定文档是否删除。被标记删除的文档仍然可以被查询匹配到, 但会在返回前从结果集中移除。
文档删除时,直接标记删除。文档更新时,旧文档标记删除,然后重新写入一个新文档。
段合并
写入的时候,由于自动刷新会每秒会创建一个新的段文件,这样会导致短时间内的段数量暴增。而且每一个段都会消耗文件句柄、内存和cpu运行周期。更重要的是,每个搜索请求都必须轮流检查每个段;所以段越多,搜索也就越慢。
ES会在后台进行段合并,并不会中断索引和搜索。段合并将小的段被合并到大的段,然后这些大的段再被合并到更大的段。那些标记删除的文档清除,并不会被拷贝到新的大段中。
合并大的段需要消耗大量的I/O和CPU资源。ES在默认情况下会对合并流程进行资源限制,防止段爆炸,使得搜索仍然有足够的资源很好地执行。
5.3 查询
查询简单分为根据ID和query(搜索词)查询文档。
根据ID查询会先查询Translog内存缓冲区和磁盘中Translog文件,再查询磁盘中段文件。根据query匹配查询则是同时去查询内存和硬盘的段文件。
查询阶段
- QUERY_AND_FETCH:查询完就返回整个文档内容,只适合于只需要查一个分片的请求;
- QUERY_THEN_FETCH:先查询出对应的文档ID ,然后再根据文档ID匹配去对应的文档;
- DFS_QUERY_THEN_FETCH:先算分,再查询。
分指的是 词频率和文档的频率(Term Frequency、Document Frequency),频率越高,相关性就更强。
QUERY_THEN_FETCH
- Query:客户端请求发送到集群的某个节点上。集群上的每个节点都是协调节点,协调节点将搜索的请求转发到各个主分片和副本分片。数据节点在每个分片上内完成过滤、排序等操作,将搜索出的文档ID返回给协调节点。
- Fetch:协调节点得到数据节点返回的文档ID,组成集合,完成合并、排序和分页等操作后,去各个节点上拉取实际的文档数据,最终返回给客户端。
6. 乐观并发控制
当文档增删改时,新版本的文档是异步复制到集群中的副本分片,那么到达的顺序也许是乱的。
ES中每个文档都有一个版本号 _version
,当文档被修改时版本号会递增。ES利用版本号来确保文档的顺序,防止变更冲突时不会导致数据丢失。如果旧版本的文档在新版本之后到达,那么直接忽略。
7. 分页
7.1 from size
from为偏移值,size为返回的数目。默认from为0,size为10,即所有的查询默认返回前10条数据。
查询的时候,协调节点会把请求转发到各个分片上,每个分片必须先先创建一个 from + size
长度的队列。协调节点需要根据 number_of_shards * (from + size)
排序文档,来找到被包含在里面的文档。
假设目前有5个分片。如果想查询前10条数据,请求到协调节点后,协调节点会把请求转发到各个分片上,每个分片取出10条数据返回给协调节点。协调节点对50条数据进行排序,取出前10条数据后返回给客户端。
如果想查询第100页的10条数据时,先从每个分片都查 1000 条数据后,协调节点对全部 5000 个结果排序,最后丢弃掉这些结果中的 4990 个结果。
缺点
- 翻页越深,每个分片返回的数据也越多,对结果排序的成本随分页的深度成指数上升。ES使用
index.max_result_window:10000
作为保护措施来避免这种情况的发生。
7.2 scroll
scroll 模拟传统的游标来记录当前读取的文档信息位置。使用 scroll 分页,不是为了实时查询数据,而是为了查询大量甚至全部的数据。
scroll 维护了一份当前索引的快照信息,在执行数据查询时候,从这个快照信息中获取数据。它相对于from size分页方式来说,不是查询所有数据再剔除掉不需要的部分,而是记录一个读取的位置来保证下次对数据的继续获取。
缺点
- scroll 是对数据的一种快照,当数据发生任何变化的情况下(例如增删改),它是不会被感知到的,并且需要维护 scroll 上下文,因此不适用于实时和高并发的场景;
- 每次的数据请求都需要上一次请求结果中的 scroll_id 来作为下次访问时的标志,因此无法对页面进行的随机跳转,只能滚动数据浏览。
7.3 search_after
search_after 是根据上一页的最后一条数据来确定下一页的位置,同时在分页请求的过程中,如果有索引数据的增删改查,这些变更是可以被感知的,也会实时的反映到游标上。因为每一页的数据依赖于上一页的最后一条数据,所以没法跳页请求。
为了找到每一页最后一条数据,每个文档那个必须有一个全局唯一值,官方推荐使用uuid作为全局唯一值,当然在业务上的id也可以。
8. 调优
设置 FileSystemCache 内存
设置 FileSystemCache 的内存为总容量的大小,或者至少可以容纳总数据量的一半。
ES严重依赖底层的 FileSystemCache。写入的时候,只有当数据被刷新到 FileSystemCache 后,数据才能被检索;查询的时候,也会将磁盘文件里的数据自动缓存到 FileSystemCache 中。
所以如果给 FileSystemCache 更多的内存,尽量让内存可以容纳所有的数据,那么搜索的时候就基本都是走内存的,性能会非常高。走磁盘,基本秒级;而走 FileSystemCache,基本毫秒级。
数据预热
做一个专门的缓存预热子系统,每隔一段时间,将经常访问的数据提前访问一下。让数据进入 FileSystemCache 里面去,这样下次访问的时候,走内存性能一定会好很多。
冷热分离
将冷热数据分不同的索引写入,确保热数据在被预热之后,都留在 FileSystemCache 中,防止被冷数据给冲刷掉。
文档模型
不使用ES中复杂的关联查询,最好是先在 Java 中完成关联,将关联好的数据直接写入ES中。搜索的时候,就不需要利用ES的搜索语法来完成 join 之类的关联搜索。
text与keyword
text:会分词,然后进行索引,用于全文搜索。支持模糊、精确查询,不支持聚合。
keyword:不分词,直接索引,用于关键词搜索。支持模糊、精确查询,支持聚合。
如果不指定类型,ES默认会将字符串同时映射成text和keyword类型。
堆大小不得超过 30G
使用 29G 或 30G 的内存,并使用 XFS,并尽可能启用 hardwareprefetch 和 llc-prefetch。
参考:
Elasticsearch: 权威指南
「扫盲」 Elasticsearch
Elasticsearch入门文章
倒排索引为什么叫倒排索引?
Elasticsearch选举原理之Bully算法
Lucene就是这么简单
Elasticsearch写入原理深入详解
ElasticSearch中字符串类型(Text和keyword)的选择
Elasticsearch分页解决方案
ES如何做到亿级数据查询毫秒级返回?
在生产环境运行Elasticsearch深度指南
最后
以上就是乐观酸奶为你收集整理的Elasticsearch 知识点整理的全部内容,希望文章能够帮你解决Elasticsearch 知识点整理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复