分布式缓存 redis集群

目录

单点Redis的问题

1数据丢失问题

2并发能力问题

3存储能力问题

4故障恢复问题

单机安装Redis

1 首先需要安装Redis所需要的依赖

2 下载安装包 Download | Redis

3 上传到服务器并解压

4 运行编译命令:

5 然后修改redis.conf文件中的一些配置:

6 启动Redis:

7 停止redis服务:

Redis持久化

RDB持久化

save和bgsave

save:

​编辑

 bgsave:

save与bgsave的对比:

RDB的缺点

注意

AOF持久化 (追加文件)

1 开启AOF

2 设置AOF命令记录频率

3 重写AOF文件 (bgrewriteaof)

​编辑3.1 手动重写

 3.2 配置重写阈值

注意

RDB与AOF的对比

Redis主从并实现读写分离

集群架构

搭建主从架构

1 准备实例和配置

1.0 在同一台服务器上启动多个redis实例 且互不干扰

1.1 创建目录

1.2 修改配置

1.3 拷贝配置文件到每个实例目录

1.4 修改每个实例的端口、工作目录

1.5 修改每个实例的声明IP 

2 启动redis

2.2 如果要一键停止

3 开启主从关系

        3.1 修改配置文件(永久生效)

        3.2 使用redis-cli客户端连接到redis服务,执行slaveof命令(重启后失效):

4 这里我们为了演示方便,使用方式二。

5 测试结果

主从数据同步原理

主从第一次同步是全量同步

 master如何判断slave是不是第一次来同步数据

全量同步的流程

注意:

优化Redis主从就集群

主-从-从链式结构

总结:

Redis哨兵

哨兵的作用和原理

哨兵结构

哨兵的作用

服务状态监控

 选举新的master

如何实现故障转移

总结

搭建哨兵集群

1 哨兵集群结构:

2 准备sentinel实例和配置

2.1 创建文件夹

2.2 修改sentinel配置

3 启动redis-sentinel

RedisTemplate的哨兵模式

1 在pom文件中引入redis的starter依赖:

2 然后在配置文件application.yml中指定sentinel相关信息:

3 配置主从读写分离

4 调用

Redis分片集群

分片集群结构

搭建分片集群

1 准备实例和配置

2 启动 6个redis实例

2.1如果要关闭所有进程

3 创建集群

3.1Redis5.0之前

3.2 Redis5.0以后

4 查看集群状态:

5 测试

集群操作时,需要给redis-cli加上-c参数才可以:

散列插槽

16384个插槽

 数据key与插槽绑定

总结:

集群伸缩

1 查看redis集群操作命令

2 添加节点 

2.1 分盘插槽

 3 例子:向集群中添加一个新的master节点,并向其中分配3000插槽

3.1 在tmp目录下创建一个7004目录

3.2 将tmp目录下的redis配置文件拷贝到7004目录了

3.3 将该配置文件中的6379全部替换7004

 3.4 运行

3.5 添加新节点

3.5.1 查看新集群状态

3.6 给新节点分盘插槽

3.6.1  重新分盘插槽

3.6.2 指定ip端口(当前链接到集群的ip和端口)

故障转移

当集群中有一个master宕机

数据迁移

例子:在7002这个slave节点执行手动故障转移,成为master地位

RedisTemplate访问分片集群


单点Redis的问题

1数据丢失问题

实现Redis数据持久化

2并发能力问题

搭建主从集群,实现读写分离

3存储能力问题

搭建分片集群,利用插槽机制实现动态扩容

4故障恢复问题

利用Redis哨兵,实现健康检测和自动恢复


单机安装Redis

环境:CentOS7   redis版本:6.2.4

1 首先需要安装Redis所需要的依赖

yum install -y gcc tcl

2 下载安装包 Download | Redis

3 上传到服务器并解压

例如,我放到了/tmp目录:

 解压缩:

tar -xvf redis-6.2.4.tar.gz

解压后:

