SpringCloud(13)— 分布式缓存(Redis集群)

分布式缓存(Redis集群)

前言 单节点Redis的问题

1.数据丢失

Redis基于内存存储,服务器重启可能会导致数据丢失

在这里插入图片描述

2.并发能力

单节点Redis的并发能力虽然已经很不错,但是依然无法满足大型的高并发场景

在这里插入图片描述

3.故障恢复

如果Redis宕机,则服务将不可用。因此需要一种自动的故障恢复手段
在这里插入图片描述

4.存储能力

Redis基于内存,单节点存储的数据量有限,难以满足海量数据的需求

在这里插入图片描述

5.解决Redis问题的方案

在这里插入图片描述

一 搭建单节点Redis

1.使用安装包搭建单节点

先下载 Redisan安装包,笔者编辑此文档时,最新版为redis-6.0.6.tar.gz,下载完成之后将安装包放置在虚拟机或服务器的指定位置下。

#1.安装依赖
yum install -y gcc tcl
#2.解压文件
tar -xvf redis-6.0.6.tar.gz
#3.进入redis文件目录
cd /redis-6.0.6
#4.编译安装
make && make install

安装过程中出现以下错误时,可以按照以下方案解决

‘struct redisServer’ has no member named ‘sentinel_mode’
         if (server.sentinel_mode && configfile && *configfile == '-')

解决方案:Redis: 部署redis6.0.6 出现问题_天黑请赶路的博客-CSDN博客

处理完成以后,重新运行make && make install命令即可完成安装

2.Docker搭建单节点 Redis

使用Docker创建一个Redis容器并且运行即可

docker run --name myredis \
            -v /usr/local/redis:/usr/local/etc/redis \
            -p 6379:6379 \
            -d redis:latest \
            redis-server /usr/local/etc/redis/redis.conf
  • -v:挂载自己的redis配置文件目录到容器指定目录
  • -p:对外映射访问端口
  • redis-server /usr/local/etc/redis/redis.conf:指定要使用的redis.conf

更多用法参考DockerHub:redis - Official Image | Docker Hub

踩坑点:redis.conf文件需要手动创建

Redis及配置文件下载地址:redis下载 – Redis中国用户组(CRUG)

二 Redis持久化

1.RDB持久化

1.RDB基础

RDB全称为Redis Database Backup file(Redis数据备份文件),也叫作Redis数据快照

简单来说就是把内存中的所有数据都记录到磁盘中,当Redis实例故障后,从磁盘读取快照文件,恢复数据。

2.RDB存储

RDB存储方式默认由Redis开启

快照文件称之为RDB文件,默认保存在当前运行目录

通过 save命令来实现RDB持久化,该命令由Redis主进程来执行,会阻塞所有命令。

使用save保存数据,当数据过大时,会导致其他线程无法访问Redis,缺点尤为明显

这里推荐使用bgsave命令,使用后台保存命令。该命令是在后台异步执行的,且由子进程执行RDB,不会造成主进程的阻塞。

在这里插入图片描述

注意:Redis停机时会自动执行一次RDB

Redis内部有触发RDB的机制,可以在 redis.conf 文件夹中找到。其中关于RDB的默认配置如下:

# 含义:900s内如果有1个key被修改,则执行 bgsave,其他行同理。
# 如果是 save "" 则表示删除所有的保存点。
# 禁用所有 save 表示完全禁用 RDB
#   save ""
save 900 1
save 300 10
save 60 10000

#其他配置信息
#是否压缩
rdbcompression yes
#是否校验和
rdbchecksum yes
#压缩文件名称
dbfilename dump.rdb
#是否删除非持久性实例中的rdb文件
rdb-del-sync-files no
#RDB文件保存位置,默认为当前目录
dir ./
3.RDB原理

bgsave命令开始执行时,会 fork 主进程得到子进程,子进程共享主进程的内存数据。

完成 fork 后读取内存数据并写入RDB文件中。

在这里插入图片描述

fork 底层采用了 copy-on-write 技术:

  • 当主进程执行读操作时,访问共享内存
  • 当主进程执行写操作时,则会拷贝一份数据,执行写操作

整体流程:

  1. fork主进程得到一个子进程,共享内存空间
  2. 子进程读取内存数据并且写入RDB文件
  3. 使用新的RDB文件替换旧的RDB文件

