「黑马 Redis」一、分布式缓存

2025 年 4 月 30 日 星期三(已编辑)
2

「黑马 Redis」一、分布式缓存

引入

单点 Redis 问题:

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

Redis 数据持久化 - 数据丢失问题

RDB 持久化

RDB:Redis Database Backup file,也称 Redis 数据快照,将内存中所有数据记录到磁盘,一旦 Redis 故障重启,就从磁盘中读取快照文件,恢复数据

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

可以利用命令手动执行命令备份,但如果是手动停机的话也会进行备份

命令 save 由主线程执行,会阻塞所有命令

命令 bgsave 后台异步备份,由子进程执行,不会影响主进程

同样 Redis 内部也有触发 RDB 的机制,在 redis.conf,save x y 意为 x 秒内,如果至少有 y 个 key 被修改,则执行 bgsave

image.png|500

image.png|500

对于 RDB 的自动备份,当 bgsave 开始时会 fork 主进程得到子进程,子进程利用页表共享主进程的内存数据(也就是 Redis 数据),完成 fork 后读取内存数据写入 RDB 文件

image.png|500

image.png|500

bgsave 的 fork 时是阻塞的,并且是利用复制过来的页表读取内存数据,如果在读取时,主进程又写入数据则会采用 copy-on-write 技术 > TODO:只复制要写的数据?怎么映射

AOF 持久化

为了弥补 RDB 的缺陷:

  1. RDB 执行间隔过长,则有可能两次 RDB 之间写入的数据有丢失风险
  2. fork 子进程、rdbcompress 压缩、写出 RDB 文件耗时、耗 cpu

AOF:Append Only File,追加文件,将每一个写命令记录在 AOF 文件中,约等于命令日志文件

格式:${下一行字符个数}\n{命令字符串}

示例 set num 12

$3
set
$3
num
$2
12

AOF 配置

注:如果启用 appendfsync 可能会因为宕机导致缓存区内的数据丢失

image.png|500

image.png|500

AOF 记录的是命令,往往会有很多无用命令,另外假如对一个 key 进行多次操作,只有最后一次有效,可见 AOF 文件一定会比 RDB 文件大很多,为了优化这一点,可以采用命令 bgwriteaof,对 AOF 文件执行重写,削减无效命令,并且还会压缩命令,更加优化空间占用

image.png|500

image.png|500

AOF 与 RDB 对比

RDB 可以作为机房备份,AOF 因为数据更完整,所以优先 AOF 恢复

image.png|500

image.png|500

Redis 主从集群 - 并发能力问题

搭建主从架构

读多写少,所以读写分离,主节点负责写并同步给从节点,从节点负责读

image.png|500

image.png|500

开启默认的 RDB 配置,关闭 AOF,如果是一台机器部署集群,修改 port,然后各自启动

replica 的叫法从 redis5.0 后启用,之前只有 slave

开启主从关系:

  • 永久:修改配置文件,添加 slaveof/replicaof <masterip> <masterport>
  • 临时:在 redis-cli 中使用命令 slaveof/replicaof <masterip> <masterport>,重启后失效

这时主从关系就已经建立,可以用 INFO REPLICATION 查看相关主从信息,主可以写、读,但是从只能读

数据同步原理

全量同步

主从第一次同步(建立连接)是全量同步

image.png|500

image.png|500

如何判断是否第一次:

  • Replication Id;简称 replid,是数据集的标记,id 一致则说明是一个数据集,每个 master 都有一个唯一的 replid,slave 会继承 master 的 replid
  • offset:偏移量,随着记录在 repl_baklog 数据增加而增大,slave 完成同步会记录当前同步的 offset,并与 master 的 offset 对比,判断数据是否落后

所以 slave 在数据同步时,需要向 master 声明自己的 replication id 以及 offset,让 master 知道要同步那些数据

增量同步

第一次是全量同步,但如果 slave 重启则进行增量同步

image.png|500

image.png|500

repl_baklog 类似于环形覆盖记录,offset 对应了位置,红色部分即为未同步部分

当红色部分满溢到覆盖红色部分,意味着增量同步失效,只能再次全量同步

优化同步

加快全量同步、避免全量同步、减少主节点压力

image.png|500

image.png|500

全量同步:master 将完整内存数据生成 RDB,发送 RDB 到 slave 后续命令则记录在 repl_baklog,逐个发送给 slave 增量同步:slave 提交自己的 replid、offset 到 master,master 返回 repl_baklog 中 offset 之后的命令

