Redis入门与实践

30 阅读6分钟

Redis入门与实践

Redis 基础概念

Redis(Remote Dictionary Server)是一个开源的内存数据结构存储系统,可以用作数据库、缓存、消息代理和流引擎。Redis 提供了多种数据结构,如字符串、哈希、列表、集合、有序集合等。

Redis 核心特性

// Redis 核心特性
const redisFeatures = {
  内存存储: "数据存储在内存中,读写速度极快",
  持久化: "支持RDB快照和AOF日志两种持久化方式",
  数据结构: "丰富的数据类型支持",
  高可用: "支持主从复制、哨兵模式、集群模式",
  事务支持: "支持事务和管道操作",
  发布订阅: "内置消息发布订阅功能",
  脚本支持: "支持Lua脚本执行"
};

Redis 应用场景

graph TD
    A[Redis应用场景] --> B[缓存系统]
    A --> C[会话存储]
    A --> D[实时应用]
    A --> E[消息队列]
    A --> F[分布式锁]
    
    B --> G[页面缓存]
    B --> H[数据库查询缓存]
    B --> I[API响应缓存]
    
    C --> J[用户登录状态]
    C --> K[购物车数据]
    C --> L[临时数据存储]
    
    D --> M[排行榜]
    D --> N[计数器]
    D --> O[限流控制]
    
    E --> P[任务队列]
    E --> Q[发布订阅]
    E --> R[流处理]
    
    F --> S[并发控制]
    F --> T[资源访问控制]

Redis vs 传统数据库

// Redis 与传统数据库对比
const redisVsDatabase = {
  Redis: {
    存储方式: "内存存储,可选持久化",
    数据模型: "键值对,多种数据结构",
    查询语言: "命令式操作",
    ACID: "有限支持(事务、原子性)",
    扩展性: "主从复制、集群分片",
    性能: "极高(微秒级)",
    使用场景: "缓存、会话、实时计算"
  },
  传统数据库: {
    存储方式: "磁盘存储",
    数据模型: "关系模型、表结构",
    查询语言: "SQL",
    ACID: "完整支持",
    扩展性: "垂直扩展为主",
    性能: "较高(毫秒级)",
    使用场景: "事务处理、数据分析"
  }
};

Docker 安装 Redis

基础安装

# 拉取 Redis 官方镜像
docker pull redis:7-alpine

# 运行 Redis 容器
docker run -d \
  --name redis-server \
  -p 6379:6379 \
  redis:7-alpine

# 进入 Redis 命令行
docker exec -it redis-server redis-cli

生产环境配置

// Redis 生产环境配置参数
const redisProductionConfig = {
  内存管理: {
    maxmemory: "2gb",
    maxmemoryPolicy: "allkeys-lru"
  },
  持久化: {
    save: "900 1 300 10 60 10000",
    appendonly: "yes",
    appendfsync: "everysec"
  },
  安全配置: {
    requirepass: "strong_password",
    bindAddress: "127.0.0.1"
  },
  网络配置: {
    port: 6379,
    tcpBacklog: 511,
    timeout: 300
  }
};
# 创建 Redis 配置文件
cat > redis.conf << EOF
# 网络配置
bind 127.0.0.1
port 6379
timeout 300

# 内存配置
maxmemory 2gb
maxmemory-policy allkeys-lru

# 持久化配置
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfsync everysec

# 安全配置
requirepass your_strong_password_here
EOF

# 使用自定义配置运行 Redis
docker run -d \
  --name redis-production \
  -p 6379:6379 \
  -v $(pwd)/redis.conf:/usr/local/etc/redis/redis.conf \
  -v redis-data:/data \
  redis:7-alpine \
  redis-server /usr/local/etc/redis/redis.conf

Redis 启动流程

flowchart TD
    A[启动 Redis 服务] --> B[加载配置文件]
    B --> C[初始化数据结构]
    C --> D[加载持久化数据]
    D --> E{AOF 文件存在?}
    E --> F[是] --> G[加载 AOF 文件]
    E --> H[否] --> I{RDB 文件存在?}
    I --> J[是] --> K[加载 RDB 文件]
    I --> L[否] --> M[空数据库启动]
    G --> N[启动事件循环]
    K --> N
    M --> N
    N --> O[监听客户端连接]
    O --> P[Redis 服务就绪]

Redis 核心操作与 SQL 对比

设置键值对

