Redis 深度解析

Redis(Remote Dictionary Server)是一个高性能的键值存储数据库,以其丰富的数据结构、持久化机制和高可用特性著称。本文将深入剖析 Redis 的核心原理、数据结构、持久化机制以及集群架构。

Redis 简介

Redis 是一个开源的、基于内存的键值对存储系统,支持多种数据结构,并提供持久化、复制、集群等功能。

Redis 的核心特性:

  • 高性能:基于内存存储,单节点可达 10万+ QPS
  • 丰富的数据结构:String、List、Set、Hash、ZSet 等
  • 原子操作:所有操作都是原子的
  • 持久化:支持 RDB 和 AOF 两种持久化方式
  • 主从复制:支持主从复制和读写分离
  • 高可用:支持哨兵模式和集群模式
  • 支持事务:通过 MULTI/EXEC 实现事务

数据结构

String(字符串)

String 是最基本的数据类型,可以存储字符串、整数、浮点数。

# 设置值
SET key value

# 获取值
GET key

# 设置过期时间
SETEX key seconds value

# 自增自减
INCR key
DECR key
INCRBY key increment

# 批量操作
MSET key1 value1 key2 value2
MGET key1 key2

底层实现:使用 SDS(Simple Dynamic String)

  • 空间预分配:减少内存重分配次数
  • 惰性释放:延迟内存释放
  • 二进制安全:可以存储任意二进制数据

Hash(哈希)

Hash 是一个键值对集合,适合存储对象。

# 设置字段
HSET key field value

# 获取字段
HGET key field

# 获取所有字段
HGETALL key

# 获取字段数量
HLEN key

# 批量设置
HMSET key field1 value1 field2 value2

底层实现:使用 ziplist 或 hashtable

  • ziplist:元素少且值小时使用,节省内存
  • hashtable:元素多或值大时使用,O(1) 查找

List(列表)

List 是一个有序的字符串集合,支持从两端插入和弹出。

# 从左插入
LPUSH key value1 value2

# 从右插入
RPUSH key value1 value2

# 从左弹出
LPOP key

# 从右弹出
RPOP key

# 获取列表长度
LLEN key

# 获取范围内的元素
LRANGE key start stop

底层实现:使用 ziplist 或 linkedlist

  • ziplist:元素少且值小时使用
  • linkedlist:元素多或值大时使用

Set(集合)

Set 是一个无序的唯一字符串集合,支持集合运算。

# 添加元素
SADD key member1 member2

# 获取所有元素
SMEMBERS key

# 判断元素是否存在
SISMEMBER key member

# 获取元素数量
SCARD key

# 集合运算
SINTER key1 key2  # 交集
SUNION key1 key2  # 并集
SDIFF key1 key2   # 差集

底层实现:使用 intset 或 hashtable

  • intset:元素都是整数且数量少时使用
  • hashtable:其他情况使用

ZSet(有序集合)

ZSet 是一个有序的唯一字符串集合,每个元素关联一个分数。

# 添加元素
ZADD key score1 member1 score2 member2

# 获取排名范围内的元素
ZRANGE key start stop

# 获取分数范围内的元素
ZRANGEBYSCORE key min max

# 获取元素排名
ZRANK key member

# 获取元素分数
ZSCORE key member

# 增加分数
ZINCRBY key increment member

底层实现:使用 skiplist(跳跃表)+ hashtable

  • skiplist:保持有序,支持范围查询
  • hashtable:快速查找元素和分数

持久化机制

RDB(RDB)

RDB 是 Redis 默认的持久化方式,通过生成快照实现。

RDB 的特点:

  • 文件紧凑,适合备份
  • 恢复速度快
  • 数据可能丢失(最后一次快照后的数据)

RDB 配置:

# 900秒内至少1个key变化则保存
save 900 1
save 300 10
save 60 10000

# RDB文件名
dbfilename dump.rdb

# RDB文件目录
dir /var/lib/redis

# 是否压缩RDB文件
rdbcompression yes

# RDB文件校验
rdbchecksum yes

