零、本文纲要
一、单机Redis的问题
二、Redis持久化
(一)RDB持久化
(二)AOF持久化
(三)RDB与AOF对比
三、Redis主从
tips:Ctrl + F快速定位所需内容进行阅读吧。
一、单机Redis的问题
1、数据丢失问题
实现Redis数据持久化;
2、并发能力问题
搭建主从集群,实现读写分离;
3、故障恢复问题
利用哨兵机制,实现健康检测和自动恢复;
4、存储能力问题
搭建分片集群,利用插槽机制实现动态扩容。
二、Redis持久化
(一)RDB持久化
1、RDB持久化
RDB全称Redis Database Backup file(Redis数据备份文件)
,也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。快照文件称为RDB文件,默认是保存在当前运行目录
。
2、持久化执行时机
- ① 执行
save命令
;
由Redis主进程来执行RDB,会阻塞所有命令;
127.0.0.1:6379> save
OK
- ② 执行
bgsave命令
;
开启子进程执行RDB,主进程可以继续处理用户请求,不受影响;
127.0.0.1:6379> bgsave
Background saving started
- ③ Redis
停机
时;
Redis停机时会执行一次save命令,实现RDB持久化,如下日志中的Saving the final RDB snapshot before exiting.
;
[47784] 30 Mar 21:55:57.615 # User requested shutdown... # 用户请求关闭服务
[47784] 30 Mar 21:55:57.615 * Saving the final RDB snapshot before exiting. # 在退出前保存RDB快照
[47784] 30 Mar 21:55:57.617 * DB saved on disk # DB快照成功保存至磁盘
[47784] 30 Mar 21:55:57.617 # Redis is now ready to exit, bye bye... # Redis准备退出,拜拜...
- ④ 触发
RDB条件
时。
Redis内部有触发RDB的机制(执行的是bgsave命令
),可以在redis.conf文件中找到,格式如下:
# save "" # remove all the previously configured save points # 开启此配置会使RDB持久化失效,默认关闭
save 900 1 # after 900 sec (15 min) if at least 1 key changed # 900秒内至少1个写操作,则触发RDB持久化
save 300 10 # after 300 sec (5 min) if at least 10 keys changed # 300秒内至少10个写操作,则触发RDB持久化
save 60 10000 # after 60 sec if at least 10000 keys changed # 60秒内至少10000个写操作,则触发RDB持久化
3、bgsave原理
bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入 RDB 文件。
fork采用的是copy-on-write技术
:
- 当主进程执行读操作时,访问共享内存;
- 当主进程执行写操作时,则会拷贝一份数据,执行写操作。
- ① bgsave过程
Ⅰ fork
主进程得到一个子进程
,共享内存
空间;
Ⅱ 子进程读取内存数据并写入新的RDB文件
;
Ⅲ 用新
RDB文件替换旧
的RDB文件。
- ② bgsave缺点
Ⅰ 如果未触发条件宕机,两次bgsave间的数据有丢失风险;
Ⅱ fork子进程、压缩、写出RDB文件都比较耗时;
Ⅲ 写新的RDB文件时,主进程是copy数据副本操作的,如果大量的写操作则需要更多的内存空间。
注意:copy-on-write在理论极端情况下可能需要双倍的内存,所以实际生产环境请给Redis预留一些额外内存。
(二)AOF持久化
1、AOF持久化
AOF全称为Append Only File(追加文件)
。Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件
。
2、AOF配置
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
3、AOF文件重写
AOF文件因为是记录命令,所以会比RDB文件大的多。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义。通过执行bgrewriteaof命令
,可以让AOF文件执行重写
功能,用最少的命令达到相同效果。
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k1 v2
OK
127.0.0.1:6379> set k2 v3
OK
127.0.0.1:6379> set k2 v4
OK
127.0.0.1:6379> bgrewriteaof
Background append only file rewriting started
上述案例四条指令其实可以简化成mset k1 v2 k2 v4
,使用bgrewriteaof
指令可以帮助我们完成命令重写。
Redis也会在触发阈值时自动去重写AOF文件。阈值也可以在redis.conf中配置:
# AOF文件比上次文件 增长超过多少百分比则触发重写
auto-aof-rewrite-percentage 100
# AOF文件体积最小多大以上才触发重写
auto-aof-rewrite-min-size 64mb
(三)RDB与AOF对比
RDB和AOF各有自己的优缺点,如果对数据安全性要求较高,在实际开发中往往会结合两者来使用。
三、Redis主从
(一)单机搭建主从
1、准备实例和配置
- ① 创建各实例目录
# 进入/tmp目录
cd /tmp
# 创建目录
mkdir 7001 7002 7003
- ② 拷贝配置文件到每个实例目录
Ⅰ xargs:命令格式somecommand |xargs -item command
;
Ⅱ -n num:后面加次数,表示命令在执行的时候一次用的argument的个数,默认是用所有的,此处我们指定-n 1
;
Ⅲ -t 表示先打印命令,然后再执行;
Ⅳ echo:用于字符串的输出,echo 7001 7002 7003
输出字符串到|
后面的命令。
# 方式一:逐个拷贝
cp /usr/local/src/redis-6.2.6/redis.conf 7001
cp /usr/local/src/redis-6.2.6/redis.conf 7002
cp /usr/local/src/redis-6.2.6/redis.conf 7003
# 方式二:管道组合命令,一键拷贝
echo 7001 7002 7003 | xargs -t -n 1 cp /usr/local/src/redis-6.2.6/redis.conf
- ③ 修改每个实例的端口、工作目录
Ⅰ sed:利用脚本来处理文本文件,语法sed [-hnV][-e<script>][-f<script文件>][文本文件]
;
Ⅱ 数据的搜寻并替换:sed 's/要被取代的字串/新的字串/g'
,寻找dir .\/
替换成dir \/tmp\/7001\/
,其中\/
是起到转义\
的作用,等价于将dir ./
替换成dir /tmp/7001/
;
Ⅲ -e:表示多点编辑;
Ⅳ -i:该选项可以直接修改文件内容,省去vi/vim操作;
修改每个文件夹内的配置文件,将端口分别修改为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
虚拟机本身有多个IP,为了避免将来混乱,我们需要在redis.conf文件中指定每一个实例的绑定ip信息,格式如下:
# redis实例的声明 IP
replica-announce-ip 192.168.150.101
# 方式一:添加
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
2、启动各实例
- ① 批量启动
Ⅰ printf:语法printf format-string [arguments...]
;
Ⅱ %s:输出一个字符串;
Ⅲ \n:换行;
Ⅳ {}:指定一个替换字符串,一般是一行一行赋值给 {};
# 第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-server {}/redis.conf
- ② 批量停止
停止各实例的指令:
redis-cli -p 7001 shutdown
redis-cli -p 7002 shutdown
redis-cli -p 7003 shutdown
printf '%s\n' 7001 7002 7003 | xargs -I{} -t redis-cli -p {} shutdown
3、开启主从关系
要配置主从可以使用replicaof 或者slaveof(5.0以前)命令。
- ① 主从关系配置
Ⅰ 修改配置文件(永久生效)
在redis.conf中添加一行配置:slaveof <masterip> <masterport>
;
Ⅱ 使用redis-cli客户端连接到redis服务,执行slaveof命令(重启后失效):
slaveof <masterip> <masterport>
注意:在5.0以后新增命令replicaof,与salveof效果一致。
- ② 开启主从关系
# 连接 7002
redis-cli -p 7002
# 执行slaveof
slaveof 192.168.253.128 7001
# 连接 7003
redis-cli -p 7003
# 执行replicaof
replicaof 192.168.253.128 7001
# 连接 7001
redis-cli -p 7001
# 查看状态
info replication
- ③ 测试主从
Ⅰ 主:可读可写;
Ⅱ 从:可读。
(二)数据同步原理
1、全量同步
- ① 全量同步过程
主从第一次连接时会发生全量同步:
- ② 全量同步原理
Replication Id
:简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid;
offset
:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。
2、增量同步
- ① 增量同步过程
从节点再次连接主节点,则可能发生增量同步,也可能是全量同步:
repl_baklog大小有上限,写满后会覆盖最早的数据。如果slave断开时间过久,导致尚未备份的数据被覆盖,则无法基于log做增量同步,只能再次全量同步。
3、优化主从集群
- ① 在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘IO;
- ② Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO;
- ③ 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步;
- ④ 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力。
四、结尾
以上即为Redis分布式缓存(一)的内容,感谢阅读。