Redis 操作
// Redis SET 操作
const redisSetOperations = {
  基本设置: "SET key value",
  带过期时间: "SET key value EX seconds",
  条件设置: "SET key value NX", // 仅当key不存在时设置
  批量设置: "MSET key1 value1 key2 value2"
};
# 基本设置
SET user:1001:name "张三"
SET user:1001:email "zhangsan@example.com"

# 设置带过期时间的键(30分钟)
SET session:abc123 "user_data" EX 1800

# 条件设置(仅当不存在时)
SET config:app_name "MyApp" NX

# 批量设置
MSET user:1001:age 25 user:1001:city "北京"
SQL 对比
-- SQL 中的等价操作
INSERT INTO users (id, name, email) VALUES (1001, '张三', 'zhangsan@example.com')
ON CONFLICT (id) DO UPDATE SET 
    name = EXCLUDED.name, 
    email = EXCLUDED.email;

-- 会话存储需要专门的表
INSERT INTO sessions (session_id, user_data, expires_at) 
VALUES ('abc123', 'user_data', NOW() + INTERVAL '30 minutes');

获取键值

Redis 操作
// Redis GET 操作
const redisGetOperations = {
  获取单个值: "GET key",
  批量获取: "MGET key1 key2 key3",
  获取并设置: "GETSET key newvalue",
  模糊匹配: "KEYS pattern",
  检查存在: "EXISTS key"
};
# 获取单个值
GET user:1001:name

# 批量获取
MGET user:1001:name user:1001:email user:1001:age

# 获取所有用户相关的键
KEYS user:1001:*

# 检查键是否存在
EXISTS session:abc123

# 获取键的剩余过期时间
TTL session:abc123
SQL 对比
-- SQL 查询操作
SELECT name FROM users WHERE id = 1001;

-- 批量查询
SELECT id, name, email, age FROM users WHERE id IN (1001, 1002, 1003);

-- 模糊匹配
SELECT * FROM sessions WHERE session_id LIKE 'abc%';

-- 检查存在性
SELECT EXISTS(SELECT 1 FROM users WHERE id = 1001);

删除键值

Redis 操作
// Redis DELETE 操作
const redisDeleteOperations = {
  删除单个: "DEL key",
  删除多个: "DEL key1 key2 key3",
  模糊删除: "先KEYS匹配,再DEL删除",
  设置过期: "EXPIRE key seconds",
  清空数据库: "FLUSHDB"
};
# 删除单个键
DEL user:1001:temp_data

# 删除多个键
DEL user:1001:cache user:1001:session

# 模糊删除(先匹配再删除)
redis-cli KEYS "temp:*" | xargs redis-cli DEL

# 设置键过期时间
EXPIRE user:1001:cache 3600

# 移除键的过期时间
PERSIST user:1001:name
SQL 对比
-- SQL 删除操作
DELETE FROM users WHERE id = 1001;

-- 条件删除
DELETE FROM sessions WHERE expires_at < NOW();

-- 清空表
TRUNCATE TABLE temp_data;

使用 Redis 的多种数据类型

字符串(String)

String 是 Redis 最基础的数据类型,可以存储文本、数字、二进制数据。

// String 类型操作示例
const stringOperations = {
  设置: "SET key value",
  获取: "GET key",
  追加: "APPEND key value",
  数值操作: "INCR key / DECR key",
  批量操作: "MSET / MGET"
};
# 基础字符串操作
SET user:profile:bio "全栈开发工程师,专注于前端架构设计"
GET user:profile:bio

# 数值操作
SET page:views 1000
INCR page:views          # 增加1,返回1001
INCRBY page:views 10     # 增加10,返回1011
DECR page:views          # 减少1,返回1010

# 字符串追加
SET log:error "Database connection failed"
APPEND log:error " at 2024-01-15 10:30:00"

# 获取字符串长度
STRLEN log:error

# 获取子字符串
GETRANGE user:profile:bio 0 5
哈希(Hash)

Hash 用于存储对象的多个字段,类似于关系数据库中的行。

// Hash 类型操作示例
const hashOperations = {
  设置字段: "HSET key field value",
  获取字段: "HGET key field",
  批量设置: "HMSET key field1 value1 field2 value2",
  获取所有: "HGETALL key",
  字段操作: "HDEL / HEXISTS / HLEN"
};
# 设置用户信息
HSET user:1001 name "张三" email "zhangsan@example.com" age 28 city "北京"

# 获取特定字段
HGET user:1001 name
HGET user:1001 email

# 批量获取
HMGET user:1001 name email age

# 获取所有字段
HGETALL user:1001

# 检查字段是否存在
HEXISTS user:1001 phone