RDB的缺点:

  • RDB执行间隔时间长,两次RDB之间写入数据有丢失的风险
  • fork子进程,压缩,写入RDB文件都比较耗时

2.AOF持久化

1.AOF基础

AOF全称为Append Only FIle(追加文件)。Redis处理的每一个命令都会记录在AOF中,可以看做是命令日志文件。

在这里插入图片描述

2.AOF存储

AOF默认是关闭状态,需要修改redis.conf配置文件开开启AOF

#是否开启AOF功能,默认为 no
appendonly yes

#AOF文件默认名称
appendfilename "appendonly.aof"

# AOF文件记录频率,Redis提供了三种方案,分别是 always,everysec,no
appendfsync everysec
  • everysec:写命令执行完先放入缓冲区,然后每隔1秒将缓冲区的数据写到AOF文件,是默认方案。牺牲一定的可靠性,但性能较好
  • no:写命令执行完先放入缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。性能最好,但是安全性最差
  • always:每执行一次写命令,立即记录到AOF文件,数据得到绝对的安全保障,但是性能最差
    在这里插入图片描述
3.存储示例

注意:RedisRDBAOF可以共同存在,一起保障数据的安全

修改redis.conf的关键配置如下:

# 注释掉所有 save 行,开启 AOF 存储
appendonly yes

重启Redis服务,此时默认目录下会生成 appendonlydir 文件,真对于 redis 的操作记录,全都记录在这个文件夹中。

在这里插入图片描述

# 进入 redis 容器内部
docker exec -it myredis bash
# 查看当前目录下的文件
ls
# 利用redis-cli工具操作redis,并且存储一个String数据
set name tony;

其中 /appendonlydir/appendonly.aof.1.incr.aof中就保存着我们操作redis的记录。

使用 cat 命令查看文件内容

# 切换至 appendonlydir 目录下
cd /appendonlydir
# 查看文件内容
cat appendonly.aof.1.incr.aof

在这里插入图片描述

${num}表示输入命令的字符串长度,例如 $6 表示输入了一个长度为 6 的信息。

以上文件内容表示执行了以下Redis 命令:

# 选择 0 号库
select 0
# 存储一个key=name,value=tony的字符串数据
set name tony

因为是记录命令,AOF文件会比RDB文件大很多。而且对同一个key的多次操作,只有最后一次才有意义。这样一来就存储了很多无用的数据。

通过执行bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到相同的效果。

bgrewriteaof

自动重写功能默认为开启状态,我们可以通过配置文件,设置触发自动重写的条件:

# 相比上次文件大小,超过指定百分比则触发重写
auto-aof-rewrite-percentage 100
# aof文件的大小达到指定大小时开始触发重写
auto-aof-rewrite-min-size 64mb

3.持久化模式对比

在这里插入图片描述

实际生产环境下往往采用两者结合的方式来使用。

三 Redis主从

单节点Redis的并发能力是有上线的,要进一步提高Redis的并发能力,就需要搭建主从架构,实现读写分离。

在这里插入图片描述

在一台服务器上开启多个端口,模拟实现搭建Redis主从架构。

1.搭建Redis主从架构

创建3个文件目录,使得它们分别去运行,彼此之间互不干扰

mkdir 7001 7002 7003

准备一份原始的redis配置文件redis.conf,然后将它复制3份,分别放在3个文件夹下面

可以通过 查找,获取到刚才安装的Redis的配置文件,恢复至原始状态,然后将其复制到创建的3个目录下,

find / -name redis.conf

在这里插入图片描述

可以使用管道组合命令,一键拷贝

echo 7001 7002 7003 | xargs -t -n 1 cp /usr/local/redis-6.0.6/redis.conf

在这里插入图片描述

修改数据保存目录为3个文件夹的各自目录以及端口号,分别执行一下命令,可快捷完成更改

sed -i -e 's/6379/7001/g' \
       -e 's/dir .\//dir \/tmp\/7001\//g' \
       -e 's/logfile ""/logfile "\/tmp\/7001\/redis.log"/g' \
       7001/redis.conf;
sed -i -e 's/6379/7002/g' \
       -e 's/dir .\//dir \/tmp\/7002\//g' \
       -e 's/logfile ""/logfile "\/tmp\/7002\/redis.log"/g' \
       7002/redis.conf;
sed -i -e 's/6379/7003/g' \
       -e 's/dir .\//dir \/tmp\/7003\//g' \
       -e 's/logfile ""/logfile "\/tmp\/7003\/redis.log"/g' \
       7003/redis.conf;

