Redis集群

目录

Redis集群

一、为什么用Redis集群?

二、Redis集群能干什么

三、Redis集群槽位

四、Redis集群的分片

1、哈希取余分区算法

3、哈希槽分区算法

五、集群搭建

1、3主3从redis集群配置

2、3主3从redis集群读写

3、主从容错切换迁移

4、主从扩容

5、主从缩容


Redis集群

一、为什么用Redis集群?

由于数据量过大,单个Master复制集难以承担,因此需要对多个复制集进行集群,形成水平扩展每个复制集只负责存储整个数据集的一部分,这就是Redis的集群,其作用是提供在多个Redis节点间共享数据的程序集。

二、Redis集群能干什么

1、Redis集群支持多个Master,每个Master又可以挂载多个Slave。
2、由于Cluster自带Sentinel的故障转移机制,内置了高可用的支持,无需再去使用哨兵功能。
3、客户端与Redis的节点连接,不再需要连接集群中所有的节点,只需要任意连接集群中的一个可用节点即可。

4、槽位slot负责分配到各个物理服务节点,由对应的集群来负责维护节点、插槽和数据之间的关系。

三、Redis集群槽位

Redis集群使用槽位(slot)来分片和存储数据。每个Redis集群共有16384个槽位,每个槽位可以存储一个键值对。

在Redis集群中,每个节点都负责一部分槽位。当一个节点加入集群时,它会被分配一些槽位。通过这种分片方式,集群中的每个节点都负责处理一部分数据,从而实现数据的分布式存储和处理。

具体来说,Redis集群将16384个槽位均匀地分配给所有的节点。例如,如果集群有3个节点,那么每个节点将被分配约5461个槽位。当一个节点加入或离开集群时,集群会重新计算和重新分配槽位,以保持数据的均衡分布。

通过使用槽位,Redis集群可以提供以下功能:

1、数据分片:将数据划分到不同的节点上,实现数据的分布式存储和处理,提高系统的吞吐量和并发性能。

2、故障转移:当一个节点发生故障时,集群会将该节点负责的槽位自动迁移到其他正常节点上,确保数据的可用性和高可靠性。

3、扩缩容:当需要扩展或缩小集群规模时,可以通过增加或减少节点来重新分配槽位,实现集群的动态扩缩容。


Redis集群_第1张图片

四、Redis集群的分片

使用Redis集群时我们会将存储的数据分散到多台redis机器上,这称为分片。简言之,集鹏中的每个Redis实例都被认为是整个数据的一个分片。

如何找到给定key的分片?

为了找到给定key的分片,我们对key进行CRC16(key)算法处理并通过对总分片数量取模。然后,使用确定性哈希函数,可以推断将来读取特定key的位置。

通过将数据分片到多个节点,Redis集群可以获得以下好处:

1、增加数据容量:每个节点只负责存储部分数据,可以利用多个节点的存储容量。

2、提高读写性能:由于数据被分散存储在多个节点上,可以同时并行地处理多个读写请求,提高系统的整体吞吐量。

3、实现高可用性:当一个节点发生故障时,集群可以自动将该节点上的哈希槽迁移到其他健康的节点上,确保数据的可用性和系统的高可用性。

1、哈希取余分区算法

该算法的基本思想是,将数据通过哈希函数映射到一个固定数量的分区上,然后通过对分区数取模计算得到对应的分区编号。

优点:只需要预估好数据规划好节点,例如3台、8台、10台,就能保证一段时间的数据支撑
使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡的作用。

缺点:原来规划好的节点,进行扩容或者缩容就比较麻烦了额,不管扩缩,每次数据变动导致节点有变动,映射关系需要重新进行计算,在服务器个数固定不变时没有问题,如果需要弹性扩容或故障停机的情况下,原来的取模公式就会发生变化:Hash(key)/3会变成Hash(key)/?。此时地址经过取余运算的结果将发生很大变化,根据公式获取的服务器也会变得不可控。 

2、一致性哈希算法分区

提出一致性Hash解决方案。目的是当服务器个数发生变动时,尽量减少影响客户端到服务器的映射关系。

步骤:1、算法构建一致性哈希环      2、服务器IP节点映射      3、key落到服务器的落键规则

算法构建一致性哈希环

一致性哈希算法必然有个hash函数并按照算法产生hash值,这个算法的所有可能哈希值会构成一个全量集,这个集合可以成为一个hash空间[0,2^32-1],这个是一个线性空间,但是在算法中,我们通过适当的逻辑控制将它首尾相连(0= 2个32),这样让它逻辑上形成了一个环形空间。

服务器IP节点映射

将集群中各个IP节点映射到环上的某一个位置。将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。假如4个节点NodeA、B、C、D,经过IP地址的哈希函数计算(hash(ip)),使用IP地址哈希后在环空间的位置如下:
Redis集群_第2张图片

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上。

Redis集群_第3张图片