# 删除字段
HDEL user:1001 age

# 数值字段操作
HINCRBY user:1001 login_count 1

# 获取所有字段名
HKEYS user:1001

# 获取所有值
HVALS user:1001
列表 (List)

List 是有序的字符串列表,支持在两端进行推入和弹出操作。

// List 类型操作示例
const listOperations = {
  左侧推入: "LPUSH key value",
  右侧推入: "RPUSH key value",
  左侧弹出: "LPOP key",
  右侧弹出: "RPOP key",
  范围获取: "LRANGE key start stop",
  长度获取: "LLEN key"
};
# 创建任务队列
RPUSH task:queue "发送邮件" "生成报告" "清理缓存"

# 获取队列长度
LLEN task:queue

# 查看队列内容
LRANGE task:queue 0 -1

# 从队列头部取出任务
LPOP task:queue

# 在指定位置插入
LINSERT task:queue BEFORE "生成报告" "数据备份"

# 设置指定索引的值
LSET task:queue 1 "更新报告模板"

# 移除指定值
LREM task:queue 1 "清理缓存"

# 保留指定范围的元素
LTRIM task:queue 0 9  # 只保留前10个元素

# 阻塞式弹出(用于实现队列)
BLPOP task:queue 30  # 30秒超时
集合 (Set)

Set 是无序的字符串集合,所有元素都是唯一的。

// Set 类型操作示例
const setOperations = {
  添加元素: "SADD key member",
  移除元素: "SREM key member",
  检查成员: "SISMEMBER key member",
  获取所有: "SMEMBERS key",
  集合运算: "SINTER / SUNION / SDIFF",
  随机获取: "SRANDMEMBER key count"
};
# 创建用户标签集合
SADD user:1001:tags "JavaScript" "React" "Node.js" "PostgreSQL"
SADD user:1002:tags "Python" "Django" "PostgreSQL" "Redis"

# 检查用户是否有特定标签
SISMEMBER user:1001:tags "React"

# 获取用户所有标签
SMEMBERS user:1001:tags

# 获取集合大小
SCARD user:1001:tags

# 两个用户的共同技能(交集)
SINTER user:1001:tags user:1002:tags

# 所有技能的并集
SUNION user:1001:tags user:1002:tags

# 用户1独有的技能(差集)
SDIFF user:1001:tags user:1002:tags

# 随机获取技能
SRANDMEMBER user:1001:tags 2

# 移除标签
SREM user:1001:tags "Node.js"

# 将元素从一个集合移动到另一个
SMOVE user:1001:tags user:1001:archived_tags "React"
有序集合 (Sorted Set)

Sorted Set 是有序的集合,每个元素都有一个分数(score),按分数排序。

// Sorted Set 类型操作示例
const sortedSetOperations = {
  添加元素: "ZADD key score member",
  范围查询: "ZRANGE key start stop",
  分数查询: "ZRANGEBYSCORE key min max",
  排名查询: "ZRANK key member",
  分数获取: "ZSCORE key member",
  移除元素: "ZREM key member"
};
# 创建用户积分排行榜
ZADD leaderboard 1500 "张三" 1200 "李四" 1800 "王五" 1350 "赵六"

# 获取排行榜前3名(按分数从高到低)
ZREVRANGE leaderboard 0 2 WITHSCORES

# 获取排行榜后3名(按分数从低到高)
ZRANGE leaderboard 0 2 WITHSCORES

# 获取指定分数范围的用户
ZRANGEBYSCORE leaderboard 1300 1600 WITHSCORES

# 获取用户排名(从0开始,分数从低到高)
ZRANK leaderboard "张三"

# 获取用户排名(从0开始,分数从高到低)
ZREVRANK leaderboard "张三"

# 获取用户分数
ZSCORE leaderboard "张三"

# 增加用户分数
ZINCRBY leaderboard 100 "张三"

# 获取指定排名范围的用户数量
ZCOUNT leaderboard 1200 1500

# 移除分数最低的用户
ZREMRANGEBYRANK leaderboard 0 0

# 移除分数在指定范围内的用户
ZREMRANGEBYSCORE leaderboard 0 1000

Redis 数据类型选择流程