声明每个实例的IP,因为虚拟机本身具有多个IP,为避免混乱和变化,最好为每个实例指定固定的IP地址,可使用一下命令快捷修改

sed -i '1a replica-announce-ip 192.168.119.101' 7001/redis.conf;
sed -i '1a replica-announce-ip 192.168.119.101' 7002/redis.conf;
sed -i '1a replica-announce-ip 192.168.119.101' 7003/redis.conf;

更改redis.conf的binddaemonize属性,允许远程访问和后台运行,可以进行快捷修改

sed -i -e 's/127.0.0.1/0.0.0.0/g' -e 's/daemonize no/daemonize yes/g' 7001/redis.conf;
sed -i -e 's/127.0.0.1/0.0.0.0/g' -e 's/daemonize no/daemonize yes/g' 7002/redis.conf;
sed -i -e 's/127.0.0.1/0.0.0.0/g' -e 's/daemonize no/daemonize yes/g' 7003/redis.conf;

然后分别运行3个redis实例,运行的时候需指定特定的redis.conf文件

redis-server 7001/redis.conf;
redis-server 7002/redis.conf;
redis-server 7003/redis.conf;

运行完成之后,查看redis进程

ps -ef |grep redis

在这里插入图片描述

可以看到3个redis实例已经全部运行成功。

最后一步,配置主从关系,我们以 7001 实例作为master,7002,7003作为replica/slave,然后分别修改redis.conf配置文件

其中,master主节点不需要修改,只需要修改两个从节点即可

# 格式: replicaof host port
replicaof 192.168.119.101 7001

# 或者
salveof 192.168.119.101 7001

Redis5.0之前使用 slaveof 参数,Redis5.0之后使用 replicaof 参数,两者效果完全一样

使用快捷命令进行修改

sed -i '1a replicaof 192.168.119.101 7001' 7002/redis.conf;
sed -i '1a replicaof 192.168.119.101 7001' 7003/redis.conf;

修改完成之后,关闭3个redis进程,然后全部重启,进行测试即可。

kill 9 57781 57787 57811

至此,Redis集群搭建完成

2.Docker 搭建主从架构

准备3份redis的配置文件(使用默认配置即可),修改配置文件中RDB的存储位置为/data/。且将配置文件分别存储在不同的目录下:

关键配置信息如下:

# 1.修改 dir 的值为 /data/
dir /data/
# 2.注释掉 bind 127.0.0.1,允许远程访问
#bind 127.0.0.1
# 3.关闭保护模式,修改参数值为 no
protected-mode no

运行以下 docker 命令,创建3个redis容器:

docker run --name redis-master \
            -v /usr/local/redis-1:/usr/local/etc/redis \
            -v /usr/local/redis-1/data/:/data/ \
            -p 7001:6379 \
            -p 27001:27001 \
            --network bridge \
            -d redis:latest \
            redis-server /usr/local/etc/redis/redis.conf;

docker run --name redis-replica-1 \
            -v /usr/local/redis-2:/usr/local/etc/redis \
            -v /usr/local/redis-2/data/:/data/ \
            -p 7002:6379 \
            -p 27002:27002 \
            --network bridge  \
            -d redis:latest \
            redis-server /usr/local/etc/redis/redis.conf;

docker run --name redis-replica-2 \
            -v /usr/local/redis-3:/usr/local/etc/redis \
            -v /usr/local/redis-3/data/:/data/ \
            -p 7003:6379 \
            -p 27003:27003 \
            --network bridge \
            -d redis:latest \
            redis-server /usr/local/etc/redis/redis.conf;
  • -v /usr/local/redis-1/data/:/data/ :将redis容器的RDB文件目录/data/挂载到Linux服务器目录/usr/local/redis-1/data/

创建容器时容器的网络模式使用了桥接模式(bridge),这是Docker中的默认网络模式,创建了一个虚拟网卡docker0,通过docker0网桥以及iptables nat表配置与宿主机通信,此模式会为每一个容器分配Network Namespace、设置IP等,并将一个主机上的 Docker 容器连接到一个虚拟网桥上。

使用以下命令查看虚拟网卡docker0的配置信息

iptables -t nat -nvL

在这里插入图片描述

使用虚拟网卡docker0提供的Network Namespace以及ip地址,可以实现容器之间的相互通信。关于Docker网络模式内容,请查阅Dokcer官网

