对线面试官 Redis | 十 Redis 集群模式
面试官:Redis 集群模式有了解过吗?具体的工作原理可以简单说一下吗?
面试官的心理分析:主要考察的是在实际工作中是否接触过海量数据+高并发+高可用的场景。以及 Redis 这几年的一个变化。因为在前几年 Redis 本身不支持集群模式,只能依赖于一些中间件,比如 codis、推特的 twemproxy 等。但是最近几年 Redis 官方支持了集群模式 Cluster,在实际应用中该集群模式也被广泛使用,面试官主要是想考察了解你对 Redis 的一个掌握程度。
派大星:有了解,前几年主要通过 Redis 的一些中间件来做,比如 codis、推特的 twemproxy 等,但是最近几年 Redis 官方支持了集群模式 Cluster。
面试官:那你简单介绍一下 Redis Cluster 吧。
派大星:好的,Redis Cluster 它会自动将数据进行分片,同时每个 master 只有一部分数据。提供内置的高可用支持,部分 master 不可用时还是可以对外提供服务的。在 Redis Cluster 架构下,每个 Redis 需要开发两个端口,比如一个是:6379 一个是 16379;另外一个就是加 1w 的端口号,比如 16379。端口号用来进行节点之间的通信,也被称为 cluster bus。cluster bus 的通信用来故障检测、配置更新、故障转移授权。cluster bus 用了另外一种二进制协议,gossip
协议,用于节点间进行高效的数据交换,占用较少的网络带宽和处理时间
面试官:不错,可以继续讲一讲节点间的内部通信机制吗
派大星:可以,首先来讲一般集群元数据的维护方式有两种:
集中式、gossip 协议,Redis 采用的是 gossip 协议进行通信。
面试官:这两个有什么区别吗?
派大星:当然,首先针对与集中式来说,它是将集群元数据(节点信息,故障信息)等集中存储在某个节点上,这种存储方式有点典型的代表就是大数据中storm
。它是分布式的大数据实时计算引擎,是集中式的元数据存储的结构,底层基于 zookeeper 对所有元数据进行存储维护。如图:
集中式的好处就在于:对于元数据的读取和更新时效性
非常好,一旦出现数据的变更,就立即更新到集中式存储中,其它节点也可以第一时间进行感知到。缺点就是所有的元数据都在一个地方。可以会导致元数据的存储有压力。
派大星:其次对于goosip
协议来讲它的优点相比较于集中式存储它的元数据信息相对比较分散,不集中在一个地方,更新请求会分散在其它有元数据的节点,从而降低了压力。相对来说时效性没有那么好。会有一些滞后。
面试官:gossip 协议你了解多少,可以简单介绍以下嘛?
派大星:gossip 协议包含很多信息,比如ping
、 pong
、 meet
、 fail
等等。
meet:某个节点会发送 meet 给新加入的节点,然后新节点就会加入集群中,并于其它节点进行通信
ping:每个节点都会给其它节点频繁的发送 ping,其中包含自己元数据信息,互相通过 ping 来交换元数据信息。
pong:返回 ping 和 meet,包含自己的状态和其它信息,用于信息广播和更新。
fail:某个节点判断另外一个节点 fail 后,就会给其它节点发送 fail。通知其它节点告诉某个节点宕机了。
派大星:ping 是要携带一些元数据,如果很频繁的话可能会导致网络开销较大。并且每个节点每秒会执行 10 次的 ping,每次会选择 5 个最久没有通信的其它节点。当然这期间如果发现了某个节点通信延时达到了(cluster_node_time_out / 2
)。那么就会立即发送平,避免数据交换延时过长,落后的时间太长了。比如说两个节点已经有 10 分钟没有交换数据了,那么整个集群就存在严重的数据不一致的情况,就会有问题。所以cluster_node_timeout
可以去调节,调节的比较好的好。ping 频率自然也就降低了。
面试官:既然 Redis Cluster 有这么多的节点,它是如何做的选择呢,也就是怎么做的节点负载均衡?
派大星:说到节点负载均衡就需要知道分布式的寻址算法:
hash 算法:(大量缓存重建)
一致性 hash 算法:(自动缓存迁移)+虚拟节点(自动负载均衡)
Redis cluster 的 Hash slot 算法
以上三种算法 Redis 中采用的是 Hash slot 算法。
面试官:那你能简单介绍下这三种算法吗?
派大星:好的,
首先 Hash 算法,会根据key计算其Hash值,然后对节点数取模
,接着打在不同的 master 节点上。一旦某一个节点宕机,所有请求打过来,都会基于最新的剩余的 master 节点进行取模尝试获取数据。这样就会导致后续所有请求过来,都无法拿到有效的缓存,导致大量的请求直接打到 DB 上。
对于一致性 Hash 算法而言,它会将整个 Hash 值空间组装成一个虚拟的圆环,整个空间按顺时针方向流转,下一步将各个 master 节点进行 Hash,这样就能确定每个节点在其 Hash 环位置上。请求过来的时候,会先根据 key 计算 Hash 值并确定此数据在环上的位置,从此位置沿着环的顺时针方向行走,遇到的第一个 master 节点就是 key 所在的位置。这种情况即使有一个节点挂了宕机了,受影响的数据仅仅是此节点到环空间前一个节点(也就是沿着逆时针方向行走遇到的第一个节点)之间的数据,其它不会受到影响,增加一个节点也同理。相比较于 Hash 算法即使挂了一个节点不会使后面的所有请求都直接打到 DB 上。但是一致性 Hash 算法如果在节点特别少的情况下,容易出现因为节点分布不均匀而造成缓存热点
的问题。为了解决这种热点问题,一致性 Hash 算法引入了虚拟节点机制
,即对每一个节点计算多个 Hash,每个计算结果位置都放置一个虚拟节点。这样就实现了数据的均匀分布,负载均衡。
至于 Redis Cluster 的 Hash slot 算法。首先 Redis Cluster 中有固定的16384
个 Hash slot,对每个 key 计算CRC16
值,然后对 16384 取模,可以获取 key 对应的 Hash Slot。
Redis Cluster 中每个 master 都会持有部分 slot,比如有 3 个 master,那么每个 master 可能会持有 5000 多个 Hash Slot。Hash Slot 让 node 的增加移除变得简化,增加一个 master,将其它 master 的 hash slot 移动部分过去即可,减少一个 slot,将它的 hash slot 移动到其它的 master 即可。移动 hash slot 的成本也很低。针对客户端的 API 可以针对指定的数据,让其走同一个 Hash Slot,通过 Hash Tag 即可以实现。
这样就保证了任何一台机器宕机,其它的节点都不受影响,因为 key 要找的是 Hash Slot 而不是机器。
面试官:不错,那 Redis Cluster 的高可用机制的主备切换原理是什么,这个有了解过吗?
派大星:首先来说 Redis Cluster 的主备切换原理其实和 Redis Sentinel 是十分相似的。
第一步:它会先判断是否宕机。如果一个节点认为另外一个节点宕机,难么就是pfail
,也就是主观宕机。假设如果多个节点都认为另外一个节点宕机了。那么就是fail
客观宕机。这里和odown
、sdown
很相似。主要表现形式则是:在cluster-node-timeout
内,某个节点一直没有返回pong
,那么就会认为是pfail
。一个节点一旦认为某个节点pfail
了,就会在gossip ping
消息中,ping
给其它的节点,如果超过半数的节点
都认为pfail
了,那么就会是fail
至于如何选举,对宕机的 master node,会从其所有的 slave node 中选举一个 master node。首先会判断并检查每个 slave node 于 master node 断开连接的时间,如果超过了cluster-node-timeout * cluster-slave-validity-factor
了,就没有资格成为 master。
这一步之后每个从节点,都会根据自己对 master 复制数据的 offset 来设置一个选举的事件,offset 越大(代表复制的数据越多)的从节点,选举的事件越靠前,会优先进行选举。这时候所有的 master node 开始对要进行选举的 slave node 进行投票,如果大部分 master node(N/2 +1 )都投给了某个 slave node。那么选举就会被通过。表明该 slave node 会切换成 master。
综上所述,整个流程和哨兵相比很类似。所以说 Redis Cluster 功能强大。直接集成了Relocation
和Sentinel
。
如有问题,欢迎加微信交流:w714771310,备注- 面试 。或关注微信公众号【码上遇见你】。
版权声明: 本文为 InfoQ 作者【派大星】的原创文章。
原文链接:【http://xie.infoq.cn/article/08a6f895b16f16b1617a3f09d】。
本文遵守【CC BY-NC-ND】协议,转载请保留原文出处及本版权声明。
评论