flowchart TD
    A[选择Redis数据类型] --> B{数据特征}
    
    B --> C[简单键值对]
    B --> D[对象多属性]
    B --> E[有序列表]
    B --> F[唯一元素集合]
    B --> G[带权重排序]
    
    C --> H[String]
    D --> I[Hash]
    E --> J[List]
    F --> K[Set]
    G --> L[Sorted Set]
    
    H --> M[缓存、计数器、会话]
    I --> N[用户信息、配置对象]
    J --> O[消息队列、时间线]
    K --> P[标签、去重、关系]
    L --> Q[排行榜、评分系统]
    
    subgraph "使用建议"
        R[考虑内存使用]
        S[考虑操作复杂度]
        T[考虑业务场景]
    end

用户登录身份存储与 PostgreSQL 集成

使用 Redis 存储用户登录会话

会话管理架构
sequenceDiagram
    participant Client as 客户端
    participant App as 应用服务
    participant Redis as Redis缓存
    participant DB as PostgreSQL
    
    Client->>App: 用户登录请求
    App->>DB: 验证用户凭据
    DB-->>App: 返回用户信息
    App->>Redis: 存储会话数据
    Redis-->>App: 返回会话ID
    App-->>Client: 返回登录成功+Token
    
    Client->>App: 访问受保护资源
    App->>Redis: 验证会话
    Redis-->>App: 返回会话数据
    App-->>Client: 返回受保护资源
实现会话存储
// 会话管理配置
const sessionConfig = {
  prefix: "session:",
  expire: 3600 * 24 * 7, // 7天过期
  refreshThreshold: 3600, // 1小时内活动则刷新
  userPrefix: "user:session:",
  maxSessions: 5 // 每用户最大会话数
};
# 用户登录成功后存储会话
SET session:abc123def456 "{\"userId\": 1001, \"username\": \"zhangsan\", \"loginTime\": \"2024-01-15T10:30:00Z\", \"ip\": \"192.168.1.100\"}" EX 604800

# 为用户维护活跃会话列表
SADD user:session:1001 "abc123def456"

# 设置用户会话列表过期时间
EXPIRE user:session:1001 604800

# 存储会话元数据
HSET session:meta:abc123def456 user_id 1001 created_at "2024-01-15T10:30:00Z" last_active "2024-01-15T10:30:00Z" ip "192.168.1.100"
EXPIRE session:meta:abc123def456 604800
会话验证与刷新
// 会话验证逻辑
const sessionValidation = {
  验证流程: [
    "检查会话是否存在",
    "检查会话是否过期",
    "更新最后活跃时间",
    "检查IP变化(可选)",
    "返回用户信息"
  ],
  刷新条件: [
    "距离上次活跃超过阈值",
    "用户执行重要操作",
    "主动刷新请求"
  ]
};
# 验证会话并获取用户信息
GET session:abc123def456

# 检查会话是否存在
EXISTS session:abc123def456

# 更新会话最后活跃时间
HSET session:meta:abc123def456 last_active "2024-01-15T11:30:00Z"
EXPIRE session:abc123def456 604800

# 获取用户所有活跃会话
SMEMBERS user:session:1001

# 检查用户会话数量是否超限
SCARD user:session:1001

# 清理过期的用户会话引用
# 这需要应用程序定期执行清理任务
会话清理与安全
# 用户主动登出
DEL session:abc123def456
DEL session:meta:abc123def456
SREM user:session:1001 "abc123def456"

# 清理用户所有会话(强制登出)
# 1. 获取用户所有会话
SMEMBERS user:session:1001

# 2. 删除所有会话数据(需要脚本批量执行)
# 3. 清空用户会话集合
DEL user:session:1001

# 设置会话黑名单(用于安全控制)
SADD session:blacklist "abc123def456"
EXPIRE session:blacklist 604800

将 Redis 与 PostgreSQL 集成

集成架构设计
graph TD
    subgraph "应用层"
        A[Web应用] --> B[会话中间件]
        B --> C[缓存管理器]
    end
    
    subgraph "缓存层"
        D[Redis集群]
        E[会话存储]
        F[用户缓存]
        G[权限缓存]
        
        D --> E
        D --> F
        D --> G
    end
    
    subgraph "数据层"
        H[PostgreSQL主库]
        I[用户表]
        J[权限表]
        K[审计日志表]
        
        H --> I
        H --> J
        H --> K
    end
    
    C --> D
    C --> H
    
    subgraph "数据流"
        L[热数据] --> D
        M[冷数据] --> H
        N[持久化数据] --> H
    end
