Redis¶
目录¶
Redis是什么¶
Redis 是一个基于内存的数据库,因此读写数据非常快,常用于缓存、消息队列、分布式锁等应用场景。
Redis为什么快¶
Redis 之所以快,主要有以下几个原因:
- 基于内存存储:所有数据都存储在内存中,避免了磁盘 I/O 的开销
- 单线程模型:采用单线程处理命令,避免了多线程的上下文切换和竞争开销(注意:Redis 6.0 引入了多线程 I/O,但命令执行仍为单线程)
- 高效的数据结构:针对不同场景设计了高效的底层数据结构
- 非阻塞 I/O:使用 I/O 多路复用技术处理并发连接
- 内存优化:对小数据有特殊的内存优化策略
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文件过大的处理方式¶
- 自动重写:Redis 提供自动重写机制,当 AOF 文件大小超过一定阈值时触发。可以通过
auto-aof-rewrite-percentage和auto-aof-rewrite-min-size配置。 - 手动触发重写:执行
BGREWRITEAOF命令 - 调整 AOF 策略:通过
appendfsync参数控制同步频率 always:每次写都同步(最安全但最慢)everysec:每秒同步(默认,平衡)no:由操作系统控制(最快但最不安全)
开启 AOF 的方式¶
- 配置文件:设置
appendonly yes - 命令行参数:启动时使用
--appendonly yes - 动态配置:运行时使用
CONFIG SET appendonly yes
Redis主从同步¶
Redis 主从同步过程分为以下几个阶段:
1. 连接建立¶
从节点启动时,通过配置的主节点地址和端口,向主节点发送命令请求建立复制关系。
2. 全量同步(初次同步)¶
- 主节点执行
BGSAVE,在后台生成 RDB 文件 - 同时将期间的写命令记录在缓冲区
- RDB 文件生成后发送给从节点
- 从节点清空数据集并加载 RDB 文件
- 主节点将缓冲区的写命令发送给从节点执行
3. 部分同步(增量同步)¶
- 全量同步完成后,主从节点进入命令传播阶段
- 主节点将后续写命令实时发送给从节点
- 如果从节点断开重连,会根据复制偏移量尝试部分同步
4. 心跳检测¶
主从节点之间定期发送心跳包,检测连接状态和同步进度。
Redis集群¶
集群扩容过程¶
- 准备新节点
- 新节点加入集群(作为主节点或从节点)
- 迁移哈希槽(slot)到新节点
- 重新平衡集群数据分布
节点间通信¶
- 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删除过期的小窗口
令牌桶算法¶
- 维护固定容量的令牌桶
- 以固定速率向桶中添加令牌
- 请求获取令牌,成功则通过
- 可使用
SETNX、DECR、INCRBY等命令实现
漏桶算法¶
- 设定固定容量的漏桶
- 以固定速率漏出请求
- 请求放入漏桶,满则拒绝
- 可使用 LIST 结构实现
4. 秒杀系统优化(千万级并发)¶
如果 Redis 也扛不住了,可以考虑: 1. 多层缓存:本地缓存 + Redis 缓存 2. 限流降级:在接入层进行限流 3. 请求排队:使用消息队列削峰填谷 4. 读写分离:主从分离,读请求走从节点 5. 分片:将数据分片到多个 Redis 实例 6. 降级方案:Redis 不可用时降级到数据库 7. 提前预热:活动前提前加载热点数据