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周)
安装配置
- Redis 安装
- redis-cli 使用
- 基本配置
五大数据类型
- String
- List
- Set
- Hash
- ZSet
第二阶段:进阶特性 (1-2周)
高级数据类型
- Bitmap
- HyperLogLog
- GeoSpatial
- Stream
持久化
- RDB 快照
- AOF 日志
发布订阅
- Pub/Sub 模式
第三阶段:高级应用 (持续)
事务与脚本
- MULTI/EXEC
- Lua 脚本
高可用
- 主从复制
- 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 # 文章浏览量+12. 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 # 数量+15. 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 # 执行事务
# 取消事务
DISCARD3. 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
endbash
# 执行脚本
EVAL script 1 product:1:stock 14. 管道 (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 # 由操作系统决定对比
| 特性 | RDB | AOF |
|---|---|---|
| 文件大小 | 小 | 大 |
| 恢复速度 | 快 | 慢 |
| 数据完整性 | 可能丢失 | 更完整 |
| 性能影响 | 低 | 中 |
🚨 缓存问题
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 None2. 缓存雪崩
问题:大量缓存同时过期,请求打到数据库。
解决方案:
- 过期时间随机化 - 避免同时过期
- 永不过期 - 异步更新
- 多级缓存 - 本地缓存 + 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 集群
多个主节点
每个主节点有从节点
数据分片存储💡 最佳实践
键命名规范
- 使用冒号分隔:
user:1000:name - 见名知意:
article:100:views - 避免过长
- 使用冒号分隔:
避免大 Key
- String 不超过 10KB
- List/Set/Hash 元素不超过 5000
- 定期清理
设置过期时间
- 防止内存溢出
- 根据业务设置合理时间
- 添加随机值避免雪崩
使用连接池
- 复用连接
- 提高性能
监控告警
- 内存使用率
- 命中率
- 慢查询
📖 学习资源
官方资源
推荐书籍
- 《Redis 设计与实现》
- 《Redis 实战》
- 《Redis 深度历险》
工具推荐
- redis-cli - 命令行工具
- RedisInsight - 官方 GUI
- Another Redis Desktop Manager - 开源客户端
准备好了吗?开始你的 Redis 学习之旅!