Redis基础总结、持久化、主从复制、哨兵模式、内存淘汰策略、缓存

文章目录

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(有序集合) :排行榜。底层数据结构压缩列表或跳表

其他数据类型

  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 :只记录当前节点的长度,避免连锁更新问题。

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 功能和高可用性

主从复制

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

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

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

  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高可靠集群:通过主从节点切换确保服务连续。

缓存击穿

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

缓存穿透

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

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

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

Cache Aside策略

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

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

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

重试机制

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

订阅BINLog

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

相关推荐
向前看-15 分钟前
验证码机制
前端·后端
Hacker_LaoYi44 分钟前
【渗透技术总结】SQL手工注入总结
数据库·sql
岁月变迁呀1 小时前
Redis梳理
数据库·redis·缓存
独行soc1 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍06-基于子查询的SQL注入(Subquery-Based SQL Injection)
数据库·sql·安全·web安全·漏洞挖掘·hw
你的微笑,乱了夏天1 小时前
linux centos 7 安装 mongodb7
数据库·mongodb
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭2 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
工业甲酰苯胺2 小时前
分布式系统架构:服务容错
数据库·架构
超爱吃士力架2 小时前
邀请逻辑
java·linux·后端
冷眼看人间恩怨2 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
独行soc3 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍08-基于时间延迟的SQL注入(Time-Based SQL Injection)
数据库·sql·安全·渗透测试·漏洞挖掘