ElasticSearch之分布式特性
1. ES 分布式特性
ES 支持集群模式,是一个分布式系统,其好处主要有两个:
- 增大系统容量,如内存,磁盘,使得 ES 可以支持 PB 级数据;
- 提高系统可用性,即使部分节点停止服务,整个集群依然可以正常服务。
ES 集群由多个 ES 实例组成,不同集群通过集群名称来区分,可以通过 cluster.name 进行修改,默认为 elastic search;每个 ES 实例实际上是一个 JVM 进程,且有自己的名称,可以通过 node.name 进行修改。
1.1 Cluster State
ES 集群相关的数据称为 cluster state ,主要记录如下信息:节点信息,包括节点名称,连接地址;索引信息,包括索引名称,索引配置。cluster state 存储在每个节点上。
1.2 Master Node
可以修改 cluster state 的节点称为 master 节点,一个集群只能有一个,cluster state 存储在每个节点上,Master 维护最新版本并同步给其他节点。master 节点是通过集群中的所有节点选举产生的,可以被选举的节点称为 master eligible 节点,相关配置为:node.master: true
1.3 Coordinating Node
处理请求的节点被称为 coordinating 节点,该节点为所有节点的默认角色,不能取消,路由请求到正确的节点处理,比如创建索引的请求到 master 节点。
1.4 Data Node
存储数据的节点称为 data 节点,默认所有节点都是 data 节点,相关配置如下:node.data: true
1.5 系统可用性,副本和分片
- 服务可用性,2个节点情况下,允许其中一个节点停止服务;
- 数据可用性,引用副本(replication)解决,使得每个节点上都有完备的数据
1.6 增大系统容量
引用分片(shard)将数据分布在所有节点上,分片是 ES 支持 PB 级数据的基石。分片存储了部分数据,可以分布于任意节点上;分片数在索引创建时指定且后续不允许更改,默认为5个;分片有主分片和副本分片之说,已实现数据的高可用;副本分片的数据由主分片同步,可以有多个,从而提高读取的吞吐量。分片数的设定很重要,需要提前规划好。过小会导致后续无法增加节点实现水平扩容;过大会导致一个节点上分布过多分片,造成资源浪费,同时会影响查询性能。
思考:
- 此时增加节点能否提高索引 test_index 的数据容量?
答:不能,因为只有三个分片,已经分布在三个节点上,新增的节点无法利用。
- 此时增加副本数能否提高索引 test_index 的读取吞吐量?
答:不能,因为新增的副本也是分布在这三台节点上,还是利用了同样的资源,如要增加吞吐量,还要增加节点。
1.7 Cluster Health
通过如下 API 可以查看集群健康状态,包括以下三种:
- green:健康状态,所有主副分片都正常分配;
- yellow:所有主分配都正常分配,但是有副分配未正常分配;
- red:有主分配未分配。
GET _cluster/health
1.8 故障转移
- 集群由三个节点组成,如图一所示,此时集群状态是 green;
- node1 所在机器宕机导致服务终止,此时集群会如何处理?
a. node2 和 node3 发现 node1 无法响应一段时间后会发起 master 选举,此时这里选择 node2 为 master 节点,此时由于主分片 P0 下线,集群状态变为 red (图二);
b. node2 发现主分片 P0 未分配,将 R0 提升为主分片,此时由于所有主分配都正常分配,集群状态变为 yellow(图三);
c. node2 为 P0 和 P1 生成新的副本,集群状态变为 green (图四);
1.9 文档分布式存储
上图中,文档是如何存储到分配 P1 的?选择 P1 的依据是什么?
其实,文档如何存储到分配上是需要文档到分配的映射算法,这样才能使得文档均匀的分布在所有分片上,以充分利用资源。对于算法的选择是否可以为随机选择或是 round-robin 算法呢?显然这两种算法都是不可取的,因为需要维护文档到分配之间的映射关系,成本巨大,可选的算法应该是根据文档值实时的计算对应的分片。
ES 通过如下的算法计算文档对应的分片:
shard = hash(routing) % numbers_of_primary_shards
- hash 算法可以保证将文档均匀的分散在分片中;
- routing 是一个关键参数,默认为文档 ID,也可以自行指定;
- numbers_of_primary_shards 为主分片数。
1.10 文档的创建与读取流程
a. 文档的创建流程
b. 文档的读取流程
c. 文档批量创建流程
d. 文档批量读取流程
1.11 脑裂问题
脑裂问题,英文为:split-brain,是分布式系统中的经典问题,如下图所示:
- node1 因网络原因,无法与 node2 和 node3 进行通信;
- node2 和 node3 会从新选举 master,比如 node2 成为新的 master,此时会更新 cluster state;
- node1 自己组成集群后,也会更新 cluster state。
同一个有两个 master,而且维护不通的 cluster state,网络恢复后无法选择正确的 master。
解决方案:
在可选举 master-eligible 节点数大于等于 quorum 时才可以进行 master 选举。
- quorum = master-eligible 节点数 / 2 + 1,例如3个 master-eligible 节点时,quorum = 2;
- 设定 discrovery.zen.minimum_master.nodes 即可避免脑裂问题。
1.12 倒排索引的不可变更
倒排索引一旦生成,不能更改,其好处有:
- 不用考虑并发写文件的问题,杜绝了锁机制带来的性能问题;
- 由于文件不再更改,可以充分利用文件系统缓存,只需载入一次,只要内存足够,对该文件的读取都是从内存读取,性能高;
- 利于生成缓存数据;
- 利于对文件进行压缩存储,节省硬盘和内存存储空间;
其坏处为需要写入新文档时,必须重新构建倒排索引文件,然后替换老文件,新文档才能被索引,导致文档实时性差。解决方案为新文档直接生成新的倒排索引文件,查询时同时查询所有的倒排索引文件,然后做结果的汇总计算即可。
1.13 文档搜索实时性
新文档直接生成新的倒排索引文件,搜索的时候查询所有的索引文件即可。
Lucene 便是采用了这种方案,它构建的单个倒排索引称为 segment,合在一起称为 Index,与 ES 的 Index 概念不同,ES 的一个 shard 对应 Lucene Index,Lucene 会有一个专门的文件来记录所有的 segment 信息,称为 commit point。
文档搜索实时性 - refresh
segment 写入磁盘的过程依然很耗时,可以借助文件系统缓存的特性,现将 segment 在缓存中创建并开放查询来进一步提高实时性,该过程在 ES 里面称为 refresh。
在 refresh 之前文档会先存储在一个 buffer 中,refresh 时将 buffer 中的所有文档清空并生成 segment。
ES 默认每1秒执行一次 refresh,因此文档的实时性提高到1秒,这也是 ES 被称为近实时(Near real time)的原因。
refresh 发生的时机主要有以下几种情况:
- 间隔时机到达时,通过 index.setting.refresh.interval 来设定;
- index buffer 占满时,其大小通过 indices.memory.index_buffer.size 设置,默认为 JVM heap 的 10%,所有 shard 共享;
- flush 发生时也会触发 refresh。
文档搜索实时性 - translog
如果在内存中的 segment 还没有写入磁盘前发生宕机,那么其中的文档就无法恢复了,ES 为了解决这个问题,引入了 translog 机制。
- 写入文档到 buffer 时,同时将该操作写入 translog ;
- translog 会即时写入到磁盘(fsync),6.X 默认每个请求都会落盘,可以修改为每5秒写一次,这样的风险便是会丢失5秒的数据,相关配置为:index.translog.*;
- ES 会在启动时检查 translog 文件,并从中恢复数据。
文档搜索实时性 - flush
flush 负责将内存中 segment 写入到磁盘,主要做如下的工作:
- 将 translog 写入磁盘;
- 将 index buffer 清空,其中的文档生成一个新的 segment,相当于一个 refresh 操作;
- 更新 commit point 并写入磁盘;
- 执行 fsync 操作,将内存中的 segment 写入到磁盘;
- 删除旧的 translog 文件。
flush 发生的时机主要有以下几种情况:
- 间隔时机到达,默认时 30 分钟,5.X 之前可以通过 index.translog.flush_threshold_period 修改,之后无法修复;
- translog 占满时,其大小可以通过 index.translog.flush_threshold_size 控制,默认 512 MB,每个 index 都有自己的 translog。
文档搜索实时性 - 删除与更新文档
segment 一旦生成就不能更改,那么要删除文档该如何操作呢?更新文档又该如何操作呢?
a. Lucene 专门维护一个 .del 文件,记录所有已经删除的文档,注意 .del 文档上记录的是文档在 Lucene 内部记录的 ID;在查询结果返回前会过滤掉 .del 中的所有文档
b. 更新文档时,会首先删除文档,然后创建新的文档。
1.14 Segment merge
随着 segment 的增多,由于一次查询的 segment 的数量增多,查询速度会变慢;ES 会定时在后台进行 segment merge 的操作,减少 segment 的数量;通过 force_merge API 可以手动强制做 segment merge 的操作。
1.15 ES Index VS Lucene Index
上一篇: js检测浏览器版本方法
下一篇: $_GET和$_POST的提交方式
推荐阅读
-
Elasticsearch篇之Search API介绍
-
ElasticSearch之分布式特性
-
MySQL5.6新特性之Multi-Range Read
-
ThinkPHP3.1新特性之Action参数绑定_PHP教程
-
Angular 入门教程系列:23:Angular 6新特性之Angular Material
-
云计算一周热文回顾:NoSQL数据库技术特性解析之文档数据库
-
java8新特性之接口的static和default的使用
-
ThinkPHP3.1新特性之命名范围的使用_PHP
-
ThinkPHP3.1新特性之字段合法性检测详解
-
JDK1.6“新“特性Instrumentation之JavaAgent(推荐)