Elasticsearch学习之路(4)机制原理

我们今天了解一下机制原理,内部是如何运行的,主分片和副本分片是如何同步的?创建索引的流程,es如何将索引数据分配到不同的分片上?索引数据是如何存储的,es是如何保证更新被持久化在断电时候也不丢失数据的,为什么删除文档不会立刻释放空间?

索引原理

上面描述了三个节点的集群,共拥有12个分片,其中有4个主分片(s0,s1,s2,s3)和8个副本分片(r0,r1,r2,r3),每个主分片对应两个副本分片,节点1是主节点Master节点,负责整个集群的状态。

写索引只能写在主分片上,然后同步到副本分片,这里有四个主分片,一条数据ES是根据什么规则写到特定的分片上的呢?这条索引数据为什么被写道S0上而不是写到s1,s2上?

首先这肯定不是随机的,否则将来获取文档的时候就不知道从何处寻找了,实际上,这个过程是根据下面这个公式决定的。

shard = hash(routing) % number_of_primary_shards

routing是一个可变值,默认是文档的_id,也可以设置成一个自定义的值,routing通过hash函数生成一个数字,然后这个数字对number_of_primary_shards取余,这个在0到numberofprimary_shards-1之间的余数,就是我们所寻求的文档所在分片的位置

这就解释了为什么我们要在创建索引的时候就确定好主分片的数量并且永远不会改变这个数量,因为如果数量变化了,所有之前路由的值都会无效,文档也就找不到了,由于在es集群中每个节点通过上面的计算公式都知道集群中的文档的存放位置,所以每个节点都有处理读写请求的能力,在一个写请求被发送到某个节点后,该节点即为前面说过的协调节点,协调节点会根据路由公式计算出需要写道哪个分片上,再将请求转发到该分片的主分片节点上。具体l流程:

假如此时数据通过路由计算公式取余后得到的值是 shard = hash(routing) % 4 = 0,

1.客户端向ES1节点发送写请求,通过路由计算公式得到值为0,则当前数据应被写道主分片s0上,

2es1节点将请求转发到s0主分片所在的节点es3,es3接受请求并写入到磁盘,

3并发将数据复制到两个副本分片R0上,其中通过乐观并发空值数据的冲突,一旦所有的副本分片都报告成功,则节点es3将向协调节点报告成功,协调节点向客户端报告成功.

存储原理

上面介绍了es内部索引的写处理流程,这个流程是在ES内存中执行的,数据被分配到特定的分片和副本上之后,最终是存储到磁盘上的,这样在断电的时候就不会丢失数据,具体的存储路径在配置文件../config/elasticsearch.yml中进行配置,默认存储在安装目录的data文件夹下,建议不要使用默认值,因为如果ES畸形了升级,可能造成数据全部丢失

path.data: /path/to/data  //索引数据

path.logs: /path/to/logs  //日志记录

分段存储

索引文档以段的形式存储在磁盘上,什么叫段?索引文件被拆分为多个子文件,则每个子文件叫做段,每一个段本身都是一个倒排索引,并且段具有不确定性,一旦索引的数据被写入硬盘就不可以再修改,在底层采用了分段的储存模式,使它在读写时几乎完全避免了锁的出现,大大提高了性能。

段被写入到磁盘会生成一个提交点,提交点时一个用来记录所有提交后端信息的文件,一个段一旦拥有了提交点,就说明这个段只有读的权限,失去了写的权限,相反,当段在内存中时,就只有写的权限,而不具备读数据的权限,意味着不能被检索。

为什么会有段的概念呢?是因为在早期全文检索中为了整个文档集合建立了一个很大的倒排索引,并将其写入磁盘中,如果索引有更新,就需要重新全量创建一个索引来替换原来的索引,这种方式在数据量很大的时候效率很低,并且由于创建一次索引的成本很高,所以多数据的更新不能过于频繁,也就不能保证时效性。

索引文件分段存储并且不可修改,那么新增,更新和删除如何处理呢?

新增,由于数据时新的,所以只需要对当前文档新增一个段就可以了。