用户信息缓存策略
// 缓存策略配置
const cacheStrategy = {
  用户基础信息: {
    key: "user:info:{userId}",
    expire: 3600, // 1小时
    source: "users表",
    updateTrigger: ["用户信息变更", "定期刷新"]
  },
  用户权限: {
    key: "user:permissions:{userId}",
    expire: 1800, // 30分钟
    source: "用户权限关联查询",
    updateTrigger: ["权限变更", "角色变更"]
  },
  用户偏好: {
    key: "user:preferences:{userId}",
    expire: 7200, // 2小时
    source: "用户配置表",
    updateTrigger: ["设置变更"]
  }
};
# 缓存用户基础信息
HSET user:info:1001 \
  username "zhangsan" \
  email "zhangsan@example.com" \
  display_name "张三" \
  avatar_url "/avatars/1001.jpg" \
  last_login "2024-01-15T10:30:00Z"
EXPIRE user:info:1001 3600

# 缓存用户权限
SADD user:permissions:1001 "user:read" "user:update" "order:create" "order:read"
EXPIRE user:permissions:1001 1800

# 缓存用户角色
SADD user:roles:1001 "customer" "premium_user"
EXPIRE user:roles:1001 1800

# 缓存用户统计信息
HSET user:stats:1001 \
  login_count 156 \
  last_order_date "2024-01-10" \
  total_orders 23 \
  loyalty_points 1250
EXPIRE user:stats:1001 7200
缓存更新策略
// 缓存更新模式
const cacheUpdatePatterns = {
  Cache_Aside: "应用程序负责缓存的读写",
  Write_Through: "数据同时写入缓存和数据库",
  Write_Behind: "先写缓存,异步写数据库",
  Refresh_Ahead: "在缓存过期前主动刷新"
};

// 缓存失效策略
const cacheInvalidation = {
  TTL过期: "设置合理的过期时间",
  主动失效: "数据变更时删除缓存",
  标签失效: "使用标签批量失效相关缓存",
  版本控制: "使用版本号控制缓存有效性"
};
# 缓存失效示例
# 1. 用户信息更新后,删除相关缓存
DEL user:info:1001
DEL user:stats:1001

# 2. 批量失效用户相关缓存
redis-cli KEYS "user:*:1001" | xargs redis-cli DEL

# 3. 使用管道操作提高效率
redis-cli --pipe <<EOF
DEL user:info:1001
DEL user:permissions:1001
DEL user:preferences:1001
EOF

# 4. 设置缓存版本控制
SET cache:version:user:1001 "v2024011501"
EXPIRE cache:version:user:1001 86400
数据一致性保证
flowchart TD
    A[数据变更请求] --> B[开始数据库事务]
    B --> C[更新PostgreSQL]
    C --> D{更新成功?}
    D --> E[是] --> F[提交事务]
    D --> G[否] --> H[回滚事务]
    
    F --> I[删除Redis缓存]
    I --> J{缓存删除成功?}
    J --> K[是] --> L[返回成功]
    J --> M[否] --> N[记录日志,异步清理]
    
    H --> O[返回错误]
    N --> P[后台清理任务]
    
    subgraph "一致性策略"
        Q[最终一致性]
        R[强一致性要求]
        S[容错机制]
    end

Redis 进阶应用

Redis 事务(Transactions)

Redis 事务允许一组命令在单一步骤中执行,具有隔离性和原子性。

事务特性
// Redis 事务特性
const transactionFeatures = {
  原子性: "所有命令要么全部执行,要么全部不执行",
  隔离性: "事务中的命令不会被其他客户端插入的命令打断",
  一致性: "事务执行前后,数据处于一致状态",
  持久性: "取决于Redis的持久化配置"
};

// 事务命令
const transactionCommands = {
  MULTI: "开始事务",
  EXEC: "执行事务",
  DISCARD: "取消事务",
  WATCH: "监视键变化",
  UNWATCH: "取消监视"
};
使用示例:
# 基础事务示例:转账操作
MULTI
DECRBY account:user1:balance 100
INCRBY account:user2:balance 100
EXEC

# 带条件的事务:库存扣减
WATCH product:1001:stock
stock_value=$(redis-cli GET product:1001:stock)
if [ $stock_value -gt 0 ]; then
    redis-cli MULTI
    redis-cli DECR product:1001:stock
    redis-cli LPUSH order:queue "product:1001:order:12345"
    redis-cli EXEC
else
    echo "库存不足"
fi

# 复杂业务事务:用户注册
MULTI
INCR user:count
SET user:1002:profile "{\"name\": \"李四\", \"email\": \"lisi@example.com\"}"
SADD users:active 1002
ZADD users:registered $(date +%s) 1002
EXEC

