ES分布式特性与分布式搜索的机制-笔记

不同的集群通过名字来区分

节点类型

coordinating node

  • 路由请求的节点,默认所有节点都是该种节点
    • 比如创建索引的请求会被路由到Master节点

data node

  • 数据节点,一个节点启动默认就是data node
  • 保存分片数据,由Master node 决定如何把分片数据分配到数据节点上
  • 增加data node可以水平扩展和解决单点问题
  • 主分片和副分片不允许在同一data node上

Master node

  • 处理创建、删除索引的请求;决定分片被分配到那个节点;负责索引的创建和删除
  • 维护并更新cluster state

Master Eligible node

  • 允许配置多个eligible(候选)主节点,这些节点有资格在Master节点故障时参与主节点选举
  • 每个节点启动后都是eligible 节点

集群状态

  • 集群状态信息,包括
    • 所有的节点信息
    • 所有的索引及其mapping与setting信息
    • 分片的路由信息
  • 每个节点都保存了集群状态信息
  • 只有Master节点才能修改集群状态信息,并负责同步给其他节点

选主过程

  • 在Master eligible node中间发生
  • 互相ping对方,ping的结果会包含节点信息,node id最小的被认为是Master节点

脑裂问题

当出现网络问题时,一个节点与其他节点无法连通,其他节点会选出一个新Master,那一个节点会认为自己是Master节点,那么集群中就会维护两份集群状态信息,当网络恢复时,就无法恢复数据

分片

主分片

  • 提升系统容量,将数据打散
  • 通过主分片,可以将一个索引(相当于一个db)的数据分散到不同的节点
  • 主分片数在创建索引时就要指定,后续不能修改,如果要修改只能重建索引

副分片

  • 为了容灾加入副分片,副分片上有完整的数据,副分片数量可以动态调整
  • 一定程度上增加副分片的数量可以提高系统的吞吐量

故障转移

原始状态

node1:p1,r3

node2:p2,r1

node3:p3,r2

当node2宕机后,主分片2、副分片1丢失,首先会把在node3上的副分片2提升为主分片2,变成

node1:p1,r3

node3:p3,p2

然后重新分配一个r2、r1到两个节点上,变成

ndoe1:p1,r2,r3

node2:p2,p3,r1

文档的分布式存储

分到不同的分片是通过实时计算,该文档被分派到哪个节点上去了

  • 文档到分片的路由算法
    • shard = hash(_routing)%number of primary shards
    • 默认的routing为文档id
    • routing可定制
    • 该算法也是设定了主分片数后不能修改的根本原因
  • 文档的路由计算是在ordinary node进行的

用户更新一个文档的流程

在这里插入图片描述

用户删除一个文档的流程

在这里插入图片描述

分片的生命周期

Lucene Index

  • 在Lucene中,单个倒排索引被称为segment,segment是自包含的不可变的,多个segment被称为一个Lucene index,一个Lucene的index对应着的是es中的shard
  • 当有新文档加入时,会生成新的segment,查询时会同时查询所有的segment,然后做一个汇总。
  • Lucene中有一个文件commit point,用来记录所有的segments的信息
  • 删除的文档的信息放到.del文件中,这样es就可以对删除的文档进行过滤

es的refresh

在这里插入图片描述

上图是es中写入一个新文档的过程:

  • 一个文档要写入时会被先写到index buffer的内存区域当中
  • 过一段时间之后
  • es会将index buffer中的文档创建一个新的segment,这一步被称为refresh,refresh默认不执行fsync刷盘。(写入segment之后就可以被查到了)

ps:因为更新文档的时候,es会先删除,在创建,所以更新也是近实时的

es的transaction log

在这里插入图片描述

虽然refresh 了,但文档还是在文件系统缓存里的,也就是还是在内存里的,不能够应对断电等故障,所以有了这个transaction log的机制,每个分片有一个transaction log

  • 文档在新加入的时候,除了写到index buffer一份,还要写到transaction log里一份,而transaction log默认是5秒钟或者在一个变更请求完成后刷一次盘的
  • 当refresh之后,transaction log不会清空,这时候,文档在transaction log的磁盘里有一份,在segment里也是有一份

es的flush操作

在这里插入图片描述

flush实际上就是将刚刚的在文件缓存(内存)里的segment落盘为主的操作

  • 执行一次refresh
  • 调用fsync刷盘将文件缓存内的segments一个一个按照segment file的形式刷到磁盘中,将commit point这个文件更新到磁盘中国,每个shard都有一个commit point文件,其中保存了当前shard成功写入磁盘的所有segment
  • 删除transaction log

因为flush操作比较重,所以默认30分钟执行一次,但如果transaction log满了也会执行

