侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

设计高并发场景下的Nginx缓存策略并解决缓存穿透、雪崩和击穿问题

2025-12-12 / 0 评论 / 4 阅读

题目

设计高并发场景下的Nginx缓存策略并解决缓存穿透、雪崩和击穿问题

信息

  • 类型:问答
  • 难度:⭐⭐⭐

考点

Nginx缓存机制,缓存异常场景处理,高并发优化,动态内容缓存

快速回答

核心解决方案要点:

  • 基础缓存配置:使用proxy_cache_path定义缓存区域,proxy_cache启用缓存
  • 缓存穿透:通过proxy_cache_bypass过滤无效请求,结合空值缓存和Bloom过滤器
  • 缓存雪崩:设置随机过期时间proxy_cache_valid,启用缓存锁proxy_cache_lock
  • 缓存击穿:使用proxy_cache_lock实现请求合并,后端熔断机制
  • 动态内容proxy_cache_key包含会话参数,proxy_ignore_headers忽略Set-Cookie
## 解析

1. 核心问题背景

在高并发场景下(如秒杀系统),Nginx缓存需要应对:

  • 缓存穿透:恶意请求不存在的数据
  • 缓存雪崩:大量缓存同时失效导致后端压力骤增
  • 缓存击穿:热点key失效瞬间大量请求直达后端

2. Nginx缓存基础配置

# 定义缓存路径及参数
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=my_cache:10m 
                 inactive=60m max_size=1g use_temp_path=off;

server {
    location / {
        proxy_pass http://backend;
        proxy_cache my_cache;  # 启用缓存
        proxy_cache_valid 200 302 10m;  # 成功状态码缓存10分钟
        proxy_cache_valid 404      1m;  # 缓存空结果

        # 缓存键设计(包含必要参数)
        proxy_cache_key "$scheme$request_method$host$request_uri$arg_user_id";

        # 缓存锁定(防击穿)
        proxy_cache_lock on;
        proxy_cache_lock_timeout 5s;

        # 跳过缓存条件(防穿透)
        proxy_cache_bypass $http_pragma $http_authorization;
    }
}

3. 针对性解决方案

3.1 缓存穿透

  • 空值缓存:缓存404响应(proxy_cache_valid 404 1m
  • 请求过滤
    # 在Nginx中实现基础Bloom过滤器(需Lua模块支持)
    location / {
        access_by_lua_block {
            local bloom = require "resty.bloom"
            local bf = bloom:new(1000000, 0.01)
            -- 从数据库加载有效key到bf(实际需定时更新)
            if not bf:get(ngx.var.request_uri) then
                return ngx.exit(404)
            end
        }
    }

3.2 缓存雪崩

  • 随机过期时间
    # 在缓存有效时间上增加随机扰动
    map $status $cache_time {
        default 0;
        200 600;  # 基础10分钟
    }
    
    proxy_cache_valid 200 $cache_time+$request_time;  # 加入请求时间作为随机因子
  • 分级缓存:L1内存缓存 + L2磁盘缓存

3.3 缓存击穿

  • 请求合并:启用proxy_cache_lock后,首个请求回源时其他请求等待
  • 后端熔断
    # 结合limit_req模块限制到后端的请求
    location /backend {
        limit_req zone=backend_burst burst=10 nodelay;
        proxy_pass http://backend_upstream;
    
        # 熔断机制(需lua-resty-circuitbreaker)
        proxy_next_upstream error timeout http_500;
    }

4. 动态内容缓存实践

  • 个性化内容:在proxy_cache_key中包含用户ID等必要参数
  • Cookie处理
    # 忽略Set-Cookie头防止缓存失效
    proxy_ignore_headers Set-Cookie;
    # 但需排除敏感路径
    location /checkout {
        proxy_cache off;
    }

5. 常见错误与优化

  • 错误1:未设置max_size导致磁盘写满 → 监控缓存目录大小
  • 错误2:缓存键未包含变化参数 → 使用$query_string或关键参数
  • 优化1:启用proxy_cache_revalidate用If-Modified-Since验证旧缓存
  • 优化2:使用proxy_cache_use_stale在更新时返回旧缓存

6. 扩展知识

  • 缓存分片:通过proxy_cache_pathlevels参数优化文件查找
  • Purge机制:使用proxy_cache_purge模块实现主动清理
  • 性能监控:通过nginx-module-vts监控缓存命中率