微服务高级篇(三):分布式缓存+Redis集群


一、单点Redis的问题及解决方案

数据丢失问题:Redis是内存存储,服务重启可能会丢失数据
并发能力问题:单节点Redis并发能力虽然不错,但也无法满足如618这样的高并发场景
故障恢复问题:如果Redis宕机,则服务不可用,需要一种自动的故障恢复手段
存储能力问题:Redis基于内存,单节点能存储的数据量难以满足海量数据需求

解决方案:
在这里插入图片描述

二、Redis持久化

2.1 单机安装Redis

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

yum install -y gcc tcl

然后将课前资料提供的Redis安装包上传到虚拟机的任意目录:

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

解压缩:

tar -xvf redis-6.2.4.tar.gz

解压后:

进入redis目录:

cd redis-6.2.4

运行编译命令:

make && make install

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

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

# 绑定地址,默认是127.0.0.1,会导致只能在本地访问。修改为0.0.0.0则可以在任意IP访问
bind 0.0.0.0
# 数据库数量,设置为1
databases 1

启动Redis:

redis-server redis.conf

停止redis服务:

redis-cli shutdown

测试服务:

在这里插入图片描述

当停止服务时,redis会将数据保存在该目录下,再次启动服务时会恢复数据。

在这里插入图片描述

Redis默认持久化,但只是在停机时会保存数据,但我们需要的是每隔一段时间就保存一下数据,以下会采用两种持久化方案。

2.2 RDB持久化

在这里插入图片描述

bgsave的流程

在这里插入图片描述

RDB持久化默认会在停机执行一次,也可以在redis.conf文件中设置保存时机,如下:

在这里插入图片描述

案例:在redis.conf中设置每5秒修改一次就保存数据,设置保存的文件名为test.rdb

  1. 修改配置文件
save 5 1
dbfilename  test.rdb
  1. 添加一条数据
    在这里插入图片描述
  2. 结果显示
    在这里插入图片描述

在这里插入图片描述

2.3 AOF持久化

在这里插入图片描述

使用方法:
在这里插入图片描述
使用AOF可以禁用RDB,方法是:修改配置文件

save ""

bgrewriteaof命令:命令压缩
在这里插入图片描述

2.4 RDB和AOF对比

在这里插入图片描述

三、Redis主从

3.1 搭建Redis主从架构

3.1.1 集群结构

我们搭建的主从集群结构如图:

在这里插入图片描述

共包含三个节点,一个主节点,两个从节点。

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

IP PORT 角色
192.168.150.101 7001 master
192.168.150.101 7002 slave
192.168.150.101 7003 slave

3.1.2 准备实例和配置

注意服务器要打开7001 7002 7003 端口

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

1)创建目录

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

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

如图:

2)恢复原始配置

修改redis-6.2.4/redis.conf文件,将其中的持久化模式改为默认的RDB模式,AOF保持关闭状态。

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

# 关闭AOF
appendonly no

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

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

5)修改每个实例的声明IP

虚拟机本身有多个IP,为了避免将来混乱,我们需要在redis.conf文件中指定每一个实例的绑定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

3.1.3 启动

为了方便查看日志,我们打开3个ssh窗口,分别启动3个redis实例,启动命令:

# 第1个
redis-server 7001/redis.conf
# 第2个
redis-server 7002/redis.conf
# 第3个
redis-server 7003/redis.conf

启动后:

在这里插入图片描述

如果要一键停止,可以运行下面命令:

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

3.1.4 开启主从关系

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

有临时和永久两种模式:

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

    • 在redis.conf中添加一行配置:slaveof <masterip> <masterport>
  • 使用redis-cli客户端连接到redis服务,执行slaveof命令(重启后失效):

    slaveof <masterip> <masterport>
    

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

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

通过redis-cli命令连接7002,执行下面命令:【注意修改IP】

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

通过redis-cli命令连接7003,执行下面命令:【注意修改IP】

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

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

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

结果:

在这里插入图片描述
在这里插入图片描述

3.1.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节点只能执行读操作。

3.2 数据同步

3.2.1 全量同步【建立连接时】

在这里插入图片描述

master如何判断slave是不是来做数据同步?首先要了解以下两个概念:

在这里插入图片描述
过程如下:

  1. slave向master发送偏移量
  2. master判断请求的repid是否一致
  3. 不一致表示二者第一次连接,然后master将自己的repid和offset发送给slave

在这里插入图片描述

3.2.2 增量同步【slave从节点重启后】

在这里插入图片描述

3.2.3 数据同步的优化

在这里插入图片描述

3.2.4 总结

在这里插入图片描述

四、Redis哨兵【Sentinel实现哨兵,故障转移】

4.1 哨兵的作用和原理

slave节点宕机恢复后可以找master节点同步数据那master节点宕机怎么办?

在这里插入图片描述

一、服务状态监控

Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:

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

二、选举master

一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:

  1. 首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-miliseconds*10)则会排除该slave节点
  2. 然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举
  3. 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
  4. 最后是判断slave节点的运行id大小,越小优先级越高。

三、如何实现故障转移?

在这里插入图片描述

4.2 搭建哨兵集群

4.2.1 集群结构

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

在这里插入图片描述

三个sentinel实例信息如下:

节点 IP PORT
s1 192.168.150.101 27001
s2 192.168.150.101 27002
s3 192.168.150.101 27003

4.2.2 准备实例和配置

注意服务器要打开7001 7002 7003 27001 27002 27003端口

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

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

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

如图:

然后我们在s1目录创建一个sentinel.conf文件,命令:vi s1/sentinel.conf,添加下面的内容:【注意修改IP】

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 monitor mymaster 192.168.150.101 7001 2:指定主节点信息
    • mymaster:主节点名称,自定义,任意写
    • 192.168.150.101 7001:主节点的ip和端口
    • 2:选举master时的quorum值

然后将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,工作目录修改成s2、s3:

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

4.2.3 启动

为了方便查看日志,我们打开3个ssh窗口,分别启动3个redis实例,启动命令:

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


# 一键停止三个redis-sentinel
printf '%s\n' 27001 27002 27003 | xargs -I{} -t redis-cli -p {} shutdown

# 也可以一个一个的停止redis-sentinel
redis-cli -p 27001 shutdown
redis-cli -p 27002 shutdown
redis-cli -p 27003 shutdown

启动后:

4.2.4 测试

尝试让master节点7001宕机,查看sentinel日志:

查看27001的日志:

在这里插入图片描述

4.3 RedisTemplate的哨兵模式

  1. 在pom文件中引入redis依赖
        <!--redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
  1. 在yml文件中配置指定sentinel【哨兵】相关信息
spring:
  redis:
    sentinel:
      master: mymaster # 指定master名称
      nodes: # 指定redis-sentinel集群【哨兵】名称
        - 39.107.236.163:27001
        - 39.107.236.163:27002
        - 39.107.236.163:27003
  1. 配置主从分离
    在这里插入图片描述

  2. 启动服务测试,插入一条数据
    在这里插入图片描述
    在这里插入图片描述

五、Redis分片集群

在这里插入图片描述

5.1 搭建分片集群

5.1.1 集群结构

分片集群需要的节点数量较多,这里我们搭建一个最小的分片集群,包含3个master节点,每个master包含一个slave节点,结构如下:

在这里插入图片描述

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

IP PORT 角色
192.168.150.101 7001 master
192.168.150.101 7002 master
192.168.150.101 7003 master
192.168.150.101 8001 slave
192.168.150.101 8002 slave
192.168.150.101 8003 slave

5.1.2 准备实例和配置

注意服务器要打开7001 7002 7003 8001 8002 8003 27001 27002 27003 28001 28002 28003 端口

首先关闭之前的主从redis和哨兵

# 关闭哨兵
printf '%s\n' 27001 27002 27003 | xar -t redis-cli -p {} shutdown
# 关闭redis主从节点
printf '%s\n' 7001 7002 7003 | xargs  redis-cli -p {} shutdown

删除之前的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文件vi 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

5.1.3 启动

一定要注意:如果是使用云服务器,一定要打开 17007 17002 17003 18001 18002 18003 端口

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

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

通过ps查看状态:

ps -ef | grep redis

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

在这里插入图片描述

如果要关闭所有进程,可以执行命令:

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

或者(还不行的话):

