Redis入门高级入门篇

单点Redis的问题

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

持久化

1.RDB(Redis快照)

RDB把内存中的所有数据都记录到磁盘中

执行时机

RDB持久化在四种情况下会执行:

  • 执行save命令
  • 执行bgsave命令
  • Redis停机时
  • 触发RDB条件时

1)save命令

save命令会导致主进程执行RDB,这个过程中其它所有命令都会被阻塞。只有在数据迁移时可能用到。

2)bgsave命令

这个命令执行后会开启独立进程完成RDB,主进程可以持续处理用户请求,不受影响。

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

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

  • 当主进程执行读操作时,访问共享内存

  • 当主进程执行写操作时,则会拷贝一份数据再执行写操作

    image-20230916203610778

3)停机时

Redis停机时会自动执行一次save命令,实现RDB持久化。

4)触发RDB条件

Redis内部有触发RDB的机制,可以在redis.conf文件中找到,格式如下:

1
2
3
4
# 900秒内,如果至少有1个key被修改,则执行bgsave , 如果是save "" 则表示禁用RDB
save 900 1
save 300 10
save 60 10000

RDB的其它配置也可以在redis.conf文件中设置:

1
2
3
4
5
6
7
8
# 是否压缩 ,建议不开启,压缩也会消耗cpu,磁盘的话不值钱
rdbcompression yes

# RDB文件名称
dbfilename dump.rdb

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

RDB缺点

  • 执行间隔长,两次RDB之间数据写入有丢失风险
  • fork子进程,压缩,写出RDB文件都需要消耗资源

2.AOF(追加文件)

Redis处理的每一个写命令都会记录在AOF文件,所以看做是某种命令日志文件

AOF配置

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

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

AOF的命令记录的频率也可以通过redis.conf文件来配:

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

三种策略的对比:

image-20230916204345695

AOF文件重写

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

image-20230916204916235

如图,AOF原本有三个命令,但是set num 123 和 set num 666都是对num的操作,第二次会覆盖第一次的值,因此第一个命令记录下来没有意义。

所以重写命令后,AOF文件内容就是:mset name jack num 666

Redis也会在触发阈值时自动去重写AOF文件。阈值也可以在redis.conf中配置:

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

RDB与AOF对比

在实际应用中要结合优缺点混合使用

image-20230916205029924

Redis主从

单节点redis的并发能力是有上限的,需要通过搭建主从集群实现读写分离

主从间数据同步原理

  • 主从第一次同步是全量同步

image-20230916212735891

master是如何判断是否是第一次同步呢?

Replication Id:其是数据集的id,每个master都有唯一的repliid,slave则会集成master结点的replid

offset:偏移量,随着repl_backlog中数据增多而增大

所以slave的数据同步必须要向master生命自己的reliid和offset以供master判断需要同步哪些数据

  • slave重启后同步,执行增量同步

image-20230916214538754

注意:repl_baklog大小有上限,写满后会覆盖最早的数据,如果slave断开时间过久,导致尚未被备份的数据被覆盖,则无法基于log做增量同步,只能再次进行全量同步

Redis主从集群的优化

  • 在master中配置repl-diskless-sync yse启动无磁盘复制,避免全量同步时的磁盘io
  • Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO
  • 适当提高repl_baklog的大小,发现从节点宕机时尽快实现故障恢复,尽量避免进行全量恢复
  • 限制一个master上的slave数量,如果slave确实多,可以采用主-从-从链式(从节点A是相对于其从节点B的master结点)结构,减轻master压力

Redis哨兵

哨兵(sentinel)的作用

  • 监控:Sentinel会不断检查master和slave是否按照预期工作
  • 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master,当故障实例恢复后也是以新的master为主
  • 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新的消息推送给Redis的客户端

image-20230917122803281

服务状态监控

Sentinel基于心跳机制检测服务状态,每隔1s向集群的每个实例发送ping指令

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

如何选举新的master

选举依据

  • 首先判断slave与master结点断开时间的长短,如果超过指定值,就会排除该slave结点
  • 然后判断slave结点的slave-priority值,越小优先局越高,若为0则用不参加选举
  • 若slave-priority值一样,则判断slave结点的offset值,越大说明数据越新,优先级越高

如何实现故障转移

  • 选定一个slave作为新的master,执行slaveof no one
  • 让所有节点执行slaveof 新master
  • 修改故障节点配置,添加slaveof 新master

image-20230917123410283

Redis分片集群

分片集群结构

主从和哨兵可以解决高可用,高并发读的问题,但是依然没有解决海量数据存储和高并发写的问题

使用分片集群可以解决上述问题,其特征如下

  • 集群中有多个master,每个master保存不同数据
  • 每个master都可以拥有多个slave结点
  • master之间通过ping检测彼此健康状态