进入redis目录:

cd redis-6.2.4

4 运行编译命令:

make && make install

如果没有出错,应该就安装成功了。

5 然后修改redis.conf文件中的一些配置:

# 绑定地址,默认是127.0.0.1,会导致只能在本地访问。修改为0.0.0.0则可以在任意IP访问
bind 0.0.0.0
# 数据库数量,设置为1
databases 1
# redis 密码 刚安装模式是无密码
requirepass redisPassword
# 让redis后台运行
daemonize yes

6 启动Redis:

redis-server redis.conf

7 停止redis服务:

redis-cli shutdown

Redis持久化

RDB持久化

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

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

save和bgsave

save:

Reids save命令执行一个同步保存操作(主进程执行),将当前Redis实例的所有数据快照(snapshort)已RDB文件的方式保存到磁盘

 Redis停机时会执行一次RDB。

 bgsave:

bgsave执行后,会立刻返回OK,Redis 会fork一个子进程,原来的redis主进程继续执行后续操作,新fork的子进程负责将数据保存到磁盘,然后退出

Redis内部有触发RDB的机制,可以在redis.conf文件中找到,格式如下:

save m n  自动触发bgsave;  m 代表多少秒内   n 代表多少个key被修改  则执行bgsave

# 900秒内,如果至少有1个key被修改,则执行bgsave , 如果是save "" 则表示禁用RDB
#save ""  则表示禁用RDB
save 900 1  
save 300 10  
save 60 10000 

RDB的其它配置也可以在redis.conf文件中设置:

# 是否压缩 ,建议不开启,压缩也会消耗cpu,磁盘的话不值钱
rdbcompression yes

# RDB文件名称
dbfilename dump.rdb  

# 文件保存的路径目录  默认是保存在当前运行目录。
dir ./ 
save与bgsave的对比:
  • save同步阻塞主进程,只有等save完后成,才能进行新操作
  • basave 是fork的子进程,非阻塞,等执行完后会通知主进程,然后关闭子进程

RDB的缺点

RDB执行间隔时间长,两次RDB之间写入数据有丢失的风险

fork子进程、压缩、写出RDB文件都比较耗时

注意

RDB 写入数据到磁盘 都是生成新的RDB文件替换旧的RDB文件

AOF持久化 (追加文件)

Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件

1 开启AOF

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

# 是否开启AOF功能,默认是no
appendonly yes
# AOF文件的名称
appendfilename "appendonly.aof"

2 设置AOF命令记录频率

AOF的命令记录的频率也可以通过redis.conf文件来配:

# 表示每执行一次写命令,立即记录到AOF文件
appendfsync always 
# 写命令执行完先放入AOF缓冲区,然后表示每隔1秒将缓冲区数据写到AOF文件,是默认方案
appendfsync everysec 
# 写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
appendfsync no

配置项

刷盘时机

优点

缺点

Always

同步刷盘

可靠性高,几乎不丢数据

性能影响大

everysec

每秒刷盘

性能适中

最多丢失1秒数据

no

操作系统控制

性能最好

可靠性较差,可能丢失大量数据

3 重写AOF文件 (bgrewriteaof)

因为是记录命令,AOF文件会比RDB文件大的多。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义。通过执行bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到相同效果。

3.1 手动重写

 3.2 配置重写阈值

Redis也会在触发阈值时自动去重写AOF文件。阈值也可以在redis.conf中配置:

# AOF文件比上次文件 增长超过多少百分比则触发重写
auto-aof-rewrite-percentage 100
# AOF文件体积最小多大以上才触发重写 
auto-aof-rewrite-min-size 64mb 

注意

AOF重写是开启一个新进程后台写入(异步执行)

RDB与AOF的对比

RDB

AOF

持久化方式

定时对整个内存做快照

记录每一次执行的命令

数据完整性

不完整,两次备份之间会丢失

相对完整,取决于刷盘策略

文件大小

会有压缩,文件体积小

