Redis 超详细入门教程:从零基础到实战精通

本文全面讲解 Redis 核心概念、数据类型、使用场景及持久化方案,适合初学者系统学习,也适合有经验的开发者查漏补缺。


一、概念与原理介绍

1.1 什么是 Redis?

Redis(Remote Dictionary Server) 是一个开源的、基于内存的键值对存储数据库,通常被称为数据结构服务器。它由 Salvatore Sanfilippo 于 2009 年开发,使用 ANSI C 语言编写。

核心特性

  1. 高性能

    • 完全基于内存操作,读写速度极快
    • 单线程模型(大部分情况下),避免了线程切换和锁的开销
    • QPS 可达 10万+(简单操作)
  2. 丰富的数据结构

    • 不仅仅是简单的 key-value 存储
    • 支持字符串、哈希、列表、集合、有序集合等复杂数据结构
  3. 持久化机制

    • RDB(Redis Database):定期将内存数据快照保存到磁盘
    • AOF(Append Only File):记录写操作日志,实现增量持久化
  4. 分布式支持

    • 主从复制
    • 哨兵模式(Sentinel)
    • 集群模式(Cluster)
  5. 原子性操作

    • 所有操作都是原子性的
    • 支持事务

1.2 Redis 与其他数据库的对比

特性 Redis MySQL MongoDB Memcached
存储方式 内存 + 磁盘 磁盘 磁盘 + 内存 内存
数据模型 键值对 关系型 文档型 键值对
持久化 支持(RDB/AOF) 支持 支持 不支持
数据结构 丰富 表结构 BSON 简单键值
读写速度 极快 较慢 中等 极快
适用场景 缓存、实时计算 事务、复杂查询 文档存储 简单缓存

核心区别:

  • Redis 是内存优先的数据库,性能远超传统磁盘数据库
  • 相比 Memcached,Redis 提供了更丰富的数据结构和持久化能力
  • 相比传统数据库,Redis 是非关系型的,不使用表结构

1.3 Redis 的工作原理

单线程模型(Reactor 模式)

Redis 采用事件驱动的单线程模型:

复制代码
┌─────────────────────────────────────┐
│         Event Loop (Reactor)        │
├─────────────────────────────────────┤
│  ┌─────┐  ┌─────┐  ┌─────┐         │
│  │Socket│  │Socket│  │Socket│ ...   │
│  └──┬──┘  └──┬──┘  └──┬──┘         │
│     │       │       │              │
│  ┌──▼───────────────▼────────▼──┐   │
│  │     IO 多路复用 (epoll)     │   │
│  └──────────┬───────────────────┘   │
│             │                       │
│       ┌─────▼─────┐                 │
│       │ 命令解析器  │                 │
│       └─────┬─────┘                 │
│             │                       │
│       ┌─────▼─────┐                 │
│       │ 命令执行器  │ (单线程处理)     │
│       └─────┬─────┘                 │
│             │                       │
│       ┌─────▼─────┐                 │
│       │ 响应返回器  │                 │
│       └───────────┘                 │
└─────────────────────────────────────┘

为什么单线程反而快?

  • 避免了线程切换和锁竞争的开销
  • 内存操作不需要多线程
  • IO 多路复用技术处理并发连接

内存管理

Redis 使用自己的内存分配器:

  • jemalloc:默认分配器(Linux)
  • tcmalloc:可选
  • 内存碎片管理:通过数据结构优化减少碎片

过期策略

Redis 使用两种策略处理过期 key:

  1. 被动过期

    • 访问 key 时检查是否过期
    • 过期则删除
  2. 主动过期

    • 定期随机抽取 key 检查
    • 删除已过期的 key
    • 避免内存泄漏

二、基本数据类型详解

2.1 字符串(String)

特性

  • 最基础的数据类型
  • 可以存储任何类型的数据(字符串、数字、二进制数据等)
  • 最大容量 512MB
  • 原子性操作:INCR/DECR 等操作是线程安全的

常用命令

bash 复制代码
# 基本操作
SET key value           # 设置 key-value
GET key                 # 获取 key 对应的值
DEL key                 # 删除 key
EXISTS key              # 判断 key 是否存在

# 过期时间
SETEX key seconds value # 设置 key 并指定过期时间(秒)
TTL key                 # 获取 key 的剩余过期时间

# 数字操作
INCR key                # key 值加 1
DECR key                # key 值减 1
INCRBY key increment    # key 值增加指定数值
DECRBY key decrement    # key 值减少指定数值

# 批量操作
MGET key1 key2 key3     # 批量获取多个 key 的值
MSET key1 val1 key2 val2 # 批量设置多个 key-value