# 使用 WATCH 实现乐观锁
WATCH user:1001:balance
balance=$(redis-cli GET user:1001:balance)
if [ $balance -ge 50 ]; then
    redis-cli MULTI
    redis-cli DECRBY user:1001:balance 50
    redis-cli INCRBY user:1001:spent 50
    redis-cli LPUSH purchase:history "user:1001:purchase:$(date +%s)"
    redis-cli EXEC
else
    redis-cli UNWATCH
    echo "余额不足"
fi
注意事项:
// Redis 事务注意事项
const transactionCaveats = {
  非关系型事务: "Redis不支持回滚,命令执行错误会继续执行其他命令",
  语法错误: "如果事务中有语法错误,整个事务会被拒绝",
  运行时错误: "如果某个命令执行失败,其他命令仍会执行",
  WATCH机制: "被监视的键发生变化时,事务会被取消",
  性能考虑: "事务会阻塞其他操作,应避免长时间事务"
};

Redis 持久化(Persistence)

Redis 提供两种持久化方式:RDB 快照和 AOF 日志。

RDB 持久化

RDB 是在指定时间间隔内生成数据集的快照。

// RDB 配置参数
const rdbConfig = {
  触发条件: {
    save_900_1: "900秒内至少1个键发生变化",
    save_300_10: "300秒内至少10个键发生变化", 
    save_60_10000: "60秒内至少10000个键发生变化"
  },
  优势: [
    "文件紧凑,适合备份",
    "恢复速度快",
    "对性能影响小"
  ],
  劣势: [
    "可能丢失最近的数据",
    "fork子进程时可能阻塞",
    "不适合实时性要求高的场景"
  ]
};
# RDB 配置示例
save 900 1     # 15分钟内至少1个键变化时保存
save 300 10    # 5分钟内至少10个键变化时保存  
save 60 10000  # 1分钟内至少10000个键变化时保存

# 手动触发快照
BGSAVE  # 后台保存
SAVE    # 前台保存(会阻塞)

# 获取最后一次保存时间
LASTSAVE

# 禁用 RDB
redis-cli CONFIG SET save ""

# 动态修改 RDB 配置
CONFIG SET save "300 10 60 1000"
AOF 持久化

AOF 记录每个写操作命令,通过重新执行命令来恢复数据。

// AOF 配置参数
const aofConfig = {
  同步策略: {
    always: "每个写命令都同步到磁盘(最安全但最慢)",
    everysec: "每秒同步一次(默认,平衡安全性和性能)",
    no: "由操作系统决定何时同步(最快但最不安全)"
  },
  重写机制: {
    auto_aof_rewrite_percentage: "AOF文件增长百分比",
    auto_aof_rewrite_min_size: "AOF文件最小重写大小"
  }
};
# AOF 配置
appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 手动触发 AOF 重写
BGREWRITEAOF

# 检查 AOF 状态
INFO persistence

# 修复损坏的 AOF 文件
redis-check-aof --fix appendonly.aof

持久化策略选择

flowchart TD
    A[选择持久化策略] --> B{业务需求}
    
    B --> C[数据安全性优先]
    B --> D[性能优先]
    B --> E[存储空间优先]
    B --> F[恢复速度优先]
    
    C --> G[AOF + everysec]
    D --> H[RDB + 适当间隔]
    E --> I[RDB]
    F --> J[RDB]
    
    G --> K[最小数据丢失]
    H --> L[高性能写入]
    I --> M[文件体积小]
    J --> N[快速启动]
    
    subgraph "混合策略"
        O[RDB + AOF] --> P[最佳可靠性]
        Q[定期RDB + 短期AOF] --> R[平衡方案]
    end

Redis 发布/订阅 (Pub/Sub)

Redis 的发布/订阅功能允许客户端订阅频道,并接收发布到这些频道的消息。

发布/订阅模型
graph TD
    subgraph "发布者"
        A[应用A] --> B[PUBLISH]
        C[应用B] --> B
        D[应用C] --> B
    end
    
    subgraph "Redis服务器"
        B --> E[频道路由]
        E --> F[user:notifications]
        E --> G[system:alerts]
        E --> H[order:updates]
    end
    
    subgraph "订阅者"
        F --> I[客户端1]
        F --> J[客户端2]
        G --> K[监控系统]
        H --> L[订单服务]
        H --> M[通知服务]
    end
发布/订阅示例
// 发布订阅场景
const pubsubScenarios = {
  实时通知: "用户通知、系统消息",
  聊天系统: "群聊、私聊消息",
  事件驱动: "订单状态变更、库存更新",
  监控告警: "系统状态、性能指标",
  日志收集: "应用日志、错误日志"
};
# 订阅频道(客户端1)
SUBSCRIBE user:notifications system:alerts