手动触发 RDB:

# 同步生成RDB
SAVE

# 异步生成RDB
BGSAVE

AOF(AOF)

AOF 通过记录每个写操作实现持久化。

AOF 的特点:

  • 数据安全性高,最多丢失1秒数据
  • 文件较大
  • 恢复速度较慢

AOF 配置:

# 开启AOF
appendonly yes

# AOF文件名
appendfilename "appendonly.aof"

# AOF持久化策略
appendfsync always    # 每次写操作都同步(最安全但最慢)
appendfsync everysec # 每秒同步一次(推荐)
appendfsync no       # 由操作系统决定(最快但可能丢失数据)

# AOF重写配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

AOF 重写:

# 手动触发AOF重写
BGREWRITEAOF

RDB vs AOF

特性 RDB AOF
文件大小
恢复速度
数据安全性 可能丢失数据
写入性能

混合持久化(Redis 4.0+):

  • RDB 做基础全量
  • AOF 做增量增量
  • 结合两者优势
# 开启混合持久化
aof-use-rdb-preamble yes

过期策略

过期时间设置

# 设置过期时间(秒)
EXPIRE key seconds

# 设置过期时间(毫秒)
PEXPIRE key milliseconds

# 设置键并指定过期时间
SETEX key seconds value

# 查看剩余过期时间
TTL key
PTTL key

# 移除过期时间
PERSIST key

过期删除策略

Redis 使用惰性删除 + 定期删除的组合策略。

惰性删除:

  • 访问键时检查是否过期
  • 过期则删除,否则返回值
  • 优点:节省 CPU
  • 缺点:占用内存

定期删除:

  • 每隔一段时间随机检查一定数量的键
  • 删除过期的键
  • 如果过期键比例超过 25%,继续检查
  • 优点:平衡 CPU 和内存

内存淘汰策略

当内存达到上限时,Redis 会根据配置淘汰键。

# 最大内存限制
maxmemory 256mb

# 淘汰策略
maxmemory-policy allkeys-lru

# 可选策略:
# noeviction          不淘汰,返回错误
# allkeys-lru         淘汰最少使用的键
# allkeys-lfu         淘汰最不频繁使用的键
# allkeys-random      随机淘汰
# volatile-lru        淘汰设置了过期时间的最少使用键
# volatile-lfu        淘汰设置了过期时间的最不频繁使用键
# volatile-random     随机淘汰设置了过期时间的键
# volatile-ttl        淘汰即将过期的键

主从复制

复制原理

Redis 主从复制采用异步复制机制。

复制流程:

  1. 从节点连接主节点,发送 SYNC 命令
  2. 主节点执行 BGSAVE,生成 RDB 文件
  3. 主节点将 RDB 文件发送给从节点
  4. 从节点加载 RDB 文件
  5. 主节点将缓冲区的写命令发送给从节点
  6. 从节点执行写命令,保持数据同步

增量复制

Redis 2.8+ 支持增量复制,减少全量复制的开销。

增量复制流程:

  1. 从节点记录主节点的复制偏移量
  2. 连接断开后,从节点记录偏移量
  3. 重新连接时,从节点发送偏移量
  4. 主节点发送增量数据

主从配置

# 主节点配置
port 6379
bind 0.0.0.0

# 从节点配置
port 6380
replicaof 127.0.0.1 6379
masterauth password

# 只读模式
replica-read-only yes

哨兵模式

哨兵简介

哨兵(Sentinel)是 Redis 的高可用解决方案,用于监控主从节点,实现自动故障转移。

哨兵的功能:

  • 监控:监控主从节点的运行状态
  • 通知:通知管理员节点故障
  • 自动故障转移:将从节点提升为主节点
  • 配置提供:为客户端提供主节点信息

哨兵配置

# 哨兵端口
port 26379

# 监控主节点
sentinel monitor mymaster 127.0.0.1 6379 2

# 主节点密码
sentinel auth-pass mymaster password

# 故障转移超时时间
sentinel down-after-milliseconds mymaster 30000

