文章目录
- 集群
- 1.基本介绍
- 2.redis集群槽位
- 3.redis集群分片
- 4.redis槽位映射
- 5.redis集群环境搭建
- 5.1三主三从redis集群配置
- 5.2启动六台redis实例
- 5.3构建主从关系
- 6.redis集群读写
- 7.redis集群主从切换
- 8.redis集群扩容
- 9.redis集群缩容
- 10.集群常用操作命令和CRC16算法分析
集群
1.基本介绍
由于数据量过大,单个Master复制集难以承担,因此需要对多个复制集进行集群,形成水平扩展每个复制集只负责存储整个数据集的一部分,这就是Redis的集群,其作用是提供在多个Redis节点间共享数据的程序集
Redis集群是Redis数据库的分布式解决方案,它可以将数据分散存储在多个节点上,以支持大规模数据存储和高并发访问
- Redis集群使用的是基于槽的分区策略,即将数据分成固定数量的槽,每个槽由一个主节点和多个从节点组成。客户端请求会根据键值的哈希值被路由到对应的槽上,从而实现数据的分布式存储和访问。同时,Redis集群还提供了多种操作槽的命令,以支持集群的管理和维护
Redis 集群的主要特点包括:
- 分布式存储:Redis 集群将数据分散存储在多个节点上,每个节点负责处理一部分数据,从而实现数据的分布式存储和访问。集群可以扩展到数千个节点,以支持海量数据存储和高并发访问。建议控制在1000个以内的节点数。
- 高可用性:Redis 集群通过多副本机制和自动故障转移机制,保证数据的可靠性和可用性。每个节点都有多个副本,其中一个副本为主节点,负责处理客户端请求,其他副本为从节点,负责复制主节点的数据。当主节点宕机时,从节点会自动选举一个新的主节点,以保证数据的连续性和可用性。
- 数据自动分片:Redis 集群将数据自动分片存储在多个节点上,以实现数据的均衡分布和高效访问。每个节点都负责处理一部分数据,同时维护一份槽指派表,记录每个槽对应的主节点和从节点。客户端请求会根据键值的哈希值被路由到对应的槽上,从而实现数据的分布式存储和访问。
- 支持在线扩容缩容:Redis 集群支持在线添加和删除节点,以扩展或缩小集群的容量,而无需停机或数据迁移。集群会自动将数据重新分片和迁移,以保证数据的连续性和可用性。
- 负载均衡:Redis 集群通过智能路由算法,将客户端请求均匀地分发到不同的节点上,以实现负载均衡和性能优化。客户端可以通过集群模式下的代理节点(cluster-enabled proxy)进行连接,代理节点会自动将请求路由到正确的节点上。
2.redis集群槽位
在Redis集群中,槽位(slot)是将数据进行分片的基本单位,也是实现数据分布式存储和访问的重要机制,Redis集群默认将16384个槽位均分给不同的节点,每个节点负责处理一部分槽位,从而实现数据的分布式存储和访问
具体来说,Redis 集群使用哈希槽(hash slot)的方式将数据进行分片,每个槽对应着一个整数编号,从 0 开始,一直到 16383。每个节点会负责处理一部分槽位,同时维护一份槽指派表(slot map),记录每个槽对应的主节点和从节点。
客户端请求会根据键值的哈希值被路由到对应的槽上,从而实现数据的分布式存储和访问,具体来说,客户端会将键值的哈希值对16384取模,得到一个槽号,然后将请求发送到对应的槽所在的节点上。如果该节点是主节点,它会将请求处理后的结果返回给客户端;如果该节点是从节点,则会将请求转发给对应的主节点进行处理
需要注意的是,槽的数量是固定的,因此如果需要扩展 Redis 集群的容量,就需要将一些槽移动到新的节点上,以实现数据的重新分片和迁移。Redis 集群提供了多种操作槽的命令,以支持集群的管理和维护。
3.redis集群分片
在 Redis 集群中,数据分片(sharding)是将数据划分成多个部分,分别存储在不同的节点上,从而实现分布式存储和访问的基本方式。Redis 集群使用哈希槽(hash slot)的方式将数据进行分片,每个节点负责处理一部分槽位,从而实现数据的分布式存储和访问。
具体来说,Redis 集群默认将 16384 个槽位均分给不同的节点,每个节点负责处理一部分槽位,同时维护一份槽指派表(slot map),记录每个槽对应的主节点和从节点。客户端请求会根据键值的哈希值被路由到对应的槽上,从而实现数据的分布式存储和访问。
数据分片能够提高 Redis 集群的容量和可用性,减少单节点的负载压力,并支持横向扩展和动态扩容。同时,数据分片也会带来一些挑战和问题,例如数据迁移、节点失效、一致性维护等方面的问题,需要进行合理的设计和实现。
优势
4.redis槽位映射
-
哈希取余分区
哈希取余分区是一种常见的数据分区技术,它将数据划分成多个分区,并将每个分区分配给集群中的不同节点,从而实现分布式存储和访问。
在哈希取余分区中,首先根据某个键的哈希值对分区总数取模,得到该键所在的分区编号,然后将该键存储在对应的节点上。当需要访问某个键值对时,同样通过哈希值计算得到该键所在的分区编号,然后访问对应的节点,从而实现数据的分布式访问
哈希取余分区技术简单易懂,易于实现,可以较好地均衡数据在各个节点之间的分布,从而提高系统的可扩展性和可用性。但是,该技术存在数据倾斜和数据迁移等问题。如果某个键的哈希值对分区总数取模后恰好落在某个分区上,那么该分区的负载将会比其他分区更重,可能会导致性能问题。此外,在节点的动态扩容和缩容时,会需要进行数据迁移,对系统的稳定性和性能也会带来影响。
-
一致性哈希算法分区
一致性哈希算法(Consistent Hashing Algorithm)是一种用于分布式存储系统的数据分区技术,它可以使得数据在集群中的分布更加均匀,同时减少在数据分区发生变化时需要重新分配的数据量。
一致性Hash算法背景
一致性哈希算法在1997年由麻省理工学院中提出的,设计目标是为了解决
分布式缓存数据变动和映射问题,某个机器宕机了,分母数量改变了,自然取余数不OK了。
在一致性哈希算法中,所有的数据被分成一定数量的分区,每个分区被映射到一个哈希环上。每个节点也被映射到哈希环上,并负责其所在的某些分区。当需要存储一个数据时,先对该数据进行哈希,然后将哈希值映射到哈希环上,找到最近的节点,并将数据存储在该节点上。当需要读取一个数据时,也先对该数据进行哈希,并映射到哈希环上,然后从离该数据最近的节点上读取数据。
一致性哈希环
一致性哈希算法的核心思想是将哈希环视为一个环形空间,并将节点和数据视为该空间上的点。通过在哈希环上的均匀分布,可以使得数据在集群中的分布更加均匀。当某个节点宕机时,只会影响该节点所负责的一部分分区,不会影响整个集群,从而提高了系统的可用性和稳定性。同时,一致性哈希算法也能够自动地将数据重新映射到新的节点上,从而减少了数据的迁移量和系统的维护成本。
一致性哈希算法已经被广泛地应用于各种分布式系统中,包括缓存系统、负载均衡系统、分布式文件系统等
redis服务器ip节点映射
将集群中各个IP节点映射到环上的某一个位置。
将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。假如4个节点NodeA、B、C、D,经过IP地址的哈希函数计算(hash(ip)),使用IP地址哈希后在环空间的位置如下:
key落到服务器的落键规则
当我们需要存储一个kv键值对时,首先计算key的hash值,hash(key),将这个key使用相同的函数Hash计算出哈希值并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器,并将该键值对存储在该节点上。
如我们有Object A、Object B、Object C、Object D四个数据对象,经过哈希计算后,在环空间上的位置如下:根据一致性Hash算法,数据A会被定为到Node A上,B被定为到Node B上,C被定为到Node C上,D被定为到Node D上。
优点:
一致性哈希算法的容错性
假设Node C宕机,可以看到此时对象A、B、D不会受到影响。一般的,在一致性Hash算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。简单说,就是C挂了,受到影响的只是B、C之间的数据且这些数据会转移到D进行存储。
一致性哈希算法的扩展性
数据量增加了,需要增加一台节点NodeX,X的位置在A和B之间,那收到影响的也就是A到X之间的数据,重新把A到X的数据录入到X上即可,
不会导致hash取余全部数据重新洗牌。
缺点:
一致性哈希算法的数据倾斜问题
一致性Hash算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题,
例如系统中只有两台服务器:
-
哈希槽分区
哈希槽分区是 Redis 集群中常用的数据分区技术,它将整个数据集划分为固定数量的槽位(slot),然后将每个槽位分配到集群中不同的节点上,从而实现数据的分布式存储和访问。
在哈希槽分区中,每个槽位都对应着一个哈希值范围,例如 0 到 16383。当需要存储某个键值对时,先计算出该键的哈希值,然后确定该哈希值所在的槽位,最后将键值对存储在负责管理该槽位的节点上。当需要访问某个键值对时,同样先计算出该键的哈希值,然后确定该哈希值所在的槽位,最后访问负责管理该槽位的节点,从而实现数据的分布式访问。
哈希槽分区技术具有简单、可扩展性强等优点,它可以自动完成节点的动态扩容和缩容,并且在数据迁移时可以只迁移部分槽位,从而降低数据迁移的成本和风险。但是,该技术也存在一些问题,例如槽位的分配不均匀可能会导致某些节点的负载过重,从而影响系统的性能和可用性,此时可以通过手动调整槽位分配来解决这个问题。
经典面试题:
为什么redis集群的最大槽数是16384个?
大概可能是:如果slot过多,每个心跳包占用带宽就过于多了,而如果槽位超过1000,网络又会拥塞,所以最合理的选择就是16384个槽给1000个以内的主机使用。在节点少的情况下,即小型集群中,因为填充率为slots/N,若采用65536的话,压缩比将会很低,不容易传输,但是采用16384的话,压缩率将会高很多,容易传输些
Redis集群并不保证强一致性,这意味着在特定条件下,Redis集群可能会丢失一些被系统写入的数据。
Redis群集在节点之间使用异步复制,最后一次故障转移赢得隐式合并功能,这意味着最后一次选择的主数据将替换所有其他副本。在分区期间可能丢失写的时候总是有一个时间窗口。
与大多数主程序相连接的客户端和与少数主程序连接的客户端则不同。
5.redis集群环境搭建
5.1三主三从redis集群配置
由于机器性能有限,这里只配置了三台虚拟机,一台虚拟机配置两个redis实例
192.168.110.175 (下面简称100)配置端口为6381和6382两个实例,配置文件分别为cluster6381.conf和cluster6382.conf
192.168.110.172(下面简称101)配置端口为6383和6384两个实例,配置文件分别为cluster6383.conf和cluster6384.conf
192.168.110.174 (下面简称102)配置端口为6385和6386两个实例,配置文件分别为cluster6385.conf和cluster6386.conf
在每台虚拟机的根目录创建/myredis/cluster
目录,然后在该目录创建两个配置文件:
以cluster6381.conf为例:
bind 0.0.0.0
daemonize yes
protected-mode no
port 6381
logfile "/myredis/cluster/cluster6381.log"
pidfile /myredis/cluster6381.pid
dir /myredis/cluster
dbfilename dump6381.rdb
appendonly yes
appendfilename "appendonly6381.aof"
requirepass 111111
masterauth 111111
cluster-enabled yes
cluster-config-file nodes-6381.conf
cluster-node-timeout 5000
5.2启动六台redis实例
启动集群实例和之前启动redis实例一样,只不过配置文件中配置了开启集群,会以集群的方式启动redis实例。
命令为:redis-server /myredis/cluster/cluster6381.conf
5.3构建主从关系
使用命令构建集群间的主从关系:redis-cli -a 密码 --cluster create --cluster-replicas 1 IP:端口号 [IP:端口号]
选项–replicas 1 表示我们希望为集群中的每个主节点创建一个从节点
IP:端口号是redis实例的地址和端口号,多个redis实例构成一个集群
主从关系是随机分配的(个人见解:一般按照输入的顺序基数位为master,偶数位为slave),其master-slave关系是随机分配的。
//注意,注意,注意自己的真实IP地址 //注意,注意,注意自己的真实IP地址
redis-cli -a 111111 –cluster create –cluster-replicas 1 192.168.111.175:6381 192.168.111.175:6382 192.168.111.172:6383 192.168.111.172:6384 192.168.111.174:6385 192.168.111.174:6386
链接进入6381作为切入点,查看节点状态:
6.redis集群读写
为6381新增两个key
报错原因:
每个key都有自己的哈希值,根据哈希值通过某种算法算出对应的槽位,该key只能存储到该槽位所在的节点上。
然而这种情况并不是我们想要的,**可以在连接redis客户端时添加
-c
参数,这样会帮我们把数据路由到指定的槽位上,即使在不同的节点上也能随便存储数据
查看某个key对应的槽位值:CLUSTER KEYSLOT key
任何字符都有对应的哈希值,所以任何字符都能计算出对应的槽位
查看某个槽位是否被占用:CLUSTER COUNTKEYSINSLOT 槽位号
返回1表示该槽位被占用;返回0表示该槽位没有被占用。
7.redis集群主从切换
- 首先查看当前节点主从关系:
INFO REPLICATION
- 手动关闭主节点6381,查看集群节点状态
在其他任何集群节点查看集群节点的状态都可以。
主节点宕机后,从节点会成为新的master。
6384成功上位
- 重新连接节点6381,查看集群节点状态
恢复6381节点后,该节点会变成新master的slave。
恢复前:
恢复后:
- 恢复6381master的身份:
CLUSTER FAILOVER
使用
cluster failover
可以恢复发生故障前的主从关系
比如从机上位的过程中,写入数据,还未上位的时候,分配的槽位到这里,可能就出现了数据丢失。
手动故障转移or节点从属调整
CLUSTER FAILOVER
8.redis集群扩容
在112虚拟机上新建两个redis实例6387和6388,此时112虚拟机上有4个redis实例分别是6385、6386、6387、6388
编写vim /myredis/cluster/redisCluster6387.conf,6388.conf
bind 0.0.0.0
daemonize yes
protected-mode no
port 6387
logfile "/myredis/cluster/cluster6387.log"
pidfile /myredis/cluster6387.pid
dir /myredis/cluster
dbfilename dump6387.rdb
appendonly yes
appendfilename "appendonly6387.aof"
requirepass 111111
masterauth 111111
cluster-enabled yes
cluster-config-file nodes-6387.conf
cluster-node-timeout 5000
启动这两个新节点,此时它们都是master
将6387节点作为master加入到集群中:redis-cli -a 密码 --cluster add-node IP:port IP:port
前者
IP:port
为需要加入到集群的节点ip和端口
后者IP:port
指集群中任一节点的ip和端口(可以理解为推荐人)
检查集群情况:redis-cli -a 密码 --cluster check IP:port
只需要指定集群中任意一个在线的节点的地址(IP:端口号), 就会自动找到集群中的其他节点,即可查看整个集群的信息。
重新分派槽号:redis-cli -a 密码 --cluster reshard IP:port
只需要指定集群中任意一个在线的节点的地址(IP:端口号)即可。
再次检查集群情况
槽号分派说明:
为主节点6387分配从节点6388
再次查看集群情况
9.redis集群缩容
查看集群情况,获得从节点6388的节点ID
首先先将从节点6388删除:redis-cli -a 密码 --cluster del-node IP:从节点端口 从节点id
节点id可以通过检查集群情况命令查看:
redis-cli -a 密码 --cluster check IP:port
也可以通过CLUSTER NODES
命令查看。
将主节点6387的槽号清空,重新分配,将清出来的槽号都给6381
再次检查集群情况
6387节点槽位被清空,成为了6381节点的从节点
这和加入6387节点到集群时填写的集群中的
IP:port
有关(6381相当于推荐人)
此时节点6387是一个从节点,将节点6387删除
检查集群情况
10.集群常用操作命令和CRC16算法分析
不在同一个slot槽位下的多键操作支持不好,可以使用通识占位符
redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放在哪个槽
CRC16算法源码:
常用命令
- 集群是否完整才能对外提供服务