记录命令,文件体积很大

宕机恢复速度

很快

数据恢复优先级

低,因为数据完整性不如AOF

高,因为数据完整性更高

系统资源占用

高,大量CPU和内存消耗

低,主要是磁盘IO资源

但AOF重写时会占用大量CPU和内存资源

使用场景

可以容忍数分钟的数据丢失,追求更快的启动速度

对数据安全性要求较高常见


Redis主从并实现读写分离

集群架构

 

搭建主从架构

本次搭建是在同一台服务上启动三个redis实例来搭建

一台master: 

192.168.150.101:7001

两台slave:

192.168.150.101:7002

192.168.150.101:7003

1 准备实例和配置

1.0 在同一台服务器上启动多个redis实例 且互不干扰

只需要创建多个新的配置文件即可 指定不同的端口号 令exe开启时加载不同的配置文件即可

不需要单独复制多分redis的文件

1.1 创建目录

要在同一台虚拟机开启3个实例,必须准备三份不同的配置文件和目录,配置文件所在目录也就是工作目录

我们创建三个文件夹,名字分别叫7001、7002、7003:

# 进入/tmp目录
cd /tmp
# 创建目录
mkdir 7001 7002 7003

1.2 修改配置

因为之前搭建了单机redis 并且开起了AOF持久化

所以这儿需要将 redis-6.2.4/redis.conf文件,将其中的持久化模式改为默认的RDB模式,AOF保持关闭状态。(若没有开启,即默认持久化就可(redis的默认持久化就是RDB))

# 开启RDB
# save ""
save 3600 1
save 300 100
save 60 10000

# 关闭AOF
appendonly no
1.3 拷贝配置文件到每个实例目录

然后将redis-6.2.4/redis.conf文件拷贝到三个目录中(在/tmp目录执行下列命令):

# 方式一:逐个拷贝
cp redis-6.2.4/redis.conf 7001
cp redis-6.2.4/redis.conf 7002
cp redis-6.2.4/redis.conf 7003
# 方式二:管道组合命令,一键拷贝
echo 7001 7002 7003 | xargs -t -n 1 cp redis-6.2.4/redis.conf
1.4 修改每个实例的端口、工作目录

修改每个文件夹内的配置文件,将端口分别修改为7001、7002、7003,将rdb文件保存位置都修改为自己所在目录(在/tmp目录执行下列命令):

sed -i -e 's/6379/7001/g' -e 's/dir .\//dir \/tmp\/7001\//g' 7001/redis.conf
sed -i -e 's/6379/7002/g' -e 's/dir .\//dir \/tmp\/7002\//g' 7002/redis.conf
sed -i -e 's/6379/7003/g' -e 's/dir .\//dir \/tmp\/7003\//g' 7003/redis.conf
1.5 修改每个实例的声明IP 

虚拟机本身有多个IP,为了避免将来混乱,我们需要在redis.conf文件中指定每一个实例的绑定ip信息(大部分都是本机ip,redis服务在那台服务器上 ip就是那台服务器上的ip),格式如下:

# redis实例的声明 IP
replica-announce-ip 192.168.150.101

每个目录都要改,我们一键完成修改(在/tmp目录执行下列命令):

# 逐一执行
sed -i '1a replica-announce-ip 192.168.150.101' 7001/redis.conf
sed -i '1a replica-announce-ip 192.168.150.101' 7002/redis.conf
sed -i '1a replica-announce-ip 192.168.150.101' 7003/redis.conf

# 或者一键修改
printf '%s\n' 7001 7002 7003 | xargs -I{} -t sed -i '1a replica-announce-ip 192.168.150.101' {}/redis.conf

因为这儿三个实例都是部署在同一台服务器上的 所以 声明的ip都是同一个

2 启动redis

# 第1个
redis-server 7001/redis.conf
# 第2个
redis-server 7002/redis.conf
# 第3个
redis-server 7003/redis.conf
2.2 如果要一键停止

