分布式架构的“集权”与“公治”

前言

分布式数据库和中间件的架构设计,核心就是围绕 “中心化” 和 “去中心化” 这两种思想展开,两种模式各有适用场景和优缺点

其中“中心化”显著特点就是有一个明确的主节点/协调节点,相当于一个团队的领导,主要负责决策和分配工作,实际干活由数据节点完成,这是一种典型的集权式管理模式

而“去中心化” 的显著特征是所有节点平等,没有一个中心节点,通过一个共识的协议完成任务分配和配合,是一种典型的共治式管理模式

中心化

中心化的分布式架构的数据库和中间件很多,例如MongoDB分片集,Hbase集群,Elasticsearch,RocketMq等等,它们的架构都有一个中心节点来负责协调组织节点完成任务,但它们的设计也都有一些自己的特点

mongodb分片集集群
mongodb

mongodb是个典型的中心化集群,其中Mongos充当协调节点,负责接收所有读写请求,解析请求后根据分片规(Sharding Key)路由到对应的分片节点执行,最后汇总结果返回给客户端

mongodb还包含一个Config Server节点,Config Server节点负责存储集群的元数据(分片规则,分片节点信息等),可以简单的理解为Config Server节点相当于mongos节点使用的数据库

每个mongos节点都是平等的,客户端可以配置多个地址,实现轮询/随机访问

Hbase集群
Hbase

Hbase中Master为主节点,负责管理元数据(依靠zk存储),处理DDL命令(创建表、列族、索引等),监控 RegionServer 心跳,故障时重新分配 Region,简而言之就是一个集群管理者,但比较特别的是它不接受请求,只负责管理,客户端可以通过zookeeper获取到集群信息,然后直接与RegionServer通信

zookeeper的定位于Mongo中ConfigServer类似,负责存储元数据,相当于Master用的一个数据库,同时Master依赖zookeeper进行选举,也依赖zookeeper监控RegionServer

Hbase的Master只有一个主节点,当主节点挂掉时,依赖zookeeper主备切换,这点与mongodb的mongos可以随意扩展的设计不一样,二者的差异主要在于Hbase的Master节点不负责处理请求,只保留一个即可,而 mongos 作为请求入口,多实例部署是为了分担客户端请求压力。

这里有个类比,mongos相当于我们常用的注册中心加网关,HMaster(ZK)相当于我们常用的注册中心

RocketMq
RocketMq

rocketmq中使用Nameserver管理元数据,充当集群协调器,监控broker的心跳

broker负责实际的读写,存储消息队列数据

客户端发送或消费信息,通过nameserver获取broker信息,然后直接与broker通信,整个过程nameserver充当类似注册中心的作用,这个逻辑和 HBase 客户端 “查 ZooKeeper 获取 .META. 地址 → 直连 RegionServer”、MongoDB 客户端 “查 mongos 获取 Shard 地址 → 直连 Shard” 的链路完全一致,核心都是中心节点只提供路由,不处理业务请求

rocketmq的nameserver自己就可以处理元数据存储和心跳监控,这种设计与hbase的zk以及mongodb的config server有所不同,主要原因是RocketMQ是专用的消息队列,场景相对单一,元数据的复杂度低、变更频率也低。简单说,RocketMQ 的元数据和协调需求 “刚刚好”,一个轻量级的 NameServer 就足够支撑,没必要引入外部依赖。

rocketmq的nameserver可以是多节点,且每个节点平等,这点类似于mongos,一样都是由客户端配置多个地址,实现轮询/随机访问

但nameserver与mongos不一样的地方,是mongos承担请求路由的任务,所以多节点有利于分担压力,但是nameserver不处理请求,职责很小,所以一般也不会部署过多

zookeeper
zookeeper

zookeeper是一个典型的中心化架构,有个唯一的Leader作为唯一的中心决策者,负责处理所有写请求,并统一协调集群状态