# 模式订阅(订阅所有用户通知)
PSUBSCRIBE user:*

# 发布消息
PUBLISH user:notifications "{\"type\": \"order\", \"message\": \"您的订单已发货\", \"userId\": 1001}"
PUBLISH system:alerts "{\"level\": \"warning\", \"message\": \"CPU使用率超过80%\", \"timestamp\": \"2024-01-15T10:30:00Z\"}"

# 查看频道信息
PUBSUB CHANNELS    # 查看所有活跃频道
PUBSUB CHANNELS user:*  # 查看匹配模式的频道
PUBSUB NUMSUB user:notifications  # 查看频道订阅者数量

# 取消订阅
UNSUBSCRIBE user:notifications
PUNSUBSCRIBE user:*
消息队列实现
# 使用 List 实现消息队列
# 生产者
LPUSH message:queue "{\"id\": 1, \"type\": \"email\", \"recipient\": \"user@example.com\"}"
LPUSH message:queue "{\"id\": 2, \"type\": \"sms\", \"recipient\": \"+8613812345678\"}"

# 消费者(阻塞式)
BRPOP message:queue 30  # 30秒超时

# 使用 Sorted Set 实现延迟队列
# 添加延迟任务(10分钟后执行)
ZADD delay:queue $(expr $(date +%s) + 600) "{\"id\": 1, \"task\": \"send_reminder\"}"

# 获取到期任务
ZRANGEBYSCORE delay:queue 0 $(date +%s) LIMIT 0 10

Redis 流 (Streams)

Redis Streams 是 Redis 5.0 引入的新数据类型,用于构建高性能的消息队列和事件存储系统。

创建和使用 Redis 流
// Streams 核心概念
const streamsConcepts = {
  Entry: "流中的单条消息,包含ID和字段值对",
  ID: "消息的唯一标识符,格式为 millisecondsTime-sequenceNumber",
  ConsumerGroup: "消费者组,用于协调多个消费者",
  PendingList: "已分发但未确认的消息列表",
  LastDeliveredID: "消费者组最后分发的消息ID"
};
# 创建流并添加消息
XADD user:actions * user_id 1001 action "login" ip "192.168.1.100" timestamp "2024-01-15T10:30:00Z"
XADD user:actions * user_id 1002 action "purchase" product_id 2001 amount 299.99

# 自动生成ID添加消息
XADD order:events * order_id 12345 status "created" customer_id 1001
XADD order:events * order_id 12345 status "paid" payment_method "credit_card"

# 读取流中的消息
XRANGE user:actions - +     # 读取所有消息
XRANGE user:actions - + COUNT 10  # 读取前10条消息
XREVRANGE user:actions + - COUNT 5  # 逆序读取最新5条消息

# 从指定时间开始读取
XRANGE user:actions "1705304400000-0" +

# 实时读取新消息
XREAD COUNT 1 BLOCK 1000 STREAMS user:actions $  # 读取最新消息,1秒超时

# 获取流信息
XLEN user:actions           # 获取流长度
XINFO STREAM user:actions   # 获取流详细信息
消费者组(Consumer Groups)
# 创建消费者组
XGROUP CREATE user:actions user_group $ MKSTREAM

# 创建从头开始消费的消费者组
XGROUP CREATE user:actions analytics_group 0

# 消费者从组中读取消息
XREADGROUP GROUP user_group consumer1 COUNT 1 BLOCK 1000 STREAMS user:actions >

# 处理消息后确认
XACK user:actions user_group "1705304461000-0"

# 查看待处理消息
XPENDING user:actions user_group

# 查看特定消费者的待处理消息
XPENDING user:actions user_group - + 10 consumer1

# 声明消息所有权(处理故障消费者的消息)
XCLAIM user:actions user_group consumer2 3600000 "1705304461000-0"

# 删除消费者组
XGROUP DESTROY user:actions old_group

# 删除消费者
XGROUP DELCONSUMER user:actions user_group inactive_consumer

Streams 消费模式

graph TD
    subgraph "生产者"
        A[应用服务1] --> B[XADD]
        C[应用服务2] --> B
        D[应用服务3] --> B
    end
    
    subgraph "Redis Stream"
        B --> E[user:actions流]
        E --> F[消息1: ID1]
        E --> G[消息2: ID2]
        E --> H[消息3: ID3]
    end
    
    subgraph "消费者组1"
        I[consumer1] --> J[XREADGROUP]
        K[consumer2] --> J
        J --> E
    end
    
    subgraph "消费者组2"
        L[analytics_consumer] --> M[XREADGROUP]
        M --> E
    end
    
    subgraph "消息确认"
        N[XACK] --> O[标记消息已处理]
        P[XPENDING] --> Q[查看未确认消息]
    end