可以运行下面命令:

printf '%s\n' 7001 7002 7003 | xargs -I{} -t redis-cli -p {} shutdown

3 开启主从关系

现在三个实例还没有任何关系,要配置主从可以使用replicaof 或者slaveof(5.0以前)命令。

有临时和永久两种模式:

        3.1 修改配置文件(永久生效)

                在redis.conf中添加一行配置:slaveof <masterip> <masterport>

        3.2 使用redis-cli客户端连接到redis服务,执行slaveof命令(重启后失效):

                slaveof <masterip> <masterport>

注意:在5.0以后新增命令replicaof,与salveof效果一致。

4 这里我们为了演示方便,使用方式二。

通过redis-cli命令连接7002,执行下面命令:

# 连接 7002
redis-cli -p 7002
# 执行slaveof
slaveof 192.168.150.101 7001

通过redis-cli命令连接7003,执行下面命令:

# 连接 7003
redis-cli -p 7003
# 执行slaveof
slaveof 192.168.150.101 7001

然后连接 7001节点,查看集群状态:

# 连接 7001
redis-cli -p 7001
# 查看状态
info replication

结果:

5 测试结果

执行下列操作以测试:

  • 利用redis-cli连接7001,执行set num 123

  • 利用redis-cli连接7002,执行get num,再执行set num 666

  • 利用redis-cli连接7003,执行get num,再执行set num 888

可以发现,只有在7001这个master节点上可以执行写操作,7002和7003这两个slave节点只能执行读操作。

主从数据同步原理

主从第一次同步是全量同步

 master如何判断slave是不是第一次来同步数据

Replication Id:简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid

offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。

因此slave做数据同步,必须向master声明自己的replication id 和offset,master才可以判断到底需要同步哪些数据

全量同步的流程

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

注意:

主从第一次同步是全量同步

slave重启后同步,则可能执行增量同步也可能是全量同步

repl_baklog大小有上限,写满后会覆盖最早的数据。如果slave断开时间过久,导致尚未备份的数据被覆盖,则无法基于log做增量同步,只能再次全量同步。

因为 repl_baklog 是一个闭环 offset 就是这个闭环里的值

 

当此闭环还为走完的时候 通过offset能在此闭环里能找到正确的增量数据,这时就执行增量同步

当此闭环已经走完一圈 并超过当初slave的点时,虽然看到增量数据是slave-master这段的数据 实际是 maseter-slave-master这段的数据,这时就做全量同步

优化Redis主从就集群

1 在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘IO。
2 Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO
3 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
4 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结         构,减少master压力

主-从-从链式结构

总结:

简述全量同步和增量同步区别?
        全量同步:master将完整内存数据生成RDB,发送RDB到slave。后续命令则记录在repl_baklog,逐个发送给slave。
        增量同步:slave提交自己的offset到master,master获取repl_baklog中从offset之后的命令给slave
什么时候执行全量同步?
        slave节点第一次连接master节点时
        slave节点断开时间太久,repl_baklog中的offset已经被覆盖时
什么时候执行增量同步?
        slave节点断开又恢复,并且在repl_baklog中能找到offset时


 

Redis哨兵

哨兵的作用和原理

哨兵结构

哨兵的作用

监控:Sentinel 会不断检查您的master和slave是否按预期工作
自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端

服务状态监控

Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:
        主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下        线。
        客观下线:若超过指定数量(quorum:sentinel.conf里配置)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。(sentinel实例的quorum 个都链接不上某redis 就认为给redis实例客观下线)

 选举新的master

一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:
        首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds * 10)则会排除该slave节点
        然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举
        如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
        最后是判断slave节点的运行id大小,越小优先级越高。

如何实现故障转移

当选中了其中一个slave为新的master后(例如slave1),故障的转移的步骤如下:

        sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master
        sentinel给所有其它slave发送slaveof 192.168.150.101 7002 命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
        最后,sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点

总结

Sentinel的三个作用是什么?
        监控
        故障转移
        通知