# 字符串操作
APPEND key value        # 在 key 对应的值后面追加内容
STRLEN key              # 获取字符串长度
GETRANGE key start end  # 获取字符串的子串
SETRANGE key offset value   # 从指定位置开始设置字符串

使用示例

bash 复制代码
# 设置用户信息
SET user:1:name "张三"
SET user:1:age 25

# 获取用户信息
GET user:1:name        # 返回 "张三"
GET user:1:age         # 返回 "25"

# 计数器示例
SET article:1001:views 0
INCR article:1001:views  # 返回 1
INCRBY article:1001:views 10  # 返回 11

# 设置带过期时间的验证码
SETEX verify:phone:13800138000 300 "123456"  # 5分钟过期
TTL verify:phone:13800138000  # 查看剩余时间

应用场景

  • 缓存
  • 计数器(文章阅读量、点赞数等)
  • Session 存储
  • 分布式锁

2.2 哈希(Hash)

特性

  • 存储键值对集合
  • 类似于 Java 的 HashMap 或 Python 的字典
  • 适合存储对象信息
  • 每个哈希可以存储 2³² - 1 个键值对(约 40 亿)

常用命令

bash 复制代码
# 基本操作
HSET key field value       # 设置哈希表 key 中字段 field 的值
HGET key field             # 获取哈希表 key 中字段 field 的值
HMSET key field1 val1 field2 val2  # 批量设置
HMGET key field1 field2    # 批量获取
HGETALL key                # 获取哈希表中所有字段和值
HDEL key field1 field2     # 删除一个或多个字段
HEXISTS key field          # 查看字段是否存在

# 字段操作
HKEYS key                  # 获取哈希表中所有字段名
HVALS key                  # 获取哈希表中所有字段值
HLEN key                   # 获取哈希表中字段数量

# 数值操作
HINCRBY key field increment    # 为哈希表中的字段增加指定数值
HINCRBYFLOAT key field increment  # 浮点数增加

使用示例

bash 复制代码
# 存储用户信息
HSET user:1 name "张三"
HSET user:1 age 25
HSET user:1 city "北京"
HSET user:1 email "zhangsan@example.com"

# 获取用户信息
HGET user:1 name           # 返回 "张三"
HGET user:1 age            # 返回 "25"

# 获取所有用户信息
HGETALL user:1
# 返回:
# 1) "name"
# 2) "张三"
# 3) "age"
# 4) "25"
# 5) "city"
# 6) "北京"
# 7) "email"
# 8) "zhangsan@example.com"

# 更新用户年龄
HINCRBY user:1 age 1       # 年龄加 1,返回 26

# 获取所有字段
HKEYS user:1               # 返回所有字段名

# 获取字段数量
HLEN user:1                # 返回 4

应用场景

  • 存储对象(用户信息、商品信息等)
  • 购物车(key 为用户ID,field 为商品ID,value 为数量)
  • 配置信息存储

2.3 列表(List)

特性

  • 存储有序的字符串列表
  • 类似于 Java 的 LinkedList
  • 可以在头部或尾部添加/删除元素
  • 支持双向操作
  • 最多存储 2³² - 1 个元素

常用命令

bash 复制代码
# 添加元素
LPUSH key value1 value2    # 在列表头部插入一个或多个值
RPUSH key value1 value2    # 在列表尾部插入一个或多个值

# 获取元素
LPOP key                   # 移除并获取列表头部的元素
RPOP key                   # 移除并获取列表尾部的元素
LRANGE key start stop      # 获取列表指定范围内的元素(索引从 0 开始)

# 其他操作
LLEN key                   # 获取列表长度
LINDEX key index           # 获取列表中指定索引的元素
LTRIM key start stop       # 修剪列表,只保留指定区间内的元素
LINSERT key BEFORE|AFTER pivot value  # 在元素 pivot 前或后插入值

使用示例

bash 复制代码
# 创建消息队列
LPUSH messages "消息1" "消息2" "消息3"
# 列表变为: ["消息3", "消息2", "消息1"]

# 获取消息
RPOP messages              # 返回 "消息1"
RPOP messages              # 返回 "消息2"

# 查看所有消息
LRANGE messages 0 -1        # -1 表示最后一个元素

# 最新动态列表(微博、推特等)
LPUSH user:1:timeline "发布了新文章"
LPUSH user:1:timeline "点赞了评论"
LPUSH user:1:timeline "关注了新用户"

# 获取最新 10 条动态
LRANGE user:1:timeline 0 9

# 列表长度
LLEN user:1:timeline        # 返回 3

# 获取指定位置的动态
LINDEX user:1:timeline 0    # 返回 "关注了新用户"