kill -9 上面截图root后面那一串数字

5.1.4 创建集群

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

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

1)Redis5.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

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,则集群开始创建:

通过命令可以查看集群状态:

redis-cli -p 7001 cluster nodes

在这里插入图片描述

5.1.5 测试

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

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

结果悲剧了:

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

redis-cli -c -p 7001

这次可以了:

5.2 散列插槽

在这里插入图片描述

redis会将数据绑定到插槽,将插槽平均分给上述7001 7002 7003 三个主节点中,下面演示:

在这里插入图片描述

那么我们如何控制同一类数据在一个redis节点中?假设我们想将a与num放在同一个redis下,那么你在设置num时,如下修改即可:

在这里插入图片描述
总结
在这里插入图片描述

5.3 集群伸缩【添加、删除Redis节点】

5.3.1 添加节点

在这里插入图片描述
在这里插入图片描述

操作如下:

# 记得要放开7004和17004端口
# 创建目录7004
mkdir 7004
cp redis.conf 7004
sed -i s/6379/7004/g 7004/redis.conf
# 启动服务
redis-server 7004 redis.conf
# 查看状态
ps -ef | grep redis
# 将7004加入到集群中
redis-cli --cluster add-node 192.168.150.101:7004 192.168.150.101:7001
# 查看集群状态
redis-cli -p 7001 cluster nodes

可见7004加入到集群中且为一个master主节点,但是还没有插槽
在这里插入图片描述

这里将7001的0-3000号插槽分配给7004:

# 将7001的插槽重新分片
redis-cli --cluster reshard 192.168.150.101:7001

在这里插入图片描述

查看状态,可以看到0-3000已经分配给7004了

在这里插入图片描述

5.3.2 删除节点

# 1.将0-3000号插槽还给7001步骤类似于上面,这里不演示了

# 2.查看帮助文档
redis-cli --cluster help
# 3.获取7004的ID
redis-cli -p 7001 cluster nodes
# 4.删除节点 
redis-cli --cluster del-node 要删除节点的IP端口 要删除节点的ID

5.4 故障转移

分片集群虽然没有哨兵,但是也可以实现故障转移

5.4.1 自动故障转移

# 动态查看7001状态
watch redis-cli -p 7001 cluster nodes
# 使7002宕机
redis-server 7002/redis.conf

下图可以看到7002宕机后,自动使8001成为master主节点:

在这里插入图片描述

5.4.2 手动故障转移

在这里插入图片描述
案例:操作7002使其回复称master主节点

[root@iZ2ze1r1nnqykr8zfme6cjZ tmp]# redis-cli -p 7002
127.0.0.1:7002> cluster failover 
OK

在这里插入图片描述

5.5 RedisTemplate访问分片集群

在这里插入图片描述

当访问http://localhost:8080/get/num时,查看日志信息,访问的是8002从节点隶属于7001主节点,从节点执行读操作

当访问http://localhost:8080/set/num/123时,查看日志信息,访问的是7001主节点,从而实现读写分离主节点执行写操作

当访问http://localhost:8080/set/a/123时,查看日志信息,访问的是7003主节点,表明不同数据有不同的插槽

相关推荐

  1. 服务-高级

    2024-03-23 13:06:03       24 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-23 13:06:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-23 13:06:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-23 13:06:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-23 13:06:03       18 阅读

热门阅读

  1. 怎样保持SSH长时连接不断开(客户机)

    2024-03-23 13:06:03       19 阅读
  2. 服务器硬防和软防是什么?

    2024-03-23 13:06:03       18 阅读
  3. Linux 文件系统:动静态库

    2024-03-23 13:06:03       21 阅读
  4. Keepalived 踩坑

    2024-03-23 13:06:03       24 阅读
  5. ArrayList的常用方法

    2024-03-23 13:06:03       16 阅读
  6. 第三十章 配置 Web Gateway 的默认参数 - ASP 重定向

    2024-03-23 13:06:03       16 阅读
  7. 什么是React

    2024-03-23 13:06:03       22 阅读
  8. Hive正则表达式使用

    2024-03-23 13:06:03       21 阅读
  9. 大厂面试--介绍下webpack的整个生命周期?

    2024-03-23 13:06:03       16 阅读