执行全量同步:slave 节点第一次连接 master 节点时;slave 节点断开时间太久,repl_baklog 中的 offset 已经被覆盖时 执行增量同步:slave 节点断开又恢复,并且在 repl_baklog 中能找到相应的 offset 时

Redis 哨兵 - 故障恢复问题

sentinel 哨兵介绍

引入:slave 宕机可以找 master 同步恢复数据,那如果 master 宕机?

sentinel 哨兵机制可以实现主从集群的故障恢复

  • 监控:不断检查 master、slave
  • 自动故障恢复:如果 master 故障,则会选择一个 slave 提升为 master,当故障实例恢复后也以新的 master 为主
  • 通知:sentinel 充当 Redis 客户端的服务发现来源,当集群故障转移时会将新消息推送到 Redis 客户端

Sentinel 利用心跳机制监测服务状态,每隔 1s 向每隔实例发送 ping

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

选举新的 master 节点,当 master 故障时

  • 判断 slave 节点与原 master 节点断开时间,超过指定值 down-after-milliseconds *10 则排除该节点
  • 判断 slave 节点的 slave-priority 值,越小越优先,如果是 0 则不参与选举
  • 判断 slave-priority 相同 offset 值,越大说明同步越多,优先级越高
  • 最后判断 slave 节点的运行 id 大小,越小的优先级越高,运行 id 实际无意义

实现故障转移 让被选的 slave 节点 slaveof no one 成为新 master节点 让其余 slave 节点 salveof ip port 认主新 master 节点,并同步数据

image.png|500

image.png|500

搭建 sentinel 哨兵集群

根据 sentinel.conf 启动 redis-sentinel,均监控 master 节点,因为 master 节点 info replication 可以得知 slave 节点信息

image.png|500

image.png|500

RedisTemplate 哨兵模式

pom 配置

指定 master 名称要与哨兵配置中的 master 名称一致,这个名称用来标识整个主从组,哨兵监测的就是这个名称标识的主从组

image.png|500

image.png|500

sentinel 通知的作用,充当了 Redis 客户端的服务发现来源,所以不用配置 Redis 节点,而是让 sentinel 维护

配置读取策略

image.png|500

image.png|500

Redis 分片集群 - 存储能力问题

搭建 Redis 分片集群

引入:单节点内存设大了,RDB 会大,设小了,存储数据又不够

分片集群解决海量数据存储问题、高并发写问题

image.png|500

image.png|500

每个 master 相互心跳检测并可以充当路由进行转发,不需要哨兵

redis.conf

image.png|500

image.png|500

建立连接,创建集群

image.png|500

image.png|500

查询分片集群情况 redis-cli -p port cluster nodes

散列插槽

Redis 会把每一个 master 节点映射到 0~16383 共 16384 个插槽 hash slot 上

数据与插槽绑定,根据有效部分,{} 内的部分,无则整体,进行 CRC16 hash 后模 16384

image.png|500

image.png|500

在 redis 连接时,要进入集群使用 redis-cli -c -p port-c 代表集群模式

根据散列值根据 key 的有效部分,也就是 {} 有则 {} 内部分,无则整个 key,可以利用 {} 将一类数据定向到同一个节点

集群伸缩

获取集群模式帮助 redis-cli --cluster help

添加节点 add-node new_host:new_port existing_host:existing_port [--cluster-slave(加了就是 slave,不加默认为 master)] [--cluster-master-id id]

分配插槽 redis-cli -c reshard ip:port 后会询问要移动 1 - 多少插槽,以及接受的 nodeId,以及拷贝的数据源的 nodeId,用 done 结束

删除节点需要先清空插槽然后再删除

故障转移

当集群中有一个 master 节点宕机,他的 slave 会接管成为 master

强制停机 redis-cli -p port shutdown

image.png|500

image.png|500

上面是自动的故障转移,某台 master 宕机会被其他 master 心跳检测到,然后其 slave 接管成为 master

当需要一台性能更好的 Redis 实例时,可以让新实例加入集群,成为弱的 master 的 slave,随后故障接管

在 slave 节点上 CLUSTER FAILOVER 接管 master

image.png|500

image.png|500

RedisTemplate 访问分片集群

application.propertities 配置

image.png|500

image.png|500

正常的使用,不过会自动进行读写分离以及写路由

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...