应用场景

  • 消息队列(生产者-消费者模式)
  • 最新动态(Timeline、时间轴)
  • 栈(LPOP/LPUSH)和队列(RPOP/LPUSH)
  • 文章评论列表

2.4 集合(Set)

特性

  • 存储无序、不重复的字符串集合
  • 类似于 Java 的 HashSet
  • 支持集合运算(并集、交集、差集)
  • 最多存储 2³² - 1 个元素

常用命令

bash 复制代码
# 基本操作
SADD key member1 member2    # 向集合添加一个或多个成员
SMEMBERS key                # 获取集合中的所有成员
SISMEMBER key member        # 判断 member 是否是集合的成员
SREM key member1 member2    # 移除集合中的一个或多个成员
SCARD key                   # 获取集合的成员数

# 集合运算
SUNION key1 key2            # 返回所有给定集合的并集
SINTER key1 key2            # 返回所有给定集合的交集
SDIFF key1 key2             # 返回所有给定集合的差集(key1 - key2)

# 随机操作
SRANDMEMBER key [count]     # 返回集合中一个或多个随机成员
SPOP key                    # 移除并返回集合中的一个随机成员

使用示例

bash 复制代码
# 标签系统
SADD article:1001:tags "Redis" "数据库" "缓存" "技术"
SADD article:1002:tags "MySQL" "数据库" "关系型"
SADD article:1003:tags "Redis" "缓存"

# 查看文章的所有标签
SMEMBERS article:1001:tags

# 共同关注(交集)
SADD user:1:following "用户A" "用户B" "用户C"
SADD user:2:following "用户B" "用户C" "用户D"
SINTER user:1:following user:2:following
# 返回: ["用户B", "用户C"]

# 推荐系统(差集)
# 找出用户1关注但用户2未关注的用户
SDIFF user:1:following user:2:following
# 返回: ["用户A"]

# 随机抽取获奖用户
SADD lottery:2024 "用户1" "用户2" "用户3" "用户4" "用户5"
SPOP lottery:2024            # 随机移除一个用户并返回

应用场景

  • 标签系统
  • 共同好友/共同关注
  • 推荐系统(基于共同兴趣)
  • 去重(如 UV 统计)
  • 抽奖系统

2.5 有序集合(Sorted Set)

特性

  • 集合中每个成员都关联一个分数(Score)
  • 根据分数自动排序
  • 分数可以重复,成员不可重复
  • 最多存储 2³² - 1 个元素

常用命令

bash 复制代码
# 基本操作
ZADD key score1 member1 score2 member2  # 向有序集合添加一个或多个成员
ZREM key member1 member2      # 移除有序集合中的一个或多个成员
ZSCORE key member             # 获取成员的分数

# 范围查询
ZRANGE key start stop [WITHSCORES]   # 返回有序集合中指定区间内的成员(按分数升序)
ZREVRANGE key start stop [WITHSCORES]  # 返回有序集合中指定区间内的成员(按分数降序)
ZRANGEBYSCORE key min max [WITHSCORES]  # 返回分数在指定区间内的成员
ZREVRANGEBYSCORE key max min [WITHSCORES]  # 降序返回

# 排名查询
ZRANK key member              # 返回成员在集合中的排名(升序,从 0 开始)
ZREVRANK key member           # 返回成员在集合中的排名(降序,从 0 开始)

# 统计操作
ZCARD key                     # 获取有序集合的成员数
ZCOUNT key min max            # 计算分数在指定区间内的成员数量
ZINCRBY key increment member  # 有序集合中对指定成员的分数加上增量

# 删除操作
ZREMRANGEBYRANK key start stop  # 移除指定排名区间内的所有成员
ZREMRANGEBYSCORE key min max    # 移除分数在指定区间内的所有成员

使用示例

bash 复制代码
# 排行榜系统
ZADD leaderboard 95 "玩家A" 87 "玩家B" 92 "玩家C" 88 "玩家D" 90 "玩家E"

# 获取前 10 名
ZREVRANGE leaderboard 0 9 WITHSCORES
# 返回:
# 1) "玩家A"
# 2) "95"
# 3) "玩家C"
# 4) "92"
# 5) "玩家E"
# 6) "90"
# ...

# 获取玩家排名
ZREVRANK leaderboard "玩家C"    # 返回 1(排名第2,从0开始)
ZREVRANK leaderboard "玩家B"    # 返回 4(排名第5)

# 获取玩家分数
ZSCORE leaderboard "玩家A"      # 返回 "95"

# 分数区间查询(获取分数在 90-100 之间的玩家)
ZRANGEBYSCORE leaderboard 90 100 WITHSCORES

