Redis 项目实战分析
1.1 项目实战一:百万 PV 新闻网站缓存架构
✅ 背景
某新闻网站日均访问量达百万级,文章访问量极不均衡(80/20 法则),对热点文章访问频繁,需设计高性能缓存方案。
📌 关键目标
- 缓存热点新闻,减轻 DB 压力
- 页面缓存 + 数据缓存结合
- 缓存过期与更新机制
📦 架构设计
缓存层 |
说明 |
技术选型 |
页面缓存 |
对静态页面直接缓存 |
Nginx + Redis |
数据缓存 |
查询 DB 前先查 Redis |
Redis |
热点预热 |
发布文章时提前缓存热点 |
后台管理逻辑 |
🧠 代码示例(Python,使用 Flask 框架)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| from flask import Flask, jsonify import redis import time
app = Flask(__name__) r = redis.Redis(host='localhost', port=6379, decode_responses=True)
def get_article_from_db(article_id): time.sleep(0.5) return {"id": article_id, "title": f"文章{article_id}", "content": "这是一篇内容丰富的文章。"}
@app.route("/article/<int:article_id>") def get_article(article_id): key = f"article:{article_id}" article = r.get(key) if article: return jsonify({"source": "cache", "data": eval(article)})
article = get_article_from_db(article_id) r.setex(key, 300, str(article)) return jsonify({"source": "db", "data": article})
if __name__ == "__main__": app.run(debug=True)
|
💡 缓存更新策略
- 发布/修改文章后,后台自动刷新 Redis 中对应的 key。
- 对热点文章列表定时进行预热(job 脚本自动执行)。
1.2 项目实战二:高并发电商抢购系统
✅ 背景
秒杀活动中,用户瞬间涌入,需要保障商品不被超卖、服务不被打垮。
📌 技术关键点
问题 |
解决方案 |
库存扣减一致性 |
Redis 原子操作 |
接口幂等性 |
防止重复请求 |
并发控制 |
限流 + 排队机制 |
🧠 示例代码:Redis 原子扣库存(Python)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| from flask import Flask, request, jsonify import redis
app = Flask(__name__) r = redis.Redis(host='localhost', port=6379, decode_responses=True)
@app.route("/buy", methods=["POST"]) def buy_item(): user_id = request.form["user_id"] product_id = request.form["product_id"] key = f"stock:{product_id}" user_key = f"purchased:{product_id}:{user_id}"
if r.exists(user_key): return jsonify({"status": "fail", "msg": "重复下单"})
with r.pipeline() as pipe: while True: try: pipe.watch(key) stock = int(pipe.get(key) or 0) if stock > 0: pipe.multi() pipe.decr(key) pipe.set(user_key, 1) pipe.expire(user_key, 3600) pipe.execute() return jsonify({"status": "success", "msg": "购买成功"}) else: pipe.unwatch() return jsonify({"status": "fail", "msg": "已售罄"}) except redis.WatchError: continue
if __name__ == "__main__": r.set("stock:1001", 100) app.run()
|
1.3 项目实战三:消息中心与延时任务系统
✅ 背景
电商平台需要给用户发送短信/站内信/推送等消息,同时支持延迟通知(如:1 小时后提醒付款)。
📌 技术设计
功能 |
方案 |
延时消息调度 |
Redis ZSET |
多级优先队列 |
队列优先级划分 |
失败重试机制 |
失败任务重新入队 |
🧠 延时队列实现(ZSET)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import redis import time import json
r = redis.Redis(host='localhost', port=6379, decode_responses=True) DELAY_QUEUE = "delay:queue"
def push_delay_task(task_id, delay_seconds): timestamp = int(time.time() + delay_seconds) task_data = {"id": task_id, "type": "sms", "msg": "请尽快完成支付"} r.zadd(DELAY_QUEUE, {json.dumps(task_data): timestamp}) print("推送任务成功")
def consume_delay_task(): while True: now = int(time.time()) items = r.zrangebyscore(DELAY_QUEUE, 0, now, start=0, num=1) if not items: time.sleep(1) continue for item in items: print("处理任务:", item) r.zrem(DELAY_QUEUE, item)
if __name__ == "__main__": push_delay_task("task_001", delay_seconds=10)
consume_delay_task()
|
🔚 附录
✅ Redis 命令速查表(部分)
功能 |
命令 |
示例 |
设置键值 |
SET |
SET user:1 "Tom" |
获取键值 |
GET |
GET user:1 |
增加数值 |
INCR |
INCR page:view |
有序集合加分 |
ZINCRBY |
ZINCRBY rank 10 "user1" |
🔍 Redis 可视化工具推荐
工具 |
特点 |
RedisInsight |
图形化分析、键空间管理 |
RDM |
跨平台、支持 SSH 连接 |
Medis |
macOS 优雅 Redis GUI |
⚠ Redis 实战坑点与建议
- 热点 key 分布不均:引入本地缓存或按用户打散 key。
- keys 命令造成阻塞:避免线上使用,替换为
scan
。
- AOF 日志膨胀:定期重写(rewrite)。
- 慢查询拖垮主线程:开启
slowlog
并监控。