我们以7001端口的容器作为主机,由上图可知,映射端口为7001端口的容器的虚拟网桥地址是172.12.0.2:6379

在从机(replace / slave) 的配置文件 redis.conf 中指定主机(master)的IP地址和端口号

# 格式: replicaof host port
replicaof 172.17.0.2 6379

# 或者
salveof 172.17.0.2 6379

Redis5.0之前使用 slaveof 参数,Redis5.0之后使用 replicaof 参数
在这里插入图片描述
完成之后重启容器进行测试,此时主机的日志会给出提示,如下图:
在这里插入图片描述
主从架构搭建完成以后,只有主机(master)可以做写操作,而从机(slave)只能做读操作

3.主从数据同步原理

1.全量同步

主从第一次同步是全量同步
在这里插入图片描述
master如何判断slave是不是第一次来同步数据?这里会用到两个很重要的概念:

  • Replication Id:简称 replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid
  • offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐变大。slave完成同步时也会记录当前同步的offset。如果slaveoffset小于masteroffset,说明slave数据落后于master,需要更新。

因此slave做数据同步,必须向master声明自己的Replication Idoffsetmaster才能判断到底需要同步哪些数据。

Redis底层通过Replication Id来判断是否为第一次数据,如果masterReplication Idslave不一样,则说明是第一次同步数据。

全量同步的完整流程:

  1. slave节点请求增量同步
  2. master节点判断repl_Id,发现不一致,拒绝增量同步
  3. master将完整内存数据生成RDB,发送RDB到slave
  4. slave清空本地数据,加载master的RDB
  5. master将RDB期间的命令记录在repl_baklog,并持续将repl_baklog中的命令发送给slave
  6. slave执行接收到的命令,保持与master之间的同步
2.增量同步

主从第一次同步是全量同步,但如果slave重启后同步,则执行增量同步

在这里插入图片描述

repl_baklog有大小上限,写满后会覆盖最早的数据。如果slave断开的时间过长,导致数据被覆盖,则无法实现增量同步,只能再次进行全量同步。

3.主从同步优化
  • 在master中配置repl-diskless-sync yes,启用无磁盘复制,避免全量同步时的IO。减少磁盘的读写,可以有效提高同步的速度
  • Redis单节点上的内存占用不用太大,减少RDB导致的过多磁盘读写
  • 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
  • 限制一个master上的slave节点数量,如果实在slave太多,则可以通过主-从-从链式结构,减少master的压力
#当带宽大时,可考虑通过启用无磁盘复制来提高同步的速度
repl-diskless-sync yes

Redis的主-从-从集群结构:

在这里插入图片描述

4.小结

全量同步与增量同步的区别:

  • 全量同步:master将完整内存数据生成RDB,发送RDB给slave,后续命令持续记录在repl_baklog中,逐个发送给slave
  • 增量同步:slave提交自己的offset到master,master获取repl_baklog中从offset之后的命令给slave

什么情景下进行全量同步?

  • slave第一次连接master节点时
  • slave断开连接太久,repl_baklog中的数据已经被覆盖时

什么时候做增量同步?

  • slave节点断开之后重新连接,并且在repl_baklog中能找到offset

四 Redis哨兵

1.哨兵的作用和原理

Redist提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。

在这里插入图片描述

1.Sentinel的作用如下:

  • 服务状态监控:不间断的检查Redis的master和slave是否按照预期工作
  • 故障恢复:如果master故障,则Sentinel会将一个slave提升为master,当故障恢复后也以新的master为主(实现主从的切换)
  • 通知:Sentinel充当Redis客户端的服务发现开源,当集群发生故障转移时,会将最新消息推送给Redis客户端

2.服务状态监控的过程:

Sentinel基于心跳机制检测服务状态,每隔1s向集群中的每个示例发送ping命令

  • 主观下线:如果Sentinel节点发现某个实例未在规定时间内响应,则认为该示例主观下线
  • 客观下线:若超过指定数量(quorum)的Sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例的一半

3.选举新的master:

  • 判断slave与master节点断开的时长,超过指定时长(down-after-milliseconds*10)则会排除该slave节点
  • 判断slave节点的slave-priority值,越小则优先级越高,为0时则不参与选举
  • 如果slave节点的slave-priority的值一样,则判断slave节点的offset值,越大说明越新,优先级也越高
  • 最后判断slave节点的运行id大小,越小优先级越高