# 玩家得分更新
ZINCRBY leaderboard 5 "玩家D"   # 玩家D分数增加5,从88变成93

# 实时新闻热度榜
ZADD news:hot:20240204 1000 "新闻A" 800 "新闻B" 1200 "新闻C"

# 每次用户点击新闻,增加热度
ZINCRBY news:hot:20240204 1 "新闻A"

# 获取热度最高的 5 条新闻
ZREVRANGE news:hot:20240204 0 4

应用场景

  • 排行榜(游戏积分榜、文章热度榜等)
  • 延时队列(使用分数作为时间戳)
  • 优先级队列
  • 范围查询(按分数范围获取数据)
  • 实时统计(如点击量、热度)

2.6 其他数据类型简介

Bitmap(位图)

  • 本质上是字符串,但按位操作
  • 用于存储二进制状态
  • 命令:SETBIT, GETBIT, BITCOUNT, BITOP
  • 应用:用户签到、在线状态等

HyperLogLog

  • 基数统计算法
  • 用于统计不重复元素的数量
  • 内存占用极少(12KB)
  • 应用:UV 统计、日活统计

Geo(地理位置)

  • 存储地理位置信息
  • 支持距离计算、范围查询
  • 命令:GEOADD, GEODIST, GEORADIUS
  • 应用:附近的人、地图服务

Stream(流)

  • Redis 5.0 新增
  • 消息队列的高级实现
  • 支持消费者组
  • 应用:日志收集、实时数据处理

三、使用场景分析

3.1 缓存

场景描述

将热点数据存储在 Redis 中,减少数据库压力,提高响应速度。

实现方式

bash 复制代码
# 缓存用户信息
# 1. 先查 Redis
GET user:info:1001

# 2. 如果 Redis 没有,查询数据库,然后写入 Redis
SET user:info:1001 '{"name":"张三","age":25}'
EXPIRE user:info:1001 3600  # 设置1小时过期

# 或者使用 SETEX 一步完成
SETEX user:info:1001 3600 '{"name":"张三","age":25}'

优点

  • 性能提升:内存读取速度远超磁盘数据库
  • 减少数据库压力:大量读请求由 Redis 处理
  • 降低成本:相比扩容数据库,使用 Redis 更经济

注意事项

  • 缓存穿透 :查询不存在的数据,绕过缓存直击数据库
    • 解决方案:布隆过滤器、缓存空值
  • 缓存雪崩 :大量缓存同时失效
    • 解决方案:随机过期时间、缓存预热
  • 缓存击穿 :热点 key 突然失效
    • 解决方案:互斥锁、永不过期

3.2 会话存储

场景描述

在分布式系统中,将用户 Session 信息存储在 Redis 中,实现会话共享。

实现方式

bash 复制代码
# 用户登录后,存储 Session
HSET session:abc123 user_id 1001
HSET session:abc123 username "张三"
HSET session:abc123 login_time 1707048000
EXPIRE session:abc123 7200  # 2小时过期

# 验证用户是否登录
HEXISTS session:abc123 user_id  # 返回 1 表示已登录

# 获取用户信息
HGET session:abc123 username  # 返回 "张三"

# 用户登出
DEL session:abc123

优点

  • 跨服务共享:多个服务实例可以共享 Session
  • 快速验证:Redis 响应速度快
  • 自动过期:设置 TTL 自动清理过期 Session

适用场景

  • 分布式 Web 应用
  • 移动端应用
  • 微服务架构

3.3 计数器

场景描述

统计文章阅读量、点赞数、商品销量等需要频繁更新的数值。

实现方式

bash 复制代码
# 文章阅读量
SET article:1001:views 0
INCR article:1001:views      # 每次阅读加 1

# 批量增加(如从其他数据源同步)
INCRBY article:1001:views 1000

# 获取阅读量
GET article:1001:views

# 点赞数(使用 Hash 存储多个维度)
HSET article:1001:stats views 10000
HSET article:1001:stats likes 500
HSET article:1001:stats comments 50

# 点赞操作
HINCRBY article:1001:stats likes 1

# 获取所有统计信息
HGETALL article:1001:stats

优点

  • 原子性操作:INCR 等操作是原子的,保证数据准确性
  • 高性能:支持高并发计数
  • 持久化:数据不会丢失(如果开启持久化)

适用场景

  • 文章阅读量/点赞数
  • 视频播放量
  • 商品销量统计
  • 日活/月活统计

3.4 排行榜

场景描述

游戏积分榜、文章热度榜、粉丝数排行等需要实时排序的场景。

实现方式