而Follower节点是被动从属节点,只能处理读请求,无法处理写请求,同时参与 Leader 选举,同时参与写请求的投票确认,确保集群数据一致性

但zookeeper的leader是选举产生的,所以从部署的角度来说,zookeeper的每个节点都是平等的,也可以算一种去中心化的架构,可以说从物理层面去中心化,从控制层面中心化

小结

虽然把mongodb、hbase、rocketmq都归为“中心化”模式,但也可以看到它们所谓的主节点所承担的职责并不一致,mongodb依靠mongos进行元数据和请求路由,是真正意义上的中心化架构,而hbase的master和rocketmq的nameserver则负责元数据和心跳监控,不处理请求,更属于一种弱中心化架构,而zk是控制层面的中心化,物理层面的去中心化

mongos保存了元数据,自然具备路由的能力,所以可以处理请求转发,相当于网关+注册中心

hbase的master和rocketmq的nameserver负责元数据,但不处理请求,客户端只通过zookeeper/nameserver获取集群信息(客户端自己缓存),然后直接与RegionServer/Broker通信,相当于注册中心

去中心化

取中心化的分布式架构的数据库和中间件也很多,例如Redis集群,Cassandra,Kafka等

中心化的架构其实最符合现实也好理解,就是一个团队有个领导牵头,负责协调分配工作

而去中心化的架构最大特点是集群各节点对等,那么如何分配活,工作怎么开展?

依靠的就是共识,也就是去中心化各节点有一个共识的协议

Redis集群
Redis

Redis Cluster 中没有类似 mongos、NameServer 这样的专用代理 / 协调节点,每个节点都是平等的

  • 每个节点都存储集群元数据(槽位与节点的映射关系),元数据通过Gossip协议(八卦协议、闲聊协议)在节点间实时同步;
  • 每个节点都能接收客户端请求,并直接处理属于自己槽位的数据;
  • 集群启动时,节点通过握手自动发现彼此,形成对等集群。

redis cluster所谓的元数据说白了最核心的就是槽位的分配,更简单的说就是哪些key对应的数据存储在哪个节点上,以下是元数据各节点公治的过程

  • 集群初始化时,会通过自动或手动分配给每个节点固定好槽位分配,这个就是最重要的元数据

  • 节点之间通过gooss协议不断同步元数据,以保证所有节点的元数据一致

  • 当发生槽位迁移,比如新增节点或手动调整槽位分配时,节点之间会通过gossip协议进行元数据同步,以保证所有节点的元数据一致

  • 同时元数据也有版本号(Config Epoch),当节点之间gossip通讯发现不一致时,滞后的节点会替换新版本的元数据

  • goosip协议可能会导致有些节点消息滞后,比如原来1000槽位属于A节点,现在已迁移或正在迁移到B节点,原请求到达A节点后,A节点一定会知道1000槽位以不属于自己,会返回MOVED重定向指令

Cassandra

Cassandra是一个排行很高的宽表数据库,它的架构和redis有很多相似之处,都是去中心化,各个节点之间通过gossip协议进行元数据同步

redis使用的是槽位定算法,而cassandra使用一致性哈希:参考: 分布式寻址算法

这里就不多做介绍了,它的架构和redis很像,只是使用一致性哈希算法,而不是槽位定算法,当一个数据来了之后,会对数据分区间hash运算,然后根据一致性hash算法进行请求分发,各节点之间也是靠gossip协议进行元数据同步

cassandra还有一点比较特殊,就是每个节点都可以作为临时协调节点,当批量读取或批量写入时,由协调节点统一协调,而redis的节点只会返回重定向命令,不做转发操作,这种设计差异的根源:Cassandra是海量持久化数据库,批量读写多分区数据是高频场景;Redis 是高性能键值缓存,单key操作占主流。

Kafka
kafka

kafka和zookeeper都有点难以界定,同样是从物理层面去中心化,但从控制层面中心化,kafka中每个broker节点都是平等的,但启动时会通过zookeeper选举出一个broker controller节点

