hi,我是蛋挞,一个初出茅庐的后端开发,希望可以和大家共同努力、共同进步!
开启掘金成长之旅!这是我参与「掘金日新计划 · 4 月更文挑战」的第 1 天,点击查看活动详情
- 起始标记->分布式特性及分布式搜索的机制(8讲):「37 | 集群分布式模型及选主与脑裂问题」
- 结尾标记->分布式特性及分布式搜索的机制(8讲):「40 | 分片及其生命周期」
集群分布式模型及选主与脑裂问题
分布式特性
- Elasticsearch 的分布式架构带来的好处
- 存储的水平扩容,支持 PB 级数据0
- 提高系统的可用性,部分节点停止服务,整个集群的服务不受影响
- Elasticsearch 的分布式架构
- 不同的集群通过不同的名字来区分,默认名字“elasticsearch”
- 通过配置文件修改,或者在命令行中 -E cluster.name=geektime 进行设定
节点
- 节点是一个 Elasticsearch 的实例
- 其本质上就是一个 JAVA 进程0
- 一台机器上可以运行多个 Elasticsearch 进程,但是生产环境一般建议一台机器上就运行一个 Elasticsearch 实例
- 每一个节点都有名字,通过配置文件配置,或者启动时候 -E node.name=geektime 指定
- 每一个节点在启动之后,会分配一个 UID,保存在 data 目录下
Coordinating Node
- 处理请求的节点,叫 Coordinating Node
- 路由请求到正确的节点,例如创建索引的请求,需要路由到 Master节点
- 所有节点默认都是 Coordinating Node
- 通过将其他类型设置成 False,使其成为 Dedicated Coordinating Node
Demo - 启动节点,Cerebro 介绍
- 启动一个节点的
- bin/elasticsearch -E nodename=node1 -E cluster.name=geektime -E pathdata=node1_data -Ehttp.port=9200
- github.com/menezes/cer…
- Overview /Filter by node /index
- Nodes
- REST / More
- Health Status
Data Node
- 可以保存数据的节点,叫做 Data Node
- 节点启动后,默认就是数据节点。可以设置 node.data: false 禁止
- Data Node的职责
- 保存分片数据。在数据扩展上起到了至关重要的作用 (由 Master Node 决定如何把 分片分o发到数据节点上)
- 通过增加数据节点
- 可以解决数据水平扩展和解决数据单点问题
Master Eligible Nodes & 选主流程
- 一个集群,支持配置多个 Master Eligible 节点。这些节点可以在必要时(如 Master 节点出现故障,网络故障时)参与选主流程,成为 Master 节点
- 每个节点启动后,默认就是一个 Master eligible 节点
- 可以设置 node.master: false 禁止
- 当集群内第一个 Master eligible 节点启动时候,它会将自己选举成 Master 节点
Master Eligible Nodes & 选主的过程
- 互相 Ping 对方,**Node ld **低的会成为被选举的节点
- 其他节点会加入集群,但是不承担 Master 节点的角色。一旦发现被选中的主节点丢失就会选举出新的 Master 节点
脑裂问题
- Split-Brain,分布式系统的经典网络问题,当出现网络问题,一个节点和其他节点无法连接
- Node 2 和 Node 3 会重新选举 Master
- Node 1自己还是作为 Master,组成一个集群,同时更新 Cluster State
- 导致 2个 master,维护不同的 cluster state。当网络恢复时,无法选择正确恢复网络断开
如何避免脑裂问题
- 限定一个选举条件,设置 quorum(仲裁),只有在 Master eligible 节点数大于 quorum 时,才能进行选举
- Quorum = (master 节点总数 /2) +1
- 当3个master eligible 时,设置 discovery.zen.minimum_master_nodes 为 2,即可避免脑裂
- 从7.0开始,无需这个配置
- 移除 minimum_master_nodes 参数,让Elasticsearch自己选择可以形成仲裁的节点
- 典型的主节点选举现在只需要很短的时间就可以完成。集群的伸缩变得更安全、更容易,并且可能造成丢失数据的系统配置选项更少了。
- 节点更清楚地记录它们的状态,有助于诊断为什么它们不能加入集群或为什么无法选举出主节点
配置节点类型
一个节点默认情况下是一个Master eligible,data and ingest node:
CodeDemo
bin/elasticsearch -E node.name=node1 -E cluster.name=geektime -E path.data=node1_data bin/elasticsearch -E node.name=node2 -E cluster.name=geektime -E path.data=node2_data bin/elasticsearch -E node.name=node3 -E cluster.name=geektime -E path.data=node3_data
相关阅读
本节知识回顾
本节主要对Elasticsearch分布式的特性做了讲解,构建了一个单节点的集群,同时对它创建了一个索引,因为该索引是一个副本分片,因为导致副本分片无法进行分配集群变黄,通过增加一个数据节点解决了这个无法分配的问题,同时也对Elasticsearch Master节点脑裂的问题做了简单的讲诉。
分片与集群的故障转移
Primary Shard - 提升系统存储容量
- 分片是 Elasticsearch 分布式存储的基石
- 主分片 /副本分片
- 通过主分片,将数据分布在所有节点上
- Primary Shard,可以将一份索引的数据,分散在多个 Data Node 上,实现存储的水平扩展
- 主分片(Primary Shard)数在索引创建时候指定,后续默认不能修改,如要修改,需重建索引
Replica Shard -提高数据可用性
- 数据可用性
- 通过引入副本分片(Replica Shard) 提高数据的可用性。一旦主分片丢失,副本分片可以 Promote 成主分片。副本分片数可以动态调整。每个节点上都有完备的数据。如果不设置副本分片,一旦出现节点硬件故障,就有可能造成数据丢失
- 提升系统的读取性能
- 副本分片由主分片(Primary Shard)同步。通过支持增加 Replica 个数,一定程度可以提高读取的吞吐量
分片数的设定
- 如何规划一个索引的主分片数和副本分片数
- 主分片数过小:例如创建了1个 Primary Shard 的index
- 如果该索引增长很快,集群无法通过增加节点实现对这个索引的数据扩展
- 主分片数过小:例如创建了1个 Primary Shard 的index
- 主分片数设置过大: 导致单个 Shard 容量很小,引发一个节点上有过多分片,影响性能
- 副本分片数设置过多,会降低集群整体的写入性能
单节点集群
- 副本无法分片,集群状态黄色
增加一个数据节点
- 集群状态转为绿色
- 集群具备故障转移能力
- 尝试着将 Replica 设置成 2 和 3查看集群的状况
再增加一个数据节点
- 集群具备故障转移能力
- Master 节点会决定分片分配到哪个节点
- 通过增加节点,提高集群的计算能力
故障转移
- 3 个节点共同组成。包含了 1个索引,索引设置了3个Primary Shard 和1个 Replica
- 节点1是Master 节点,节点意外出现故障。集群重新选举Master 节点
- Node 3上的 RO 提升成 PO,集群变黄
- RO和R1分配,集群变绿
集群健康状态
Green:健康状态,所有的主分片和副本分片都可用Green:
Yellow: 亚健康,所有的主分片可用,部分副本分片不可用
Red: 不健康状态,部分主分片不可用
本节知识回顾
回顾了主分片和副本分片的作用,同时讲解了elasticsearch是如何做一个故障转移的,通过实例演示了当es出现节点丢失的时候是怎么样通过故障转移的方式保证了这个数据不会丢失。
文档分布式存储
文档存储在分片上
- 文档会存储在具体的某个主分片和副本分片上: 例如 文档1,会存储在 PO和 RO分片上
- 文档到分片的映射算法
- 确保文档能均匀分布在所用分片上,充分利用硬件资源,避免部分机器空闲,部分机器繁忙
- 潜在的算法
- 随机/ Round Robin。当查询文档 1,分片数很多,需要多次查询才可能查到 文档1
- 维护文档到分片的映射关系,当文档数据量大的时候,维护成本高
- 实时计算,通过文档1,自动算出,需要去那个分片上获取文档
文档到分片的路由算法
- shard = hash(_routing)% number_of_primary_shards
- Hash 算法确保文档均匀分散到分片中
- 默认的_routing 值是文档 id
- 可以自行制定 routing数值,例如用相同国家的商品,都分配到指定的 shard
- 设置 Index Settings 后, Primary 数,不能随意修改的根本原因
更新一个文档
删除一个文档
本节知识回顾
介绍了elasticsearch文档和分片的路由算法,更新和删除文档大概会经过那些步骤。
分片及其生命周期
分片的内部原理
- 什么是 ES 的分片
- ES中最小的工作单元/是一个 Lucene 的index
- 一些问题
- 为什么 ES的搜索是近实时的(1 秒后被搜到)
- ES如何保证在断电时数据也不会丢失
- 为什么删除文档,并不会立刻释放空间
倒排索引不可变性
- 倒排索引采用 Immutable Design,一旦生成,不可更改
- 不可变性,带来了的好处如下:
- 无需考虑并发写文件的问题,避免了锁机制带来的性能问题
- 一旦读入内核的文件系统缓存,便留在哪里。只要文件系统存有足够的空间,大部分请求就会直接请求内存,不会命中磁盘,提升了很大的性能
- 缓存容易生成和维护/数据可以被压缩
- 不可变更性,带来了的挑战: 如果需要让一个新的文档可以被搜索,需要重建整个索引。
Lucene Index
- 在 Lucene 中,单个倒排索引文件被称为Segment。Segment 是自包含的,不可变更的多个 Segments 汇总在一起,称为 Lucene 的Index,其对应的就是ES 中的 Shard
- 当有新文档写入时,会生成新 Segment,查询时会同时查询所有 Segments,并且对结果汇总。Lucene 中有一个文件,用来记录所有Segments 信息,叫做 Commit Point
- 删除的文档信息,保存在“.del”文件中
什么是 Refresh
- 将Index buffer 写入 Segment 的过程叫Refresh。Refresh 不执行 fsync 操作
- Refresh 频率:默认1秒发生一次,可通过index.refresh interval 配置。Refresh 后数据就可以被搜索到了。这也是为什么Elasticsearch 被称为近实时搜索
- 如果系统有大量的数据写入,:那就会产生很多的 Segment
- Index Buffer 被占满时,会触发 Refresh,默认值是JVM的10%
什么是 Transaction Log
- Segment 写入磁盘的过程相对耗时,借助文件系统缓存,Refresh 时,先将Segment 写入缓存以开放查询
- 为了保证数据不会丢失。所以在 index 文档时,同时写 Transaction Log,高版本开始,Transaction Log 默认落盘。每个分片有一个 Transaction Log
- 在 ES Refresh 时,Index Buffer 被清空Transaction log 不会清空
什么是 Flush
- ES Flush & Lucene Commit
- 调用 Refresh,Index Buffer 清空并且 Refresh
- 调用 fsync,将缓存中的 Segments写入磁盘
- 清空(删除) Transaction Log
- 默认 30 分钟调用一次
- Transaction Log 满 (默认 512 MB)
Merge
- Segment 很多,需要被定期被合并
- 减少 Segments / 删除已经删除的文档
- ES 和 Lucene 会自动进行 Merge 操作
- POST my_index/_forcemerge
本节知识回顾
介绍了Elasticsearch分片,本质就是Lucene的index,在Lucene的index当中包含了很多的Segments,Segments是通过一个Commit Point来做记录的,Elasticsearch在删除一个文档过后并不是立刻将文档删除,而是会把相应的信息记录到.del的文件当中,es在文档写入的时候会先把文档写入到一个indexbuff当中然后定期触发refalsh,使得文档进入Segments变得被搜索,了解了什么是refalsh、falsh,如何通过 Merge对文件进行合并。
此文章为4月Day1学习笔记,内容来源于极客时间《Elasticsearch 核心技术与实战》