优点:

  1. 均衡性:一致性哈希算法能够将节点均匀地映射到哈希环上,从而实现负载均衡。在增加或删除节点时,只会影响到相邻的节点,对整体的影响较小,使得系统能够快速适应节点变化。
  2. 扩展性:由于哈希环的结构,一致性哈希算法能够有效地支持节点的动态扩展和收缩。当增加或删除节点时,只需要重新映射受影响的数据,而不需要重新分配所有数据,降低了数据迁移的成本。
  3. 缓存友好:一致性哈希算法在分布式缓存系统中应用广泛。由于节点的增加或删除只会影响到少部分数据,缓存的命中率相对较高,减少了缓存失效带来的性能损失。
  4. 容错性:一致性哈希算法通过将数据复制到多个节点来提高系统的容错性。当某个节点故障时,数据可以自动转移到其他节点上,保证系统的可用性。

缺点:

  1. 数据倾斜:由于哈希函数的输出可能存在冲突,一致性哈希算法在某些情况下可能导致数据倾斜。部分节点可能会负载过重,而其他节点负载较轻。为了解决这个问题,可以引入虚拟节点来增加哈希的离散性,使得数据更均匀地映射到节点上。
  2. 节点增删复杂性:当节点增加或删除时,会导致部分数据需要重新映射和迁移,可能会对系统的稳定性和性能造成一定的影响。为了减少这种影响,可以采用渐进式增删策略,逐渐迁移数据,避免一次性的大规模数据迁移。
3、哈希槽分区算法

为了解决均匀分配的问题,在数据和节点之间又加入了一层,把这层称为哈希槽(slot),用于管理数据和节点之间的关系,现在就相当于节点上放的槽,槽里放的是数据。

槽解决的是粒度问题,相当于把粒度变大了,这样便于数据移动。哈希解决的是映射问题,使用key的哈希值来计算所在的槽,便于数据分配。

Redis集群_第4张图片

一个集群只能有16384个槽,编号0-16383(0-2^14-1)。这些槽会分配给集群中的所有主节点,分配策略没有要求。
集群会记录节点和槽的对应关系,解决了节点和槽的关系后,接下来就需要对key求哈希值,然后对16384取模,余数是几key就落入对应的槽里。HASH_SLOT = CRC16(key) mod 16384。以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。

面试题:为什么redis集群的最大槽数是16384个(2^14)而不是65536(2^16)个?

(1)如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。
在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。当槽位为65536时,这块的大小是:65536:8÷1024=8kb

在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。当槽位为16384时,这块的大小是:16384:8÷1024=2kb
因为每秒钟,redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为65536,这个ping消息的消息头太大了,浪费带宽。

(2)redis的集群主节点数量基本不可能超过1000个。
集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者不建议redis cluster节点数量超过1000个。那么,对于节点数在1000以内的redis cluster集群,16384个槽位够用了。没有必要拓展到65536个。

(3)槽位越小,节点少的情况下,压缩比高,容易传输
Redis主节点的配置信息中它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中会对bitmap进行压缩,但是如果bitmap的填充率slots / N很高的话(N表示节点数), bitmap的压缩率就很低。如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。

Redis集群不能保证其强一致性

Redis集群不能保证其强一致性,可能会出现数据丢失或者不一致的情况。这是因为,Redis集群采用异步复制机制来进行数据同步,而异步复制存在一定的延迟和不确定性,从而导致新的写入请求不能立即被同步和复制到所有节点上。

五、集群搭建

集群搭建设计图

Redis集群_第5张图片

Redis集群_第6张图片  

1、3主3从redis集群配置

配置3台虚拟机,每台配置一主一从

Redis集群_第7张图片

修改redis主机配置文件:/myredis/cluster/redisCluster6381.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
  1. bind:指定Redis服务绑定的IP地址。在本例中,使用0.0.0.0表示服务将绑定到所有可用的IPv4地址上。

  2. daemonize:决定Redis是否以守护进程方式运行。当设置为yes时,Redis将在后台运行,不会向终端输出日志信息。

  3. protected-mode:控制Redis是否启用保护模式。当设置为no时,Redis将不会检查访问请求是否来自本地主机。

  4. port:指定Redis服务监听的端口号。在本例中,服务将监听6381端口。

  5. logfile:指定Redis日志文件的路径和文件名。在本例中,日志将写入/myredis/cluster/cluster6381.log文件。

  6. pidfile:指定Redis进程ID文件的路径和文件名。在本例中,文件名为cluster6381.pid。

  7. dir:指定Redis数据库文件和AOF文件所在的目录。在本例中,它们将存储在/myredis/cluster目录下。

  8. dbfilename:指定Redis数据库文件的文件名。在本例中,文件名为dump6381.rdb。

  9. appendonly:决定Redis是否启用AOF持久化。当设置为yes时,Redis将记录所有修改操作,并将其写入AOF文件中。

  10. appendfilename:指定AOF文件的文件名。在本例中,文件名为appendonly6381.aof。

  11. requirepass:设置Redis的访问密码。在本例中,密码为111111。

  12. masterauth:设置Redis主节点的访问密码。在本例中,主节点密码也为111111。

  13. cluster-enabled:决定Redis是否启用集群模式。当设置为yes时,Redis将启用集群模式。

  14. cluster-config-file:指定Redis集群配置文件的路径和文件名。在本例中,文件名为nodes-6381.conf。

  15. cluster-node-timeout:指定Redis集群节点之间的超时时间。在本例中,超时时间为5000毫秒

修改redis从机配置文件:/myredis/cluster/redisCluster6382.conf 添加一下配置

bind 0.0.0.0
daemonize yes
protected-mode no
port 6382
logfile "/myredis/cluster/cluster6382.log"
pidfile /myredis/cluster6382.pid
dir /myredis/cluster
dbfilename dump6382.rdb
appendonly yes
appendfilename "appendonly6382.aof"
requirepass 111111
masterauth 111111

cluster-enabled yes
cluster-config-file nodes-6382.conf
cluster-node-timeout 5000

分别启动6台服务

查看进程看到是以集群的方式开启的

构建主从关系命令

redis-cli -a 111111 --cluster create --cluster-replicas 1 192.168.111.185:6381 192.168.111.185:6382 192.168.111.172:6383 192.168.111.172:6384 192.168.111.184:6385
192.168.111.184:6386

--cluster-replicas 1表示为每个master创建一个slave节点

Redis集群_第8张图片

 创建成功Redis集群_第9张图片

集群配置号后会产生nodes-conf文件

Redis集群_第10张图片

以6381为切入点查看节点状态

Redis集群_第11张图片

 查看集群节点关系:CLUSTER NODES

2、3主3从redis集群读写

Redis集群_第12张图片

当写入数据时会报这个错误,说明k1要到6385服务器去存储,redis集群需要路由到所在的槽位

解决方法:连接redis时带  -c 参数打开路由

redis-cli -a 111111 -p 6381 -c

Redis集群_第13张图片

 从定向到6385这台redis

Redis集群_第14张图片

3、主从容错切换迁移

 关闭6381查看6384是否上位

Redis集群_第15张图片

进入6382查看主从关系,看到6381主机掉线,6384从机上位

Redis集群_第16张图片 从新打开6381主机,6381变成了从机

Redis集群_第17张图片

Redis集群_第18张图片

6831宕机重启后变成了从机,如果还想6381变成主机使用一下命令

CLUSTER FAILOVER

Redis集群_第19张图片

4、主从扩容

重新配置一主一从

查看是否启动成功

Redis集群_第20张图片

将新增的6387作为master节点加入原有集群

redis-cli -a密码--cluster add-node自己实际IP地址:6387自己实际IP地址:6381

6387就是将要作为master新增节点
6381就是原来集群节点里面的领路人,相当于6387拜拜6381的码头从而找到组织加入集群

redis-cli -a 111111 --cluster add-node 192.168.111.184:6387 192.168.111.185:6381

 新节点添加成功Redis集群_第21张图片

Redis集群_第22张图片

从新分配槽位

命令:redis-cli -a密码--cluster reshard IP地址:端口号
redis-cli -a 111111 --cluster reshard 192.168.111.175:6381l

 分配多少槽位,分配主机ID是多少

Redis集群_第23张图片

 

 检查是否正确分配完成

redis- cli -a 111111 --cluster check 192.168.111.185:6381

为什么6387是3个新的区间,以前的还是连续?
重新分配成本太高,所以前3家各自匀出来一部分,从6381/6382/6383三个旧节点分别匀出1364个坑位给新节点6387

给新主机添加从机

redis-cli -a密码--cluster add-node ip:新slave端口 ip:新master端口--cluster-slave --cluster-master-id新主机节点ID

redis-cli - a 111111 --cluster add-node 192.168.111.184:6388 192.168.111.184.6387

--cluster-slave --cluster-master-id 307a5f6617a6eeb4949f3cb9124edo4c6962c348
 

 Redis集群_第24张图片

重新查看主从关系

Redis集群_第25张图片

5、主从缩容

检查集群情况获取从节点6388的节点ID

redis- cli -a 111111 --cluster check 192.168.111.184:6385

Redis集群_第26张图片

 从集群中将节点6388删除

redis-cli -a密码--cluster del-node ip:从机端口从机6388节点ID

Redis集群_第27张图片 

将6387的槽位清空,重新分配槽位

redis- cli -a 111111 -- cluster reshard 192.168.111.185:6381

4096个槽位都指给6381,它变成了8192个槽位,相当于全部都给6381了,不然要输入3次 

Redis集群_第28张图片

检查集群情况,此时6381有两个从节点

将6387节点删除

redis-cli -a密码--cluster del-node ip:端口6387节点ID

再检查集群情况、6387和6388被删除

注意:不在同一个slot槽位下的键值无法使用mset.mget等多键操作

Redis集群_第29张图片

 可以通过{}来定义同一个组的概念,使key中内相同内容的键值对放到一个slot槽位去

Redis集群_第30张图片

查看槽位是否被占用,1被占用,0未被占用

CLUSTER COUNTKEYSINSLOT 12706

你可能感兴趣的:(Redis,redis,java,数据库)