Elasticsearch原理架构分析


一 简介

学习es之前,可以看一下es的官方文档:https://www.elastic.co/guide/cn/elasticsearch/guide/current/intro.html
在我们使用es的时候,我们首先要明白,elasticsearch是一个开源分布式的搜索引擎,开源是es使用java的技术,底层基于Lucence做索引和存储而建立的搜索引擎框架,目前的开源地址github:elasticsearch,分布式是es的集群部署支持水平扩展,能够基于选主和发现的策略对于集群内部的节点进行整合,并提供高性能的数据搜索服务

二 Elasticsearch基础理论

1,elasticsearch的集群架构(分布式的集群架构设计)

空集群
在这里插入图片描述
空集群是集群的节点中只含有一个节点数的集群部署策略,当集群的节点只含有一个,即该节点为主节点,所有的索引分片都是会部署到该节点上,如果索引的分片策略设置副本数时,此时的集群节点健康状况是会出现yellow状态,即副本的数据不可用,实际上,副本分片都是unassigned-它们都没有被分配到任何节点
多节点集群
在这里插入图片描述
多节点集群实际上是内部可通信的局域网中含有相同cluster.name配置的节点组合而成,他们共同承担数据和负载的压力,当有节点加入的时候或集群节点移除的时候,集群将会重新的平均分配所有的数据压力,如上图,某一个索引blogs的索引分配策略配置如下:

PUT /blogs
{
   "settings" : {
      "number_of_shards" : 3,
      "number_of_replicas" : 1
   }
}

即该索引会生成三个主分片,每一个分片含有一个副本,即六个分片数据,实际上会均匀的分片在对应的节点上

2,elasticsearch选主和发现策略

分布式的系统场景中,最重要的一个问题就是节点之间的选主和发现机制,比如在kafka中,实际上依赖的是zookeeper集群的选举策略,但是在es中,并没有引入第三方的分布式协调服务类的选举服务,而是基于内部的实现策略,这样的好处是部署服务的成本和复杂度降低了,不用预先依赖一个服务发现的集群,缺点当然是将复杂度带入了 Elasticsearch 内部。
服务发现以及选主:ZenDiscovery
  1,节点启动后先ping(这里的ping是 Elasticsearch 的一个RPC命令。如果 discovery.zen.ping.unicast.hosts 有设置,则ping设置中的host,否则尝试ping localhost 的几个端口, Elasticsearch 支持同一个主机启动多个节点)
  2,Ping的response会包含该节点的基本信息以及该节点认为的master节点。
  3,选举开始,先从各节点认为的master中选,规则很简单,按照id的字典序排序,取第一个。
  4,如果各节点都没有认为的master,则从所有节点中选择,规则同上。这里有个限制条件就是 discovery.zen.minimum_master_nodes,如果节点数达不到最小值的限制,则循环上述过程,直到节点数足够可以开始选举。
  5,最后选举结果是肯定能选举出一个master,如果只有一个local节点那就选出的是自己。
  6,如果当前节点是master,则开始等待节点数达到 minimum_master_nodes,然后提供服务。
  7,如果当前节点不是master,则尝试加入master。

Elasticsearch 将以上服务发现以及选主的流程叫做 ZenDiscovery 。由于它支持任意数目的集群(1-N),所以不能像 Zookeeper/Etcd 那样限制节点必须是奇数,也就无法用投票的机制来选主,而是通过一个规则,只要所有的节点都遵循同样的规则,得到的信息都是对等的,选出来的主节点肯定是一致的。但分布式系统的问题就出在信息不对等的情况,这时候很容易出现脑裂(Split-Brain)的问题,大多数解决方案就是设置一个quorum值,要求可用节点必须大于quorum(一般是超过半数节点),才能对外提供服务。而 Elasticsearch 中,这个quorum的配置就是 discovery.zen.minimum_master_nodes 。

3,elasticsearch的Shard Allocation策略

腾讯云的解析介绍

4,elasticsearch的写数据的过程

1,客户端选择一个 node 发送请求过去,这个 node 就是 coordinating node(协调节点)。
2,协调节点对document(文档)进行路由,将请求转发给对应的node(有primary shard)
  路由算法:shard = hash(routing) % number_of_primary_shards