Sentinel如何判断一个redis实例是否健康?
        每隔1秒发送一次ping命令,如果超过一定时间没有相向则认为是主观下线
        如果大多数sentinel都认为实例主观下线,则判定服务下线
故障转移步骤有哪些?
        首先选定一个slave作为新的master,执行slaveof no one
        然后让所有节点都执行slaveof 新master
        修改故障节点配置,添加slaveof 新master

搭建哨兵集群

1 哨兵集群结构:

这里我们搭建一个三节点形成的Sentinel集群,来监管之前的Redis主从集群。如图:

 三个sentinel实例信息如下:

s1        192.168.150.101        27001   

s2        192.168.150.101        27002   

s3        192.168.150.101        27003

2 准备sentinel实例和配置

要在同一台虚拟机开启3个实例,必须准备三份不同的配置文件和目录,配置文件所在目录也就是工作目录。

2.1 创建文件夹

我们创建三个文件夹,名字分别叫s1、s2、s3:

# 进入/tmp目录
cd /tmp
# 创建目录
mkdir s1 s2 s3

如图:

2.2 修改sentinel配置

然后我们在s1目录创建一个sentinel.conf文件,添加下面的内容:

port 27001
sentinel announce-ip 192.168.150.101
sentinel monitor mymaster 192.168.150.101 7001 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
dir "/tmp/s1"

解读:

  • port 27001:是当前sentinel实例的端口
  • sentinel announce-ip 192.168.150.101  :声明sentinel实例的ip地址
  • sentinel monitor mymaster 192.168.150.101 7001 2:指定主节点信息
    • sentinel monitor:sentinel 监听
    • mymaster:主节点名称,自定义,任意写
    • 192.168.150.101 7001:主节点(master)的ip和端口 
    • 2:选举master时的quorum值 (当超过2时就认为redis的服务客观下线)
  • down-after-milliseconds mymaster 5000    slave与master断开最长超时时间 默认
  • failover-timeout mymaster 60000     slave故障恢复的时间 默认

只需要指定主节点信息即可 sentinel会自己去redis集群里去获得其它slave的信息

然后将s1/sentinel.conf文件拷贝到s2、s3两个目录中(在/tmp目录执行下列命令):

# 方式一:逐个拷贝
cp s1/sentinel.conf s2
cp s1/sentinel.conf s3
# 方式二:管道组合命令,一键拷贝
echo s2 s3 | xargs -t -n 1 cp s1/sentinel.conf

修改s2、s3两个文件夹内的配置文件,将端口分别修改为27002、27003:

sed -i -e 's/27001/27002/g' -e 's/s1/s2/g' s2/sentinel.conf
sed -i -e 's/27001/27003/g' -e 's/s1/s3/g' s3/sentinel.conf

3 启动redis-sentinel

# 第1个
redis-sentinel s1/sentinel.conf
# 第2个
redis-sentinel s2/sentinel.conf
# 第3个
redis-sentinel s3/sentinel.conf

RedisTemplate的哨兵模式

1 在pom文件中引入redis的starter依赖:

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

2 然后在配置文件application.yml中指定sentinel相关信息:

spring:
  redis:
    sentinel:
      master: mymaster # 指定master名称
      nodes: # 指定redis-sentinel集群信息 
        - 192.168.150.101:27001
        - 192.168.150.101:27002
        - 192.168.150.101:27003

3 配置主从读写分离

 匿名内部类格式

@Bean
public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
    return new LettuceClientConfigurationBuilderCustomizer(){
        @Override
        public void customize(LettuceClientConfiguration.LettuceClientConfigurationBuilder 
 clientConfigurationBuilder){
            clientConfigurationBuilder.readFrom(ReadFrom,REPLICA_PREFERRED):
        }
    };
}

或 

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

这里的ReadFrom是配置Redis的读取策略,是一个枚举,包括下面选择:

MASTER:从主节点读取
MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica
REPLICA:从slave(replica)节点读取
REPLICA _PREFERRED:优先从slave(replica)节点读取,所有的slave都不可用才读取master

4 调用

@RestController
public class HelloController {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @GetMapping("/get/{key}")
    public String hi(@PathVariable String key) {
        return redisTemplate.opsForValue().get(key);
    }

    @GetMapping("/set/{key}/{value}")
    public String hi(@PathVariable String key, @PathVariable String value) {
        redisTemplate.opsForValue().set(key, value);
        return "success";
    }
}

Redis分片集群

分片集群结构

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

        1 海量数据存储问题

        2 高并发写的问题

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

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

最小的分片集群,包含3个master节点,每个master包含一个slave节点,结构如下:

搭建分片集群

这里我们会在同一台虚拟机中开启6个redis实例,模拟分片集群,信息如下:

192.168.150.1017001master
192.168.150.1017002master
192.168.150.1017003master
192.168.150.1018001slave
192.168.150.1018002slave
192.168.150.1018003slave

1 准备实例和配置

如果配置了之前的redis主从模式 哨兵模式  请删除之前的7001 7002 7003 这几个目录,

再重新创建7001、7002、7003、8001、8002、8003目录:

# 进入/tmp目录
cd /tmp
# 删除旧的,避免配置干扰
rm -rf 7001 7002 7003
# 创建目录
mkdir 7001 7002 7003 8001 8002 8003

在/tmp下准备一个新的redis.conf文件,内容如下:

port 6379
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file /tmp/6379/nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir /tmp/6379
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 192.168.150.101
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile /tmp/6379/run.log

将这个文件拷贝到每个目录下:

# 进入/tmp目录
cd /tmp
# 执行拷贝
echo 7001 7002 7003 8001 8002 8003 | xargs -t -n 1 cp redis.conf

修改每个目录下的redis.conf,将其中的6379修改为与所在目录一致:

# 进入/tmp目录
cd /tmp
# 修改配置文件
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t sed -i 's/6379/{}/g' {}/redis.conf

2 启动 6个redis实例

因为已经配置了后台启动模式,所以可以直接启动服务:

# 进入/tmp目录
cd /tmp
# 一键启动所有服务
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-server {}/redis.conf

通过ps查看状态:

ps -ef | grep redis

发现服务都已经正常启动:

2.1如果要关闭所有进程

可以执行命令:

ps -ef | grep redis | awk '{print $2}' | xargs kill

或者(推荐这种方式):

printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-cli -p {} shutdown

3 创建集群

虽然服务启动了,但是目前每个服务之间都是独立的,没有任何关联。

我们需要执行命令来创建集群,在Redis5.0之前创建集群比较麻烦,5.0之后集群管理命令都集成到了redis-cli中。

3.1Redis5.0之前

Redis5.0之前集群命令都是用redis安装包下的src/redis-trib.rb来实现的。因为redis-trib.rb是有ruby语言编写的所以需要安装ruby环境。

# 安装依赖
yum -y install zlib ruby rubygems
gem install redis

然后通过命令来管理集群:

# 进入redis的src目录
cd /tmp/redis-6.2.4/src
# 创建集群
./redis-trib.rb create --replicas 1 192.168.150.101:7001 192.168.150.101:7002 192.168.150.101:7003 192.168.150.101:8001 192.168.150.101:8002 192.168.150.101:8003
3.2 Redis5.0以后

我们使用的是Redis6.2.4版本,集群管理以及集成到了redis-cli中,格式如下:

redis-cli --cluster create --cluster-replicas 1 192.168.150.101:7001 192.168.150.101:7002 192.168.150.101:7003 192.168.150.101:8001 192.168.150.101:8002 192.168.150.101:8003

命令说明:

  • redis-cli --cluster或者./redis-trib.rb:代表集群操作命令
  • create:代表是创建集群
  • --replicas 1或者--cluster-replicas 1 :指定集群中每个master的副本个数为1,此时节点总数 ÷ (replicas + 1) 得到的就是master的数量。因此节点列表中的前n个就是master,其它节点都是slave节点,随机分配到不同master