# 故障转移超时时间
sentinel failover-timeout mymaster 180000

# 同时进行故障转移的从节点数量
sentinel parallel-syncs mymaster 1

故障转移流程

  1. 哨兵检测到主节点下线
  2. 多个哨兵确认主节点下线(客观下线)
  3. 哨兵选举 Leader
  4. Leader 选择新的主节点
  5. Leader 提升新主节点
  6. Leader 通知其他从节点复制新主节点
  7. Leader 通知客户端新主节点信息

集群模式

集群简介

Redis Cluster 是 Redis 的分布式解决方案,支持数据分片和高可用。

集群特点:

  • 数据分片:使用哈希槽(16384 个)
  • 高可用:每个主节点有多个从节点
  • 自动故障转移:类似哨兵模式
  • 无中心:所有节点地位平等

数据分片

Redis Cluster 使用 CRC16 算法计算键的哈希值,然后对 16384 取模,确定键所在的哈希槽。

# 计算键的哈希槽
slot = CRC16(key) % 16384

哈希槽分配:

  • 每个主节点负责一部分哈希槽
  • 槽可以迁移,实现扩缩容
  • 支持手动和自动迁移

集群配置

# 开启集群模式
cluster-enabled yes

# 集群配置文件
cluster-config-file nodes.conf

# 集群超时时间
cluster-node-timeout 15000

# 集群总线端口
cluster-port 16379

集群操作

# 创建集群
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 \
  127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
  --cluster-replicas 1

# 添加节点
redis-cli --cluster add-node new_node:7000 existing_node:7000

# 槽迁移
redis-cli --cluster reshard existing_node:7000

# 检查集群状态
redis-cli --cluster check 127.0.0.1:7000

事务

Redis 通过 MULTI、EXEC、DISCARD、WATCH 实现事务。

# 开启事务
MULTI

# 执行命令
SET key1 value1
SET key2 value2
GET key1

# 提交事务
EXEC

# 取消事务
DISCARD

# 监控键
WATCH key

# 如果被监控的键被修改,EXEC 会失败

事务特性:

  • 原子性:事务中的命令要么全部执行,要么全部不执行
  • 隔离性:事务执行期间不会被其他命令打断
  • 不支持回滚:如果命令执行失败,不会回滚已执行的命令

性能优化

内存优化

  • 选择合适的数据结构:根据场景选择最优数据结构
  • 设置过期时间:避免内存无限增长
  • 使用压缩列表:减少内存占用
  • 禁用不必要的功能:如禁用慢查询日志
# 禁用慢查询日志
slowlog-log-slower-than -1

# 设置最大内存
maxmemory 256mb

# 设置淘汰策略
maxmemory-policy allkeys-lru

网络优化

  • 使用管道:减少网络往返
  • 批量操作:使用 MGET、MSET 等命令
  • 启用 TCP Keepalive:保持连接活跃
# 使用管道
echo -e "SET key1 value1\nSET key2 value2\nGET key1" | redis-cli --pipe

持久化优化

  • 合理配置 RDB:根据数据量调整保存频率
  • 使用 AOF 重写:减少 AOF 文件大小
  • 使用混合持久化:结合 RDB 和 AOF 优势

最佳实践

  • 使用连接池:避免频繁创建连接
  • 设置合理的过期时间:避免内存泄漏
  • 使用 Pipeline:提高批量操作性能
  • 监控 Redis:使用 INFO 命令监控 Redis 状态
  • 定期备份:定期备份 RDB 文件
  • 使用集群:数据量大时使用集群模式
  • 避免大 Key:大 Key 会阻塞 Redis
  • 使用 Lua 脚本:减少网络往返

总结

Redis 是一个功能强大的键值存储系统,提供了丰富的数据结构、持久化机制和高可用方案。本文介绍了 Redis 的核心数据结构、持久化机制、主从复制、哨兵模式、集群架构以及性能优化技巧。掌握这些知识后,可以更好地应用 Redis 解决缓存、消息队列等场景的问题。