es的merge操作

随着时间的流逝,segment会很多,es会定期把多个segment合并成一个,合并操作被称为merge,同时merge操作也会把.del文件里记录的文档做一个真正的删除

一个老哥写的关于新增一个文档的过程的笔记

1)客户端发起数据写入请求,对你写的这条数据根据_routing规则选择发给哪个Shard。
确认Index Request中是否设置了使用哪个Filed的值作为路由参数,
如果没有设置,则使用Mapping中的配置,
如果mapping中也没有配置,则使用_id作为路由参数,然后通过_routing的Hash值选择出Shard,最后从集群的Meta中找出出该Shard的Primary节点。
2)写入请求到达Shard后,先把数据写入到内存(buffer)中,同时会写入一条日志到translog日志文件中去。
当写入请求到shard后,首先是写Lucene,其实就是创建索引。
索引创建好后并不是马上生成segment,这个时候索引数据还在缓存中,这里的缓存是lucene的缓存,并非Elasticsearch缓存,lucene缓存中的数据是不可被查询的。
3)执行refresh操作:从内存buffer中将数据写入os cache(操作系统的内存),产生一个segment file文件,buffer清空。
写入os cache的同时,建立倒排索引,这时数据就可以供客户端进行访问了。
默认是每隔1秒refresh一次的,所以es是准实时的,因为写入的数据1秒之后才能被看到。
buffer内存占满的时候也会执行refresh操作,buffer默认值是JVM内存的10%。
通过es的restful api或者java api,手动执行一次refresh操作,就是手动将buffer中的数据刷入os cache中,让数据立马就可以被搜索到。
若要优化索引速度, 而不注重实时性, 可以降低刷新频率。
4)translog会每隔5秒或者在一个变更请求完成之后,将translog从缓存刷入磁盘。
translog是存储在os cache中,每个分片有一个,如果节点宕机会有5秒数据丢失,但是性能比较好,最多丢5秒的数据。。
可以将translog设置成每次写操作必须是直接fsync到磁盘,但是性能会差很多。
可以通过配置增加transLog刷磁盘的频率来增加数据可靠性,最小可配置100ms,但不建议这么做,因为这会对性能有非常大的影响。
5)每30分钟或者当tanslog的大小达到512M时候,就会执行commit操作(flush操作),将os cache中所有的数据全以segment file的形式,持久到磁盘上去。
第一步,就是将buffer中现有数据refresh到os cache中去。
清空buffer 然后强行将os cache中所有的数据全都一个一个的通过segmentfile的形式,持久到磁盘上去。
将commit point这个文件更新到磁盘中,每个Shard都有一个提交点(commit point), 其中保存了当前Shard成功写入磁盘的所有segment。
把translog文件删掉清空,再开一个空的translog文件。
flush参数设置:
index.translog.flush_threshold_period:
index.translog.flush_threshold_size:
#控制每收到多少条数据后flush一次
index.translog.flush_threshold_ops:
6)Segment的merge操作:
随着时间,磁盘上的segment越来越多,需要定期进行合并。
Es和Lucene 会自动进行merge操作,合并segment和删除已经删除的文档。
我们可以手动进行merge:POST index/_forcemerge。一般不需要,这是一个比较消耗资源的操作。

es的分布式查询及相关性算分

es的搜索会分为两步:

query和fetch

第一步,Query

  • 用户发出搜索请求到es节点,该节点会以coordinating节点的身份从每一个分片中选择其主分片或者副分片中的一个,将查询请求发送给他们
  • 被选中的分片会执行查询请求,在本地排序,查询的大小为客户端请求的from+size,然后把文档id和排序值返回给coordinating节点

第二步,Fetch

  • coordinating节点接收到所有的分片的结果后,对每个分片获得的id列表根据算分排序,选取from到from-size的文档id
  • 以multi-get请求的方式,到相应的分片(hash(id)路由)获取到详细的文档数据

存在的问题

  • 性能问题
    • 每个文档都是from+size个,coordinating节点要处理number_of_shard*(from+size),所以当from值越大,查询的压力就越大,所以到深度分页时要慎用
  • 相关性算法不准确
    • 每个分片都是基于自己的分片的数据算的分,排的序,并把排序后的结果返回给coordinating节点,因为没有统一的按照所有数据排序,所以算分会有影响
    • 解决方案:
      • 当数据量小时,使用一个分片;数据量大时:使得数据均匀的在不同的分片上
      • 使用_search?search_type=dfs_query_then_fetch可以让每个分片把各自的词频和文档频率进行收集,然后完整地进行一次相关性算分,但这样对cpu和内存压力会大
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值