运行后的样子:

这里输入yes,则集群开始创建:

4 查看集群状态:

redis-cli -p 7001 cluster nodes

5 测试

尝试连接7001节点,存储一个数据:

# 连接
redis-cli -p 7001
# 存储数据
set num 123
# 读取数据
get num
# 再次存储
set a 1

结果悲剧了:

集群操作时,需要给redis-cli加上-c参数才可以:
redis-cli -c -p 7001

这次可以了:

散列插槽

16384个插槽

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

 

 数据key与插槽绑定

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

        key中包含"{}",且“{}”中至少包含1个字符,“{}”中的部分是有效部分

        key中不包含“{}”,整个key都是有效部分

例如:key是num,那么就根据num计算,如果是{itcast}num,则根据itcast计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值。

总结:

Redis如何判断某个key应该在哪个实例?
        将16384个插槽分配到不同的实例
        根据key的有效部分计算哈希值,对16384取余
        余数作为插槽,寻找插槽所在实例即可
如何将同一类数据固定的保存在同一个Redis实例?
        这一类数据使用相同的有效部分,例如key都以{typeId}为前缀

集群伸缩

1 查看redis集群操作命令

redis-cli --cluster提供了很多操作集群的命令,可以通过下面方式查看:

redis-cli --cluster help

2 添加节点 

参数说明:

        new_host:new_port        新的节点ip和端口

        existing_host:existiong_prot        现有redis集群里的ip和端口

可以加的参数:如果不加 添加的节点默认就是master节点

        cluster-slave      指定该节点是从节点          

        clster-master-id        新加的从节点是那个master下的从节点(用节点id指定)

2.1 分盘插槽

 3 例子:向集群中添加一个新的master节点,并向其中分配3000插槽

需求:
启动一个新的redis实例,端口为7004
添加7004到之前的集群,并作为一个master节点
给7004节点分配插槽,使得num这个key可以存储到7004实例

3.1 在tmp目录下创建一个7004目录
mkdir 7004
3.2 将tmp目录下的redis配置文件拷贝到7004目录了
cp redis.conf 7004
3.3 将该配置文件中的6379全部替换7004
send -i s/6379/7004/g 7004/redis.conf    
 3.4 运行
redis-server 7004/redis.conf
3.5 添加新节点
redis-cli --cluster add-node 192.168.150.101:7004 192.168.150.101:7001
3.5.1 查看新集群状态
redis-cli -p 7001 cluster nodes

3.6 给新节点分盘插槽
3.6.1  重新分盘插槽
redis-cli --cluster reshard
3.6.2 指定ip端口(当前链接到集群的ip和端口)
redis-cli --cluster reshard 192.168.150.101:7001

移动多少个插槽?3000个

 谁接收插槽  7004

 从哪儿拷贝  7001

 结束  done->回车

 再次确认 yes->回车

查看结果  7004  的插槽就成了 0-2999

故障转移

当集群中有一个master宕机

1 首先是该实例与其它实例失去连接

2 然后是疑似宕机:

3 最后是确定下线,自动提升一个slave为新的master:

数据迁移

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

手动的Failover支持三种不同模式:(一般选择默认流程即可)

        缺省:默认的流程

        force:省略了对offset的一致性校验

        takeover:直接执行第5歩,忽略数据一致性、忽略master状态和其它master的意见

例子:在7002这个slave节点执行手动故障转移,成为master地位

未迁移之前 7002是slave

链接7002

redis-cli -p 7002

迁移

CLUSTER FAILOVER

迁移之后 slave成了master

RedisTemplate访问分片集群

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

1 引入redis的starter依赖

2 配置分片集群地址

3 配置读写分离

与哨兵模式相比,其中只有分片集群的配置方式略有差异,如下:

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值