3,实际的node上的primary shard处理请求,然后将数据同步倒replica node
4,协调节点如果发现primary shard和所有的replica shard都搞定的时候,就返回响应结果给客户端
在这里插入图片描述
写操作的底层原理
在这里插入图片描述
1,先写入内存 buffer,在 buffer 里的时候数据是搜索不到的;同时将数据写入 translog 日志文件。
2,如果 buffer 快满了,或者到一定时间,就会将内存 buffer 数据 refresh 到一个新的 segment file 中,但是此时数据不是直接进入 segment file 磁盘文件,而是先进入 os cache 。这个过程就是 refresh。
3,每隔 1 秒钟,es 将 buffer 中的数据写入一个新的 segment file,每秒钟会产生一个新的磁盘文件 segment file,这个 segment file 中就存储最近 1 秒内 buffer 中写入的数据。
4,但是如果 buffer 里面此时没有数据,那当然不会执行 refresh 操作,如果 buffer 里面有数据,默认 1 秒钟执行一次 refresh 操作,刷入一个新的 segment file 中。
操作系统里面,磁盘文件其实都有一个东西,叫做 os cache,即操作系统缓存,就是说数据写入磁盘文件之前,会先进入 os cache,先进入操作系统级别的一个内存缓存中去。只要 buffer中的数据被 refresh 操作刷入 os cache中,这个数据就可以被搜索到了。
为什么叫 es 是准实时的? NRT,全称 near real-time。默认是每隔 1 秒 refresh 一次的,所以 es 是准实时的,因为写入的数据 1 秒之后才能被看到。可以通过 es 的 restful api 或者 java api,手动执行一次 refresh 操作,就是手动将 buffer 中的数据刷入 os cache中,让数据立马就可以被搜索到。只要数据被输入 os cache 中,buffer 就会被清空了,因为不需要保留 buffer 了,数据在 translog 里面已经持久化到磁盘去一份了。

重复上面的步骤,新的数据不断进入 buffer 和 translog,不断将 buffer 数据写入一个又一个新的 segment file 中去,每次 refresh 完 buffer 清空,translog 保留。随着这个过程推进,translog 会变得越来越大。当 translog 达到一定长度的时候,就会触发 commit 操作。

commit 操作发生第一步,就是将 buffer 中现有数据 refresh 到 os cache 中去,清空 buffer。然后,将一个 commit point写入磁盘文件,里面标识着这个 commit point 对应的所有 segment file,同时强行将 os cache 中目前所有的数据都 fsync 到磁盘文件中去。最后清空 现有 translog 日志文件,重启一个 translog,此时 commit 操作完成。

这个 commit 操作叫做 flush。默认 30 分钟自动执行一次 flush,但如果 translog 过大,也会触发 flush。flush 操作就对应着 commit 的全过程,我们可以通过 es api,手动执行 flush 操作,手动将 os cache 中的数据 fsync 强刷到磁盘上去。

translog 日志文件的作用是什么?你执行 commit 操作之前,数据要么是停留在 buffer 中,要么是停留在 os cache 中,无论是 buffer 还是 os cache 都是内存,一旦这台机器死了,内存中的数据就全丢了。所以需要将数据对应的操作写入一个专门的日志文件 translog 中,一旦此时机器宕机,再次重启的时候,es 会自动读取 translog 日志文件中的数据,恢复到内存 buffer 和 os cache 中去。

translog 其实也是先写入 os cache 的,默认每隔 5 秒刷一次到磁盘中去,所以默认情况下,可能有 5 秒的数据会仅仅停留在 buffer 或者 translog 文件的 os cache 中,如果此时机器挂了,会丢失 5 秒钟的数据。但是这样性能比较好,最多丢 5 秒的数据。也可以将 translog 设置成每次写操作必须是直接 fsync 到磁盘,但是性能会差很多。

实际上你在这里,如果面试官没有问你 es 丢数据的问题,你可以在这里给面试官炫一把,你说,其实 es 第一是准实时的,数据写入 1 秒后可以搜索到;可能会丢失数据的。有 5 秒的数据,停留在 buffer、translog os cache、segment file os cache 中,而不在磁盘上,此时如果宕机,会导致 5 秒的数据丢失。

总结一下,数据先写入内存 buffer,然后每隔 1s,将数据 refresh 到 os cache,到了 os cache 数据就能被搜索到(所以我们才说 es 从写入到能被搜索到,中间有 1s 的延迟)。每隔 5s,将数据写入 translog 文件(这样如果机器宕机,内存数据全没,最多会有 5s 的数据丢失),translog 大到一定程度,或者默认每隔 30mins,会触发 commit 操作,将缓冲区的数据都 flush 到 segment file 磁盘文件中。
引至:es写入数据底层原理

5,elasticsearch的读数据的过程

可以通过 doc id 来查询,会根据 doc id 进行 hash,判断出来当时把 doc id 分配到了哪个 shard 上面去,从那个 shard 去查询
1,客户端发送请求到任意一个 node,成为 coordinate node。
2,coordinate node 对 doc id 进行哈希路由,将请求转发到对应的 node,此时会使用 round-robin随机轮询算法,在 primary shard 以及其所有 replica 中随机选择一个,让读请求负载均衡。
3,接收请求的 node 返回 document 给 coordinate node。
4,coordinate node 返回 document 给客户端。

6,elasticsearch倒排序和DocValues,Fileddata

elasticsearch底层使用的是lucence,elasticsearch会为每一个索引中的字段建立一个倒排索引(value-index)倒排索引以字或词为关键字进行索引,表中关键字所对应的记录项记录了出现这个字或词的所有文档
DocValues:本质上是一个序列化的列式存储,这个结构非常适用于聚合(aggregations)、排序(Sorting)、脚本(scripts access to field)等操作。而且,这种存储方式也非常便于压缩,特别是数字类型。这样可以减少磁盘空间并且提高访问速度(不支持analyzed的字符串)
Fileddata:与 doc values 不同,fielddata 构建和管理 100% 在内存中,常驻于 JVM 内存堆。
引入:elasticsearch倒排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值