Redis 集群 (Cluster)

Redis 集群提供数据分片和高可用性,支持自动故障转移。

集群架构
graph TD
    subgraph "Redis集群"
        subgraph "主节点"
            A[Master1<br/>Slots: 0-5460]
            B[Master2<br/>Slots: 5461-10922]
            C[Master3<br/>Slots: 10923-16383]
        end
        
        subgraph "从节点"
            D[Slave1] --> A
            E[Slave2] --> B
            F[Slave3] --> C
        end
    end
    
    subgraph "客户端"
        G[应用1] --> H[集群客户端]
        I[应用2] --> H
        H --> A
        H --> B
        H --> C
    end
    
    subgraph "故障转移"
        J[节点监控] --> K[故障检测]
        K --> L[选举新主节点]
        L --> M[更新集群配置]
    end
集群模式安装
# 创建集群配置文件模板
mkdir redis-cluster
cd redis-cluster

# 生成6个节点的配置文件(3主3从)
for port in 7000 7001 7002 7003 7004 7005; do
    mkdir node-${port}
    cat > node-${port}/redis.conf <<EOF
port ${port}
cluster-enabled yes
cluster-config-file nodes-${port}.conf
cluster-node-timeout 5000
appendonly yes
appendfilename "appendonly-${port}.aof"
dbfilename "dump-${port}.rdb"
logfile "redis-${port}.log"
daemonize yes
protected-mode no
EOF
done

# 启动所有节点
for port in 7000 7001 7002 7003 7004 7005; do
    redis-server node-${port}/redis.conf
done

# 创建集群(Redis 5.0+)
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 -p 7000 cluster info
redis-cli -p 7000 cluster nodes

# 连接集群
redis-cli -c -p 7000  # -c 启用集群模式

# 集群操作示例
redis-cli -c -p 7000
127.0.0.1:7000> set user:1001 "张三"
-> Redirected to slot [1935] located at 127.0.0.1:7000
OK
127.0.0.1:7000> set user:1002 "李四"  
-> Redirected to slot [16383] located at 127.0.0.1:7002
OK

# 查看键的槽位信息
127.0.0.1:7000> cluster keyslot user:1001
(integer) 1935

# 添加新节点到集群
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000

# 重新分片
redis-cli --cluster reshard 127.0.0.1:7000

# 删除节点
redis-cli --cluster del-node 127.0.0.1:7000 <node-id>
集群管理与监控
// 集群监控指标
const clusterMetrics = {
  节点状态: "cluster_state, cluster_known_nodes",
  槽位分布: "cluster_slots_assigned, cluster_slots_fail",
  网络状态: "cluster_stats_messages_sent, cluster_stats_messages_received",
  故障转移: "cluster_current_epoch, cluster_my_epoch",
  性能指标: "operations_per_second, memory_usage, connection_count"
};
# 集群状态监控
redis-cli -p 7000 cluster info
redis-cli -p 7000 cluster nodes
redis-cli -p 7000 cluster slots

# 节点健康检查
redis-cli --cluster check 127.0.0.1:7000

# 集群修复
redis-cli --cluster fix 127.0.0.1:7000

# 备份集群配置
redis-cli --cluster backup 127.0.0.1:7000 /path/to/backup

# 集群性能测试
redis-cli --cluster call 127.0.0.1:7000 ping
redis-benchmark -c 50 -n 10000 -t set,get -p 7000

Redis 性能优化最佳实践

// Redis 性能优化建议
const performanceOptimization = {
  内存优化: {
    选择合适数据类型: "使用最节省内存的数据结构",
    设置过期时间: "及时清理不需要的数据",
    内存碎片整理: "定期执行MEMORY PURGE",
    压缩配置: "启用适当的压缩算法"
  },
  
  网络优化: {
    管道操作: "使用pipeline批量执行命令",
    连接池: "复用连接避免频繁建立连接",
    集群就近访问: "客户端连接最近的节点"
  },
  
  命令优化: {
    避免大键: "拆分大的集合和哈希",
    使用批量操作: "MGET, MSET代替多次GET, SET",
    合理使用索引: "避免全量扫描操作"
  }
};