Redis基础总结、持久化、主从复制、哨兵模式、内存淘汰策略、缓存
创始人
2024-11-16 00:07:31
0

文章目录

    • Redis 基础
      • Redis 是什么,有哪些特点
      • 为什么要使用 Redis 而不仅仅依赖 MySQL
      • Redis 是单线程吗
      • Redis 单线程为什么还这么快
    • Redis 数据类型和数据结构
      • 五种基本数据结构及应用场景
      • 其他数据类型
      • Redis 底层数据结构
    • Redis 持久化
      • 数据不丢失的实现
      • AOF 日志
      • RDB 快照
      • 混合持久化
      • AOF 和 RDB 的选择
      • AOF 重写的执行过程
      • RDB 快照的执行过程
      • 混合持久化的执行过程
    • Redis 功能和高可用性
      • 主从复制
        • 全量复制
        • 增量复制
        • 全量复制使用 RDB 的原因
      • 哨兵模式
      • 切片集群
      • 集群脑裂
    • 过期删除
    • 内存淘汰策略
      • LRU 和 LFU 算法
    • Redis缓存
      • 缓存雪崩
        • 应对策略
      • 缓存击穿
      • 缓存穿透
        • 常见原因及处理方法
      • 保证数据库和缓存的一致性
        • 写策略
        • 读策略
      • 保证删除缓存操作一定能成功
        • 重试机制
        • 订阅BINLog

Redis 基础

Redis 是什么,有哪些特点

Redis 是一个开源的基于内存的数据库,具有以下特点:

  1. 基于内存:读写速度非常快,适用于缓存、高性能应用场景。
  2. 持久性:支持将数据持久化到磁盘,防止数据丢失。
  3. 多数据结构:支持字符串、哈希表、列表、集合、有序集合等。
  4. 原子性操作:保证操作的原子性,确保数据一致性。
  5. 分布式特性:提供多种集群方案,提高可扩展性和可用性。

为什么要使用 Redis 而不仅仅依赖 MySQL

  • 高性能:读写速度快,适用于频繁读写的数据。
  • 高并发:高效处理并发请求,适用于快速响应的场景。
  • 丰富的数据结构:处理特定类型数据和实现特定功能更灵活。
  • 减轻数据库压力:缓存常用数据,减轻 MySQL 等数据库的压力。

Redis 是单线程吗

Redis 的网络请求模块是单线程的,但其他模块使用多线程,以提高性能。

Redis 单线程为什么还这么快

  1. 基于内存存储:内存访问速度快。
  2. 非阻塞单线程:避免多线程竞争和同步开销。
  3. 高效的数据结构:如 STRING、LIST、HASH 等。
  4. I/O 多路复用:同时监听多个 Socket,实现高效并发处理。

Redis 数据类型和数据结构

五种基本数据结构及应用场景

  1. String(字符串):缓存对象、计数、分布式锁。底层的数据结构实现主要是SDS(简单动态字符串)
  2. List(列表):消息队列。底层数据结构是双向链表或者压缩列表
  3. Set(集合):点赞、共同关注、抽奖活动。底层由哈希表或整数集合(都是整数且元素个数小于 512个)实现
  4. Hash(哈希):缓存对象、购物车。底层由哈希表或压缩列表(哈希类型元素个数小于512个,所有值小于 64 字节)实现
  5. Zset(有序集合):排行榜。底层数据结构压缩列表或跳表
    image-20240802164324909|500|500

其他数据类型

  1. BitMap:签到统计、用户登陆态判断。
  2. HyperLogLog:基数统计,如网页面 UV 计数。不准确。优点在输入元素的 数量或者体积非常非常大时,所需的内存空间总是固定的、并且很小
  3. GEO:存储地理位置信息。
  4. Stream:消息队列。自动生成全局唯一ID,支持以消费组形式消费数据

Redis 底层数据结构

  1. SDS(简单动态字符串):动态扩容,支持字符串和二进制数据。
  2. 双端链表:快速插入和删除。无法很好的利用CPU缓存,内存开销比较大
  3. 压缩列表:压缩列表是一种紧凑的、可变⻓度,由连续内存块组成的顺序型数据结构。在内存使用效率上比较高
  4. 哈希表:快速查询,采用了拉链法解决哈希冲突。
  5. 整数集合:高效存储整数值。二进制表示
  6. 跳表:多层有序链表,查找复杂度 O(logN)。
  7. quicklist:双向链表+压缩列表的组合。quicklist 就是一个链表,而链表中的每个元素又是一个压缩列 表
  8. listpack:只记录当前节点的长度,避免连锁更新问题。
    image-20240802164814316|500|500

