NoSQL之Redis集群
一、Redis集群方式
Redis 有三种模式:分别是主从复制、哨兵模式、Cluster
1:主从模式
主从复制是高可用 Redis的基础,哨兵和群集都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单故障恢复。
缺陷:故障恢复无法自动化,写操作无法负载均衡,存储能力受到单机的限制。
2:哨兵模式
在主从复制的基础上,哨兵实现了自动化的故障恢复。
缺陷:写操作无法负载均衡,存储能力受到单机的限制,哨兵无法对从节点进行自动故障转移;在读写分离场景下,从节点故障会导致读服务不可用,需要对从节点做额外的监控、切换操作。
3:集群模式
通过集群,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案。
Redis-Cluster 是在 Redis3.0 版中推出,支持 Redis 分布式集群部署模式,采用无中心分布式架构。所有的 Redis 节点彼此互联(PING-PONG 机制),内部使用二进制协议优化传输速度和带宽。节点的 fai1 是通过集群中超过半数的节点检测失败时才生效。客户端与 Redis节点直连,不需要中间代理层。客户端也不需要连接集群所有节点,连接集群中任何一个可用节点即可,这样即减少了代理层,也大大提高了 Redis 集群性能。
Redis Cluster 通过创建多个副本来保证数据的可靠性。每个分片都有一个主节点和多个从节点,主节点负责处理读写操作,而从节点则复制主节点的数据。当主节点发生故障时从节点会自动切换为主节点,提供读写服务。这样可以确保即使发生节点故障,系统仍然能够继续提供服务,保证数据的高可用性。
模式 | 版本 | 优点 | 缺点 |
---|---|---|---|
主从模式 | redis2.8之前 | 解决数据备份问题;做到读写分离,提高服务器性能 | master 故障,无法自动故障转移需人工介入;master 无法实现动态扩容 |
哨兵模式 | redis2.8级之后的模式 | Master 状态监测;master 节点故障,自动切换主从,故障自愈;所有 slave 从节点,随之更改新的master 节点 | slave 节点下线,sentinel 不会对其进行故障转移,连接从节点的客户端因为无法获取到新的可用从节点;master 无法实行动态扩容 |
redis cluster模式 | redis3.0版本之后 | 有效的解决了 redis 在分布式方面的需求;遇到单机内存,并发和流量瓶颈等问题时,可采用 Cluster 方案达到负载均衡的目的;可实现动态扩容;P2P 模式,无中心化;通过 Gossip 协议同步节点信息;自动故障转移、Slot 迁移中数据可用;自动分割数据到不同的节点上;整个集群的部分节点失败或者不可达的情况下能够继续处理命令 | 架构比较新,最佳实践较少;为了性能提升,客户端需要缓存路由表信息;节点发现、reshard 操作不够自动化;不支持处理多个 keys 的命令,因为这需要在不同的节点间移动数据;Redis 集群不像单机 Redis 那样支持多数据库功能,集群只使用默认的0号数据库,并且不能使用 SELECTindex命令 |
二、集群模式
集群,即 Redis Cluster, 是Redis 3.0开始引入的分布式存储方案。集群由多个节点(Node)组成,Redis 的数据分布在这些节点中。集群中的节点分为主节点和从节点;只有主节点负责读写请求和集群信息的维护;从节点只进行主节点数据和状态信息的复制。
redis 集群采用 master-slave 的方式,即1个 master 节点可以包含多个 slave 节点,slave 节点主要对 master 节点的数据进行备份,如果 master 节点挂了,可以启动 salve 节点替换掉原先的 master 节点,作为新的 master 节点。redis 集群使用投票容错机制,如果集群中超过半数以上的节点投票认为某节点挂了,那么这个节点就会被认为挂掉了,所以,在设置 redis 集群时,最少的 master 节点为3个,如果每一个master 节点都添加一个 slave节点的话,搭建一个redis集群总共需要6个节点,即3个master 节点,3 个slave 节点。
redis 集群没有统一的入口,客户端连接集群的时候,连接集群中的任意节点即可。
Redis 集群是一个由多个主从节点群组成的分布式服务集群,它具有复制、高可用和分片特性。Redis 集群不需要 sentinel 哨兵也能完成节点移除和故障转移的功能。需要将每个节点设置成集群模式,这种集群模式没有中心节点,可水平扩展,据官方文档称可以线性扩展到上万个节点(官方推荐不超过 1000 个节点)。redis 集群的性能和高可用性均优于之前版本的哨兵模式,且集群配置非常简单。redis 集群的运用主要是针对海量数据+高并发+高可用的场景。
三、数据分片方式
对象保存到 redis 之前先经过 CRC16 哈希到一个指定的 Node 上,这个过程即 rediscluster 的分片,集群内部将所有的key 映射到 16384个 Slot 中,集群中的每个 RedisInstance 负责其中的一部分的 Slot 的读写。集群客户端连接集群中任一 Redis Instance即可发送命令,当 Redis Instance 收到自己不负责的 Slot 的请求时,会将负责请求 Key所在 Slot 的 Redis Instance 地址返回给客户端,客户端收到后自动将原请求重新发往这个地址,对外部透明。一个Key 到底属于哪个Slot由(HASH_SLOT=CRC16(key)mod 16384)决定,也就是先对 key 进行哈希,然后对哈希值%16384 求余数算出槽位号。只有 master节点会被分配槽位,slave 节点不会分配槽位。
Redis Cluster 通过哈希算法将数据分散到多个节点上,实现数据的分片。每个节点负责管理一部分数据,并提供相应的读写操作。分片机制可以将数据均匀地分布在多个节点上,提高系统的并发处理能力。当某个节点发生故障时,只会影响该节点上的数据,而不会影响整个系统的可用性。
具体的分片方式有客户端分片、代理分片和Twemproxy 代理分片机制。
客户端分片
客户端分片方案是将分片工作放在业务程序端。程序代码根据预先设置的路由规则,直接对多个 Redis 实例进行分布式访问。这样的好处是,群集不依赖于第三方分布式中间件,实现方法和代码都自己掌控,可随时调整,不用担心踩到坑。这实际上是一种静态分片技术,Redis 实例的增减,都得手工调整分片程序。基于此分片机制的开源产品,现在仍不多见。
这种分片机制的性能比代理式更好(少了一个中间分发环节),但缺点是升级麻烦,对研发人员的个人依赖性强,需要有较强的程序开发能力做后盾。如果主力程序员离职,可能新的负责人会选择重写一遍。所以这种方式下可运维性较差,一旦出现故障,定位和解决都得研发人员和运维人员配合解决,故障时间变长。因此这种方案,难以进行标准化运维,不太适合中小公司。
代理分片
代理分片方案是将分片工作交给专门的代理程序来做。代理程序接收到来自业务程序的数据请求,根据路由规则,将这些请求分发给正确的 Redis 实例并返回给业务程序。这利机制下,一般会选用第三方代理程序(而不是自己研发)。因为后端有多个 Redis实例,所以这类程序又称为分布式中间件。这种分片机制的好处是业务程序不用关心后端 Redis实例,维护起来也方便。虽然会因此带来些性能损耗,但对于Redis 这种内存读写型应用,相对而言是能容忍的。这是比较推荐的集群实现方案。像 Twemproxy、Codis 就是基于该机制的开源产品的其中代表,应用非常广泛。
(1)Twemproxy 代理分片机制
Twemproxy 是一种代理分片机制,由 Twitter 开源。Twemproxy 作为代理,可接受来自多个程序的访问,按照路由规则,转发给后台的各个edis服务器,再原路返回。这个方案顺理成章地解决了单个 Redis 单实例问题。当然Twemproxy 本身也是单点,需要用Keepalived 做高可用方案。在很长的时间内,Twemproxy 是应用范围最广、稳定性最高最久经考验的分布式中间件。
这种分片方式无法平滑地扩容/缩容,增加了运维难度。当业务量突增需要增加 Redis服务器或业务量萎缩需要减少 Redis 服务器时,Twemproxy 都无法平滑地进行扩容或缩容等操作。
并且 Twemproxy 代理分片机制对运维操作不友好,甚至没有控制面板。由于使用了中间件代理,相比客户端直接连接服务器方式,性能上有所损耗,实测性能效果降低了 20%左右。
(2)Codis 代理分片机制
Codis 由豌豆荚于 2014 年 11 月开源,基于 Go 语言和C语言开发,是近期涌现的国人开发的优秀开源软件之一,现已广泛用于豌豆荚的各种 Redis 业务场景。从各种压力测试来看,Codis 的稳定性符合高效运维的要求。实测 Codis 集群业务处理性能改善很多,最初集群处理数据性能要比 Twemproxy差20%左右,现在比 Twemproxy好很多。并且 Codis具有可视化运维管理界面。因此综合方面会优于Twemproxy 很多。目前越来越多的公司选择 Codis。
Codis 引入了 Group 的概念,每个 Group包括1个Redis Master 及至少1个RedisSlave,这是和 Twemproxy 的区别之一。这样做的好处是,如果当前 Master 有问题则运维人员可通过 Dashboard“自助式”切换到 Slave,而不需要小心翼翼地修改程序配置文件。
为支持数据热迁移(Auto Rebalance),出品方修改了 Redis Server 源码,并称之为CodisServer。Codis 采用预先分片(Pre-Sharding)机制,事先规定分成1024个 slots(也就是说,最多能支持后端 1024 个 Codis Server),这些路由信息保存在 zookeeper 中。
服务器端分片
服务器端分片是 Redis 官方的集群分片技术。Redis-Cluster 将所有 Key 映射到16384个 slot 中,集群中每个 Redis 实例负责一部分,业务程序是通过集成的Redis-Cluster 客户端进行操作。客户端可以向任一实例发出请求,如果所需数据不在该实例中,则该实例引导客户端自动去对应实例读写数据。Redis-Cluster 成员之间的管理包括节点名称、IP、端口、状态、角色等,都通过节点与之间两两通讯,定期交换信息并更新。
四、负载均衡的实现
客户端路由: 在 Redis Cluster 中,客户端需要根据数据的键名选择正确的节点进行读写操作。Redis Cluster 使用哈希槽(hash slot)来划分数据,并将每个哈希槽映射到相应的节点上。客户端可以根据键名的哈希值,将请求发送到对应的节点上,实现负载均衡。
自动迁移: Redis Cluster 具有自动迁移功能,当节点加入或离开集群时,系统会自动重新分配数据,保持各个节点上哈希槽的均衡。当节点加入集群时,系统会将一部分哈希槽从其他节点迁移到新节点上;当节点离开集群时,系统会将该节点上的哈希槽重新分配给其他节点。这种机制可以在节点数目变化时,自动调整数据的分布,实现负载均衡。
故障检测与恢复: Redis Cluster 具有故障检测和自动恢复的机制。集群中的节点会相互监控,检测节点的健康状态。当某个节点被检测到不可用时,系统会自动将该节点标记为下线,并将该节点上的哈希槽重新分配给其他节点。当节点恢复正常时,系统会将其重新加入集群,并进行数据迁移,保持数据的一致性。
Redis Cluster 通过分片和副本机制实现了数据的高可用性和负载均衡。分片机制将数据均匀地分布在多个节点上,提高了系统的并发处理能力;副本机制则保证了数据的可靠性,即使发生节点故障,也能够继续提供服务。同时,Redis Cluster 通过客户端路由、自动迁移和故障检测与恢复等机制,实现了负载均衡和故障自动转移。在实际应用中,合理设计和配置 Redis Cluster,可以提高系统的性能、可靠性和可扩展性。
五、故障的处理
1.故障转移
当从节点发现自己的主节点变为已下线(FAIL)状态时,便尝试进 Failover,以期成为新的主。
以下是故障转移的执行步骤:
(1)从下线主节点的所有从节点中选中一个从节点
(2)被选中的从节点执行 SLAVEOF NO NOE命令,成为新的主节点
(3)新的主节点会撤销所有对已下线主节点的槽指派,并将这些槽全部指派给自己
(4)新的主节点对集群进行广播PONG消息,告知其他节点已经成为新的主节点
(5)新的主节点开始接收和处理槽相关的请求
6)集群 slots是否必须完整才能对外提供服务
多slave选举
在多个 slave 情况下如果一个 master 宕机,需要基于 Raft 协议选举方式来实现的新主的选举。步骤如下:
(1)当从节点发现自己的主节点进行已下线状态时,从节点会广播一条CLUSTERMSG TYPE FAILOVER AUTH REQUEST 消息,要求所有收到这条消息,并且具有投票权的主节点向这个从节点投票。
(2)如果一个主节点具有投票权,并且这个主节点尚未投票给其他从节点,那么主节点将向要求投票的从节点返回一条,CLUSTERMSG TYPEFAILOVER AUTH ACK 消息,表示这个主节点支持从节点成为新的主节点。
(3)每个参与选举的从节点都会接收CLUSTERMSG TYPEFAILOVER AUTH ACK消息,并根据自己收到了多少条这种消息来统计自己获得了多少主节点的支持。
(4)如果集群里有N个具有投票权的主节点,那么当一个从节点收集到大于等于集群 N/2+1张支持票时,这个从节点就成为新的主节点。
(5)如果在一个选举周期没有从能够收集到足够的支持票数,那么集群进入一个新的选举周期,并再次进行选主,直到选出新的主节点为止。
六、Redis群集部署
安装redis
(每个节点都要安装)
修改配置文件
(每个节点都要配置)
注释:
开启Cluster: cluster-enabled yes
集群配置文件:cluster-config-file nodes-7000.conf。这个配置文件不是要我们去配的,而是 Redis 运行时保存配置的文件,所以我们也不可以修改这个文件。
集群超时时间:cluster-node-timeout 15000。结点超时多久则认为它宕机了。
槽是否全覆盖:cluster-require-full-coverage no。默认是yes,只要有结点宕机导致16384个槽没全被覆盖,整个集群就全部停止服务,所以一定要改为no
创建redis集群
(任意单台节点即可)
备注:
需要至少3个 master 节点,副本数至少为1,即每个 master 需要一个从节点
测试群集
集群信息查看
添加节点
2种方法
第一种
例如存在节点 192.168.10.107(并且已在配置文件中开启集群相关配置),把192.168.10.107 加入现有集群
第二种
例如存在节点 192.168.10.108(并且已在配置文件中开启集群相关配置),把192.168.10.108 加入现有集群
注意:
10.108 是要新添加的节点,10.107 可以是当前集群中的任意一个节点
修改新节点为其他节点的从节点
让10.108 成为10.107的从节点,此ID(c7084cce5659dc57bea94c588b13928c5ab75403) 的 ID
注意:10.108 需要先加入到集群,再设置为其他master 的slave。
重新分配槽位
重新分片基本上意味着将 slot 重新分配,就像集群创建一样,它是使用 redis-cli实用程序完成的。
注意:平均分配所有的槽位,使用以下命令会自动将16384个槽位自动分配给集群的每一个 master,不用手动指定槽为分配。
只需要指定一个老的节点(192.168.10.101:6379),redis 会自动查找其他节点
删除节点
(1)清除 10.107的槽位信息
(2)删除107节点
注意:此 ID为10.108 的 ID
注意;
如果删除的 slave 节点,直接删除即可,如果删除的是 master 节点,需要先清除槽信息再删除,并且建议清除 redis 实例中的集群配置文件并重启实例,例如/var/lib/redis/6379/nodes-6379.conf