ES 集群
携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
1. ES 集群相关概念
单体的 ES 做数据存储,必然面临两个问题:
- 海量数据存储问题:因为业务增长所以查询条件越来越多,索引越来越多。表数据增加,数据拆分越来越复杂。为了搜索精准度所有需要对大体量的数据进行全文搜索,耗时长。
- 单点故障问题:如果 ES 中出现故障,会让整个系统无法运作。
所以我们通过分布式创建 ES 集群解决上述的两个问题:
-
海量数据存储解决方法:将索引库从逻辑上拆分为 N 个分片(shard),存储到多个节点。
我们将所数据分成 8 片
-
单点故障解决方法:将分片数据在不同节点备份(replica)
为了数据可以保证高可用性,我们的每一片分片都需要备份一份。在高可用和成本间寻求平衡,我们考虑是将
- 对数据分片,存储到不同的节点
- 对每个分片进行备份,放在除本节点外的其他节点上,完成互相备份
- 集群(cluster):一组拥有共同的 cluster name 的节点。
- 节点(node):集群中的一个 ES 实例
- 分片(shard):索引拆分为不同的部分进行存储。每一个部分就是一个分片。在集群环境下,一个索引的不同分片可以拆分到不同的节点中。
- 主分片(Primary shard):相对于副本分片的定义
- 副本分片(Replica shard):每个主分片可以有一个或多个副本,数据和主分片一致
2. 集群脑裂问题
2.1 集群职责划分
集群中的节点有不同的职责划分:
节点类型 | 配置参数 | 默认值 | 节点职责 |
---|---|---|---|
master -eligible | node.master | true | 备选主节点:主节点可以管理和记录集群状态、决定分片在哪个节点、处理创建和删除索引库的请求 |
data | node.data | true | 数据节点:存储数据、搜索、聚合、CRUD |
ingest | node.ingest | true | 数据存储之前的预处理 |
coordinating | 上面3个参数都为false则为coordinating节点 | 无 | 路由请求到其他节点,合并其他节点处理的结果返回给用户 |
默认情况下,集群中任何一个节点都同时具有上述的四种角色。
上诉节点职责详解
- 主节点:即 Master -Eligible 节点。主节点的主要职责是和集群操作相关的内容,如创建或删除索引,跟踪哪些节点是群集的一部分,并决定哪些分片分配给相关的节点。稳定的主节点对集群的健康是非常重要的。默认情况下任何一个集群中的节点都有可能被选为主节点。索引数据和搜索查询等操作会占用大量的cpu,内存,io资源,为了确保一个集群的稳定,分离主节点和数据节点是一个比较好的选择。虽然主节点也可以协调节点,路由搜索和从客户端新增数据到数据节点,但最好不要使用这些专用的主节点。一个重要的原则是,尽可能做尽量少的工作。
- 数据节点:即 Data 节点。数据节点主要是存储索引数据的节点,主要对文档进行增删改查操作,聚合操作等。数据节点对 CPU、内存、IO 要求较高,在优化的时候需要监控数据节点的状态,当资源不够的时候,需要在集群中添加新的节点。
- 负载均衡节点:也称作 Coordinating 节点。当一个节点既不配置为主节点,也不配置为数据节点时,该节点只能处理路由请求,处理搜索,分发索引操作等,从本质上来说该客户节点表现为智能负载平衡器。独立的客户端节点在一个比较大的集群中是非常有用的,他协调主节点和数据节点,客户端节点加入集群可以得到集群的状态,根据集群的状态可以直接路由请求。
- 预处理节点:也称作 Ingest 节点,在索引数据之前可以先对数据做预处理操作,所有节点其实默认都是支持 Ingest 操作的,也可以专门将某个节点配置为 Ingest 节点。
如果在现实工作环境中的居群一定将集群职责分离:
- master节点:对CPU要求高,但是内存要求第
- data节点:对CPU和内存要求都高
- coordinating节点:对网络带宽、CPU要求高
职责分离可以让我们根据不同节点的需求分配不同的硬件去部署,而且能避免业务之间的互相干扰。
下面就是一个典型的 es 集群职责划分图:
2.2 脑裂问题
-
什么是脑裂现象
当主节点因负载压力过大或集群环境中的网络问题导致和其他节点的通讯没有及时响应,那么其他节点就会认为主节点宕机并重新选择新主节点。当旧主节点恢复了和其他节点的通讯时,此时整个集群便拥有了两个主节点,这种情况官方称之为“脑裂现象”
例如一个集群中,主节点与其它节点失联:
此时,node2和node3认为node1宕机,就会重新选主:
当node3当选后,集群继续对外提供服务,node2和node3自成集群,node1自成集群,两个集群数据不同步,出现数据差异。
当网络恢复后,因为集群中有两个master节点,集群状态的不一致,出现脑裂的情况:
-
脑裂现象成因
- 网络问题:集群间的网络延迟导致一些节点访问不到master,认为master挂掉了从而选举出新的master,并对master上的分片和副本标红,分配新的主分片。
- 节点负载:主节点的角色既为master又为data,访问量较大时可能会导致ES停止响应造成大面积延迟,此时其他节点得不到主节点的响应认为主节点挂掉了,会重新选取主节点。
- 内存回收:data节点上的ES进程占用的内存较大,引发JVM的大规模内存回收,造成ES进程失去响应。
-
解决方案:
-
角色分离:即master节点与data节点分离,限制角色;数据节点时需要承担存储和搜索的工作的,压力会很大。所以如果该节点同时作为候选主节点和数据节点,那么一旦选上它作为主节点了,这时主节点的工作压力将会非常大,出现脑裂现象的概率就增加了。
-
减少误判:配置主节点的响应时间,在默认情况下,主节点3秒没有响应,其他节点就认为主节点宕机了,那我们可以把该时间设置得长一点,该配置是:discovery.zen.ping_timeout:5
-
选举触发:discovery.zen.minimum_master_nodes:1(默认是1),该属性定义的是为了形成一个集群,有主节点资格并互相连接的节点的最小数目。
要求选票超过 ( eligible节点数量 + 1 )/ 2 才能当选为主,因此eligible节点数量最好是奇数。
-
对应配置项是discovery.zen.minimum_master_nodes,在es7.0以后,已经成为默认配置,因此一般不会发生脑裂问题
3. 集群分布式存储
当新增文档时,应该保存到不同分片,保证数据均衡,那么coordinating node如何确定数据该存储到哪个分片呢?
3.1 分片存储测试
插入三条数据:
测试可以看到,三条数据分别在不同分片:
结果:
3.2 分片存储原理
elasticsearch会通过hash算法来计算文档应该存储到哪个分片:
说明:
- _routing默认是文档的id
- 算法与分片数量有关,因此索引库一旦创建,分片数量不能修改!
新增文档的流程如下:
解读:
- 1)新增一个id=1的文档
- 2)对id做hash运算,假如得到的是2,则应该存储到shard-2
- 3)shard-2的主分片在node3节点,将数据路由到node3
- 4)保存文档
- 5)同步给shard-2的副本replica-2,在node2节点
- 6)返回结果给coordinating-node节点
4. 集群分布式查询
ES 分布式有两种搜索方式:
-
scatter phase:分散阶段,coordinating node会把请求分发到每一个分片
-
gather phase:聚集阶段,coordinating node汇总data node的搜索结果,并处理为最终结果集返回给用户
5. 集群故障转移
集群的master节点会监控集群中的节点状态,如果发现有节点宕机,会立即将宕机节点的分片数据迁移到其它节点,确保数据安全,这个叫做故障转移。
1)例如一个集群结构如图:
现在,node1是主节点,其它两个节点是从节点。
2)突然,node1发生了故障:
宕机后的第一件事,需要重新选主,例如选中了node2:
node2成为主节点后,会检测集群监控状态,发现:shard-1、shard-0没有副本节点。因此需要将node1上的数据迁移到node2、node3: