Redis 集群
1. 基本介绍
由于数据量过大,单个 Master 复制集难以承担,因此需要对多个复制集进行集群,形成水平扩展每个复制集只负责存储整个数据集的一部分,这就是Redis的集群,其作用是提供在多个Redis节点间共享数据的程序集。
https://redis.io/docs/reference/cluster-spec/
Redis 集群是一个提供在多个Redis 节点间共享数据的程序集
作用
Redis 集群支持多个 Master , 每个 Master 又可以挂载多个 Slave
由于 Cluster 自带 Sentinel 的故障转移机制,内置了高可用的支持,无需再去使用哨兵功能
客户端与 Redis 的节点连接,不再需要连接集群中所有的节点,只需要任意连接集群中的一个可用节点即可
槽位 slot 负责分配到各个物理服务节点,由对应的集群来负责维护节点、插槽和数据之间的关系
2. 集群算法
2.1 槽位
Redis 集群没有使用一致性 hash , 而是引入了 hash 槽的概念
Redis 集群有 16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责部分 hash 槽,例如,比如当前集群有 3 个节点那么:
集群每一个节点负责一部分 hash 槽位
2.2 分片
使用 Redis 集群时我们会将存储的数据分散到多台 redis 机器上,这称为分片。简言之,集群中的每个 Redis 实例都被认为是整个数据的一个分片。
为了找到给定 key 的发片,对 key 进行 CRC16 ( key ) 算法处理斌通过对总分片数量取模,同一个 key 同样的算法得到的槽位是固定的
2.3 槽位和发片的优势
方便扩缩容,方便数据查找
如果想添加一个新节点,就从另外的节点上得到部分槽位到新节点上。移除一个节点时,需要将槽位移到另外的几个节点
由于从一个节点将哈希槽移动到另一个节点,并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态
2.4 slot 槽位映射三种算法
哈希取余分区
hash( key ) % n
( n 表示几个主机 )
优点:简单粗暴,直接有效,只需要预估好数据规划好节点,例如3台、8台、10台,就能保证一段时间的数据支撑。使用 Hash 算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡+分而治之的作用。
缺点:进行扩容缩容之后,n 会发送变化,需要重新计算所有数据的映射关系,数据会发送混乱
一致性哈希算法分区
一致性哈希算法必然有个hash函数并按照算法产生hash值,这个算法的所有可能哈希值会构成一个全量集,这个集合可以成为一个hash空间[0,2^32-1],这个是一个线性空间,但是在算法中,我们通过适当的逻辑控制将它首尾相连(0 = 2^32),这样让它逻辑上形成了一个环形空间。
节点取模法是对节点(服务器)的数量进行取模。而一致性Hash算法是对2^32取模,简单来说,一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环
把这个由2^32个点组成的圆环称为Hash环
哈希槽算法空间
因为一致性 hash 算法有数据倾斜的问题
哈希槽本质上就是一个数据,范围是[0,2^14-1]
形成 hash slot 空间
能解决均匀分配的问题,在数据和节点之间又加了一层,把这层称为哈希槽(slot),用于管理数据和节点之间的关系,就相当于节点上放的是槽,槽里放的是数据
总共 16384 个槽,这些槽会平均分配给所有 redis 的主节点
集群会记录节点和槽的对应关系,解决了节点和槽的关系后,先对 key 求哈希值,然后对16384 取模,余数是几 key 就落入对应的槽里。HASH_SLOT = CRC16(key) mod 16384
3. 为什么 redis 集群的最大槽数是 16384 个
CRC16 算法产生的 hash 值有 16bit,该算法可以产生 2^16 = 65536 个值。
如果槽位为 65536,发送心跳信息的消息头达 8k,发送的心跳包过于庞大
16384 个比特 -> 16284 ÷ 8 ÷ 1024 = 8kb
65536 个比特 -> 65536 ÷ 8 ÷ 1024 = 2kb
每秒钟,redis 节点需要发送一定数量的 ping 消息作为心跳包,如果槽位为 65536,这个 ping 消息的消息头太大了,浪费带宽
redis 的集群主节点数量基本不可能超过 1000 个
集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者不建议redis cluster节点数量超过1000个
槽位越小,节点少的情况下,压缩比高,容易传输
Redis 主节点的配置信息中它所负责的哈希槽是通过一张 bitmap 的形式来保存的,在传输过程中会对 bitmap 进行压缩,但是如果 bitmap 的填充率 slots / N 很高的话 ( N表示节点数 ) ,bitmap 的压高缩率就很低。 如果节点数很少,而哈希槽数量很多的话,bitmap 的压缩率就很高
4. redis 集群不保证强一致性
Redis 集群不保证强一致性,这意味着在特定的条件下,Redis 集群可能会丢掉一些被系统收到的写入请求命令
5. 集群搭建 ( 三主三从 )
首先创建目录文件
# 1.给每个节点单独创建一个目录
mkdir -p docker/redis/redis-cluster/{redis-1,redis-2,redis-3,redis-4,redis-5,redis-6}
# 2.data目录
mkdir -p docker/redis/redis-cluster/{redis-1,redis-2,redis-3,redis-4,redis-5,redis-6}/data
# 3.每个redis目录下面创建redis.conf
touch docker/redis/redis-cluster/{redis-1,redis-2,redis-3,redis-4,redis-5,redis-6}/redis.conf
在
redis.conf
文件中添加如下配置
port 6380
bind 0.0.0.0
daemonize no
protected-mode no
logfile "redis.log"
pidfile "redis.pid"
dir /data
requirepass Sakura
masterauth Sakura
# 持久化相关
appendonly yes
dbfilename dump.rdb
# 集群配置相关
cluster-enabled yes # 开启集群
cluster-config-file nodes.conf # 集群配置文件
cluster-node-timeout 5000 # 集群节点多久未响应为丢失
编写
docker-compose.yaml
文件,并启动
version: "3"
services:
redis1:
image: redis:latest
volumes:
- ./redis-1/redis.conf:/etc/redis/redis.conf
- ./redis-1/data/:/data
container_name: redis-1
network_mode: "host"
command: redis-server /etc/redis/redis.conf
redis2:
image: redis:latest
volumes:
- ./redis-2/redis.conf:/etc/redis/redis.conf
- ./redis-2/data/:/data
container_name: redis-2
network_mode: "host"
command: redis-server /etc/redis/redis.conf
redis3:
image: redis:latest
volumes:
- ./redis-3/redis.conf:/etc/redis/redis.conf
- ./redis-3/data/:/data
container_name: redis-3
network_mode: "host"
command: redis-server /etc/redis/redis.conf
redis4:
image: redis:latest
volumes:
- ./redis-4/redis.conf:/etc/redis/redis.conf
- ./redis-4/data/:/data
container_name: redis-4
network_mode: "host"
command: redis-server /etc/redis/redis.conf
redis5:
image: redis:latest
volumes:
- ./redis-5/redis.conf:/etc/redis/redis.conf
- ./redis-5/data/:/data
container_name: redis-5
network_mode: "host"
command: redis-server /etc/redis/redis.conf
redis6:
image: redis:latest
volumes:
- ./redis-6/redis.conf:/etc/redis/redis.conf
- ./redis-6/data/:/data
container_name: redis-6
network_mode: "host"
command: redis-server /etc/redis/redis.conf
进入任意一个容器,执行以下命令
# 进去容器
docker exec -it redis-1 /bin/bash
# 构建集群关系
redis-cli -a Sakura --cluster create --cluster-replicas 1 192.168.74.128:6380 192.168.74.128:6381 192.168.74.128:6382 192.168.74.128:6383 192.168.74.128:6384 192.168.74.128:6385
看到以下命令配置成功
集群配置成功之后一定会产生 node.conf 节点配置文件
进入任何一个容器,查看节点关系
# 进入任何一个redis容器
docker exec -it redis-1 /bin/bash
redis-cli -p 6380
auth Sakura
# 查看节点关系
info replication
# 查看一个节点的关系
cluster info
# 查看集群节点关系
cluster nodes
6. 集群读写
6.1 集群读写方式
正常进入 redis 写数据可以发现,有些 key 会写入失败
是因为 key 会经过槽位映射算法分配到对应的槽中,要去槽所在的节点读写才有效
127.0.0.1:6381> set k1 v1
(error) MOVED 12706 192.168.74.128:6382
127.0.0.1:6381> set k2 v2
(error) MOVED 449 192.168.74.128:6380
127.0.0.1:6381> set k3 v3
(error) MOVED 4576 192.168.74.128:6380
127.0.0.1:6381> set k4 v4
OK
解决方法:在连接 redis 的时候加入 -c 防止路由失效
root@Sakura:/data# redis-cli -a Sakura -p 6380 -c
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6380> set k1 v1
-> Redirected to slot [12706] located at 192.168.74.128:6382
OK
对外三台 redis 是一个整体
6.2 查看 key 对应的槽位
192.168.74.128:6382> cluster keyslot k1
(integer) 12706
192.168.74.128:6382> cluster keyslot k6
(integer) 325
192.168.74.128:6382> cluster keyslot k7
(integer) 4452
192.168.74.128:6382> cluster keyslot k5
(integer) 12582
评论区