ElasticSearch学习之数据写入及查询流程分析

ElasticSearch写入数据

写入数据node节点

  • 写入流程图

    ElasticSearch数据写入概览

  • 流程分析

    集群有三个节点,都存储数据,indexA 有5个分片,2个复制集。数据如下分布

    Node1: shard1
    Node2: shard2,shard3,shard1-R1(shard1的复制集)
    Node3: shard4,shard5,shard-R2(shard1的复制集)

    为了简化问题,shard2,shard5等shard的复制集忽略问题了,现在以写入shard1为例说明问题。

    1. 首先客户端根据配置的连接节点,通过轮询方式连接到一个coordinate节点。

      coordinate节点不是master/client/data节点一个维度的描述,它就是指处理客户端请求的节点。这个描述和cassandra的coordinate节点是一个概念。集群中所有的节点都可以是coordinate节点

    2. coodinate节点通过hash算法计算出数据在shard1上shard = hash(document_id) % (num_of_primary_shards),然后根据节点上维护的shard信息,将请求发送到node1上。

    3. node1 对索引数据进行校验,然后写入到shard中。具体细节见下一节写入到shard。

    4. 主节点数据写入成功后,将数据并行发送到副本集节点Node2,Node3

    5. Node2,Node3写入数据成功后,发送ack信号给shard1主节点Node1

    6. Node1发送ack给coordinate node

    7. coordinate node发送ack给客户端

    整个过程coordinate node部分类似cassandra,主shard节点和副本集受master-slave模式影响,必须有master决定写入成功与否,和mysql类似的。

写入数据shard分片

  • 写入流程图

    ElasticSearch数据写入shard

  • 流程分析

    1. 数据写入到内存buffer;

    2. 同时写入到数据到translog buffer;

    3. 每隔1s数据从buffer中refresh到FileSystemCache中,生成segment文件,一旦生成segment文件,就能通过索引查询到了;

    4. refresh完,memory buffer就清空了;

    5. 每隔5s中,translog 从buffer flush到磁盘中;

    6. 定期/定量从FileSystemCache中,结合translog内容flush index到磁盘中。做增量flush的。

  • 注意事项

    在每一个Shard中,写入流程分为两部分:先写入Lucene,再写入TransLog

    写入请求到达Shard后,先写Lucene文件,创建好索引,此时索引还在内存里面,接着去写TransLog,写完TransLog后,刷新TransLog数据到磁盘上,写磁盘成功后,请求返回给用户。

    这里有几个关键点:

    1. 一是和数据库不同,数据库是先写CommitLog,然后再写内存,而Elasticsearch是先写内存,最后才写TransLog。可能的原因是Lucene的内存写入会有很复杂的逻辑,很容易失败,比如分词,字段长度超过限制等,比较重,为了避免TransLog中有大量无效记录,减少recover的复杂度和提高速度,所以就把写Lucene放在了最前面。

    2. 二是写Lucene内存后,并不是可被搜索的,需要通过Refresh把内存的对象转成完整的Segment后,然后再次reopen后才能被搜索,一般这个时间设置为1秒钟,导致写入Elasticsearch的文档,最快要1秒钟才可被从搜索到,所以Elasticsearch在搜索方面是NRT(Near Real Time)近实时的系统。

    3. 三是当Elasticsearch作为NoSQL数据库时,查询方式是GetById,这种查询可以直接从TransLog中查询,这时候就成了RT(Real Time)实时系统。

    4. 四是每隔一段比较长的时间,比如30分钟后,Lucene会把内存中生成的新Segment刷新到磁盘上,刷新后索引文件已经持久化了,历史的TransLog就没用了,会清空掉旧的TransLog。

ElasticSearch查询数据

  • 流程分析

    1. 搜索被执行成一个两阶段过程,我们称之为 Query Then Fetch

    2. 在初始查询阶段时,查询会广播到索引中每一个分片拷贝(主分片或者副本分片)。 每个分片在本地执行搜索并构建一个匹配文档的大小为 from + size 的优先队列

      PS:在搜索的时候是会查询 Filesystem Cache 的,但是有部分数据还在 MemoryBuffer,所以搜索是近实时的。

    3. 每个分片返回各自优先队列中 所有文档的 ID 和排序值 给协调(coordinate)节点,它合并这些值到自己的优先队列中来产生一个全局排序后的结果列表。

    4. 接下来就是 取回阶段,协调节点辨别出哪些文档需要被取回并向相关的分片提交多个 GET 请求。每个分片加载并 丰富 文档,如果有需要的话,接着返回文档给协调节点。一旦所有的文档都被取回了,协调节点返回结果给客户端。

    5. 补充:Query Then Fetch 的搜索类型在文档相关性打分的时候参考的是本分片的数据,这样在文档数量较少的时候可能不够准确,DFS Query Then Fetch 增加了一个预查询的处理,询问 Term 和 Document frequency,这个评分更准确,但是性能会变差。*

其他

  • MySQL和ElasticSearch

    数据库 | 记录日志,刷磁盘 | 复制日志 | 备注

    mysql | redo logs | bin log | redo logs写buffer的,

    elastic search | translog | translog | 写buffer的

  • refresh和flush的区别

    es通过refresh(默认1s)把in-memory buffer(也就是内存缓冲区)的数据刷到file-system cache中去形成segment,通过lucene的indexreader可以reopen缓存中新产生的segment,就可以搜索了,所以从写入到可搜索默认要1s,这也是es被叫做准实时的原因。

    但是在内存里面终归不是个稳妥的办法,需要持久化,所以又有了个flush(默认30分钟),是将segment从文件系统缓存刷到磁盘上,同时提交commit point以及清除translog,最终还是通过reopen来打开磁盘上的segment实现可搜索

    那么为什么要有refresh这一步而不是一直flush呢,因为flush中要用到fsync,这个是十分消耗系统资源的,频繁调用不靠谱,但是又想近实时搜索,refresh是个很好的这种办法。

参考链接

  • elasticsearch 的一次写入数据的过程

    https://blog.csdn.net/star1210644725/article/details/106448772

  • ElasticSearch读写底层原理及性能调优

    https://blog.csdn.net/co_zjw/article/details/108265794

  • 深入分析Elastic Search的写入过程

    https://juejin.cn/post/6844903898176552973

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值