Redis 持久化

数据不丢失的实现

Redis 通过以下三种方式实现数据持久化,将数据存储到磁盘,确保在重启时可以恢复数据:

  • AOF 日志:记录每个写操作命令,以日志形式存储。
  • RDB 快照:定期将内存数据快照保存为二进制文件。
  • 混合持久化:结合 AOF 和 RDB 的优点,提供更快的恢复速度和较少的数据丢失。

AOF 日志

  • 机制:先执行命令,把数据写入内存,记录每个写操作命令,重启时重放日志恢复数据。
  • 优点:避免记录错误命令,不阻塞当前写操作。
  • 写回策略
    • Always:每次写操作后立即写回磁盘,最安全,但性能较低。
    • Everysec:每秒写回一次,折中方案,性能和数据安全性较好。
    • No:由操作系统控制写回时机,性能最高,但数据安全性较低。
  • 重写机制:扫描数据中所有的键值对数据,然后为每一个键值对生成一条写操作命令,接着将该命令写入到新的 AOF 文件,重写完成后,就替换掉现有的 AOF 日志。重写的过程是由后台子进程完成的,这样可以使得主进程可以继续正常处理命令。
    • 触发时机
      • 手动执行 bgrewriteaof 命令。
      • 主从复制完成。
      • AOF 重写被设置为待调度执行。
      • AOF 文件大小比例超出阈值,以及 AOF 文件的大小绝对值超出阈值。

RDB 快照

  • 机制:记录某一时刻的内存数据快照,以二进制方式保存到磁盘。
  • 优点:数据恢复速度快,文件体积小。
  • 缺点:频率太低会丢失数据,频率太高会影响性能。
  • 生成方式
    • save:在主线程执行,可能阻塞 Redis 的其他操作。
    • bgsave:在子进程执行,避免阻塞主线程,适合大规模数据保存。

混合持久化

  • 机制:结合 AOF 和 RDB,先将内存数据以 RDB 方式写入 AOF 文件,然后将增量命令以 AOF 方式写入。文件前半部分是 RDB 格式的全量数据(加载速度快),后半部分是 AOF 格式的增量数据(数据丢失更少)。
  • 优点:快速恢复数据,降低数据丢失风险,结合了 RDB 的快速加载和 AOF 的持久性优势。
  • 缺点:AOF 文件可读性变差,兼容性较差(Redis 4.0 之前版本不支持)。

AOF 和 RDB 的选择

  • AOF 优点:持久性更好,丢失数据较少,但恢复速度较慢。
  • RDB 优点:数据恢复速度快,但快照频率难以掌控。
  • 混合持久化:综合两者优点,适合需要快速恢复数据且不希望数据丢失的场景。

AOF 重写的执行过程

  1. 启动重写:手动或触发条件满足时,Redis 启动 AOF 重写。
  2. 生成新文件:子进程遍历所有数据,生成新的 AOF 文件。
  3. 处理增量数据:在生成新文件过程中,增量数据被记录到缓冲区。
  4. 替换旧文件:新 AOF 文件生成完毕后,增量数据写入新文件,替换旧 AOF 文件。

RDB 快照的执行过程

  1. save 命令:主线程执行,阻塞其他操作。
  2. bgsave 命令:子进程执行,避免主线程阻塞。
  3. 文件生成:快照生成的文件包含当前内存中的所有数据。
  4. 文件加载:重启时加载 RDB 文件恢复数据。

混合持久化的执行过程

  1. 启动重写:AOF 重写过程中,子进程将内存数据以 RDB 方式写入 AOF 文件。
  2. 记录增量数据:主线程处理的操作命令记录到重写缓冲区,以 AOF 方式写入新文件。
  3. 文件替换:新文件生成后,通知主进程将其替换旧文件。新文件前半部分为 RDB 格式数据,后半部分为 AOF 格式数据。
  4. 快速恢复:重启时,先加载 RDB 部分,快速恢复大部分数据,再加载 AOF 部分,确保数据一致性。

