目录

集群

数据分片算法

1. 哈希求余

2 一致性哈希算法

3. 哈希槽分区算法 (Redis 使用)

Docker搭建集群

i:创建目录和配置文件

编写 generate.sh 脚本

执行生成命令

ii:编写 docker-compose.yml

网络配置

iii: 构建集群

连接并验证集群

重定向

主节点宕机自动处理流程

故障判定

故障迁移

Fail 状态的影响

实验

集群扩容

一、加入集群

二、分配哈希槽

三、添加从节点


  • 本章节相关操作不需要记忆,后续工作中如果用到了能查到即可。
  • 重点在于理解流程和原理。
基本概念
  • 上篇文章讲述的哨兵模式, 提高了系统的可用性. 但是真正用来存储数据的还是 master 和 slave 节点. 所有的数据都需要存储在单个 master 和 slave 节点中.
  • 如果数据量很大, 接近超出了 master/slave 所在机器的物理内存, 就可能出现严重问题了.
  • 虽然硬件价格在不断降低, 一些中大厂的服务器内存已经可以达到 TB 级别了, 但是 1TB 在当前这个 "大数据" 时代, 俨然不算什么, 有的时候我们确实需要更大的内存空间来保存更多的数据.

如何获取更大的空间?

加机器即可! 所谓 "大数据" 的核心, 其实就是一台机器搞不定了, 用多台机器来搞.

Redis 的集群就是在上述的思路之下, 引入多组 Master/Slave, 每一组 Master/Slave 存储数据全集的一部分, 从而构成一个更大的整体, 称为 Redis 集群 (Cluster)

集群

集群这个词,可以从广义上来理解,也可以从狭义上来理解。

  • 其中广义的集群,只要是多个机器,构成了分布式系统。我们前面学过的哨兵模式,也可以算作是一种广义上的集群。
  • 狭义的集群,是 Redis 提供的一种集群模式,在这个集群模式之下,主要解决存储空间不足的问题,即 拓展存储空间。

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

  • 但是集群中主要要解决的问题就是要 引入多台机器, 每台机器存储一部分数据。
  • 只要机器规模足够大, 就可以存储任意数据的大小了。比如:

  • Redis 的集群通过引入多组 Master/Slave 来分散数据存储压力。
  • 每一组 Master/Slave 存储数据全集的一部分,构成一个更大的整体。
  • 假定整个数据 全集为 1TB,三组 Master/Slave 可以每组存储 1/3 的数据。
  • 每个 Slave 是对应 Master 的备份(Master 故障时,Slave 会补位成 Master)。
  • 每个 红框部分称为一个分片 (Sharding),用于进一步扩展存储容量。

关于使用硬盘代替内存

  • 硬盘虽然可以存储更多数据,但访问速度远慢于内存。
  • 在某些应用场景(如搜索引擎),既需要存储较多数据,又希望有非常高的读写速度。这时我们就可以引入 redis 集群啦

这其中每个服务器集群上都需要存储一定规模的数据,也就是把数据分为了多份,但是数据在分成多份的时候,应该怎么分?这就是我们接下来需要主要研究的问题。


数据分片算法

分片的核心思路是用多组机器来存数据的每个部分,那么接下来的核心问题就是,给定一个数据(一个具体的 key),那么这个数据应该存储在哪个分片上?读取的时候又应该去哪个分片读取?围绕这个问题,业界有三种比较主流的实现方式:

  1. 哈希求余
  2. 一致性哈希算法
  3. 哈希槽分区算法

1. 哈希求余

哈希求余,就是借鉴了哈希表的基本思想

借助哈希函数,把一个 key 映射到整数,再针对数据的长度,求余就可以得到一个数组的下标。

