跳转至

Redis

目录

  1. Redis是什么
  2. Redis为什么快
  3. Redis基本数据类型和结构
  4. Redis持久化
  5. Redis主从同步
  6. Redis集群
  7. Redis应用场景

Redis是什么

Redis 是一个基于内存的数据库,因此读写数据非常快,常用于缓存、消息队列、分布式锁等应用场景。

Redis为什么快

Redis 之所以快,主要有以下几个原因:

  1. 基于内存存储:所有数据都存储在内存中,避免了磁盘 I/O 的开销
  2. 单线程模型:采用单线程处理命令,避免了多线程的上下文切换和竞争开销(注意:Redis 6.0 引入了多线程 I/O,但命令执行仍为单线程)
  3. 高效的数据结构:针对不同场景设计了高效的底层数据结构
  4. 非阻塞 I/O:使用 I/O 多路复用技术处理并发连接
  5. 内存优化:对小数据有特殊的内存优化策略

Redis基本数据类型和结构

1. String

String 类型的底层数据结构实现主要是 SDS(简单动态字符串)。SDS 相比 C 原生字符串的优势:

  • 可以保存文本数据和二进制数据
  • 获取字符串长度的时间复杂度是 O(1)
  • API 安全,拼接字符串不会造成缓冲区溢出,会自动扩容

2. List

在 Redis 3.2 版本之后,List 数据类型底层数据结构只由 quicklist 实现,替代了双向链表和压缩列表。

3. Hash

在 Redis 7.0 中,压缩列表数据结构已废弃,交由 listpack 数据结构实现。

4. Set

  • 如果集合中的元素都是整数且元素个数小于 512(默认值,可通过 set-maxintset-entries 配置),使用 整数集合
  • 否则使用 哈希表

5. Zset(有序集合)

在 Redis 7.0 中,压缩列表数据结构已废弃,交由 listpack 和跳表共同实现。

Redis持久化

RDB(快照)

  • 生成某个时间点的数据快照文件
  • 优点:恢复速度快,文件紧凑
  • 缺点:可能丢失最后一次快照后的数据

AOF(Append Only File)

  • 记录每个写命令到文件
  • 优点:数据更安全,可配置不同的同步策略
  • 缺点:文件通常比 RDB 大,恢复速度较慢

AOF文件过大的处理方式

  1. 自动重写:Redis 提供自动重写机制,当 AOF 文件大小超过一定阈值时触发。可以通过 auto-aof-rewrite-percentageauto-aof-rewrite-min-size 配置。
  2. 手动触发重写:执行 BGREWRITEAOF 命令
  3. 调整 AOF 策略:通过 appendfsync 参数控制同步频率
  4. always:每次写都同步(最安全但最慢)
  5. everysec:每秒同步(默认,平衡)
  6. no:由操作系统控制(最快但最不安全)

开启 AOF 的方式

  1. 配置文件:设置 appendonly yes
  2. 命令行参数:启动时使用 --appendonly yes
  3. 动态配置:运行时使用 CONFIG SET appendonly yes

Redis主从同步

Redis 主从同步过程分为以下几个阶段:

1. 连接建立

从节点启动时,通过配置的主节点地址和端口,向主节点发送命令请求建立复制关系。

2. 全量同步(初次同步)

  • 主节点执行 BGSAVE,在后台生成 RDB 文件
  • 同时将期间的写命令记录在缓冲区
  • RDB 文件生成后发送给从节点
  • 从节点清空数据集并加载 RDB 文件
  • 主节点将缓冲区的写命令发送给从节点执行

3. 部分同步(增量同步)

  • 全量同步完成后,主从节点进入命令传播阶段
  • 主节点将后续写命令实时发送给从节点
  • 如果从节点断开重连,会根据复制偏移量尝试部分同步

4. 心跳检测

主从节点之间定期发送心跳包,检测连接状态和同步进度。

Redis集群

集群扩容过程

  1. 准备新节点
  2. 新节点加入集群(作为主节点或从节点)
  3. 迁移哈希槽(slot)到新节点
  4. 重新平衡集群数据分布

节点间通信

  • Redis 集群使用 Gossip 协议进行节点间通信
  • 每个节点定期向其他节点发送 ping 消息
  • 节点通过消息交换了解集群状态变化
  • 使用 gossip 协议可以在没有中心节点的情况下实现集群状态同步

Redis应用场景

1. 缓存(旁路缓存)

在项目中用于旁路缓存,例如在 DWS 层写入数据时需要将 DWD 明细数据与维度数据进行 join,这时会: - 先尝试读取 Redis - 未命中则读取 HBase 维表 - 将结果缓存到 Redis,设置一天的 TTL

缓存失效回源查询: 1. 应用程序查询缓存 2. 未命中则回源查询 HBase 3. 更新缓存并设置过期时间 4. 可使用 Spring Cache 等框架简化实现

2. 分布式锁

实现方式 加锁 解锁 说明
SETNX SETNX key value DEL key 基础实现
SET 命令 SET key value NX PX ms DEL key 支持过期时间
Redisson RLock.lock() RLock.unlock() 功能完善的框架

3. 限流器

固定窗口计数器

  • 设定固定时间窗口(如 1 秒)
  • 使用 INCR 统计请求次数
  • 超过阈值则拒绝请求
  • 使用 EXPIRE 设置过期时间

滑动窗口计数器

  • 将固定窗口分成多个小窗口
  • 使用有序集合(Sorted Set)存储每个小窗口的计数和时间戳
  • 通过 ZREMRANGEBYSCORE 删除过期的小窗口

令牌桶算法

  • 维护固定容量的令牌桶
  • 以固定速率向桶中添加令牌
  • 请求获取令牌,成功则通过
  • 可使用 SETNXDECRINCRBY 等命令实现

漏桶算法

  • 设定固定容量的漏桶
  • 以固定速率漏出请求
  • 请求放入漏桶,满则拒绝
  • 可使用 LIST 结构实现

4. 秒杀系统优化(千万级并发)

如果 Redis 也扛不住了,可以考虑: 1. 多层缓存:本地缓存 + Redis 缓存 2. 限流降级:在接入层进行限流 3. 请求排队:使用消息队列削峰填谷 4. 读写分离:主从分离,读请求走从节点 5. 分片:将数据分片到多个 Redis 实例 6. 降级方案:Redis 不可用时降级到数据库 7. 提前预热:活动前提前加载热点数据

评论