Redis 功能和高可用性

主从复制

image.png|500|500
Redis 通过主从复制模式实现数据的高可用性,保证数据副本的一致性。主从复制模式下,读写操作分离:

  • 读操作:主库和从库都可以接收。
  • 写操作先在主库执行,然后同步到从库
全量复制
  1. 建立连接:从库与主库建立连接,主库确认后开始同步。
  2. 主库发送数据:主库发送当前数据的 RDB 快照及增量写命令。
  3. 从库接收数据:从库接收 RDB 文件和增量写命令,更新数据状态。
    image.png|500|500
增量复制

从库发生宕机,重新连接后数据的同步操作(增量复制)
image.png|500|500

  1. 从库宕机重连:从库发生宕机,主库会把断连期间收到的写操作命令,写到repl_backlog_buffer中;从库重新连接主库后,发送 psync 命令并传递当前的复制偏移量slave_repl_offset。
  2. 数据同步:主库根据从库的复制偏移量,决定进行增量复制还是全量复制(从库相差 > repl_backlog_buffer)。
全量复制使用 RDB 的原因
  1. 压缩数据:RDB 文件内容是经过压缩的二进制,文件较小。
  2. 性能影响小:AOF 文件需要选择文件刷盘的策略,选择不当会影响性能,而 RDB 文件只在备份和同步时生成。

哨兵模式

Redis 的哨兵模式用于监控主从服务器,提供主从节点故障转移的功能,实现自动故障转移和高可用性。哨兵的功能包括:

  • 监控:定期检查主从服务器状态。
  • 通知:发现问题时通知相关人员。
  • 故障迁移:自动主从切换。
  • 配置管理:统一管理主从地址。

切片集群

当缓存数据量大到一台服务器无法承载时,使用 Redis 切片集群将数据分布在多个服务器上,降低系统对单主机点的依赖,提高读写性能。切片集群的工作原理:

  1. 数据分片:将数据集划分为 16384 个槽,每个节点管理部分槽的数据。
  2. 节点间通信:节点通过 gossip 协议互相通信,保持一致性。
  3. 数据分布:根据键的 CRC16 哈希值确定数据属于哪个槽,并存储到相应节点。
  4. 故障检测:哨兵机制检测节点状态,重新分配槽并选举新主节点。
  5. 客户端路由:客户端根据键的哈希值确定目标节点,直接与负责数据的节点通信。
  6. 数据复制:每个槽有一个主节点和若干个从节点,数据写入主节点后异步复制到从节点。

集群脑裂

脑裂是指在网络故障时,主节点的网络突然发生了问题与所有的从节点都失联,但与客户端正常通信,这些数据被主节点缓存到了缓冲区里。哨兵 也发现主节点失联了,就会在从节点中选举出一个leader作为主节点,导致出现多个主节点。解决方法:

  1. 主节点写保护:主节点在发现从节点断开或通信超时数量少于阈值时,禁止写操作。
  2. 从节点配置:设置主节点需要从节点的 ACK 消息数量和延迟限制,确保数据一致性。

过期删除

Redis 支持为键设置过期时间,自动删除过期键值对,采用以下删除策略:

  1. 定时删除:设置定时事件,到时间自动删除键,占用 CPU 时间多。
  2. 惰性删除:不主动删除,访问键时检查其是否过期,节省 CPU 时间,但可能浪费内存。
  3. 定期删除:每隔一段时间随机抽取部分键进行检查和删除,均衡 CPU 和内存使用。
    Redis 选择「惰性删除+定期删除」这两种策略配和使用,以求在合理使用 CPU 时间和避免内存浪费之间取得平衡

内存淘汰策略

当内存不足时,Redis 会根据配置的淘汰策略删除一些键以释放内存。常见策略:

  1. NoEviction:不进行数据淘汰,内存不足时返回错误。
  2. VolatileTTL:优先淘汰更早过期的键。
  3. VolatileLRU:对带过期时间的键使用 LRU 策略,其他键使用 NoEviction 策略。
  4. VolatileRandom:对带过期时间的键随机淘汰,其他键使用 NoEviction 策略。
  5. VolatileLFU:对带过期时间的键使用 LFU 策略,其他键使用 NoEviction 策略。
  6. AllKeysLRU:根据最近最少使用原则淘汰最久未使用的键。
  7. AllKeysRandom:随机选择一个键进行淘汰。
  8. AllKeysLFU:根据最少频繁使用原则淘汰最少使用的键。
    可以使用 config get maxmemory-policy 命令,来查看当前 Redis 的内存淘汰策略