bash 复制代码
# 游戏积分榜
ZADD game:leaderboard 10000 "玩家A" 9500 "玩家B" 8800 "玩家C" 9200 "玩家D"

# 玩家得分后更新
ZINCRBY game:leaderboard 100 "玩家C"  # 玩家C增加100分

# 获取前 10 名
ZREVRANGE game:leaderboard 0 9 WITHSCORES

# 获取自己的排名
ZREVRANK game:leaderboard "玩家C"  # 返回排名

# 获取特定分数区间的玩家
ZRANGEBYSCORE game:leaderboard 9000 10000 WITHSCORES

# 文章热度榜(基于点赞数)
ZADD article:hot:20240204 100 "文章A" 200 "文章B" 150 "文章C"

# 每次点赞,增加热度
ZINCRBY article:hot:20240204 1 "文章A"

# 获取最热文章
ZREVRANGE article:hot:20240204 0 4

优点

  • 实时更新:分数变化后立即反映在排名中
  • 范围查询:可以查询特定排名或分数区间的数据
  • 高性能:即使有大量数据,查询依然快速

适用场景

  • 游戏积分榜
  • 文章热度榜
  • 商品销量排行
  • 粉丝数排行

3.5 消息队列

场景描述

使用 List 实现简单的消息队列,实现生产者-消费者模式。

实现方式

bash 复制代码
# 生产者:发送消息
LPUSH mq:tasks "任务1:发送邮件"
LPUSH mq:tasks "任务2:生成报表"
LPUSH mq:tasks "任务3:处理图片"

# 消费者:获取并处理消息
RPOP mq:tasks  # 返回 "任务1:发送邮件"

# 使用 BRPOP 实现阻塞式获取(无消息时阻塞等待)
BRPOP mq:tasks 30  # 最多等待 30 秒

优点

  • 简单易用:Redis List 天然支持队列操作
  • 高性能:基于内存,速度快
  • 持久化:消息不会丢失(如果开启持久化)

局限性

  • 不支持消息确认机制
  • 不支持复杂的消息路由
  • 不支持多个消费者组

高级替代方案:

  • Redis Stream(支持消费者组)
  • 专业的消息队列:RabbitMQ、Kafka 等

适用场景

  • 简单的任务队列
  • 异步处理(如发送邮件、生成报表)
  • 延时任务(配合有序集合)

3.6 分布式锁

场景描述

在分布式系统中,防止多个进程同时操作同一资源。

实现方式

bash 复制代码
# 加锁(使用 SET 命令一步完成)
SET lock:resource:1 "unique_value" NX EX 30
# NX:只在 key 不存在时设置
# EX:设置过期时间(秒)

# 解锁(确保只有锁的持有者才能解锁)
# Lua 脚本保证原子性
if redis.call("GET", KEYS[1]) == ARGV[1] then
    return redis.call("DEL", KEYS[1])
else
    return 0
end

优点

  • 简单易用:只需几条命令即可实现
  • 高性能:基于内存,加锁/解锁速度快
  • 自动过期:避免死锁

注意事项

  • 需要设置唯一的 value,确保只能释放自己的锁
  • 建议使用 Redisson 等成熟的客户端库
  • 对于高可靠性场景,建议使用 Redlock 算法

适用场景

  • 限时抢购
  • 库存扣减
  • 分布式任务调度

3.7 其他实用场景

标签系统(使用 Set)

bash 复制代码
# 添加标签
SADD user:1001:tags "程序员" "游戏玩家" "电影迷"

# 查找共同标签的用户
SINTER user:1001:tags user:1002:tags

限流(使用字符串 + 过期时间)

bash 复制代码
# 每分钟限制 100 次请求
INCR limit:api:1001:202402041028
EXPIRE limit:api:1001:202402041028 60

# 检查是否超限
GET limit:api:1001:202402041028
# 如果返回值 > 100,则拒绝请求

最近浏览(使用 List)

bash 复制代码
# 添加浏览记录
LPUSH recent:user:1001 "商品1"
LPUSH recent:user:1001 "商品2"
LPUSH recent:user:1001 "商品3"

# 只保留最近 10 条
LTRIM recent:user:1001 0 9

# 获取最近浏览
LRANGE recent:user:1001 0 -1

在线状态(使用 Bitmap)

bash 复制代码
# 记录用户在线状态(按位存储,每个 bit 代表一个用户)
SETBIT online:20240204 1001 1  # 用户 1001 在线
SETBIT online:20240204 1002 0  # 用户 1002 离线

# 统计在线人数
BITCOUNT online:20240204

# 检查用户是否在线
GETBIT online:20240204 1001  # 返回 1 表示在线

