Skip to content

Redis 数据库

欢迎来到 Redis 数据库知识库!

🔴 Redis 简介

Redis (Remote Dictionary Server) 是一个开源的内存数据结构存储系统,可用作数据库、缓存和消息队列。以其极高的性能、丰富的数据类型和原子性操作而著称。

🎯 Redis 特点

✅ 核心优势

  • 极高性能 - 单线程 + 内存存储,QPS 10w+
  • 丰富的数据类型 - String、List、Set、Hash、ZSet、Stream
  • 原子性操作 - 单个操作都是原子的
  • 持久化 - RDB + AOF 双重持久化
  • 主从复制 - 高可用和读写分离
  • 发布订阅 - 消息通信机制
  • Lua 脚本 - 复杂逻辑原子执行
  • 过期策略 - 自动删除过期键

🎯 适用场景

✅ 特别适合

1. 缓存

  • 数据库查询缓存 - 减轻 DB 压力
  • 页面缓存 - 静态页面、热点数据
  • 会话缓存 - Session 存储

2. 计数器

  • 网站访问量 - INCR 原子递增
  • 点赞数、评论数 - 实时统计
  • 库存扣减 - 秒杀场景

3. 排行榜

  • 游戏排行 - ZSet 有序集合
  • 热门文章 - 按分数排序
  • 实时榜单 - 动态更新

4. 分布式锁

  • 防止重复操作 - SETNX + 过期时间
  • 并发控制 - 分布式环境

5. 消息队列

  • 简单队列 - List 实现
  • 发布订阅 - Pub/Sub
  • Stream - 消息流

6. 社交功能

  • 关注列表 - Set 集合运算
  • 共同好友 - 交集运算
  • 推荐系统 - 并集、差集

⚠️ 不太适合

  • 大数据量存储(受内存限制)
  • 复杂查询(非关系型)
  • 需要强一致性的场景

🎯 学习路线

第一阶段:基础入门 (1周)

  1. 安装配置

    • Redis 安装
    • redis-cli 使用
    • 基本配置
  2. 五大数据类型

    • String
    • List
    • Set
    • Hash
    • ZSet

第二阶段:进阶特性 (1-2周)

  1. 高级数据类型

    • Bitmap
    • HyperLogLog
    • GeoSpatial
    • Stream
  2. 持久化

    • RDB 快照
    • AOF 日志
  3. 发布订阅

    • Pub/Sub 模式

第三阶段:高级应用 (持续)

  1. 事务与脚本

    • MULTI/EXEC
    • Lua 脚本
  2. 高可用

    • 主从复制
    • Sentinel 哨兵
    • Cluster 集群

📖 数据类型详解

1. String(字符串)

bash
# 设置/获取
SET key value
GET key
MSET key1 value1 key2 value2
MGET key1 key2

# 递增/递减
INCR counter
INCRBY counter 10
DECR counter
DECRBY counter 5

# 过期时间
SETEX key 60 value  # 60秒后过期
TTL key  # 查看剩余时间
EXPIRE key 60  # 设置过期

# 应用场景
SET user:1000:name "张三"
SET article:1:views 0
INCR article:1:views  # 文章浏览量+1

2. List(列表)

bash
# 左侧/右侧插入
LPUSH list value
RPUSH list value

# 弹出
LPOP list
RPOP list

# 范围查询
LRANGE list 0 -1  # 查询所有
LRANGE list 0 9   # 前10个

# 长度
LLEN list

# 应用场景
LPUSH消息队列 message1
BRPOP 消息队列 0  # 阻塞式弹出

# 最新动态(朋友圈)
LPUSH user:1000:posts "发布了新动态"
LRANGE user:1000:posts 0 9  # 最新10条

3. Set(集合)

bash
# 添加/删除
SADD set member1 member2
SREM set member1

# 查询
SMEMBERS set
SISMEMBER set member  # 是否存在

# 集合运算
SINTER set1 set2   # 交集(共同好友)
SUNION set1 set2   # 并集
SDIFF set1 set2    # 差集

# 应用场景
# 关注列表
SADD user:1000:following user:1001
SADD user:1000:following user:1002

# 共同关注
SINTER user:1000:following user:2000:following

# 标签
SADD article:1:tags "Python" "后端" "数据库"

4. Hash(哈希)

bash
# 设置/获取
HSET hash field value
HGET hash field
HMSET hash field1 value1 field2 value2
HGETALL hash

# 递增
HINCRBY hash field 1

# 应用场景
# 用户信息
HMSET user:1000 username "张三" age 25 city "北京"
HGET user:1000 username
HINCRBY user:1000 age 1

# 购物车
HSET cart:1000 product:1 2  # 商品1,数量2
HINCRBY cart:1000 product:1 1  # 数量+1

5. ZSet(有序集合)

bash
# 添加
ZADD zset score1 member1 score2 member2

# 范围查询
ZRANGE zset 0 -1  # 按分数升序
ZREVRANGE zset 0 9  # 按分数降序,前10名
ZRANGE zset 0 -1 WITHSCORES  # 带分数

# 分数操作
ZINCRBY zset 10 member  # 分数+10
ZSCORE zset member  # 查询分数

# 排名
ZRANK zset member  # 正序排名
ZREVRANK zset member  # 倒序排名