4.故障转移

在这里插入图片描述

2.搭建Redis哨兵集群

创建一个sentinel.conf,或者在Redis中的解压文件中找到sentinel.conf,并且将它分别复制到3个redis实例的目录下7001 7002 7003

可以使用一下快捷复制命令,注意,要在7001 7002 7003的父级目录下使用一下命令

echo 7001 7002 7003 | xargs -t -n 1 cp /usr/local/redis-6.0.6/sentinel.conf

然后修改相关配置参数

# 指定哨兵的端口号
port 27001
# 指定当前哨兵节点的IP地址
sentinel announce-ip 192.168.119.101
# 指定主节点哨兵的实例名称(这里是mymaster),及主节点IP,和主观下线值(quorum),超过这个值则重新选举主节点
sentinel monitor mymaster 192.168.119.101 7001 2
# 主节点的最大断开时长
sentinel down-after-milliseconds mymaster 5000
# 故障恢复时间
sentinel failover-timeout mymaster 60000
# 是否后台运行
daemonize yes
# 指定工作路径,即sentinel.conf的目录
dir "/tmp/7001"
# 指定日志文件目录
logfile ""

一键修改全部实例的命令

sed -i -e 's/26379/27001/g' \
       -e 's/dir \/tmp/dir "\/tmp\/7001" /g' \
       -e 's/daemonize no/daemonize yes/g' \
       -e 's/logfile ""/logfile "\/tmp\/7001\/sentinel.log"/g' \
       -e 's/127.0.0.1 6379 2/192.168.119.101 7001 2/g' \
       7001/sentinel.conf;
sed -i -e 's/26379/27002/g' \
       -e 's/dir \/tmp/dir "\/tmp\/7002" /g' \
       -e 's/daemonize no/daemonize yes/g' \
       -e 's/logfile ""/logfile "\/tmp\/7002\/sentinel.log"/g' \
       -e 's/127.0.0.1 6379 2/192.168.119.101 7001 2/g' \
       7002/sentinel.conf;
sed -i -e 's/26379/27003/g' \
       -e 's/dir \/tmp/dir "\/tmp\/7003" /g' \
       -e 's/daemonize no/daemonize yes/g' \
       -e 's/logfile ""/logfile "\/tmp\/7003\/sentinel.log"/g' \
       -e 's/127.0.0.1 6379 2/192.168.119.101 7001 2/g' \
       7003/sentinel.conf;

一键添加哨兵配置

sed -i '1a sentinel announce-ip 192.168.119.101' \
     7001/sentinel.conf;
sed -i '1a sentinel announce-ip 192.168.119.102' \
     7002/sentinel.conf;
sed -i '1a sentinel announce-ip 192.168.119.103' \
     7003/sentinel.conf;

一键运行哨兵

redis-sentinel 7001/sentinel.conf;
redis-sentinel 7002/sentinel.conf;
redis-sentinel 7003/sentinel.conf;

通过 ps -ef|grep redis 查看,可以看到3个sentinel实例,和3个redis实例均已运行

4.RedisTemplate哨兵模式

在Sentinel集群监管下的Redis主从集群,其节点会因为自动故障转移而发生改变,Redis的客户端必须感知这种变化,及时更新连接信息。Spring的RedisTemplate底层利用lettuce框架实现了节点的感知和自动切换。

1.引入RedisTemplate

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.配置Redis的读写分离

@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
    return clientConfigurationBuilder ->clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}

此处的ReadFrom是一个枚举,用来配置Redis的读取策略,包括下面选择:

  • MASTER:从主节点读取
  • MASTER_PREFERRED:优先读取主节点,主节点不可用时才读取从节点
  • REPLICA:从replica节点读取
  • REPLICA_PREFERRED:优先从replica节点读取,从节点不可用时从主节点读取

3.修改配置文件

spring:
  redis:
    sentinel:
      # 配置主节点名称
      master: mymaster
      # 配置redis-sentinel集群节点
      nodes:
        - 192.168.119.101:27001
        - 192.168.119.101:27002
        - 192.168.119.101:27003

五 Redis分片集群

1.分片集群结构

主从和哨兵可以解决高可用,高并发读取的问题。但是依然有两个问题没有解决:

  • 海量数据存储问题
  • 高并发写入的问题