四、Redis 持久化方案深度解析

Redis 提供了两种主要的持久化方案:RDBAOF,以及两者的混合模式。正确选择持久化方案是 Redis 架构设计的核心决策点。

4.1 RDB(Redis Database)

工作原理

RDB 是 Redis 默认的持久化方式,它通过定期生成内存数据快照 并保存到磁盘上的 .rdb 文件来实现持久化。

复制代码
fork() → 子进程遍历内存数据 → 写入临时文件 → 原子性替换旧的 RDB 文件

优点

  1. 文件紧凑:二进制格式,文件体积小,适合备份和传输
  2. 恢复极快:服务重启时直接加载到内存,无需解析
  3. 对性能影响小:子进程完成持久化,主进程几乎不阻塞
  4. 适合灾难恢复:文件独立,可异地备份

缺点

  1. 数据丢失风险:最后一次快照后的数据会丢失(默认可能丢失 15 分钟数据)
  2. fork 开销:大数据量时 fork 会卡顿(毫秒到秒级)
  3. 不实时:无法做到秒级持久化

配置示例

bash 复制代码
# RDB 快照规则
save 900 1        # 900 秒内至少 1 个 key 变化时触发
save 300 10       # 300 秒内至少 10 个 key 变化时触发
save 60 10000     # 60 秒内至少 10000 个 key 变化时触发

# 其他配置
rdbcompression yes     # 压缩 RDB 文件
rdbchecksum yes        # 启用 CRC64 校验
rdbfilename dump.rdb    # RDB 文件名
dir /var/lib/redis     # 文件存储目录

最佳使用场景

  • ✅ 数据可容忍分钟级丢失(缓存、临时数据)
  • ✅ 需要快速备份和恢复
  • ✅ 定时备份到远程存储

4.2 AOF(Append Only File)

工作原理

AOF 通过记录所有写操作命令来实现持久化,类似于数据库的 WAL(Write-Ahead Log)。

复制代码
写命令 → 写入 AOF 缓冲区 → 写入磁盘(根据 fsync 策略)→ AOF 重写

三种 fsync 策略(核心差异)

策略 描述 性能影响 数据安全
always 每次写都 fsync 最低(性能下降 10-100 倍) 最高(不丢数据)
everysec 每秒 fsync(默认) 较好 最多丢 1 秒数据
no 由操作系统决定 fsync 最高 可能丢失更多数据

优点

  1. 数据安全:最多丢失 1 秒数据(everysec 策略)
  2. 可读性强:AOF 文件是文本格式,可人工查看和修复
  3. 自动重写:防止文件过大(当 AOF 文件超过上次重写后的一定比例时触发)
  4. 容错性好:Redis 启动时自动修复损坏的 AOF 文件

缺点

  1. 文件大:通常比 RDB 大 2-3 倍
  2. 恢复慢:需要重放所有命令,恢复速度较慢
  3. 性能影响大:频繁的磁盘写入影响性能

配置示例

bash 复制代码
# 启用 AOF
appendonly yes
appendfilename "appendonly.aof"

# fsync 策略
appendfsync everysec    # 推荐:每秒同步一次

# AOF 重写配置
auto-aof-rewrite-percentage 100   # 比上次重写后增长 100%
auto-aof-rewrite-min-size 64mb    # 最小 64MB 才触发重写

# AOF 加载恢复时,是否忽略最后可能损坏的命令
aof-load-truncated yes

最佳使用场景

  • ✅ 数据不能丢失(如账户余额、订单数据)
  • ✅ 需要审计能力(可查看历史操作记录)
  • ✅ 对数据完整性要求高

4.3 混合持久化(Redis 4.0+)

工作原理

混合持久化结合了 RDB 和 AOF 的优点:AOF 重写时,子进程将内存数据以 RDB 格式写入 AOF 文件开头,主进程将重写期间的新命令追加到文件末尾。

复制代码
AOF 文件结构:
[RDB 格式的数据快照] + [重写期间新增的 AOF 命令]

优势

  • 文件比纯 AOF 小
  • 恢复速度比纯 AOF 快
  • 数据安全性接近纯 AOF

配置示例

bash 复制代码
aof-use-rdb-preamble yes   # 启用混合持久化

推荐:生产环境优先开启。


4.4 持久化方案对比总结

方案 本质 写入方式 恢复速度 数据完整性 性能影响 文件大小
RDB 快照 间隔性全量写入 极快 可能丢失数秒到数分钟 低(fork 时有阻塞)
AOF 日志 实时追加写 较慢 最少丢失 1 秒数据 高(频繁写磁盘)
混合持久化 快照+日志 RDB+增量AOF 较快 最少丢失 1 秒数据

