快速了解elasticsearch原理
来自lucene的Segment到底是什么?
倒排索引inverted index:
通过倒排索引机制,我们可以快速的根据词项信息来检索他属于哪一个文档。由term dictionary与posting list组成
- term dictionary是分词之后的词项,按序排序后可以使用二分法查找,将时间复杂度从On改变到了Ologn
- posting list则是用于记录词项出现在哪个文档中
term index(加快搜索):term dictionary由于产生数据量巨大,因此不会像redis一样放在内存中,由于磁盘IO速度较慢,因此引入该部分。term index就是一棵前缀树,通过前缀匹配和偏移量快速查到数据对应的位置。
stored fields(原文存储):行式存储结构,用于存储文档本身,每一行都是一个完整的数据
doc values(排序聚合):列式存储结构,用于存储文档的索引和需要排序的数值
由上述inverted index、term index、stored fields、doc values共同组成了segment,segment是具备一个完整搜索功能的最小单元。
每次写入的时候都会生成一个新的segment,然后会不定期进行segment merging(段合并)。
在删除文档的时候,输入删除指令后都是在文档中存放一个删除字段保证该字段不会被读出来,段合并的时候才会进行真正的删除。
多段segment组成了现在的lucene
elasticsearch如何实现的高可用高性能高拓展性?
elasticsearch如何基于lucene实现的高性能:
lucene的读写资源易耗尽,因此我们可以增加lucene的数量:在index较小的时候,为每个index设置一个单独的lucene,如果index过大,则需要像数据库那样进行拆分,将一个index拆分到多少shards中,每个shard对应一个lucene。这样就降低了单个lucene的压力,通过使用多个lucene实现了高性能。
shard是elasticsearch中的最小存储单位
elasticsearch如何基于lucene实现高拓展性:
shard过多会导致单机CPU与内存过高,影响整体性能。通过申请更多的机器,每个机器作为一个node,将shard部署在node上分担压力
elasticsearch如何基于lucene实现高可用性:
为了防止node瘫痪导致shard不可用,我们对shard添加副本形成主从模式。(这里的主从类似MySQL,副分片负责读,主分片负责写;一旦主分片挂了,还能让副分片升级为新的主分片)
角色分化:elasticsearch也会实现集群部署,总共有三个功能需要实现:集群管理master node、处理请求coordinate node、存储数据data node
去中心化:利用raft算法自动实现选举过程,减去了zookeeper的使用
elasticsearch是如何完成读写的?
elasticsearch的写入:
请求先发送到coordinate node协调节点
协调节点根据hash路由,确定将数据写入哪个节点的哪个主shard分片。
分片是基于lucene的,因此数据会写入lucene中,lucene中的segment。segment中将数据存入倒排索引inverted index、store fields、term index、doc values中。
主分片写入成功后,将数据同步到副分片
副分片写完后,主分片会返回协调节点一个ACK,协调节点返回给客户端写入完成
elasticsearch的读取:
查询阶段query phase:
- 请求先发送到coordinate node协调节点
- 协调节点根据index name了解到shard的信息,并将请求转发给多个分片
- 请求到分片后,会并发搜索多个segment,利用segment的倒排索引获取到文档id、doc values获取排序信息
- 分片们会将结果聚合返回给协调节点,然后协调节点根据信息进行排序聚合,舍弃不需要的信息
获取阶段fetch phase:
- 协调节点根据上述获取的信息再次请求对应shard
- shard内的lucene库从segment里的store fields读出完整的文档内容
- shard将读取的内容返回给coordinate node,由coordinate node返回给客户端