哈希求余的分片算法具体是什么样子的呢?

  • 比如有三个分片,编号 0 1 2,此时就可以针对要插入的数据的 key 计算出一个哈希值
  • (计算 哈希值的算法,一般是针对一个字符串里面的内容进行一系列的变换,比如 md5 算法就是一种哈希算法,它是把一个字符串变换成为一个 16 进制的数字)。
  • 在把这个 哈希值余上一个分片个数,就会得到一个下标。此时就可以把这个数据放到该下标对应的分片中了。

  • 比如,hash(key) % N => 0,由于求出的余数是 0,此时这个 key 对应的数据就要 存储在 0 号分片中。
  • 后续查询 key 的时候也是同样的算法。只要 key 是一样的,hash 函数式一样的,得到的分片的值就是一样的。
  • 随着业务逐渐增长,数据变多的时候,仅有的几个分片就不足以保存数据了,这就需要对集群进行扩容,引入新的分片。

这时候,哈希求余算法的缺点就体现出来了,就是在增加集群容量,需要对数据进行 搬运的时候,开销非常大,很多数据都需要搬运原因就是,扩容后 N的值会变大,那么原先的求余就不再适用了,此时要把 所有数重新计算。计算完毕后,还要面临复杂的搬运数据的过程。,大部分的数据都是需要搬运的,这就是扩容的开销非常大。

从上图中可以看到,其中的 21 个数据,只有 3 个 key 没有被搬运,其他的 key 都是搬运过的。

当然,哈希求余的分片算法也是有一定优点的,那就是 简单高效,数据分配比较均匀。


2 一致性哈希算法

哈希求余这种操作中,当前的 key 属于哪个分片是交替的。例如某些数据的 hash 值分别是 102, 103, 104,这些数据在对 3 求余后,得到的值分别是 0, 1, 2,它们哈希求余求出的值是交替的,交替分布在不同的集群中。

而在一致性哈希算法中,我们改进了这种交替存储的方式为连续存储。一致性哈希算法的过程如下:

  • 数据空间映射首先把数据空间全部映射到一个圆环上,数据按照顺时针方向增长。
  • 分片定位:假设当前存在三个分片,将这些 分片放到圆环的某个位置。
  • Key 映射与分配:对于每一个 key,通过哈希函数 计算得到 哈希值 H,并将 H 映射到圆环上的对应位置。从 H 所在的位置开始,顺时针向下找,找到的第一个分片即为该 key 所从属的分片。

这相当于 N 个分片的位置将整个圆环分成了 N 个管辖区间,key 的哈希值落在某个区间内,就归该区间管理。

在这种一致性哈希算法情况下,如果需要对数据进行扩容,原有分片在环上的位置不动,只需要在环上 安排一个新的分片(如下图粉色区域)。

此时只需把 3 号分片上的部分数据搬运给新增的分片(如 4 号分片),而其他分片管理的区间保持不变。

这种方式 相比哈希求余减少了数据搬运成本,但可能导致各分片的数据量不均匀,出现 数据倾斜 现象。


3. 哈希槽分区算法 (Redis 使用)

  • 求余%:扩容不便
  • 一致性分片:数据倾斜

为了解决上述问题,Redis 集群引入了哈希槽算法,其公式为:

hash_slot = crc16(key) % 16384
  • 这里 CRC 是一种哈希算法,16384 等于 16*1024 或者说是 2^14。
  • 此算法 结合了 一致性哈希 和 哈希求余 的特点
  • 将哈希值映射到 16384 个槽位上,然后把这些 槽位均匀地分配给每个分片。每个分片会使用“位图” 这样的数据结构来记录自己持有的槽位号,用 0/1 表示是否持有该槽位。

假设当前有三个分片,一种可能的分配方式如下:

  • 0 号分片: [0,5461],共 5462 个槽位
  • 1 号分片: [5462,10923],共 5462 个槽位
  • 2 号分片: [10924,16383],共 5460 个槽位

实际上,分片方式非常灵活,每个分片持有的 槽位号可以是连续或不连续的。尽管不是严格意义上的均匀,但差异很小,使得数据分布较为均衡。