4.5 持久化方案选择决策树

复制代码
你的数据能容忍丢失吗?
│
├─ 能接受分钟级丢失 → RDB 单独使用
│   (推荐场景:缓存、临时数据)
│
└─ 不能接受丢失(或最多 1 秒)
    │
    ├─ 对性能要求极高 → RDB + AOF(fsync=no)
    │   (风险:可能丢失较多数据)
    │
    ├─ 平衡性能与安全 → RDB + AOF(fsync=everysec)+ 混合持久化
    │   (推荐:生产环境标准配置)
    │
    └─ 数据绝对安全 → AOF(fsync=always)
        (代价:性能下降 10-100 倍,慎重)

4.6 生产环境推荐配置

通用推荐(平衡性能与安全)

bash 复制代码
# RDB 配置
save 900 1
save 300 10
save 60 10000

# AOF 配置
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes   # 混合持久化

极致性能(可接受少量数据丢失)

bash 复制代码
# 仅使用 RDB
save 900 1
save 300 10
save 60 10000

appendonly no

极致安全(数据不可丢失)

bash 复制代码
# 仅使用 AOF,fsync=always
appendonly yes
appendfsync always

# 可选:同时启用 RDB 用于备份
save 900 1

4.7 持久化实战注意事项

主从复制的持久化策略

  • 主节点:建议启用 AOF,保证数据安全
  • 从节点:可以使用 RDB 或不持久化,从主节点同步数据即可
  • 原因:从节点宕机不影响主节点数据

监控指标

bash 复制代码
# 查看持久化状态
INFO persistence

# 关注指标:
# rdb_last_bgsave_time_sec:上次 RDB 耗时
# aof_last_rewrite_time_sec:上次 AOF 重写耗时
# aof_rewrite_in_progress:是否正在重写

灾难恢复流程

  1. 停止 Redis 服务
  2. 检查 RDB 和 AOF 文件完整性
  3. 优先使用 AOF 恢复(更完整)
  4. 若 AOF 损坏,尝试使用 redis-check-aof 修复
  5. 若修复失败,使用 RDB 恢复
  6. 启动 Redis,验证数据

4.8 常见问题

Q1:RDB 和 AOF 同时开启,哪个优先?

A: 重启时优先使用 AOF 文件恢复(因为它更完整)。

Q2:fork 卡顿怎么解决?

A:

  • 调整 repl-backlog-size 增大缓冲区
  • 使用无 fork 持久化(Redis 6.0+ 的无 fork AOF)
  • 拆分实例,减少单个实例数据量

Q3:AOF 文件太大怎么办?

