关于Redis的集群(上)

server/2025/3/18 22:23:45/

目录

基本概念

数据分片算法

哈希求余

​编辑一致性哈希算法

哈希槽分区算法

搭建集群环境

创建目录和配置

编写 docker-compose.yml

启动容器

构建集群


基本概念

广义的集群,只要是多个机器构成了分布式系统,都可以成为是一个“集群”。

但是redis提供的集群模式是狭义的集群,这个集群模式之下,主要是解决,存储空间不足的问题(拓展存储空间)。

哨兵模式提高了系统的可用性。哨兵模式中本质上还是redis主从节点存储数据。其中就要求一个主节点/从节点,就得存储整个数据的“全集”。

此处关键问题,就是引入多台机器,每台机器存储一部分数据。每个存储数据的机器还需要搭配若干个从节点。

每个 Slave 都是对应 Master 的备份(当 Master 挂了, 对应的 Slave 会补位成 Master).
每个红框部分都可以称为是⼀个 分片(Sharding).

把数据分成多份,具体该如何去分呢?


数据分片算法

有三中主流的分片方式。

哈希求余

借鉴了哈希表的基本思想。借助hash函数,把一个key映射到一个数组下标上。再针对数组的长度求余,就可以得到一个数组下标。

比如有三个分片,编号0,1,2。此时就可以针对要插入的数据的key(redis都是键值对结构的数据)计算hash值。(比如md5)再把这个hash值余上分片个数,就得到了一个下标。此时就可以把这个数据放到该下标对应的分片中了。

后续查询key的时候,也是同样的算法。

拓展:MD5是一个非常广泛使用的hash算法。

        特点:1.md5计算结果是定长的。无论输入的原字符串多长,最终算出的结果就是固定长度。

                   2.md5计算结果是分散的。两个原字符串,哪怕大部分都相同,只有一个小的地方不同,算出来的md5值也会差别很大。

                   3.md5计算结果是不可逆的。给你原字符串,可以很容易算出md5的值。给你md5值,很难还原出原始的字符串的。

一旦服务器集群需要扩容,就需要更高的成本。分片主要目的就是为了能提高存储能力。分片越多,能存的数据越多,成本也更高。随着业务的增长,数据变多了,需要更多的分片。

当引入更多的分片的时候,N(分片数量)就改变了。如果发现某个数据,在扩容之后,不应该在当前的分片中了,就需要重新进行分配(搬运数据)。绝大部分数据都需要进行搬运,成本过高。

一致性哈希算法

 1)把 0 -> 2^32-1 这个数据空间, 映射到⼀个圆环上. 数据按照顺时针⽅向增⻓。

2)假设当前存在三个分⽚, 就把分⽚放到圆环的某个位置上。

3) 假定有⼀个 key, 计算得到 hash 值 H, 那么这个 key 映射到哪个分⽚呢? 规则很简单, 就是从 H
所在位置,顺时针往下找, 找到的第⼀个分⽚, 即为该 key 所从属的分⽚。

这就相当于, N 个分⽚的位置, 把整个圆环分成了 N 个管辖区间。Key 的 hash 值落在某个区间内, 就归对应区间管理。

此时,如果增加分片,会怎样呢?

原有分⽚在环上的位置不动, 只要在环上新安排⼀个分片位置即可。

此时, 只需要把 0 号分片上的部分数据,搬运给 3 号分片即可。1 号分片和 2 号分片管理的区间都是不变的。

优点: 大大降低了扩容时数据搬运的规模, 提⾼了扩容操作的效率。
缺点: 数据分配不均匀 (有的多有的少, 数据倾斜)。

哈希槽分区算法

这是redis真正采用的分片算法。采用以下公式:

hash_slot = crc16(key) % 16384

crc16也是一种计算hash的算法,这里不多展开。

16384 = 16* 1024

得到结果hash_slot,称为哈希槽

会把这些哈希槽分配到不同的分片上。

此时,这三个分片上的数据就是比较均匀的了。会先根据key算出哈希槽,再根据哈希槽,映射到分片。这种算法,本质就是把上述两种方式结合了一下。

这里只是一种可能的方式,实际上分片是非常灵活的。

每个分片持有的槽位号,可以是连续的,也可以是不连续的。

此时,每个分片都会使用“位图”这样的数据结构,表示出当前有多少槽位号。

16384个bit位,用每一位0 / 1来区分自己这个分片当前是否持有该槽位号。  