可以考虑使用分片集群来解决上述问题,分片集群的特征:

  • 集群中有多个master,每个master保存不同的数据
  • 每个master都可以有多个slave节点
  • master之间通过ping检测彼此的健康状态
  • 客户端请求可以访问集群中的任意节点,最终都会被转发到正确可用的节点

在这里插入图片描述

2.分片集群搭建

分片集群数量较多,以最小的分片集群作为示例演示,包含3个master,其中每一个master节点包含一个slave节点

在这里插入图片描述

2.集群搭建准备,之前搭建集群和哨兵的目录可以删除掉

# 1.创建文件夹
mkdir 7001 7002 7003 8001 8002 8003
# 2.拷贝配置文件
echo 7001 7002 7003 8001 8002 8003 | xargs -t -n 1 cp /usr/local/redis-6.0.6/redis.conf

3.关键参数配置

port 7001
#开启集群配置
cluster-enabled yes
#节点配置文件,无需创建,由Redis自行维护,放开即可
cluster-config-file nodes-6379.conf
#节点心跳失败的超时时间
cluster-node-timeout 15000
#持久化文件存放目录,可根据实际情况修改
dir /data/
#绑定地址,允许远程访问
bind 0.0.0.0
#后台运行
daemonize yes
#注册的实例ip及端口号,根据实际情况修改
replica-announce-ip 192.168.119.101
replica-announce-port 7001
#保护模式
protected-mode no
#数据库数量,一般情况下修改为1即可,默认情况下为16
databases 1
# 日志,配置日志文件的位置及名称
logfile /tmp/7001/cluster.log

4.运行Redis集群实例

redis-server 7001/redis.conf;
redis-server 7002/redis.conf;
redis-server 7003/redis.conf;
redis-server 8001/redis.conf;
redis-server 8002/redis.conf;
redis-server 8003/redis.conf;

在这里插入图片描述

5.此时的 Redis 实例已经全部运行,但是之间并无直接关联,现在还需要去创建集群。运行以下命令创建集群

redis-cli --cluster create --cluster-replicas 1 \
         192.168.119.101:7001 \
         192.168.119.101:7002 \
         192.168.119.101:7003 \
         192.168.119.101:8001 \
         192.168.119.101:8002 \
         192.168.119.101:8003
  • redis-cli --cluster:Redis的集群操作命令
  • create:创建集群
  • --cluster-replicas 1:指定集群中每个master的副本数量为 1,此时 节点数 ÷ ( replica+1 ) 得到的就是master的数量。因此节点列表前n个就是,master,其他节点都是slave,随机分配到不同的master

运行之后,redis会给出一个集群方案

在这里插入图片描述

确定这个集群分案没有问题后,则输入 yes ,至此,分片集群创建完成。

6.检查集群状态,可以通过主节点的端口号查看集群状态,下面以 7001 作为示例

redis-cli -p 7001 cluster nodes

在这里插入图片描述

3.散列插槽

Redis会把每一个master节点映射到【0~16383】共计16384个插槽( hash slot)上,查看集群信息时就能看到,参考上图。

1.Redis中的数据 key 不与节点绑定

Redis中的数据 key 不与节点绑定,而是跟插槽绑定。redis 会根据 key 的有效部分计算插槽值。有以下两种情况:

  • key 中包含 “{}” ,且 “{}” 中至少包含一个字符,“{}” 中的部分是有效的
  • key 中不包含 “{}” ,整个 key 都是有效部分

例如:key 值为 num, 那么就根据 num 值进行计算,如果是 { shawn } num,则根据 shawn 计算。计算方法为利用CRC16算法得到一个哈希值,然后对16383取余,最后得到的结果就是 slot 值

2.集群模式下进入Redis

进入指定端口的集群存测试数据存储

redis-cli -c -p [port]
# 示例
redis-cli -c -p 7001
3.Redis如何判断某个 key 应该在哪个实例?
  • 将 16384 个插槽分配到不同的实例
  • 根据 key 的有效部分计算哈希值,然后对 16384 取余
  • 余数作为插槽,寻找插槽所在实例即可
4.如何将同一数据固定的保存在同一个Redis实例?
  • 如果同一类数据计算出来的插槽是一样,则可以保证它们都存储在同一个Redis实例中
  • 只需要保证 key 的有效部分一样即可,例如 key 都以 {typeId}为前缀

4.集群伸缩

redis-cli --cluster 中提供了很多方法,可以通过一下命令查看