# 应用场景
# 排行榜
ZADD game:ranking 1000 "玩家A" 950 "玩家B"
ZREVRANGE game:ranking 0 9 WITHSCORES  # Top 10

# 热门文章
ZINCRBY hot:articles 1 "article:100"  # 浏览量+1
ZREVRANGE hot:articles 0 9  # 热门前10

🔥 高级特性

1. 发布订阅

bash
# 订阅频道
SUBSCRIBE channel1

# 发布消息
PUBLISH channel1 "Hello Redis"

# 模式订阅
PSUBSCRIBE news:*  # 订阅所有 news 开头的频道

2. 事务

bash
MULTI  # 开始事务
SET key1 value1
SET key2 value2
EXEC  # 执行事务

# 取消事务
DISCARD

3. Lua 脚本

lua
-- 原子性扣减库存
local stock = redis.call('GET', KEYS[1])
if tonumber(stock) >= tonumber(ARGV[1]) then
    redis.call('DECRBY', KEYS[1], ARGV[1])
    return 1
else
    return 0
end
bash
# 执行脚本
EVAL script 1 product:1:stock 1

4. 管道 (Pipeline)

python
# Python 示例
import redis

r = redis.Redis()
pipe = r.pipeline()
pipe.set('key1', 'value1')
pipe.set('key2', 'value2')
pipe.get('key1')
results = pipe.execute()

💾 持久化

RDB(快照)

bash
# 配置
save 900 1      # 900秒内至少1个键改变
save 300 10     # 300秒内至少10个键改变
save 60 10000   # 60秒内至少10000个键改变

# 手动触发
SAVE        # 阻塞
BGSAVE      # 后台

AOF(日志)

bash
# 配置
appendonly yes
appendfsync always     # 每次写入
appendfsync everysec   # 每秒(推荐)
appendfsync no         # 由操作系统决定

对比

特性RDBAOF
文件大小
恢复速度
数据完整性可能丢失更完整
性能影响

🚨 缓存问题

1. 缓存穿透

问题:查询不存在的数据,缓存和数据库都没有。

解决方案

  • 布隆过滤器 - 快速判断数据是否存在
  • 缓存空值 - 将 null 也缓存起来
python
# 布隆过滤器示例
from pybloom_live import BloomFilter

bf = BloomFilter(capacity=10000, error_rate=0.001)
bf.add("user:1000")

if "user:9999" in bf:
    # 可能存在,查询缓存/数据库
    pass
else:
    # 一定不存在
    return None

2. 缓存雪崩

问题:大量缓存同时过期,请求打到数据库。

解决方案

  • 过期时间随机化 - 避免同时过期
  • 永不过期 - 异步更新
  • 多级缓存 - 本地缓存 + Redis
python
# 随机过期时间
import random
expire_time = 3600 + random.randint(0, 300)  # 3600-3900秒
redis.setex(key, expire_time, value)

3. 缓存击穿

问题:热点数据过期,大量请求打到数据库。

解决方案

  • 互斥锁 - 只有一个请求查询数据库
  • 永不过期 - 异步刷新
python
# 互斥锁示例
def get_data(key):
    # 1. 查询缓存
    data = redis.get(key)
    if data:
        return data
    
    # 2. 获取锁
    lock_key = f"lock:{key}"
    if redis.setnx(lock_key, 1):
        redis.expire(lock_key, 10)  # 锁过期时间
        
        # 3. 查询数据库
        data = db.query(key)
        
        # 4. 写入缓存
        redis.setex(key, 3600, data)
        
        # 5. 释放锁
        redis.delete(lock_key)
        
        return data
    else:
        # 等待并重试
        time.sleep(0.1)
        return get_data(key)

4. 缓存一致性

策略

  • Cache Aside - 先更新数据库,再删除缓存
  • Read/Write Through - 缓存负责读写数据库
  • Write Behind - 异步写入数据库
python
# Cache Aside 模式
def update_data(key, value):
    # 1. 更新数据库
    db.update(key, value)
    
    # 2. 删除缓存(而不是更新)
    redis.delete(key)

🚀 高可用架构

主从复制

Master (读写)
   |
   +-- Slave1 (只读)
   |
   +-- Slave2 (只读)

Sentinel 哨兵

Sentinel 监控集群
   |
   +-- 自动故障转移
   +-- 主从切换

Cluster 集群

多个主节点
每个主节点有从节点
数据分片存储

💡 最佳实践

  1. 键命名规范

    • 使用冒号分隔:user:1000:name
    • 见名知意:article:100:views
    • 避免过长
  2. 避免大 Key

    • String 不超过 10KB
    • List/Set/Hash 元素不超过 5000
    • 定期清理
  3. 设置过期时间

    • 防止内存溢出
    • 根据业务设置合理时间
    • 添加随机值避免雪崩
  4. 使用连接池

    • 复用连接
    • 提高性能
  5. 监控告警

    • 内存使用率
    • 命中率
    • 慢查询

📖 学习资源

官方资源

推荐书籍

  • 《Redis 设计与实现》
  • 《Redis 实战》
  • 《Redis 深度历险》

工具推荐

  • redis-cli - 命令行工具
  • RedisInsight - 官方 GUI
  • Another Redis Desktop Manager - 开源客户端

准备好了吗?开始你的 Redis 学习之旅!