Redis Cluster是redis分布式数据库方案,集群通过分片(sharding),在多个Redis节点间共享数据的程序集并对数据进行管理,
集群具备分片间数据复制、故障转移和流量调度的能力。
Redis 集群使用的是基于槽的分区策略,即将数据分成固定数量的槽,每个槽由一个主节点和多个从节点组成。
客户端请求会根据键值的哈希值被路由到对应的槽上,从而实现数据的分布式存储和访问。
同时,Redis 集群还提供了多种操作槽的命令,以支持集群的管理和维护。
分布式存储:Redis 集群将数据分散存储在多个节点上,每个节点负责处理一部分数据,从而实现数据的分布式存储和访问
集群可以扩展到数千个节点,以支持海量数据存储和高并发访问。建议控制在1000个以内的节点数。
高可用性:Redis 集群通过多副本机制和自动故障转移机制,保证数据的可靠性和可用性。每个节点都有多个副本,
其中一个副本为主节点,负责处理客户端请求,其他副本为从节点,负责复制主节点的数据。当主节点宕机时,
从节点会自动选举一个新的主节点,以保证数据的连续性和可用性。
数据自动分片:Redis 集群将数据自动分片存储在多个节点上,以实现数据的均衡分布和高效访问。每个节点都负责处理一部分数据,
同时维护一份槽指派表,记录每个槽对应的主节点和从节点。客户端请求会根据键值的哈希值被路由到对应的槽上,
从而实现数据的分布式存储和访问
支持在线扩容缩容:Redis 集群支持在线添加和删除节点,以扩展或缩小集群的容量,而无需停机或数据迁移。
集群会自动将数据重新分片和迁移,以保证数据的连续性和可用性。
负载均衡:Redis 集群通过智能路由算法,将客户端请求均匀地分发到不同的节点上,以实现负载均衡和性能优化。
客户端可以通过集群模式下的代理节点(cluster-enabled proxy)进行连接,代理节点会自动将请求路由到正确的节点上。
注意:不支持处理多个key:因为数据分散在多个节点,在数据量大高并发的情况下会影响性能;
?使用Redis集群时我们会将存储的数据分散到多台redis机器上,这称为分片。数据分别存储在不同的节点上,从而实现分布式存储和访问的基本方式。
?为了找到给定key的分区,我们对key进行CRC16(key)算法处理并通过对总分区数量取模。然后,使用确定性哈希函数,这意味着给定的key将多次始终映射到同一个分片,我们可以推断将来读取特定key的位置。
?方便扩缩容和数据分派查找。
?容易添加或者删除节点,比如如果我想新添加个节点D,我需要从节点A、B、C中取部分槽到D上,如果我移除节点A,需要将A中的槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可。由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态
?redis集群没有使用一致性hash,而是引入了哈希槽的概念。
?redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。从而实现数据的分布式存储和访问
例如:比如当前集群有3个节点,
那么:redis slot槽位映射,一般业界有3种解决方案
?哈希取余分区是一种常见的数据分区技术,它将数据划分成多个分区,
并将每个分区分配给集群中的不同节点,从而实现分布式存储和访问。
在哈希取余分区中,首先根据某个键的哈希值对分区总数取模,得到该键所在的分区编号,然后将该键存储在对应的节点上。
当需要访问某个键值对时,同样通过哈希值计算得到该键所在的分区编号,然后访问对应的节点,从而实现数据的分布式访问。
哈希取余分区技术简单易懂,易于实现,可以较好地均衡数据在各个节点之间的分布,
从而提高系统的可扩展性和可用性。但是,该技术存在数据倾斜和数据迁移等问题。
如果某个键的哈希值对分区总数取模后恰好落在某个分区上,那么该分区的负载将会比其他分区更重,可能会导致性能问题。此外,在节点的动态扩容和缩容时,会需要进行数据迁移,对系统的稳定性和性能也会带来影响。
一致性哈希算法是一种用于分布式存储系统的数据分区技术,它可以使得数据在集群中的分布更加均匀,
同时减少在数据分区发生变化时需要重新分配的数据量。提出一致性HASH解决方案,目的是当服务器个数发生变动时,尽量减少影响客户端到服务器的映射关系
实现步骤
算法构建一次性哈希环
Redis服务器IP节点映射
将集群中各个IP节点映射到环上的某一个位置。
将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。
假如4个节点Node A、B、C、D,经过IP地址的哈希函数计算(hash(ip)),使用IP地址哈希后在环空间的位置如下:
key落到服务器的落键规则
优点
缺点
一致性hash分区总结
为了在节点数据发生改变时尽可能少的迁移数据。
将所有的存储节点排列在收尾相接的Hash环上,每个key在计算Hash后会顺时针找到哦啊临近的存储节点存放。而当有节点加入或者退出时仅影响该节点在Hash环上顺时针相邻的后续节点。
优点: 加入和删除节点只影响哈希环中顺时针方向的相邻的节点,对其他节点无影响。
缺点: 数据的分布和节点的位置有关,因为这些节点不是均匀的分布在哈希环上的,所以数据在进行存储时达不到均匀分布的效果
哈希槽分区是 Redis 集群中常用的数据分区技术,它将整个数据集划分为固定数量的槽位(slot),然后将每个槽位分配到集群中不同的节点上,从而实现数据的分布式存储和访问。
4 哈希槽计算
架构图如下:
在本机上启动6个实例,模拟集群。
节点名 | IP | 端口 | 配置文件 |
M1 | 127.0.0.1 | 6379 | cluster_6379.conf |
M2 | 127.0.0.1 | 6381 | cluster_6381.conf |
M3 | 127.0.0.1 | 6383 | cluster_6383.conf |
S1 | 127.0.0.1 | 6380 | cluster_6380.conf |
S2 | 127.0.0.1 | 6382 | cluster_6382.conf |
S3 | 127.0.0.1 | 6384 | cluster_6384.conf |
以实例cluster-6379.conf为例,配置文件内容如下所示:
cluster-6379.conf
#bind 127.0.0.1 -::1
port 6379
daemonize yes
appendonly yes
pidfile "/usr/local/redis/cluster-6379.pid"
logfile "/usr/local/redis/logs/cluster-6379.log"
dbfilename "cluster-dump-6379.rdb"
dir "/usr/local/redis"
appenddirname "appendonlydir-6379"
requirepass "123456"
masterauth 123456
cluster-enabled yes ? ? ? ? ? # 开启集群
cluster-config-file nodes-6379.conf ? # 集群生成的配置文件
cluster-node-timeout 5000 ? ? ? ? ? # 集群节点之间的超时时间
其他配置文件根据上面做相应的修改
启动集群实例和之前启动redis实例一样,只不过配置文件中配置了开启集群,会以集群的方式启动redis实例。
?redis-server /usr/local/redis/cluster/cluster-6379.conf
?redis-server /usr/local/redis/cluster/cluster-6380.conf
?redis-server /usr/local/redis/cluster/cluster-6381.conf
?redis-server /usr/local/redis/cluster/cluster-6382.conf
?redis-server /usr/local/redis/cluster/cluster-6383.conf
?redis-server /usr/local/redis/cluster/cluster-6384.conf
使用命令构建集群间的主从关系:redis-cli -a 密码 --cluster create --cluster-replicas 1 IP:端口号 [IP:端口号]
选项:
–replicas 1 为集群中的每个主节点创建一个从节点
IP:端口号是redis实例的地址和端口号,多个redis实例构成一个集群主从关系是随机分配的
redis-cli -a 123456 --cluster create --cluster-replicas 1? 172.16.134.25:6379 172.16.134.25:6380? 172.16.134.25:6381 172.16.134.25:6382 172.16.134.25:6383 172.16.134.25:6384
info replication
cluster info
cluster nodes
每个key都有自己的哈希值,根据哈希值通过某种算法算出对应的槽位,该key只能存储到该槽位所在的节点上。然而这种情况并不是我们想要的,可以在连接redis客户端时添加-c参数,这样会帮我们把数据路由到指定的槽位上,即使在不同的节点上也能随便存储数据
查看某个key对应的槽位值:CLUSTER KEYSLOT key
任何字符都有对应的哈希值,所以任何字符都能计算出对应的槽位
查看某个槽位是否被占用:CLUSTER COUNTKEYSINSLOT 槽位号
返回1表示该槽位被占用;返回0表示该槽位没有被占用
注意:在其他任何集群节点查看集群节点的状态都可以。
主节点宕机后,从节点会成为新的master
关闭6379节点前后状态对比,6379的从节点(6384)角色变更为master,6379节点状态为fail
恢复6379节点后,该节点会变成新master的slave。
使用cluster failover可以调整主从关系及手动故障转移
切换总结: 当主节点宕机后从节点上位,挂掉的主节点重新启动后会成为原先从节点(新主节点)的从节点。集群不保证数据一致性100%OK,一定会有数据丢失的情况, Redis集群不保证强一致性,这意味着在特定的条件下,Redis集群可能会丢掉一些被系统受到的写入请求命令。
?redis-server /usr/local/redis/cluster/cluster-6385.conf
?redis-server /usr/local/redis/cluster/cluster-6388.conf
启动完成后角色都是master
??
redis-cli -a 密码 --cluster add-node 自己实际ip地址:6387 自己实际IP地址:6379
# 6387 将要作为master新增节点
# 6379 原集群节点里面的领路人,相当于6387通过6379从而找到组织加入集群。这个节点为原集群中任意一主节点
redis-cli -a 123456 --cluster add-node 172.16.134.25:6385 172.16.134.25:6379
?? ?
redis-cli -a 密码 --cluster check 真实ip地址:6385
只需要指定集群中任意一个在线的节点的地址(IP:端口号), 就会自动找到集群中的其他节点,即可查看整个集群的信息
redis-cli -a 123456 --cluster check? 172.16.134.25:6379
? ?
6385已经加入集群,角色为master,0 slots
redis-cli -a 密码 --cluster reshard IP地址:端口号
只需要指定集群中任意一个在线的节点的地址(IP:端口号)即可
redis-cli -a 123456 --cluster reshard 172.16.134.25:6379
指定迁移槽个数、接受槽位节点ID、被迁移槽位节点ID,如果是所有,请使用all
redis-cli -a 123456 --cluster check 172.16.134.25:6379
槽位重新分配成功
?先添加从节点到集群中,并查看状态
?redis-cli -a 123456 --cluster add-node 172.16.134.25:6388 172.16.134.25:6379? ?
?然后把6388添加成6385的从节点
?redis-cli -a 密码 --cluster add-node ip:新slave端口 ip:新master端口 --cluster-slave --cluster-master-id 新主机节点ID
?redis-cli -a 密码 --cluster add-node 172.16.134.25:6388 172.16.134.25:6385 --cluster-slave? --cluster-master-id 5d6799591c1cdd2d494a6259e38a95bc442335eb
集群状态检查,从节点已经添加完成
首先先将从节点6388删除:redis-cli -a 密码 --cluster del-node IP:从节点端口 从节点id
redis-cli -a 123456 --cluster del-node 172.16.134.25:6388 e22e527194cf9aa1ea7d20e61476bdb26e
节点id可以通过检查集群情况命令查看:redis-cli -a 密码 --cluster check IP:port
也可以通过CLUSTER NODES命令查看。
?从节点删除成功
主分配了hash槽的,需要先把主节点里的hash槽迁移到其他可用主节点,然后再进行移除节点操作,不然会出现数据丢失问题
这里将清空的槽号全部分配给6379节点(当然也可以平均分配回之前的三个主节点,只不过要操作三次)
redis-cli -a 123456 --cluster reshard 172.16.134.25:6379
?
移除槽位后检查集群情况
6385节点槽位被清空,成为了6379的从节点,这和加入6385节点到集群时填写的集群中的IP:port有关(6379相当于推荐人)
此时节点6385是一个从节点,将节点6385删除
redis-cli -a 123456 --cluster del-node? 172.16.134.25:6385 e22e527194cf9aa1ea7d20e61476bdb26e
再次查询集群状态,已经回到最初的3主3从架构
? ?
redis-server /data/cluster/redis/cluster/cluster-6385.conf
redis-server /data/cluster/redis/cluster/cluster-6388.conf
redis-cli -a 123456 --cluster add-node 172.16.134.25:6385 172.16.134.25:6379
redis-cli -a 123456 --cluster check? 172.16.134.25:6379
redis-cli -a 123456 --cluster reshard 172.16.134.25:6379
? ? redis-cli -a 123456 --cluster add-node 172.16.134.25:6388 172.16.134.25:6379 ?
? ? redis-cli -a 密码 --cluster add-node ip:新slave端口 ip:新master端口 --cluster-slave --cluster-master-id 新主机节点ID
? ? redis-cli -a 密码 --cluster add-node 172.16.134.25:6388 172.16.134.25:6385 --cluster-slave? --cluster-master-id 5d6799591c1cdd2d494a6259e38a95bc442335eb
redis-cli -a 123456 --cluster del-node? 172.16.134.25:6388 e22e527194cf9aa1ea7d20e61476bdb26e
?redis-cli -a 123456 --cluster reshard 172.16.134.25:6379
?redis-cli -a 123456 --cluster del-node? 172.16.134.25:6385 5d6799591c1cdd2d494a6259e38a95bc442335eb
cluster failover
redis-cli -a 123456 --cluster check 172.16.134.25:6379
??