# 查看 redis-cli --cluster 命令帮助
redis-cli --cluster help
# 添加节点
redis-cli --cluster add-node [new_host]:[new_port] [exist_host]:[exist_port]

准备一个8004的文件夹,和 redis 配置文件,修改端口号等相关配置参数,然后运行该实例

#运行 8004 实例
redis-server 8004/redis.conf
1.添加为主节点
#1.不加任何选项时默认添加的为主节点(master),且不分配插槽
redis-cli --cluster add-node 192.168.119.101:8004 192.168.119.101:7001
#2.为指定节点分配插槽,使用 reshard 命令
redis-cli --cluster reshard 192.168.119.101:7001

在这里插入图片描述

输入要分配的插槽数量,这里我们输入 3000 ,然后敲击回车

在这里插入图片描述

输入要接收插槽的节点ID,我们通过命令查询到,输入即可

在这里插入图片描述

输入想要获取的插槽所在的节点Id,这里我们从 7002 中拿出3000个插槽分配给 8004,这里输入 7002 的节点Id,

在这里插入图片描述

从多个节点分配时,输入多个,结束时输入 done 即可,

等待分配完成,查看集群状态
在这里插入图片描述

此时,原本在 7002 节点上的 【6462 - 9461】插槽 被迁移到了 8004 节点,且上面的数据也被迁移了过来。

这也说明了,Redis分片集群中的数据,是和插槽绑定的,而非节点

2.添加为从节点
# 增加 --cluster-slave 选项,添加进去的 8004 节点将变成从节点,并且指定主节点的ID(通过redis-cli -p 7001 cluster nodes查询)
redis-cli --cluster add-node 192.168.119.101:8004 192.168.119.101:7001 \
          --cluster-slave \
          --cluster-master-id 94a1478400df69fcf0e197fb6a129a39298f359b

通过redis-cli -p 7001 cluster nodes查询,可以看到 7001 下面有两个从节点
在这里插入图片描述

更多命令通过 redis-cli --cluster help 查看用法。

3.删除指定节点

删除从节点时使用命令直接删除即可,删除主节点时需要把主节点上的插槽转移到其他节点上方可删除

# 语法示例
redis-cli --cluster del-node [host]:[port] 【nodeId】
# 删除示例
redis-cli --cluster del-node 192.168.119.101:8004 e12ee3d58e459db6272750dafef410ed5d632f8c

5.故障转移

尝试关闭或重启指定集群,然后观察日志

# 关闭指定集群,以 7002 为例
redis-cli -p 7002 shutdown
# 重启指定集群,以 7002 为例
redis-server 7002/redis.conf

会发现原来的从节点变成了主节点,而重启之后的 7002 实例,变成了 从节点,成功完成了主从切换,实现了故障转移

6.手动故障转移

利用 cluster failover 命令手动让集群中的某个master节点宕机,切换到执行 cluster failover 命令的这个slave节点上,实现无感知的数据迁移。

在这里插入图片描述

手动的FialOver命令支持三种不同模式

  • 默认模式:流程如上图
  • force:省略了对 offset 的校验
  • takeover:直接执行第5步,忽略数据一致性,忽略 master 状态 和其他 master 意见

具体实现:

以 7002 示例为例,现在的 7002 已经是从节点,而它的主节点为 8001

在这里插入图片描述

连接 7002 ,输入 cluster fialover 命令,实现主从切换

# 1.连接 7002 实例
redis-cli -c -p 7002
# 2.输入命令 cluster fialover
cluster fialover
# 3.退出 exit
exit
# 4.查看集群状态
redis-cli -p 7001 cluster nodes

在这里插入图片描述

可以看到,此时的 7002 已经变成了 master 节点,而 8001 则变成了 slave 节点,从而实现手动故障转移

7.RestTemplate访问分片集群

RedisTemplate底层基于 lettuce 实现了分片集群的支持,而使用的步骤基本与哨兵模式一致

1.引入redis的starter依赖

2.配置分片集群地址

spring:
  redis:
    cluster:
      # 指定分片集群中的每一个节点信息
      nodes:
        - 192.168.119.101:7001
        - 192.168.119.101:7002
        - 192.168.119.101:7003
        - 192.168.119.101:8001
        - 192.168.119.101:8002
        - 192.168.119.101:8003
        - 192.168.119.101:8004

3.配置读写分离

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值