进行扩容:

上述过程中,只有被移动的槽位,对应的数据才需要搬运。降低了搬运成本。

redis中,当前某个分片包含哪些槽位,都是可以手动配置的。

问题1:Redis集群最多有16384个分片吗?

如果⼀个分片只有⼀个槽位, 这对于集群的数据均匀其实是难以保证的。
实际上 Redis 的作者建议集群分片数不应该超过 1000。而且, 16000 这么⼤规模的集群, 本⾝的可用性也是⼀个⼤问题. ⼀个系统越复杂, 出现故障的概率是越⾼的。

问题2:为什么是16384个槽位?

节点之间通过心跳包通信,心跳包中包含该节点持有那些槽位。如果16384个槽位,每个分片需要2KB大小的位图,来表示持有的槽位。如果槽位更多,就需要消耗更大的空间,更大的网络带宽。16384是比较均衡的值,个数上基本够用,也不会占据大的硬件资源(网络带宽)。


搭建集群环境

这里使用docker来搭建redis集群。

创建目录和配置

创建 redis-cluster ⽬录。内部创建两个⽂件。

redis-cluster/
├── docker-compose.yml
└── generate.sh

generate.sh 内容如下:

for port in $(seq 1 9); \
do \
mkdir -p redis${port}/
touch redis${port}/redis.conf
cat << EOF > redis${port}/redis.conf
port 6379
bind 0.0.0.0
protected-mode no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.30.0.10${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
EOF
done
# 注意 cluster-announce-ip 的值有变化.
for port in $(seq 10 11); \
do \
mkdir -p redis${port}/
touch redis${port}/redis.conf
cat << EOF > redis${port}/redis.conf
port 6379
bind 0.0.0.0
protected-mode no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.30.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
EOF
done

在linux上,以.sh后缀结尾的文件,称为“shell脚本”。使用linux的时候,都是通过一些命令来进行操作的。使用命令操作,就非常适合把命令给写到一个文件中,批量化执行。同时还能加入条件,循环,函数等机制。就可以基于这些来完成更复杂的工作了。

此时需要创建11个redis节点,这些redis的配置文件内容,大同小异。此时就可以使用脚本来批量生成。

• cluster-enabled yes 开启集群。
• cluster-config-file nodes.conf 集群节点⽣成的配置。
• cluster-node-timeout 5000 节点失联的超时时间。
• cluster-announce-ip 172.30.0.101 节点⾃⾝ ip。
• cluster-announce-port 6379 节点⾃⾝的业务端⼝。
• cluster-announce-bus-port 16379 节点⾃⾝的总线端⼝. 集群管理的信息交互是通过这个端口进行的。

编写 docker-compose.yml

• 先创建 networks, 并分配⽹段为 172.30.0.0/24
• 配置每个节点. 注意配置⽂件映射, 端⼝映射, 以及容器的 ip 地址. 设定成固定 ip ⽅便后续的观察和操作。

version: '3.7'
networks:
mynet:
ipam:
config:
- subnet: 172.30.0.0/24
services:
redis1:
image: 'redis:5.0.9'
container_name: redis1
restart: always
volumes:
- ./redis1/:/etc/redis/
ports:
- 6371:6379
- 16371:16379
command:
redis-server /etc/redis/redis.conf
networks:
mynet:
ipv4_address: 172.30.0.101
redis2:
image: 'redis:5.0.9'
container_name: redis2
restart: always
volumes:
- ./redis2/:/etc/redis/
ports:
- 6372:6379
- 16372:16379
command:
redis-server /etc/redis/redis.conf
networks:
mynet:
ipv4_address: 172.30.0.102
redis3:
image: 'redis:5.0.9'
container_name: redis3
restart: always
volumes:
- ./redis3/:/etc/redis/
ports:
- 6373:6379
- 16373:16379
command:
redis-server /etc/redis/redis.conf
networks:
mynet:
ipv4_address: 172.30.0.103

启动容器

docker-compose up -d

构建集群

接下来,要把上述redis节点构建成集群。

redis-cli --cluster create 172.30.0.101:6379 172.30.0.102:6379
172.30.0.103:6379 172.30.0.104:6379 172.30.0.105:6379 172.30.0.106:6379
172.30.0.107:6379 172.30.0.108:6379 172.30.0.109:6379  --cluster-replicas 2

列出每个参与构建集群的ip和端口。(端口都是容器内部的端口)

cluster create: 表⽰建⽴集群. 后⾯填写每个节点的 ip 和地址。

cluster-replicas 2: 描述集群的每个主节点,应该有2个从节点。一共9个节点,设置了之后,redis就知道了3个节点是一伙的(一个分片)。

执⾏之后, 容器之间会进⾏加⼊集群操作。⽇志中会描述哪些是主节点, 哪些从节点跟随哪个主节点。

>>> Performing hash slots allocation on 9 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.30.0.105:6379 to 172.30.0.101:6379
Adding replica 172.30.0.106:6379 to 172.30.0.101:6379
Adding replica 172.30.0.107:6379 to 172.30.0.102:6379
Adding replica 172.30.0.108:6379 to 172.30.0.102:6379
Adding replica 172.30.0.109:6379 to 172.30.0.103:6379
Adding replica 172.30.0.104:6379 to 172.30.0.103:6379

以上,关于redis集群,希望对你有所帮助。


http://www.ppmy.cn/server/176067.html

相关文章

【eNSP实战】基本ACL实现网络安全

拓扑图 要求&#xff1a; PC3不允许访问其他PC和Server1PC2允许访问Server1服务器&#xff0c;不允许其他PC访问各设备IP配置如图所示&#xff0c;这里不做展示 AR1接口vlan配置 vlan batch 10 20 30 # interface Vlanif10ip address 192.168.1.254 255.255.255.0 # inter…

轨道交通CPU+FPGA控制器,支持codesys/vxWorks/翼辉等实时系统

1. 控制器优势 1&#xff09;功能强大&#xff0c;配套软件齐备&#xff08;已配套符合IEC61311-3标准的Codesys3.5&#xff0c;实时操作系统vxWorks7.0&#xff0c;标准的PTU软件&#xff09;&#xff0c;可方便进行二次开发和维护; 2&#xff09;接口资源丰富&#xff08;7…

[蓝桥杯 2023 省 A] 买瓜 --暴力DFS+剪枝优化

题目来自洛谷&#xff1a; 暴力思路&#xff1a; ①根据题目&#xff0c;可以知道有三种操作&#xff0c;第一种操作选择这个瓜&#xff0c;第二种操作不选择这个瓜&#xff0c;第三种操作选择这个瓜的一半。我们可以用一个res来记录这三种操作返回的结果&#xff0c;最后在返…

STM32 DAC详解:从原理到实战输出正弦波

目录 一、DAC基础原理1.1 DAC的作用与特性1.2 DAC功能框图解析 二、DAC配置步骤2.1 硬件配置2.2 初始化结构体详解 三、DAC数据输出与波形生成3.1 数据格式与电压计算3.2 正弦波生成实战3.2.1 生成正弦波数组3.2.2 配置DMA传输3.2.3 定时器触发配置 四、常见问题与优化建议4.1 …

游戏引擎学习第163天

我们可以在资源处理器中使用库 因为我们的资源处理器并不是游戏的一部分&#xff0c;所以它可以使用库。我说过我不介意让它使用库&#xff0c;而我提到这个的原因是&#xff0c;今天我们确实有一个选择——可以使用库。 生成字体位图的两种方式&#xff1a;求助于 Windows 或…

现代密码学 | 具有数字签名功能的安全方案

1.案例背景 1.1冒用签名触发信任危机&#xff0c;360安全大脑率先截杀解除警报 2020年8月&#xff0c;360安全大脑独家发现冒用数字签名的网络攻击再度活跃&#xff0c;且继此前360安全大脑披露过的Go Daddy、Starfield Secure、赛门铁克、Verisign和DigiCert等国际知名CA证书…

前端性能优化回答思路

前端性能优化是面试中经常涉及的一个话题&#xff0c;面试官通常希望了解你在实际项目中如何处理性能瓶颈&#xff0c;如何识别和优化性能问题。以下是一些前端性能优化的常见问题以及你可以用来回答的思路&#xff1a; 如何提升页面加载速度&#xff1f; 回答思路&#xff1…

【Git】配置Git

配置Git 忽略特殊文件 在日常开发中&#xff0c;有些文件不想或不应该提交到远端&#xff0c;如保存数据库密码的配置文件。 在Git工作区的根目录下创建一个特殊的.gitignore文件&#xff0c;把要忽略的文件名填进去&#xff0c;Git就会自动忽略这些文件。 不需要从头写.gi…