当需要进行扩容时,比如新增一个 3 号分片,可以通过重新分配原有的槽位来实现:

  • 0 号分片: [0,4095],共 4096 个槽位
  • 1 号分片: [5462,9557],共 4096 个槽位
  • 2 号分片: [10924,15019],共 4096 个槽位
  • 3 号分片: [4096,5461]+[9558,10923]+[15019,16383],共 4096 个槽位

此时,每个分片分出一部分槽位给新来的分片,并且保证最终所有分片持有的槽位个数接近,此处因为 16384 / 4可以除尽,所以最终四个分片的槽位数目完全相同。

最后进行数据拷贝时,只需要0 1 2三个分片,分别单向拷贝一部分数据给3号分片即可。

此外,还有一些关于 Redis 集群的问题需要注意:

Redis 集群最多有 16384 个分片吗?

在 Redis 集群中,key 是要先映射到槽位上,再映射到分片上的。这种设计的目的是为了确保数据分布的均匀性:

  • 如果每个分片包含的槽位较多,并且槽位个数相当,那么可以认为每个分片包含的 key 数量也是相等的,从而保证了数据分布的均匀性。
  • 然而,如果每个分片包含的槽位非常少,槽位的数量可能无法直观地反映出 key 的数量,这种情况之下,数据的均匀性就难以保证。
  • 此外,如果每个分片中包含的槽数非常少,则会导致集群中的服务器规模变得非常庞大,随着服务器数量的增加,出现故障的概率也会相应增大。

为什么是16384个槽位?

  • 节点之间通过心跳包通信,心跳包中包含了该节点持有哪些槽位,这个是使用位图这样的数据结构表示的。
  • 表示 16384 个槽位需要的位图大小是 2KB,如果给定的槽位数更多了,此时就需要消耗更多的空间。
  • 这对于内存来说不算什么,但是 在频繁的网络心跳包中,还是一个不小的开销,因为网络带宽是比内存更稀缺的资源
  • 另一方面,Redis 集群一般不建议超过 1000 个分片。16384个槽位,对于最大 1000 个分片来说是足够用的,同时也会使对应的槽位配置位图体积不至于很大

参考:


Docker搭建集群

接下来使用docker搭建一个如下集群,拓扑结构如下:

注意

  • 本示例中我们将创建11个Redis节点
  • 其中前9个用于演示集群的搭建,后两个用于演示集群扩容。

i:创建目录和配置文件

首先,创建一个名为 redis-cluster 的目录,并在该目录下创建两个文件:

编写 generate.sh 脚本

generate.sh 内容如下,此脚本将为每个 Redis 实例创建配置文件并设置不同的 IP 地址:

#!/bin/bash

# 创建并配置前9个节点
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

# 创建并配置第10和11个节点(用于后续扩容)
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

C++ 和 Java 中的循环

  • C++: range based for(C++ 也有 std::for_each,STL 中的一个函数)
  • Java: for each

Shell 脚本中的循环如上

解释

  • seq: 一个 Linux 命令,生成 [1, 9]
  • \: 续行符,把下一行的内容和当前行合并成一行。
    • 默认情况下,shell 要求把所有的代码都写到一行里,使用续行符来换行。
  • { }: 在 shell 中表示变量,不是表示代码块。
    • 对于 for使用 dodone 来表示代码块的开始和结束
    • 循环体内的代码。
  • 字符串拼接:在 shell 中拼接字符串是直接写到一起,而不需要使用 +

预期效果

  • 得到 11 个目录,每个目录里都有一个配置文件。
  • 配置文件中,IP 地址各不相同。

注意cluster-announce-ip 172.30.0.10${port} 的值对于每个实例是不同的,以确保它们在网络中的唯一性。


执行生成命令

运行以下命令以执行 generate.sh 脚本,这将在 redis-cluster/ 目录下生成相应的子目录及配置文件:

bash generate.sh

生成后的目录结构应类似于:

每个 redis.conf 文件的内容除了 cluster-announce-ip 不同外,其他部分都相同。例如,redis1/redis.conf 包含如下内容:

配置说明

  • 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: 节点自身的总线端口,用于集群管理信息交互。

注意:

  • cluster-announce-ip: Docker 容器的 IP 地址。
  • port: 容器内的  Redis 端口。
  • 业务端口: 用于业务数据通信。(eg. 客户端访问的
  • 管理端口: 用于管理任务通信。

故障处理

  • 如果某个分片中的 Redis 主节点挂了,就需要让从节点成为主节点,就需要通过刚才 管理端口 来完成相应的操作。
  • 服务器端口绑定: 一个服务器可以绑定多个端口号。

ii:编写 docker-compose.yml

接下来,我们需要编写 docker-compose.yml 文件来定义 Docker 容器网络和服务。以下是配置示例:

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
  redis4:
    image: 'redis:5.0.9'
    container_name: redis4
    restart: always
    volumes:
      - ./redis4/:/etc/redis/
    ports:
      - 6374:6379
      - 16374:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.104
  redis5:
    image: 'redis:5.0.9'
    container_name: redis5
    restart: always
    volumes:
      - ./redis5/:/etc/redis/
    ports:
      - 6375:6379
      - 16375:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.105
  redis6:
    image: 'redis:5.0.9'
    container_name: redis6
    restart: always
    volumes:
      - ./redis6/:/etc/redis/
    ports:
      - 6376:6379
      - 16376:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.106
  redis7:
    image: 'redis:5.0.9'
    container_name: redis7
    restart: always
    volumes:
      - ./redis7/:/etc/redis/
    ports:
      - 6377:6379
      - 16377:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.107
  redis8:
    image: 'redis:5.0.9'
    container_name: redis8
    restart: always
    volumes:
      - ./redis8/:/etc/redis/
    ports:
      - 6378:6379
      - 16378:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.108
  redis9:
    image: 'redis:5.0.9'
    container_name: redis9
    restart: always
    volumes:
      - ./redis9/:/etc/redis/
    ports:
      - 6379:6379
      - 16379:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.109
  redis10:
    image: 'redis:5.0.9'
    container_name: redis10
    restart: always
    volumes:
      - ./redis10/:/etc/redis/
    ports:
      - 6380:6379
      - 16380:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.110
  redis11:
    image: 'redis:5.0.9'
    container_name: redis11
    restart: always
    volumes:
      - ./redis11/:/etc/redis/
    ports:
      - 6381:6379
      - 16381:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.111
网络配置
  • subnet: 此处为了后续创建静态的 IP,就需要先手动创建出网络,同时给这个网段分配 IP。这里分配的 网络号是 172.30.0,其中这个网络号是私网格式的一种,需要注意的是,不能和当前主机上现有的其他网段冲突0/24 是主机号。
  • volumes: 配置文件映射,确保容器内的配置文件与宿主机上的配置文件同步更新。
  • ports: 端口映射,需要注意的是,映射右边的端口必须和配置文件中的保持一致。
  • ipv4_address: 静态配置的网络 IP,这里的 IP 也必须和之前的配置文件中的一致。

启动容器之前,要把之前测试的容器关掉,避免冲突

博主在测试机上没什么有用的,就粗暴的直接全都删掉了

由于要启动是一个容器,所以上面的文件会比较长。

启动容器:

docker compose up -d

此时十一个容器就启动了。

但是这些容器目前还是单独的节点,尚未构成集群。


iii: 构建集群

接下来需要把这些服务容器全部构建为集群,使用如下命令:

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
  • --cluster create 表示建立集群,后面填写每个节点的 IP 和端口。
  • --cluster-replicas 2 表示每个主节点需要两个从节点备份。设置了这个配置之后,Redis 就会知道,每 3 个节点是一组(一个分片)。但是分配的时候,谁是主节点,谁是从节点,都是随机的。

这样redis就会依据规则自动构建集群,每三个节点构成一个分片(因为指定了一个主有两个从),并且会自动构建主从关系。

输入命令后,出现以下界面:

  • 1 部分,是信号槽的分配部分,可以看到redis内部采用了连续分配的方式,将信号槽均匀的分配给三个分片。
  • 2 部分,是主从关系的建立部分,第一行表示:172.30.0.105:6379成为172.30.0.101:6379的从节点。那么这六行日志,就表示xxx.101xxx.102xxx.103成为了三个主节点,其余的节点成为这三个的从节点。
  • 3 部分,是一段日志,就是具体把那一部分槽位具体分配给哪一个分片,比如xxx.101拿到了[0-5460]的槽位号。

输入 yes 之后才会真正创建。

见到 [OK] 之后说明集群建立完成。

连接并验证集群

使用客户端连接集群中的任何一个节点,都相当于连上了整个集群。:

redis-cli -h 172.30.0.101 -p 6379

在客户端中,我们使用 cluster nodes 来查看当前集群的信息。

重定向

尝试插入数据:

报错了,因为当前集群发生了分片,每个分片都只能存储一部分数据,key1经过哈希运算,发现并不是这个节点可以存储的值,于是就报错了。

想要解决这个问题,可以在启动时加上-c选项,此时插入数据,会自动重定向到对应的节点。

如图,每次操作数据是,如果该数据不属于当前分片,就会触发一次重定向,自动跳转到对应的客户端。命令行前面的 ip 一直在改变,这就说明我们的客户端一直在切换。

但是redis中,有一些命令同时操作多个key,比如最后一个命令mget,此时又报错了。因为这几个key属于不同分片,那么就无法同时处理,因此在集群的情况下,最好不要一次性操作多个key


主节点宕机自动处理流程

如果在集群中,某一个分片的主节点宕机了,会发生什么?在部署集群时,并没有引入哨兵节点,但是集群也会完成哨兵的工作,如果主节点宕机了,集群会自动完成重新选主的过程。

接下来就讲解集群中是如何完成故障转移的。

故障判定

Redis 集群中的所有节点会周期性地使用心跳包进行通信,确保各节点之间的连接状态和集群配置信息的同步。以下是心跳包交互的具体过程:

  • 跳包通信:节点A给节点B发送ping包,B接收到后返回一个pong。这些消息除了类型属性外,其余部分相同,并包含以下集群配置信息:
    • 节点ID
    • 所属分片
    • 主/从角色
    • 附属主节点(如果为从节点)
    • 持有的哈希槽位图
  • 随机化心跳检测每个节点每秒钟随机选择一部分节点发送ping包,而非向所有节点发送,以减少大量节点存在时的心跳包数量。
  • PFAIL 状态:当节点A尝试与节点B通信未果时,A首先尝试重置TCP连接;若仍然失败,则将B标记为PFAIL(主观下线)状态。
  • Gossip协议确认:一旦A判定B为PFAIL,它会通过内置的Gossip协议与其他节点沟通,确认B的状态。每个节点维护自己的“下线列表”,反映其视角下的故障节点。
  • FAIL 状态:如果多数节点(超过半数)也认为B处于PFAIL状态,那么A将正式把B标记为FAIL(客观下线),并通知其他节点更新状态。
故障迁移

当一个节点被标记为FAIL时,根据该节点的角色,可能触发不同的响应:

  • 从节点故障:如果是从节点,通常不需要特别处理,因为它们不直接服务客户端请求。
  • 主节点故障:如果故障节点是主节点,则需要进行故障迁移,流程如下:
    1. 资格审查:从节点检查自身是否符合晋升条件,即与原主节点的最后通信时间不超过设定阈值。
    2. 休眠等待:符合条件的从节点进入一段随机的休眠期,休眠时间=500ms基础时间+[0,500ms]随机时间+排名*1000msoffset 的值越大,则排名越靠前(越小)。这一策略有助于防止多个从节点同时竞选。
    3. 拉票选举:休眠结束后的 从节点开始向其他集群的主节点拉票。只有主节点有投票权,且每个主节点只能投一票。
    4. 晋升为主:获得超过半数主节点支持的从节点晋升为主节点,并执行SLAVEOF NO ONE命令脱离原主节点控制。并且让同一分片中的其它节点执行 slaveof
    5. 最后,新的主节点会把自己成为主节点的消息,同步给其他集群的节点,大家也都会更新自己保存的集群结构信息

此过程类似于 Raft算法,旨在选出网络状况较好的节点作为新的主节点,保证集群的服务连续性和数据一致性。

Fail 状态的影响

在某些情况下,单个节点的故障可能导致整个集群进入fail状态,具体情形包括但不限于:

  • 某一分片内的所有主节点和从节点都不可用。
  • 某一分片内主节点故障且 无可用从节点可晋升。
  • 超过半数的主节点失效。

实验

如图:

首先通过docker stop redis1,关掉了redis1节点,也就是xxx.101下线了,而这是一个主节点。登录6372端口的客户端,查看当前集群,可以发现xxx.106成为了新的主节点,而xxx.105原先是xxx.101的从节点。

重启redis1,其变为了reids5的从节点。

此处 集群的故障转移,和哨兵的故障转移是有一些差别的

  • 哨兵:sdown/odown
  • 集群:PFAIL/FAIL

集群扩容

一、加入集群
  • 命令格式
    • 使用 --cluster add-node 选项将新节点添加到集群。
  • 具体操作
    • 新增节点:要增加到集群的节点。
    • 集群任意节点:用于标识要加入哪一个集群。
redis-cli --cluster add-node 172.30.0.110:6379 172.30.0.101:6379

这样就可以把xxx.110节点加入到集群中,登入任意客户端查看:

通过上述命令,可以将 xxx.110 节点加入到集群中。登录任意客户端查看,可以看到集群内部已有 xxx.110,且是一个主节点。但需要注意的是,新增节点没有分配哈希槽。

二、分配哈希槽
  • 命令格式
    • 使用 --cluster reshard 选项给新节点分配哈希槽(注意是 reshard 不是 shared)。
redis-cli --cluster reshard 172.30.0.101:6379

执行步骤

  • 系统会询问要移动多少个 slots(哈希槽)。假设需要移动4096个哈希槽给新节点,则输入 4096
  • 接着询问将这些哈希槽移动给哪个节点。此时应选择 哈希槽为 0的主节点,并复制其ID。

  • 最后询问从哪些节点中空出这些哈希槽。可以 选择 all 表示从所有现有节点平均提取,或自己指定节点ID,以 done 结束。
  • 最终向用户确认是否要执行该操作。

执行完毕后,进入任意客户端查看集群现状,可以看到新节点获得了三个范围的哈希槽。

问题:搬运哈希槽的过程可能比较久,在此期间用户的访问合法性如何?

  • 大部分哈希槽在搬运过程中仍可正常访问。
  • 如果 用户访问正在移动的哈希槽,则可能会导致访问失败。
三、添加从节点
  • 命令格式
    • 使用 add-node 命令配合 --cluster-slave--cluster-master-id 选项来添加从节点。
redis-cli --cluster add-node 新节点 --cluster-slave --cluster-master-id 主节点的ID
  • 参数说明
    • --cluster-slave:指定新添加的节点作为从节点。
    • --cluster-master-id:后面跟着的是主节点的ID,表示该节点从属于哪一个节点。
redis-cli --cluster add-node 172.30.0.111:6379 172.30.0.101:6379 --clusterslave --cluster-master-id  [172.30.1.110 节点的 nodeId-->] 7ec6d4a0e616916afab017f30d9a1434e375e80a

此时扩容目标初步达成,但是为了保证整个集群的可用性,还需要给主节点添加一些从结点,保证主节点宕机之后,有接班人~

sum:

主从复制:分担了读取压力

哨兵:监控,稳健性提高

集群:存储数据量 提升

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