LRU 和 LFU 算法

  1. LRU(Least Recently Used):淘汰最近最少使用的对象。
    • 实现:随机取若干值,淘汰最久未使用的对象。
  2. LFU(Least Frequently Used):淘汰使用频率最低的对象。
    • 实现:维护使用计数,淘汰使用计数最低的对象。

区别

  • LRU:关注最近访问情况,认为最近访问的对象更可能被再次访问。
  • LFU:关注使用频率,认为使用频率低的对象未来访问概率低。

Redis缓存

由于用户请求频繁访问数据库,直接访问数据库可能导致数据库崩溃,因此常常使用Redis作为数据库的缓存层。

缓存雪崩

缓存雪崩:某个时间点,缓存中的大量数据同时失效,大量请求涌向数据库,导致数据库压力剧增。原因可能是缓存过期时间设置相近或Redis故障。

应对策略
  1. 大量数据同时过期

    • 均匀设置过期时间:加随机数,避免大量数据同一时间失效。
    • 使用互斥锁:确保同一时间只有一个请求构建缓存。
    • 后台线程定时更新缓存:让缓存设置“永久有效”。
  2. Redis故障宕机

    • 服务熔断或请求限流:减少直接对数据库的压力。
    • 构建Redis高可靠集群:通过主从节点切换确保服务连续。

缓存击穿

缓存击穿:热点数据过期时,大量并发请求查询该数据,导致直接访问数据库,增加数据库负载。可以通过互斥锁或后台更新缓存来解决。

缓存穿透

缓存穿透:请求的数据既不在缓存中,也不在数据库中,导致所有请求直接访问数据库,增加负载。

常见原因及处理方法
  • 业务误操作或恶意攻击
  • 对非法请求做限制
  • 缓存中设置空值或默认值
  • 使用布隆过滤器判断数据是否存在
  • image.png|500|500

保证数据库和缓存的一致性

Cache Aside策略

写策略
  • 更新数据库后删除缓存。
读策略
  • 缓存命中返回数据;未命中从数据库读取数据后写入缓存并返回。

为了高缓存命中率,可以采用更新数据库加更新缓存的方法,但需解决并发导致的一致性问题,例如加分布式锁或设置较短的缓存过期时间。

保证删除缓存操作一定能成功

重试机制

引入消息队列,应用删除失败从消息队列重新读取数据再进行删除,重试多次未成功则报错。

订阅BINLog

订阅binlog日志,准确删除缓存中的数据。通过模拟MySQL从节点获取binlog,解析后删除缓存数据。

相关内容

热门资讯

一文彻底搞懂Transform...         在Transformer模型中,Add & Norm(残...
jmeter服务器性能监控分析... ServerAgent介绍:支持监控CPU,memory,...
uniapp的微信小程序如何跳... 微信小程序跳转h5页面1.新建webView页面2.跳转页面并且转递参数3.webView页面接收参...
微信小程序(百战商城)的实战项... 👨‍💻个人主页:@开发者-曼亿点὆...
uniapp微信小程序通过萤石... 需求:在uniapp微信小程序上查看海康威视的摄像机监控视频和和操作摄像机拍摄方向在萤...
针对微信小程序的渗透测试实战 材料准备:burp suite、模拟器(把微信装好)、node.js、wxappUnp...
基于微信小程序+SpringB... 博主介绍:✌全网粉丝50W+,csdn特邀作者、博客专家、CSDN新星计划导师...
手把手教你CrossOver ... 兔八哥爱分享要和大家分享的是一款可以让我们直接在Mac上安装和运行Windows软件和游戏的软件——...
ELK 日志分析系统 一、基本概述1.总体概览ELK由ElasticSearch、Logstash、Kiabana三个开源...
微信小程序接入支付功能并实现支... 微信支付是微信公众平台提供的一种在线支付服务,可以为用户提供快速、方便、安全的支付体验...