Redis 高级篇(分布式缓存)

发布于:2024-08-15 ⋅ 阅读:(132) ⋅ 点赞:(0)

一、Redis分布式缓存

单点Redis问题:

  • 数据丢失(实现Redis数据持久化)
  • 并发能力(搭建主从集群,实现读写分离)
  • 存储能力(搭建分片集群,利用插槽机制实现动态扩容)
  • 故障恢复能力(利用Redis哨兵,实现健康监测和自动恢复)

1.1 Redis持久化(解决数据丢失)

RDB

概述

RDB(Redis数据备份文件),也称Redis数据快照。简单的说就是将内存中的所有数据都记录到磁盘中,当Redis实例故障重启后,从磁盘中读取快照文件,恢复数据。

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

Redis主进程执行RDB,会阻塞所有命令:

save

开启子进程执行RDB,避免主进程受到影响

bgsave

Redis停机时会执行一次RDB

redis.conf 配置

Redis内部有触发RDB的机制,可以在redis.conf文件中的配置找到

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

save 900 1

RDB的其他在redis.conf文件中的配置

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

#RDB文件名
dbfilename dump.db

#文件保存的路径目录
dir ./
RDB方式的bgsave的基本流程
  • fork子进程:Redis主进程(父进程)会fork一个子进程。在Linux操作系统中,fork操作会复制父进程的内存页表给子进程,而不是复制整个内存,这使得fork操作非常快速。共享内存空间

  • 子进程执行快照:子进程开始执行快照操作,它将读取内存数据并写入新的RDB文件中。这个过程中,父进程可以继续处理客户端的请求。
  • 写入数据:子进程会遍历所有数据库中的键,并且将每个键及其值序列化后写入到RDB文件中。
  • 完成同步:一旦快照写入完成,子进程会用新RDB文件替换旧的RDB文件(如果存在)

RDB会在什么时候执行?save 60 1000 代表什么含义?
  • 默认是服务停止时
  • 代表60秒内至少执行1000次修改则触发RDB

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

AOF

概述

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

redis.conf配置

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

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

#AOF文件的名
appendfilename "appendonly.aof"

AOF的命令记录的频率也可以通过在redis.conf文件中配置

# 表示每执行一次写命令,立即记录到AOF文件
appendfsync always

#写命令执行完先放入AOF缓存区,然后表示每周1秒将缓存区数据写到AOF文件,是默认方案
appendfsync everysec

#写命令执行先放入AOF缓冲区,有操作系统决定何时将缓冲区内容写回磁盘
appendfsync no
配置项 刷盘时机 优点 缺点
Always 同步刷盘 可靠性高,几乎不丢失数据 性能影响大
everysec 每秒刷盘 性能适中 最多丢失1秒数据
no 操作系统控制 性能最好 可靠性较差,可能丢失大量数据

BGREWRITEAOF

比较RDB和AOF的区别

RDB AOF
持久化方式 定时对整个内存做快照 记录每一次执行的命令
数据完整性 不完整,两次备份之间会丢失 相对完整,即决于刷盘策略
文件的大小 会有压缩,文件体积小 记录命令,文件体积很大
宕机恢复速度 很快
数据恢复优先级 低,因为数据完整性不如AOF 高,因为数据完整性更高
数据的优先级 高,大量CPU和内存消耗 低,主要是磁盘IO资源,但是AOF重写时会占用大量CPU和内存资源
使用场景 可以容忍数分钟的数据丢失,追求更快的启动速度 对数据安全性要求较高单常见

1.2 Redis主从(解决并发问题)

搭建主从架构

首先创建3个实例的目录(用于存放不同redis)

mkdir 7001 7002 7003

 拷贝配置文件到每个实例目录(在/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

修改每个文件夹内的配置文件,将端口分别修改为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

虚拟机本身有多个IP,为了避免将来混乱,我们需要在redis.conf文件中指定每一个实例的绑定ip信息。每个目录都要改,我们一键完成修改(在/tmp目录执行下列命令)

注意:这里单点IP地址要根据自己的进行修改

# 逐一执行
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个ssh窗口,分别启动3个redis实例,启动命令:

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

开启主从关系

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

5.0版本以后新增replicaof,其效果跟slaveof命令一致

有临时和永久两种模式:

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

设置7002和7003是从节点,7001s

通过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

数据同步原理 

 

1.3 Redis哨兵(故障恢复)

哨兵的作用和工作原理

 

 

 

 

 搭建哨兵集群

在tmp目录中创建三个目录分别用于存储哨兵

mkdir s1 s2 s3

在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 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:

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个ssh窗口,分别启动3个redis实例,启动命令:

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

RedisTemplate哨兵模式

创建项目redis-demo

引入依赖

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

配置redis:

logging:
  level:
    io.lettuce.core: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
spring:
  redis:
    sentinel:
      master: mymaster
      nodes:
        - 192.168.92.138:27001
        - 192.168.92.138:27002
        - 192.168.92.138:27003

配置主从读写分离:

@SpringBootApplication
public class RedisDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(RedisDemoApplication.class, args);
    }

    //配置主从读写分离
    @Bean
    public LettuceClientConfigurationBuilderCustomizer configurationBuilderCustomizer(){
        return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.MASTER_PREFERRED);
    }

}

ReadForm是配置Redis的读取策略,是枚举,有以下选择:

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

遇到问题

如果遇到了没有连接成功,记得关闭防火墙

sudo systemctl stop firewalld

1.4 Redis分片集群

Redis分片集群结构

搭建Redis分片集群结构 

要想使7001、7002、7003均为master,他们的slave节点分片对应8001、8002、8003节点

首先,删除之前的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文件,内容如下:

注意:修改为对应的Redis端口号,默认为6379,记得修改注册的示例ip地址

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.92.138
# 保护模式
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

启动 

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

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

通过ps查看状态:

ps -ef | grep redis

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

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

创建集群(先确保所有redis都启动服务)

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

我们需要执行命令来创建集群,在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.92.138:7001 192.168.92.138:7002 192.168.92.138:7003 192.168.92.138:8001 192.168.92.138:8002 192.168.92.138:8003

2)Redis5.0以后

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

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

命令说明:

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

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

redis-cli -p 7001 cluster nodes

测试

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

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

报错(error) MOVED 15495 192.168.92.138:7003

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

redis-cli -c -p 7001

Redis散列插槽 

Redis集群伸缩

Redis故障迁移


网站公告

今日签到

点亮在社区的每一天
去签到