A:

  • 自动重写会触发(auto-aof-rewrite-percentage
  • 手动执行 BGREWRITEAOF
  • 开启混合持久化

Q4:如何禁用持久化?

A: 将 save "" 注释所有 RDB 规则,appendonly no 禁用 AOF。仅用于纯缓存场景。


五、实战练习

练习 1:构建简单的用户缓存系统

目标:实现用户信息的缓存,包含设置、获取、过期操作。

bash 复制代码
# 1. 设置用户信息
HSET user:1001 name "张三"
HSET user:1001 age 25
HSET user:1001 email "zhangsan@example.com"

# 2. 设置过期时间(1小时)
EXPIRE user:1001 3600

# 3. 获取用户信息
HGET user:1001 name

# 4. 检查用户是否存在
EXISTS user:1001

# 5. 查看剩余过期时间
TTL user:1001

练习 2:实现文章阅读量统计

目标:统计文章的阅读量和点赞数。

bash 复制代码
# 1. 初始化文章统计
HSET article:1001 stats:views 0
HSET article:1001 stats:likes 0
HSET article:1001 stats:comments 0

# 2. 文章被阅读
HINCRBY article:1001 stats:views 1

# 3. 文章被点赞
HINCRBY article:1001 stats:likes 1

# 4. 获取文章统计数据
HGETALL article:1001

# 5. 获取阅读量
HGET article:1001 stats:views

练习 3:构建游戏排行榜

目标:实现实时游戏积分榜,支持分数更新和排名查询。

bash 复制代码
# 1. 添加玩家积分
ZADD game:leaderboard 1000 "玩家A" 950 "玩家B" 880 "玩家C" 920 "玩家D"

# 2. 玩家得分
ZINCRBY game:leaderboard 50 "玩家C"

# 3. 获取前 3 名
ZREVRANGE game:leaderboard 0 2 WITHSCORES

# 4. 获取自己的排名
ZREVRANK game:leaderboard "玩家B"

# 5. 获取积分在 900-1000 之间的玩家
ZRANGEBYSCORE game:leaderboard 900 1000 WITHSCORES

练习 4:实现简单的消息队列

目标:使用 List 实现生产者-消费者模式的消息队列。

bash 复制代码
# 生产者:发送任务
LPUSH task:queue "发送邮件给用户1001"
LPUSH task:queue "生成月度报表"
LPUSH task:queue "处理图片压缩"

# 消费者:处理任务
RPOP task:queue  # 获取并移除任务

# 查看队列中剩余任务数
LLEN task:queue

# 查看所有待处理任务
LRANGE task:queue 0 -1

六、总结与最佳实践

6.1 Redis 的优势总结

  1. 极致性能:基于内存,响应速度快,QPS 高
  2. 丰富数据结构:支持多种数据类型,满足不同场景需求
  3. 原子性操作:保证数据一致性
  4. 持久化支持:数据不会因服务重启而丢失
  5. 分布式支持:主从复制、哨兵、集群保证高可用
  6. 简单易用:命令简单直观,学习成本低

6.2 最佳实践

Key 命名规范

bash 复制代码
# 使用冒号分隔
user:1001:info
article:1001:views
session:abc123

# 使用有意义的名称,避免过长
# ❌ bad
# ✅ good

内存优化

  • 选择合适的数据结构
  • 及时设置过期时间
  • 使用压缩列表(List、Hash、Set、ZSet 的内部编码)

性能优化

  • 使用 Pipeline 批量操作
  • 避免大 key(单个 key 的 value 过大)
  • 使用 Lua 脚本实现原子性复杂操作
  • 合理配置 maxmemory 和淘汰策略

安全性

  • 设置密码(requirepass)
  • 禁用危险命令(FLUSHALL、FLUSHDB、KEYS 等)
  • 使用 ACL(访问控制列表)
  • 网络隔离(防火墙)

持久化选择

场景 推荐方案
生产环境标准配置 RDB + AOF(everysec)+ 混合持久化
纯缓存(数据可丢) RDB 单独使用或完全不持久化
金融/订单等核心数据 AOF(everysec 或 always)
备份/灾难恢复 RDB 定期备份到远程

附录:常用命令速查表

命令 描述
通用命令
SET key value 设置 key-value
GET key 获取 key 的值
DEL key 删除 key
EXISTS key 判断 key 是否存在
EXPIRE key seconds 设置过期时间
TTL key 获取剩余过期时间
字符串
INCR key 值加 1
DECR key 值减 1
INCRBY key increment 值增加指定数值
APPEND key value 追加字符串
哈希
HSET key field value 设置字段
HGET key field 获取字段值
HGETALL key 获取所有字段
HINCRBY key field inc 字段值增加
列表
LPUSH key value 头部插入
RPUSH key value 尾部插入
LPOP key 头部弹出
RPOP key 尾部弹出
LRANGE key start stop 获取范围
集合
SADD key member 添加成员
SMEMBERS key 获取所有成员
SISMEMBER key member 判断成员是否存在
SUNION key1 key2 并集
SINTER key1 key2 交集
有序集合
ZADD key score member 添加成员
ZRANGE key start stop 获取范围(升序)
ZREVRANGE key start stop 获取范围(降序)
ZINCRBY key inc member 分数增加
ZSCORE key member 获取分数
ZREVRANK key member 获取排名(降序)

结语

Redis 的强大之处不仅在于其高性能,更在于其丰富的数据结构能够优雅地解决各种复杂业务场景。持续学习和实践,你将能够在实际项目中游刃有余地运用 Redis。

相关推荐
m0_706653232 小时前
用Python批量处理Excel和CSV文件
jvm·数据库·python
山岚的运维笔记2 小时前
SQL Server笔记 -- 第15章:INSERT INTO
java·数据库·笔记·sql·microsoft·sqlserver
Lw老王要学习3 小时前
CentOS 7.9达梦数据库安装全流程解析
linux·运维·数据库·centos·达梦
qq_423233903 小时前
Python深度学习入门:TensorFlow 2.0/Keras实战
jvm·数据库·python
Wasim4043 小时前
【渗透测试】SQL注入
网络·数据库·sql
laplace01234 小时前
Claude Code 逆向工程报告 笔记(学习记录)
数据库·人工智能·笔记·学习·agent·rag
難釋懷4 小时前
优惠卷秒杀集群环境下的并发问题
redis·缓存
2401_836563184 小时前
用Python读取和处理NASA公开API数据
jvm·数据库·python
2301_818732064 小时前
项目启动报错,错误指向xml 已解决
xml·java·数据库·后端·springboot