删除  由于不可修改,所以对于删除操作,不会把文档从旧的段中移除,二十通过新增一个.del文件,文件中会列出这些被删除文档的段信息,这个被标记删除的文档仍然可以被查群匹配到,但他会在最终结果被返回前从结果集中移除

更新  不能将修改旧的段来进行反应文档的更新,其实更新相当于时删除和新增这两个动作的组合,会将就得文档在.del文件中编辑删除,然后文档的新版本被所引导一个新的段中,可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前就会被移除

段被设定为不可修改具有一定的优势,也有一定的缺点

优点:

不需要锁,如果你从来不更新索引,就不需要担心多进程同时修改数据的问题

一旦索引被读入内核的文件系统缓存中,便会留在那里,由于不变性,只要文件系统缓存中还有足够的空间,那么大部分读请求会直接请求内存,而不会兵种磁盘,提高了性能。

其他缓存在索引的生命周期内始终有效,他们不需要再每次数据改变时被重建,因为数据不会变化

写入单个大的倒排索引允许数据被压缩,减少磁盘I/O和需要被缓存到内存的索引的使用量

缺点:

当对旧数据进行删除时,旧数据不会马上被删除,而在时.del文件中被标记未删除,而旧数据只能等到段更新时才会被移除,这样会造成大量的空间浪费

如果有一条数据频繁更新,每次更新都是新增新的标记旧的,则会有大量的空间房费,每次刑责数据时都需要新增一个段来存储数据,当段的数量太多时,对服务器的资源例如文件句柄的消耗会非常大

查询时候会优先排除被标记删除的旧数据,增加了查询的负担。

延迟写策略

每当有新增的数据时,就将其先写入到内存中,在内存和磁盘之间是文件系统缓存,当达到默认的时间(1秒钟)或者内存的数据达到一定量时,会触发一次刷新(Refresh),将内存中的数据生成到一个新的段上并缓存到文件缓存系统 上,稍后再被刷新到磁盘中并生成提交点

这里的内存使用的是ES的JVM内存,而文件缓存系统使用的是操作系统的内存。新的数据会继续的被写入内存,但内存中的数据并不是以段的形式存储的,因此不能提供检索功能。由内存刷新到文件缓存系统的时候会生成了新的段,并将段打开以供搜索使用,而不需要等到被刷新到磁盘。

在 Elasticsearch 中,写入和打开一个新段的轻量的过程叫做 refresh (即内存刷新到文件缓存系统)。默认情况下每个分片会每秒自动刷新一次。这就是为什么我们说 Elasticsearch 是近实时搜索,因为文档的变化并不是立即对搜索可见,但会在一秒之内变为可见。我们也可以手动触发 refresh, POST/_refresh 刷新所有索引, POST/nba/_refresh刷新指定的索引。

虽然通过延时写的策略可以减少数据往磁盘上写的次数提升了整体的写入能力,但是我们知道文件缓存系统也是内存空间,属于操作系统的内存,只要是内存都存在断电或异常情况下丢失数据的危险。

为了避免丢失数据,Elasticsearch添加了事务日志(Translog),事务日志记录了所有还没有持久化到磁盘的数据。添加了事务日志后整个写索引的流程如下:

  • 一个新文档被索引之后,先被写入到内存中,但是为了防止数据的丢失,会追加一份数据到事务日志中。不断有新的文档被写入到内存,同时也都会记录到事务日志中。这时新数据还不能被检索和查询。

  • 当达到默认的刷新时间或内存中的数据达到一定量后,会触发一次 refresh,将内存中的数据以一个新段形式刷新到文件缓存系统中并清空内存。这时虽然新段未被提交到磁盘,但是可以提供文档的检索功能且不能被修改。

  • 随着新文档索引不断被写入,当日志数据大小超过512M或者时间超过30分钟时,会触发一次 flush。内存中的数据被写入到一个新段同时被写入到文件缓存系统,文件系统缓存中数据通过 fsync 刷新到磁盘中,生成提交点,日志文件被删除,创建一个空的新日志。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值