1 前言
主从复制实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。但是缺陷也很突出:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。
而哨兵模式,在复制的基础上,实现了自动化的故障恢复。缺陷有:写操作无法负载均衡;存储能力受到单机的限制。
集群模式,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案。
下图为Redis 集群(Cluster)示意图:
2 机制
2.1 设计目标
Redis 集群是 Redis 的分布式实现,Redis3.0以后版本正式提供支持。在设计中按重要性顺序具有以下目标:
- 高性能和线性可扩展性,多达
1000个节点。没有代理,使用异步复制,并且不对值执行合并操作。 - 可接受的写入安全:系统尝试(采用
best-effort方式)保留所有连接到master节点的client发起的写操作。通常会有一个小的时间窗,时间窗内的已确认写操作可能丢失(即,在发生failover之前的小段时间窗内的写操作可能在failover中丢失)。而在(网络)分区故障下,对少数派master的写入,发生写丢失的时间窗会很大。 - 可用性:
Redis Cluster在以下场景下集群总是可用:- 大部分master节点可用,并且对少部分不可用的master,每一个master至少有一个当前可用的slave。
- 更进一步,通过使用
replicas migration技术,当前没有slave的master会从当前拥有多个slave的master接受到一个新slave来确保可用性。
3 模块
3.1 哈希槽(Hash Slot)
Redis-Cluster没有使用一致性hash,而是引入了哈希槽的概念。
Redis-cluster中有16384(即$2^{14}$)个哈希槽,每个key通过CRC16校验后对16383取模来决定放置哪个槽。
Cluster中的每个节点负责一部分哈希槽(hash slot)。比如集群中存在三个节点,则可能存在的一种分配如下:
- 节点A包含
0~5500号哈希槽; - 节点B包含
5501~11000号哈希槽; - 节点C包含
11001~16384号哈希槽。
3.2 Hash tags
提供了一种途径,用来将多个(相关的)key分配到相同的hash slot中。这时Redis Cluster中实现multi-key操作的基础。
Hash tag规则如下:
- 如果key包含
{...}模式,则仅对{和}之间的子字符串(即:...)进行哈希处理,以获取哈希槽。 - 但是,由于可能存在多次出现
{或},则算法由以下规则指定:- key包含一个
{字符; - 并且如果在这个
{的右面有一个}字符; - 并且如果在
{和}之间存在至少一个字符
然后,不对key进行哈希处理,而只对第一次出现{和下一个第一次出现}之间的内容进行哈希处理。
- key包含一个
举例:
{user1000}.following和{user1000}.followers这两个key会被hash到相同的hash slot中,因为只有user1000会被用来计算hash slot值。foo{}{bar}这个key不会启用hash tag,因为第一个{和}之间没有字符。foo{{bar}}zap这个key中的{bar部分会被用来计算hash slot;foo{bar}{zap}这个key中的bar会被用来计算计算hash slot,而zap不会。从算法得出的结论是,如果key以
{}打头,则保证将其作为一个整体进行哈希处理。这在使用二进制数据作为键名时很有用。
3.3 集群节点属性
3.3.1 节点名称(node name)
每个节点在集群中都有一个唯一的名称。节点名称是 160 位十六进制的随机数表示形式,在节点首次启动时获得(通常使用 /dev/urandom)。
节点将把其 ID 保存在节点配置文件中,并将永远使用相同的 ID,或者至少只要系统管理员未删除节点配置文件,或者通过 CLUSTER RESET 命令请求硬重置。
节点ID被用来标识整个cluster中每个节点。一个节点可以修改自己的IP地址而不需要修改自己的ID。Cluster可以检测到IP/port的改动并通过运行在cluster bus上的gossip协议重新配置该节点。
节点ID不是唯一与节点绑定的信息,但是他是唯一的一个总是保持全局一致的字段。
3.3.2 其他属性
除了节点ID,集群节点还包含以下信息:节点的IP和port,节点标签,master node id(如果这是一个slave或replica节点),最后被挂起的ping的发送时间(如果没有挂起的ping则为0),最后一次收到pong的时间,当前的节点configuration epoch,链接状态,以及最后是该节点服务的hash slots。
下面是一个发送到一个拥有3个节点的小集群的master节点的CLUSTER NODES输出的例子。
$ redis-cli cluster nodes
d1861060fe6a534d42d8a19aeb36600e18785e04 127.0.0.1:6379 myself - 0 1318428930 1 connected 0-1364
3886e65cc906bfd9b1f7e7bde468726a052d1dae 127.0.0.1:6380 master - 1318428930 1318428931 2 connected 1365-2729
d289c575dcbc4bdd2931585fd4339089e461a27d 127.0.0.1:6381 master - 1318428931 1318428931 3 connected 2730-4095在上面的列表中,不同的字段按顺序排列:
节点ID,地址:端口,标志,上次发送ping的时间戳,收到的最后一个pong的时间戳,配置纪元,链路状态,插槽。3.4 集群总线
每个Redis 集群节点都有一个额外的 TCP 端口,用于接收来自其他 Redis 集群节点的传入连接。
比如,
- 如果 Redis 节点正在侦听端口
6379上的客户端连接,并且您没有在redis.conf中添加集群端口参数,则将打开集群总线端口16379。 - 如果 Redis 节点正在侦听端口
6379上的客户端连接,并且您在redis.conf中设置了集群端口20000,则会打开集群总线端口20000。
节点到节点通信仅使用集群总线和集群总线协议进行:由不同类型和大小的帧组成的二进制协议。
集群总线二进制协议未公开记录,因为它不适用于外部软件设备使用此协议与 Redis 集群节点通信。但是,您可以通过阅读 Redis 集群源代码中的
cluster.h和cluster.c文件来获取有关集群总线协议的更多详细信息。
3.5 集群拓扑
- Redis 集群是一个完整的网格,其中每个节点都使用 TCP 连接与其他节点连接。
- 在由
N个节点组成的集群中,每个节点都有N-1个传出 TCP 连接和N-1个传入连接。 - 这些 TCP 连接
始终保持活动状态,而不是按需创建。当节点期望 pong 回复以响应集群总线中的 ping 时,在等待足够长的时间将节点标记为无法访问之前,它将尝试通过从头开始重新连接来刷新与节点的连接。 - 虽然 Redis 集群节点形成全网状,但节点使用
gossip 协议和配置更新机制,以避免在正常情况下节点之间交换过多消息,因此交换的消息数量不是指数级的。
3.6 节点握手
节点总是接受集群总线端口的链接,并且总是会回复ping请求,即使ping来自一个不可信节点。然而,如果发送节点被认为不是当前集群的一部分,所有其他包将被抛弃。
节点认定其他节点是当前集群的一部分有两种方式:
- 如果一个节点出现在了一条
MEET消息中。一条MEET消息非常像一个PING消息,但是它会强制接收者接受一个节点作为集群的一部分。节点只有在接收到系统管理员的如下命令后,才会向其他节点发送MEET消息:CLUSTER MEET ip port - 如果一个被信任的节点
gossip了某个节点,那么接收到gossip消息的节点也会把那个节点标记为集群的一部分。也就是说,如果在集群中,A知道B,而B知道C,最终B会发送gossip消息到A,告诉A节点C是集群的一部分。这时,A会把C注册为网络的一部分,并尝试与C建立连接。
这意味着,一旦我们把某个节点加入了连接图(connected graph),它们最终会自动形成一张全连接图(fully connected graph)。
这也意味着只要系统管理员强制加入了一条信任关系(在某个节点上通过meet命令加入了一个新节点),集群可以自动发现其他节点。
Gossip协议3
节点间通信,按照通信协议可以分为几种类型:单对单、广播、Gossip协议等。重点是广播和Gossip的对比。
广播是指向集群内所有节点发送消息;
优点:集群的收敛速度快(集群收敛是指集群内所有节点获得的集群信息是一致的);缺点:每条消息都要发送给所有节点,CPU、带宽等消耗较大。Gossip协议的特点是:在节点数量有限的网络中,每个节点都“随机”的与部分节点通信(并不是真正的随机,而是根据特定的规则选择通信的节点),经过一番杂乱无章的通信,每个节点的状态很快会达到一致。
优点:负载(比广播)低、去中心化、容错性高(因为通信有冗余)等;缺点:主要是集群的收敛速度慢。
4 功能
4.1 数据分片
作用:
- Redis Cluster将数据按
key哈希到16384个slot上; - Cluster中的不同节点负责
一部分slot。
两个动作:
- 分片:将slots划分给不同节点的过程;
- 再分配:将一些slots从当前节点(source)迁移到其他节点(target)。
常见的分片算法有:哈希取余分区、一致性哈希分区2、带虚拟节点的一致性哈希分区
4.1.1 哈希取余分区
- 原理:计算key的hash值,然后对节点数量进行取余,从而决定数据映射到哪个节点上。
- 优点:简单、快速、高效、适用于大规模快速查询。
- 缺点:
数据分布不均匀:如果使用简单的哈希取余算法,可能会出现数据倾斜的情况,导致某些节点负载过高,而某些节点负载过轻;数据迁移困难:使用哈希取余算法进行数据分布后,如果需要添加或删除节点,就需要重新计算每个数据对应的节点,然后将其迁移到新节点上,这个过程非常繁琐,而且需要暂停对集群的写操作;扩展性受限:使用哈希取余算法进行数据分布时,如果需要增加节点,那么需要将所有的数据重新计算分配,这样就会限制集群的扩展性;大量缓存重建问题:主节点如果宕机,那么Hash运算时根据现有存活节点进行取模,得到的数值与原有存储数据时的数值不匹配,请求走不到原有路由节点上,从而导致大量的key瞬间全部失效。
4.1.2 一致性哈希分区
- 原理:将整个哈希值空间组织成一个虚拟的圆环,如下图所示,范围为0~$2^{32}$-1;对于每个数据,根据key计算hash值,确定数据在环上的位置,然后从此位置沿环
顺时针行走,找到的第一台服务器就是其应该映射到的服务器。数据的存储与读取都在此节点进行。 - 优点:保证任何一个主节点宕机,只会影响在之前那个主节点上的数据,此前的主节点宕机,查询时这部分数据会丢失,写入时沿着
顺时针去到下一个主节点; - 缺点:
数据丢失过大:在节点比较少的情况下, 丢失的数据量还是非常庞大的;缓存热点问题:如果某些数据被频繁地访问,会导致热点数据集中在某个节点上,造成负载不均;数据倾斜问题:节点数量较少时,由于数据分布不均,可能会导致某个节点负载过重,影响系统的性能。这是因为Hash函数的输出值在Hash环上并不是均匀分布的,而是有规律的。一致性哈希算法可以通过引入虚拟节点来解决这个问题,将每个物理节点映射到多个虚拟节点上,使得数据更加均匀地分布在环上;一致性问题:由于节点的添加或删除会影响哈希值的计算,可能会导致数据分布不均,这个问题可以通过一些技术手段来解决,例如虚拟节点、数据复制等
4.1.3 带虚拟节点的一致性哈希分区
- 原理:该方案在一致性哈希分区的基础上,引入了
虚拟节点的概念。Redis集群使用的便是该方案,其中的虚拟节点称为槽(slot)。槽是介于数据和实际节点之间的虚拟概念;- 每个实际节点包含
一定数量的槽,每个槽包含哈希值在一定范围内的数据。 - 引入槽以后,数据的映射关系由
数据hash->实际节点,变成了数据hash->槽->实际节点。
Redis-Cluster的一致性哈希原理示意图
- 过程
- 在
HashSlot算法中,取值范围是0~16383。Redis将整个key空间分成了16384个槽,也就是16384个slot,每个主节点负责一部分槽; - 客户端根据
Key计算CRC16值,将值对16384取模,找到对应的槽,然后根据槽对应的主节点进行数据访问; - Redis中的每个
主节点都对应一部分槽位。增加一个主节点时,只需要将其他主节点的槽位分配一部分到新槽位。删除一个主节点时,就将此主节点的槽位移动到其他的主节点上去。移动Hash槽的成本是非常低的; HashSlot算法还可以将不同的数据类型映射到不同的槽中,以达到更好的负载均衡效果。同时,Redis还支持将相邻的多个槽划分到同一个节点,以便在某些场景下提高数据读取的效率;- 如果想确保一些Key总是被分配到同一个节点,那么您可以使用
哈希标签(Hash Tag)功能来强制让这些键映射到同一个槽位。 哈希标签是在 RedisKey 上使用大括号
"{}"的一种特殊语法,详见3.2节。例如:set mykey1:{100}和set mykey2:{100},它们的hash tag都是{100},那么它们就会被存储在同一个hash slot中.
- 在
16384槽位由来
CRC16算法产生的Hash值有16bit,该算法可以产生65536个值。值是分布在0~65535之间,那么其实在做取模运算时,我们是可以取模65536的,但是Redsi作者采取了16384;
作者的回答1是:Redis集群节点数量如果超过1000个那么会造成网络拥堵,所以建议节点数量不超过1000个,那么1000个节点使用16384个槽位完全够用了。如果使用65536个槽位会导致主节点之间交互心跳包时,浪费带宽。槽位数量过少不够用,过多浪费带宽,所以作者通过实测计算得出一个16384的值,不多不少刚刚好。
- 读写分离
- ‘我’并不负责‘你’要的key,告诉’你‘正确的吧。
- 返回
CLUSTER_REDIR_MOVED错误,和正确的节点。 - 客户端向该【正确的节点】重新发起请求,注意这次依然有发生
重定向的可能。
Move重定向4.2.2 ASK
步骤: - ‘我’负责请求的key,但不巧的这个key当前在
migraging状态,且‘我’这里已经取不到了。告诉‘你’importing他的‘家伙’吧,去碰碰运气。 - 返回
CLUSTER_REDIR_ASK,和importing该key的节点。 - 客户端向新节点发送
ASKING,之后再次发起请求 - 新节点对发送过
ASKING,且key已经migrate过来的请求进行响应。
Ask重定向
4.2.3 区别
区分这两种重定向的场景是非常有必要的:
MOVE,申明的是slot所有权的转移,收到的客户端需要更新其key-node映射关系;ASK,申明的是一种临时的状态,所有权还并没有转移,客户端并不更新其映射关系。前面加的ASKING命令也是申明其理解当前的这种临时状态。
4.3 状态检测及维护
4.3.1 状态
Cluster中的每个节点都维护一份在自己看来当前整个集群的状态,主要包括:
- 当前集群状态
- 集群中各节点所负责的slots信息,及其migrate状态
- 集群中各节点的master-slave状态
- 集群中各节点的存活状态及不可达投票
当集群状态变化时,如新节点加入、slot迁移、节点宕机、slave提升为新Master,我们希望这些变化尽快的被发现,传播到整个集群的所有节点并达成一致。
节点之间相互的心跳(PING,PONG,MEET)及其携带的数据是集群状态传播最主要的途径。
4.3.2 Gossip协议
Gossip优点
分布式高效:Gossip协议是一种去中心化的协议,节点之间相互交流信息,每个节点都可以通过传播信息来实现全局一致性,不需要中央控制节点,使得节点加入或退出集群更加高效;可伸缩性:Gossip协议可以很好地适应不同规模的系统,当节点数目增加时,节点间通信的成本是对数级别的;容错性:Gossip协议具有一定的容错能力,由于每个节点可以通过交互信息来更新状态,因此即使一部分节点失效,其他节点仍然可以更新状态,保持整个集群的一致性;自适应性:Gossip协议在传输信息时会根据实时情况进行调整,根据反馈信息和可靠性要求,自动选择合适的节点进行信息交流,从而提高了信息传输的效率和可靠性;低延迟:Gossip协议采用分散的信息传播方式,信息可以在整个网络中快速地传播,从而使得系统的响应速度更快。
Gossip缺点
延迟问题:由于Gossip协议的传播速度相对较慢,因此可能存在节点状态更新的延迟问题。特别是在网络拓扑结构较为复杂或节点数量较大时,这种延迟问题会更加突出;带宽开销:由于Gossip协议的信息需要在节点之间不断传播,因此可能会产生较大的网络带宽开销。特别是在节点数量较大时,这种开销会更加严重;数据一致性问题:由于Gossip协议是基于随机的节点通信机制实现的,因此可能会出现数据不一致的情况。特别是在节点状态频繁变化时,这种问题会更加明显;安全性问题:Gossip协议需要在节点之间传递敏感信息,因此存在安全性问题。特别是在没有适当的加密和认证机制时,这种问题会更加严重。
3.6节大致提了一嘴Gossip协议,这里讲讲在Redis Cluster中的应用。
4.3.2.1 Gossip协议的使用
Redis 集群是去中心化的,彼此之间状态同步靠 gossip 协议通信,集群的消息有以下几种类型:
Meet:通过cluster meet ip port命令,已有集群的节点会向新的节点发送邀请,加入现有集群。Ping:节点每秒会向集群中其他节点发送ping 消息,消息中带有自己已知的两个节点的地址、槽、状态信息、最后一次通信时间等。Pong:节点收到ping 消息后会回复pong 消息,消息中同样带有自己已知的两个节点信息。Fail:节点ping不通某节点后,会向集群所有节点广播该节点挂掉的消息。其他节点收到消息后标记已下线。
4.3.2.2 基于Gossip协议的故障检测
集群中的每个节点都会定期地向集群中的其他节点发送PING消息,以此交换各个节点状态信息,检测各个节点状态:在线状态、疑似下线状态PFAIL、已下线状态FAIL。
自己保存信息:当主节点A通过消息得知主节点B认为主节点D进入了疑似下线(PFAIL)状态时,主节点A会在自己的clusterState.nodes字典中找到主节点D所对应的clusterNode结构,并将主节点B的下线报告添加到clusterNode结构的fail_reports链表中,并后续关于主节点D疑似下线的状态通过Gossip协议通知其他节点。一起裁定:如果集群里面,半数以上的主节点都将主节点D报告为疑似下线,那么主节点D将被标记为已下线(FAIL)状态,将主节点D标记为已下线的节点会向集群广播主节点D的FAIL消息,所有收到FAIL消息的节点都会立即更新nodes里面主节点D状态标记为已下线。最终裁定:将 node 标记为 FAIL 需要满足以下两个条件:- 有
半数以上的主节点将 node 标记为PFAIL状态。 当前节点也将 node 标记为PFAIL状态。
- 有
相关数据结构:
- clusterState:从当前节点的视角来看的集群状态,每个节点维护一份
- myself:指针指向自己的clusterNode
- currentEpoch:当前节点见过的最大epoch,可能在心跳包的处理中更新
- nodes:当前节点感知到的所有节点,为clusterNode指针数组
- slots:slot与clusterNode指针映射关系
- migrating_slots_to, importing_slots_from:记录slots的迁移信息
- failover_auth_time, failover_auth_count, failover_auth_sent, failover_auth_rank, failover_auth_epoch:Failover相关
- clusterNode:代表集群中的一个节点
- slots:位图,由当前clusterNode负责的slot为1
- salve, slaveof:主从关系信息
- ping_sent, pong_received:心跳包收发时间
- clusterLink *link:Node间的联接
- list *fail_reports:收到的节点不可达投票
- clusterLink,负责处理网络上的一条链接来的内容。
4.3.3 心跳
4.3.3.1 心跳时机
Redis节点会记录其向每一个节点上一次发出ping和收到pong的时间(详见3.3.2节),心跳发送时机与这两个值有关。通过下面的方式既能保证及时更新集群状态,又不至于使心跳数过多:
- 每次Cron向所有
未建立链接的节点发送ping或meet; 每1秒从所有已知节点中随机选取5个,向其中上次收到pong最久远的一个发送ping;- 每次Cron向收到
pong超过timeout/2的节点发送ping; - 收到
ping或meet,立即回复pong。
4.3.3.2 心跳数据
Header:发送者自己的信息- 所负责slots的信息
- 主从信息
- ip port信息
- 状态信息
Gossip:发送者所了解的部分其他节点的信息- ping_sent, pong_received
- ip, port信息
- 状态信息,比如发送者认为该节点已经不可达,会在状态信息中标记其为
PFAIL或FAIL
4.3.3.3 心跳处理
新节点加入- 发送
meet包加入集群 - 从
pong包中的gossip得到未知的其他节点 - 循环上述过程,直到最终加入集群
新节点加入
- 发送
Slots信息- 判断发送者声明的
slots信息,跟本地记录的是否有不同- 如果不同,且发送者
epoch较大,更新本地记录 - 如果不同,且发送者
epoch小,发送Update信息通知发送者
- 如果不同,且发送者
- 判断发送者声明的
- Master slave信息:发现发送者的
master、slave信息变化,更新本地状态 - 节点Fail探测
- 超过
超时时间仍然没有收到pong包的节点会被当前节点标记为PFAIL PFAIL标记会随着gossip传播- 每次收到心跳包会检测其中对其他节点的
PFAIL标记,当做对该节点FAIL的投票维护在本机 - 对某个节点的
PFAIL标记达到大多数时,将其变为FAIL标记并广播FAIL消息。
- 超过
4.3.4 广播
当需要发布一些非常重要且需要立即送达的信息时,上述心跳加Gossip的方式就显得捉襟见肘了,这时就需要向所有集群内机器的广播信息,使用广播发消息的场景:
- 节点的Fail信息:当发现某一节点不可达时,探测节点会将其标记为
PFAIL状态,并通过心跳传播出去。当某一节点发现这个节点的PFAIL超过半数时修改其为FAIL并发起广播; - Failover Request信息:slave尝试发起
FailOver时广播其要求投票的信息; - 新Master信息:Failover成功的节点向整个集群广播自己的信息。
4.4 故障恢复(Failover)
当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。由于挂掉的master可能会有多个slave。Failover的过程需要经过类Raft协议的过程在整个集群内达到一致, 其过程如下:
- slave发现自己的master变为
FAIL; - 将自己记录的集群
currentEpoch加1,并广播Failover Request信息; - 其他节点收到该信息,只有master响应,判断请求者的合法性,并发送
FAILOVER_AUTH_ACK,对每一个epoch只发送一次ack; - 尝试failover的slave收集
FAILOVER_AUTH_ACK; 超过半数后变成新Master;- 广播
Pong通知其他集群节点。
Failover
4.5 扩容&缩容
4.5.1 扩容
- 新节点向集群中的一个已知节点发送
meet 命令请求加入集群; - 已知节点向集群中
其他节点发送meet 命令,将新节点加入集群;(新添加的节点默认在集群中都是主节点。) - 新节点加入集群后,会通过
ping/pong报文与其他节点建立心跳连接,同步集群信息,包括集群节点的数量、槽位信息等;
当新节点成为集群的一员时,集群中的数据迁移将开始,数据迁移过程中对客户端是透明的。具体的数据迁移过程如下
- 集群会从
所有原节点中选取一部分槽位的数据迁移到新节点上,具体的迁移槽位和数量取决于集群中的数据分布情况; - 在数据迁移期间,如果有客户端访问迁移的槽位,集群会返回一个
ASK 错误,告知客户端要访问的槽位已经迁移到了新节点上,同时告知客户端新节点的地址,客户端会根据返回的地址重新发起请求; - 当所有数据迁移完成后,集群会向客户端返回
MOVED信息,告知客户端对应的槽位已经迁移到了新节点上; - 客户端收到
MOVED信息后,会更新本地的【槽位/节点映射表】,以便后续请求可以直接定位到新节点。
Redis数据迁移
4.5.2 缩容
- 确定下线的节点是否有负责槽(是否是主节点),如果是,需要把槽迁移到其他节点,保证节点下线后整个槽节点映射的完整性。
- 当下线节点不在负责槽或着本身是从节点时,就可以通知集群内其他节点忘记下线节点,当所有节点忘记该节点后就可以正常关闭。
Redis集群缩容过程一般是先下线从节点,再下线主节点。以免不必要的全量同步。
5 其它常见方案
5.1 Redis Sentinel 集群 + Keepalived/Haproxy

- 优点:
- 秒级切换
- 对应用透明
- 缺点:
- 维护成本高
- 存在脑裂
- Sentinel 模式存在短时间的服务不可用
5.2 Twemproxy

- 优点:开发简单,对应用几乎透明历史悠久,方案成熟
- 缺点:
- 代理影响性能
LVS和Twemproxy会有节点性能瓶颈- Redis 扩容非常麻烦
- Twitter 内部已放弃使用该方案,新使用的架构未开源
5.3 Codis

Codis是由豌豆荚开源的产品,涉及组件众多,其中 ZooKeeper 存放路由表和代理节点元数据、分发 Codis-Config 的命令;Codis-Config是集成管理工具,有 Web 界面供使用;Codis-Proxy是一个兼容 Redis 协议的无状态代理;Codis-Redis基于 Redis 2.8 版本二次开发,加入 slot 支持,方便迁移数据。
- 优点:
- 开发简单,对应用几乎透明;
- 性能比
Twemproxy好; - 有图形化界面,扩容容易,运维方便。
- 缺点:
- 代理依旧影响性能;
- 组件过多,需要很多机器资源;
- 修改了 Redis 代码,导致和官方无法同步,新特性跟进缓慢;
- 开发团队准备主推基于 Redis 改造的
reborndb。
6 总结
Redis集群方案是一种高可用、可扩展的解决方案,通过分片和主从复制机制来实现数据的分布式存储和故障转移。
它具有以下优点:
- 高可用:多个主节点,每个主节点有对应多个从节点,主节点宕机Redis Cluster机制会
自动将某个从节点切换到主节点; - 扩展性:
- 横向扩展:通过增加机器实现增加能力上限;
- 读写扩展:基于主从模式,通过读写分离,增加读写能力,避免单点故障;
- 分布式存储:Redis Cluster采用
分片技术将数据均匀分布到多个节点上,每个节点只保存部分数据,避免了单个节点存储数据过大的问题,提高了存储容量和性能。
- 自动数据迁移:Redis Cluster支持
自动数据迁移,当新增或删除节点时,会自动将数据迁移到其他节点上,保证数据均衡和数据完整性。
缺点也有很多:
- 部署和管理复杂:Redis集群方案需要部署多个节点,并且需要进行一些配置和管理工作,例如设置节点数量、槽的分配、主从复制等。
- 可能存在数据丢失:由于Redis集群方案使用
异步复制机制,当主节点宕机时,可能存在一段时间内的数据丢失。因此,在数据可靠性要求较高的场景中,需要进行备份和恢复等措施。 - 不支持事务:由于Redis集群方案中不同的节点存储着不同的数据,因此
不支持事务操作。如果需要进行事务处理,可以使用Redis单节点方案。

