• 常见组件的集群原理(Redis、ES、NSQ)


    今天发现大家对NSQ等组件的集群原理还不了解,所以这遍文章对一些常见组件的集群原理做一个汇总整理。我会不定期更新,增加一些新的组件或修改错误。

    1 NSQ

    NSQ集群比较简单,主要包含4个部分,一是生产者(图上没画)、二是nsq实例(nsqd)、三是服务发现nsqlookupd、四是消费者(Comsumer)。
    这4个部分的工作方式如下:

    1. 生产者
    • 生产者需要指定将消息写入哪个实例nsqd
    • 当一个nsqd实例宕机时,生产者可以选择将消息写到其他的实例
    • 生产者也可以将同一条消息写入两个nsqd(HA)
    1. nsqd
    • 消息不会在nsqd之间传递,生产者把消息写到哪个nsqd就只能在该nsqd消费
    • 不同的nsqd可以接收同一个生产者的相同的消息,参考生产者的说明
    • nsqd会将自己的服务信息广播给集群内的nsqlookupd
    1. 服务发现nsqlookupd
    • nsqlookupd与集群内的所有nsqd建立连接,检测实例的状态,并接收实例广播过来的服务注册
    • nsqlookupd接收消费者客户端的服务发现请求,将对应的实例返回给消费者(这里可以是多个实例)
    • 一个集群可以有多个nsqlookupd
    1. 消费者comsumer
    • 消费者可以与nsqd直连,但为了防止单点故障,不应该有这种固定的关系
    • 官方推荐走服务发现nsqlookupd,参考生产者的说明,当一个nsqd宕机时,生产者可以将消息写入其他的nsqd,或者为了HA,生产者可以双写

    针对上述特性说明,我们可以得出以下结论或支撑系统高可用的方案:

    • 当一个nsqd宕机时,这台机上尚未消费且尚未落盘的消息会丢失;集群本身不提供副本和分片
    • 鉴于上一条,对于幂等且不可丢失的消息,生产者可以选择双写,一条消息同时写两个实例
    • 当正在写的nsqd宕机时,生产者可以选择写入其他的nsqd。前提是消费者通过nsqlookupd完成服务发现,及时感知集群的变化;或者消费者可以同时连上集群内所有的Nsqd实例
    • 生产者可以做一定的负载均衡,将消息分散生产到不同的nsqd中

    2 Elasticsearch

    2.1 拓扑结构

    ES集群涉及数据迁移、负载均衡和HA等,所以会比NSQ集群更复杂些,下面我们通过一张图来简单介绍下:

    ES的节点可以通过两组配置项来决定每个节点类型,即"node.master: true/false"和"node.data: true/false",具体类型如下表:

    node.master node.data 是否参与选主 是否保存数据 是否参与计算 对应上图节点
    true true Node A/B
    true false Node C
    false true Node D
    false false Node E

    特殊的,像Node E这种又不参与选主,又不保存数据的节点,也是有用的,它可以用来处理用户请求。所有的节点都可以接收并处理用户请求。具体逻辑见后续章节。
    ES集群还支持其他的节点类型,在此不展开讨论。
    集群内所有节点理论上两两相连(网络异常时允许部分节点之间通讯中断,保证最终整个集群是拓扑连续的即可)。每个节点都会保存与其相连的其他节点的信息,用于选主和路由。节点之间通过Gossip谣言传播算法实现数据交换和最终一致性,具体的原理细节这里就不讨论了。

    2.2 数据分布

    ES支持数据分片和分片副本:

    • 主分片与副本分片一般分布在不同的节点(HA高可用)
    • 不同的主分片可以在同一个节点
    • 数据更新只能发生在主分片
    • 查询请求可以在主副分片
    • 当主分片丢失时,会自动选择一个最新的副本分片作为主

    分片分布在哪个节点上是不固定的,随着集群的数据变化和节点的增加删除,分片会在不同节点之间移动。这个由master主节点来负责协调。具体参见“master主节点”章节。

    2.3 数据访问

    集群所有节点均可接收用户请求
    2.1章节提到每个节点会保存其他节点的信息,所以当一个用户请求到来时,当前节点负责解析用户请求,并从本地节点列表中选择有相关分片的节点(数据分片往往被打散到不同的节点)将请求转发过去。

    对于写请求:

    1. Node A收到用户请求,解析后确定需要写Node B所保存的主分片,则Node A将请求转发给Node B
    2. Node B完成主分片的写入(注意,只有主分片能写,副本分片从主分片同步数据)
    3. Node B将数据同步给集群内其他副本分片,待所有分片均返回后,响应Node A写入成功
    4. Node A响应用户请求

    对于读请求:

    1. Node A收到用户请求,解析后确认涉及哪些分片,从本地节点列表中找出有相关分片的节点将请求转发过去
    2. 各分片完成查询,将数据返回给Node A
    3. Node A将数据运算汇总后,响应用户请求

    2.4 master主节点

    主节点是由集群自动选举出来的
    集群内有且只能有一个master主节点,它负责集群的协调工作,比如新节点加入、分片的转移等。
    根据2.1章节的描述,只有node.master配置为true的节点才有可能成为主节点。

    集群选举

    1. 选举由node.master配置为true的节点发起,当某个候选节点发现当前集群缺少master的时候,会主动发起选举(节点之间会相互通过ping交换信息,包括主节点信息,如果超过半数的节点都连不上主节点时,就认为没有主节点)
    2. 选举的方式是集群所有节点投票,投票规则是每个节点都选择本地列表中version最高的(如果存在并列最高,则选id最小的那个节点),节点通过join指令投票。
    3. 被选节点通过收集join的次数,超过集群节点总数的一半+1的节点选自己为主节点时,选举即成功。
    4. 否则超时开启下一轮选举,直到集群选出master。

    关于脑裂
    当集群存在两个或以上的master时,我们称之为脑裂。这种情况会导致集群的一致性受到威胁。
    略有遗憾的是ES存在小概率的脑裂问题。比如当Node A发起选举,Node X投了一票;但选举迟迟未成功,接着又有个节点发起了一轮投票,刚好这时Node X发现Node B的版本更高,又投了一票给Node B。于是Node X投出了两票,条件契合的情况下,Node A/B可能同时认为自己被选上。这种情况可以通过引入选举周期来解决,同一周期一个节点只投一票,最终选择周期最新的节点为主。

    特别注意:只有两个节点的集群,一旦通讯异常,master就选不出来了,因为拿不到总节点数/2 + 1的票数
    类似的,当集群有超过半数的节点宕机,集群将变的不可用。

    2.5 节点发现和退出

    当有节点需要加入集群时,通过给它配置discovery.zen.ping.unicast.hosts: [xx.xx.xx.xx, yy.yy.yy.yy]参数来完成自动发现,加入集群。原理是节点会向上述hosts列表发送请求,寻找master,然后join master。该hosts建议配置成所有的主候选节点。
    节点需要退出时,先标记待退出状态,待master将分片全部移走时,才能退出集群。

  • 相关阅读:
    洛谷 1736 创意吃鱼法
    有多重限制的背包
    洛谷 1417 烹调方案
    2008 noip 传纸条
    环形石子合并 洛谷 1880 && hdu 3506 Monkey Party
    洛谷 1282 多米诺骨牌
    (金明的预算方案)依赖性的背包
    分组背包问题
    混合背包问题
    多重背包问题
  • 原文地址:https://www.cnblogs.com/JoZSM/p/12455719.html
Copyright © 2020-2023  润新知