这个broker controller节点负责元数据管理(存储到zk中),比如新建删除topic等,同时负责元数据同步到其它broker节点,broker之间就不需要类似gossip协议进行元数据同步

同时broker controller节点也是一个不同的broker节点,只是增加了controller的角色

生产者客户端启动时,会从任意一个broker节点获取元数据,然后按需与需要对接的broker建立长链接,根据元数据和消息的key计算hash取模将消息直接发给对应的broker节点

消费者客户端启动时,会从任意一个broker节点获取元数据,然后按需与需要(broker会进行消费者的分区分配)对接的broker建立长链接,然后消费数据

分区分配是Group Coordinator(某台普通 Broker)的活儿,每个broker都可以充当Group Coordinator,有一个计算公式来针对不同消费者组分配分区,这个公式是:

  • 对消费组名称做哈希计算;
  • 哈希值对Topic分区数取模;
  • Topic 对应分区的 Leader Broker,就是该消费组的 Coordinator

Kafka新版提供了另外一种不需要Zookeeper的集群机制,Kraft集群

Elasticsearch
Elasticsearch

Elasticsearch相比于之前的架构可以说是非常特殊,首先它每个节点本身是对等的,但是可以给不同的节点赋予不同的角色,是不是有一个专门的主节点全在于你怎么分配角色,这种相对就非常灵活

  • 主节点(Master Node):负责集群管控(轻量级)。
  • 数据节点(Data Node):存储分片数据、处理读写请求。
  • 协调节点(Coordinating Node):路由客户端请求。

一般情况下主节点和数据节点两个角色都分给不同的节点,此时es的中心化架构还是比较明显的,由主节点管理集群元数据,确保元数据的一致性和权威性,同时会通过Zen协议(基于gossip)把元数据同步给其他节点

实际作为主节点的节点只有一个,但一般都要多部属几个Master Node,这样主节点宕机时,其他节点会自动选举出新的主节点

es的协调节点可以单独部署,也可以比如把让一个节点同时承担数据节点和协调节点两个角色,非常的灵活,协调节点的存在就好比Cassandra的临时协调节点一样,都是为了整合分布在不同节点的数据,然后把数据返回给客户端

es即由主机点的角色来中心管理元数据,又使用了类似goosip的zen协议进行数据同步,主要是因为zen协议相比于goosip多了一致性校验和多数派确认,而非goosip那种天然一致

这里就有一个疑问,同样是分布式架构的数据库,为啥es不像Cassandra那样直接使用goosip协议进行元数据同步,而完全区中心化呢,非要高出一个中心化的主节点?

这里其实就好和cap扯上关系了,一个分布式系统的架构不能CAP并存

  • Elasticsearch 的核心诉求是 “快速、准确的全文检索”,这就要求集群的元数据(分片分布、主副本关系)必须强一致,所以ES的架构偏向CP
  • Cassandra 的核心诉求是 “海量数据下的高吞吐、高可用读写”,比如物联网数据、日志流水等场景,要求集群无单点故障,节点可以线性扩容,所以架构偏向AP
小结

去中心化的架构,一般都会在初始化集群的阶段,就把各节点的职责划分清楚,然后通过类似gossip这种协议进行元数据同步,不断的保证各节点的职责信息在整个集群最终一致

思考

整体的思考下捋下思路:

  1. 中心化架构,一般都有个明确的中心节点负责管理元数据,这种设计确保元数据的一致性,而主节点一定拥有最权威唯一的元数据版本,一般偏向CP架构

  2. 去中心化架构,所有节点都是对等的,就像一个部门没有领导,初始化集群的时候已经完成了职责的划分,有变动大家一起商量,多数人认可就算通过,一般偏向AP架构

中心化架构相当于有个绝对权威的领导,手里拿着最准确的职责划分规则,其他节点再抄走这个规则,然后按照这个规则进行操作

而去中心化架构相当于部门没有领导,初始化时划分好了规则,有决策时大家一起商量答案,多数认可就算通过

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容