首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >深入理解缓存容灾:应对高并发下的三大致命风险

深入理解缓存容灾:应对高并发下的三大致命风险

原创
作者头像
连连LL
发布2025-05-10 23:55:22
发布2025-05-10 23:55:22
16500
代码可运行
举报
文章被收录于专栏:技术技术
运行总次数:0
代码可运行

摘要

在高并发系统中,如果没有合适的缓存防护机制,数据库就像裸奔一样,很容易在某个节点集体崩溃。特别是像“缓存穿透”、“缓存击穿”、“缓存雪崩”这三兄弟,稍微一个不注意,就能让系统压力直线上升。本篇文章结合 Flask + Redis 的接口 Demo,聊聊实际项目中我们怎么构建防护机制,保证系统能稳稳当当抗住各种冲击。

引言

想象一个场景:你的系统平时访问量不大,但突然一波高并发请求打进来,某个热点数据刚好缓存过期,然后所有请求一起冲向数据库……结果数据库直接罢工,后端服务连带挂掉,用户报错满屏飞。

这就是经典的“缓存击穿”现场。

再比如说,如果有人频繁请求根本不存在的数据项,如果你没有做“空值缓存”,每次都得去数据库查一遍,很容易撑爆数据库——这叫“缓存穿透”。

更可怕的是,当缓存大面积过期,或者 Redis 节点故障,缓存瞬间全失效,全量请求打向数据库,那就是“缓存雪崩”。

听起来挺吓人?别急,下面我们拆开讲讲这三个问题怎么一一解决。

缓存问题的分类与本质

缓存穿透:数据库查不到的数据被频繁请求

本质: 请求数据根本就不存在,缓存也不存,数据库每次都查,白查一通。

应对策略: 缓存空值。

缓存击穿:某个热点 Key 失效时被高并发打穿

本质: 单个高频 Key 到期后,大量请求并发击向数据库。

应对策略: 设置互斥锁、热点隔离、二级缓存。

缓存雪崩:大面积缓存集中失效,导致数据库崩盘

本质: 大量 Key 同时失效,瞬时流量击穿数据库。

应对策略: 过期时间随机化、预加载、异步刷新等。

实战:用 Flask + Redis 模拟一个抗压缓存接口

我们来构建一个接口:查询商品详情。假设商品信息来自数据库,但我们希望通过 Redis 缓存提升性能并添加防护。

项目依赖

代码语言:bash
复制
pip install flask redis

基础服务代码结构

代码语言:txt
复制
.
├── app.py            # Flask 主应用
├── cache_utils.py    # 缓存封装逻辑
├── mock_db.py        # 模拟数据库查询
└── README.md

代码模块详解

mock_db.py:模拟数据库查询

代码语言:python
代码运行次数:0
运行
复制
import time

MOCK_DB = {
    "1001": {"id": "1001", "name": "iPhone", "stock": 10},
    "1002": {"id": "1002", "name": "MacBook", "stock": 5},
}

def query_product_from_db(product_id):
    time.sleep(0.5)  # 模拟延迟
    return MOCK_DB.get(product_id)

cache_utils.py:封装缓存读取逻辑(含空值缓存、击穿保护)

代码语言:python
代码运行次数:0
运行
复制
import redis
import json
import time

r = redis.Redis(host='localhost', port=6379, decode_responses=True)

EMPTY_CACHE = "__null__"

def get_cache_with_fallback(key, loader, ttl=60, empty_ttl=30):
    data = r.get(key)

    if data:
        if data == EMPTY_CACHE:
            return None
        return json.loads(data)

    # 防击穿:加一个简单互斥锁
    lock_key = f"{key}_lock"
    if r.setnx(lock_key, "1"):
        r.expire(lock_key, 5)
        try:
            result = loader()
            if result:
                r.set(key, json.dumps(result), ex=ttl)
            else:
                r.set(key, EMPTY_CACHE, ex=empty_ttl)
            return result
        finally:
            r.delete(lock_key)
    else:
        time.sleep(0.05)
        return get_cache_with_fallback(key, loader, ttl, empty_ttl)

app.py:商品详情接口

代码语言:python
代码运行次数:0
运行
复制
from flask import Flask, jsonify
from cache_utils import get_cache_with_fallback
from mock_db import query_product_from_db

app = Flask(__name__)

@app.route("/product/<product_id>")
def get_product(product_id):
    def db_loader():
        return query_product_from_db(product_id)

    cache_key = f"product:{product_id}"
    product = get_cache_with_fallback(cache_key, db_loader, ttl=60, empty_ttl=20)

    if product:
        return jsonify({"code": 0, "data": product})
    else:
        return jsonify({"code": 404, "msg": "Product not found"})

if __name__ == "__main__":
    app.run(debug=True)

实际场景分析

电商秒杀系统:

热点商品详情如果不做击穿保护,活动一开始,所有请求会集中打向数据库。通过二级缓存 + 锁机制,可以有效兜住第一波流量。

用户查询接口:

用户 ID 错误或恶意刷接口时,如果不做空值缓存,容易把数据库搞死。设置空值缓存,是一种非常实用的“打假”手段。

推荐系统的缓存雪崩:

推荐数据一般有个统一刷新周期,一旦批量过期,可以通过设置随机过期时间 + 缓存预热来缓解。

QA 环节

Q: 空值缓存会不会缓存太多“无用数据”?

会,但设置较短的 empty_ttl,比如 30 秒,可以在防止攻击的同时兼顾空间利用。

Q: 互斥锁是不是也会影响性能?

性能肯定有影响,但锁是保护机制,牺牲的是少部分性能,换来整体系统稳定。

Q: 大规模缓存雪崩真的能防住吗?

不能 100% 防住,但通过随机过期、预热加载、热点隔离等多种手段组合,大部分场景都能“救回来”。

总结

缓存是把双刃剑,用好了可以大幅提升性能,用不好就是一场灾难。我们要认识到:

  • 缓存穿透本质是“重复无效请求”,可以通过空值缓存干掉。
  • 缓存击穿是热点数据在关键时刻“掉链子”,可以通过锁、隔离策略兜住。
  • 缓存雪崩是全局灾难,要靠时间错峰、预加载、分级缓存打组合拳。

架构不是一开始就搭好塔楼,而是一步一步“围墙叠砖”式演进。

未来展望

未来系统如果规模继续扩大,我们还可以引入以下策略:

  • 本地缓存 + 分布式缓存(双层)
  • 异步缓存刷新机制
  • 热点 Key 检测与限流

这些都属于“更进一步”的优化方案,但第一步,先把基础的保护措施做好,系统才能撑得住下一波高并发浪潮。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 摘要
  • 引言
  • 缓存问题的分类与本质
    • 缓存穿透:数据库查不到的数据被频繁请求
    • 缓存击穿:某个热点 Key 失效时被高并发打穿
    • 缓存雪崩:大面积缓存集中失效,导致数据库崩盘
  • 实战:用 Flask + Redis 模拟一个抗压缓存接口
    • 项目依赖
  • 基础服务代码结构
  • 代码模块详解
    • mock_db.py:模拟数据库查询
    • cache_utils.py:封装缓存读取逻辑(含空值缓存、击穿保护)
    • app.py:商品详情接口
  • 实际场景分析
    • 电商秒杀系统:
    • 用户查询接口:
    • 推荐系统的缓存雪崩:
  • QA 环节
    • Q: 空值缓存会不会缓存太多“无用数据”?
    • Q: 互斥锁是不是也会影响性能?
    • Q: 大规模缓存雪崩真的能防住吗?
  • 总结
  • 未来展望
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档