Redis 分布式缓存

Redis 基础: https://blog.yexca.net/archives/157/
Redis 分布式缓存: 本文

引言

所以这俩文章同时写的但却过了一年才发是吧

其实是我当时有三个要写的来着,但每次想起来看的时候都忘了要写啥,就过了快一年。。。

问题

单机 Redis 存在

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

Redis 持久化

Redis 持久化有两种方案:RDB 与 AOF

RDB 持久化

RDB 全称 Redis Database Backup file (Redis 数据备份文件),也叫做 Redis 数据快照。简单来说就是把内存中所有数据都记录到磁盘中。当 Redis 实例故障重启后,从磁盘读取快照文件,恢复数据。快照文件成为 RDB 文件,默认保存在运行目录

RDB 会在以下四种情况下执行:

  • 执行 save 命令:立即执行,会导致主进程执行 RDB,其他所有命令被阻塞。仅在数据迁移时可能用到
  • 执行 bgsave 命令:异步执行,开启独立进程完成 RDB,主进程可以持续处理用户请求,不受影响
  • Redis 停机时:停机时会执行一次 save 命令
  • 触发 RDB 条件时:配置文件配置,如下
# 900秒内,如果至少有1个key被修改,则执行bgsave , 如果是save "" 则表示禁用RDB
save 900 1  
save 300 10  
save 60 10000 

其他配置

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

# RDB文件名称
dbfilename dump.rdb  

# 文件保存的路径目录
dir ./ 

RDB 原理

bgsave 开始时会 fork 主进程得到子进程,子进程共享主进程的内存数据。完成 fork 后读取内存数据并写入 RDB 文件

fork采用的是 copy-on-write 技术:

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

image

RDB 的缺点:

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

AOF 持久化

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

AOF 默认是关闭的,修改配置文件开启

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

记录频率也可以通过 redis.conf 配置

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

配置项对比:

配置项 刷盘时机 优点 缺点
always 同步刷盘 可靠性高,几乎不丢数据 性能影响大
everysec 每秒刷盘 性能适中 最多丢失 1 秒数据
no 操作系统控制 性能最好 可靠性差,可能丢失大量数据

文件重写

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

假设原先命令为:

set num 123
set name jack
set num 666

重写后:

mset name jack num 666

Redis 也会在触发阈值时自动重写 AOF 文件,在配置文件配置

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

RDB 与 AOF 对比

RDB 与 AOF 各有自己的优缺点,如果对数据安全性要求过高,在实际开发中往往会结合两者来使用

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

Redis 主从架构

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

image

按照集群

基于 CentOS7

参考上图一共三个节点,部署在同一个机子,端口为 7001(master)、7002、7003

首先创建目录

cd /tmp
mkdir 7001 7002 7003

如更改配置,需恢复默认的 RDB 模式

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

# 关闭AOF
appendonly no

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

# 方式一
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

修改每个实例的端口,工作目录(端口修改,rdb 文件保存位置修改)

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,每个目录都要改 (替换 ip_address)

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

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

启动

# 第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