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 条件时:配置文件配置,如下
1
2
3
4
# 900秒内,如果至少有1个key被修改,则执行bgsave , 如果是save "" 则表示禁用RDB
save 900 1  
save 300 10  
save 60 10000 

其他配置

1
2
3
4
5
6
7
8
# 是否压缩 ,建议不开启,压缩也会消耗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 默认是关闭的,修改配置文件开启

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

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

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

配置项对比:

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

文件重写

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

假设原先命令为:

1
2
3
set num 123
set name jack
set num 666

重写后:

1
mset name jack num 666

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

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

RDB 与 AOF 对比

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

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

Redis 主从架构

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

image

按照集群

基于 CentOS7

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

首先创建目录

1
2
cd /tmp
mkdir 7001 7002 7003

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

1
2
3
4
5
6
7
8
# 开启RDB
# save ""
save 3600 1
save 300 100
save 60 10000

# 关闭AOF
appendonly no

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

1
2
3
4
5
6
7
# 方式一
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 文件保存位置修改)

1
2
3
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)

1
2
3
4
5
6
7
# 逐一执行
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
2
3
4
5
6
# 第1个
redis-server 7001/redis.conf
# 第2个
redis-server 7002/redis.conf
# 第3个
redis-server 7003/redis.conf

停止

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