Redis 集群架构剖析 (1):认识 cluster
本文档主要是学习 redis cluster 的一下学习笔记和想法,通过这篇文章,希望你能了解 redis 的 cluster 是如何构建的,以及里面的数据结构是怎么样的。当然,也值得去思考 redis 的集群架构设计思路,这个其实对自己的分布式系统架构设计是由帮助的。
总所周知,Redis 集群是 Redis 提供的分布式数据库方案,集群通过分片(sharding)来进行数据共享,并提供复制和故障转移功能。那么:
如何启动一个集群节点呢?
又如何创建一个集群呢?
创建好的集群,通过什么记录集群信息,又记录哪些信息呢?
一个新的节点又是如何加入一个集群的呢?
节点启动
一个集群由多个节点组成,为了形成一个集群,那这个节点启动的配置一定不一般。
通常我们启动 redis,不考虑集群的话,正常都是直接用默认配置,用 docker 或者直接二进制起。但是要注意的是,如果想要将该节点加入某个集群,那么配置文件中的cluster-enabled
必须设置为 true,否则无法加入任意一个集群。启动时的内部逻辑大致如下:
创建集群
从上一节我们得知一个 Redis 集群由多个节点(node)组成。一开始的时候,每个节点都是独立的,都处于一个只包含自己的集群当中。那么为了建立一个集群,那就需要把他们都连接起来。
连接节点的指令,可以通过CLUSTER MEET
指令:
向一个节点 node 发送CLUSTER MEET
指令,目的是为了让 node 和指定的 IP/PORT node 握手。当握手成功时,node 节点就会把对应的节点加到当前所在集群中。
下图用 3 个 redis 节点作为例子,端口分别是 6370、6371 和 6372,均在同一台服务器上部署(为了测试)
注意,这是一个节点一个节点添加到集群内的,也可以通过redis-cli create cluster
指令来创建集群,可以参考另一篇 redis 的集群搭建,会详细介绍:Redis集群docker部署 - 知乎 (zhihu.com)
集群数据结构
了解了集群节点的启动和创建,那集群的信息是怎么存的呢?
在集群模式下会用到的数据,节点会将它们存在cluster.h/clusterNode
结构、cluster.h/clusterLink
结构,以及cluster.h/clusterState
结构里面。
clusterNode
集群中的我是谁,我有什么证明
clusterNode 结构保存了一个节点的当前状态,比如节点的创建时间、节点的名字、节点当前的配置纪元、节点的 IP 地址和端口号等等。
每个节点都会使用一个 clusterNode 结构来记录自己的状态,并为集群中的所有其他节点(包括主节点和从节点)都创建一个相应的 clusterNode 结构,以此来记录其他节点的状态。
clusterLink
如果集群有一个节点想要访问我,怎么可以快速访问到我
clusterNode 结构的 link 属性是一个 clusterLink 结构,该结构保存了连接节点所需的有关信息,比如套接字描述符,输入缓冲区和输出缓冲区:
redisClient 结构中的套接字和缓冲区用于连接客户端的,而 clusterLink 结构中的是连接节点的
clusterState
集群里面还有谁,我要记住你们
同时每个节点都会保存一个 clusterState 结构,这个结构记录了当前节点的视角下,集群目前所处的状态,好比说集群现在有多少个节点,当前是下线还是上线:
redis 的集群数据结构其实是可以在自己的分布式架构借鉴的,当前节点信息,别人怎么联系我,当前集群拓扑,这三个数据结构里面存的东西就可以表示一个集群当前的节点状态信息。
节点加入集群
我们在第二节讲了用CLUSTER MEET
这个指令来创建集群,在了解了集群数据结构之后,再来详细地剖析下,这个指令到底做了什么,上一节讲的数据结构又会填入哪些值,握手又是如何完成的。
假设现在 6370 节点对 6371 节点发起CLUSTER MEET
指令:
6370 会创建一个
clusterNode
,并将这个clusterNode
加到clusterState
6370 根据
CLUSTER MEET
的 IP 和 PORT,向 6371 节点发送一个MEET
消息6371 如果收到
MEET
消息,就会创建一个 6370 节点的clusterNode
,并加到自己的clusterState
里面然后 6371 会向 6370 发送一个
PONG
6370 收到
PONG
后,就认为 6731 收到MEET
消息之后 6370 会再向 6371 发送
PING
6371 收到 6370 的
PING
之后,认为 6370 收到自己的PONG
,此时握手完成6370 会将 6371 的节点信息通过 Goosip 协议传播给集群的其他节点,让其他节点也去和 6371 握手。过一段时间之后,集群的其他节点就都会认识 6371
集群建好了
在前几节的步骤之下,集群已经创建好了。然后我们通过 6370 的视角,看一下现在的集群,根据第三节的数据结构,可以看到集群数据结构存的内容如下:
nodes 里面是 kv,key 是 node 的名称(正常不是这样的),value 就是对应的节点的 clusterNode。如果是别的节点视角,那对应的就是 myself 节点改一下。
注意到的是clusterState
数据结构里面的一个字段 state,还是 REDIS_CLUSTER_FAIL。这意味着,我们现在创建好了集群,但是这个集群状态不可用。为什么不可用呢?我们知道的是 redis 是一个 kv 数据库,要存的东西的,那谁存什么值我们似乎还没有分配好,这个会不会是集群不可用的原因呢?请待下回分解。
评论