最有效方式是在nginx层拦截读请求并前置缓存。通过proxy_cache缓存静态页、openresty+lua本地缓存动态数据、多级缓存协同及穿透雪崩防护,实现毫秒级响应与高并发承载。

直接在 Nginx 层拦截大量读请求,让数据库几乎不参与秒杀期间的常规查询,是降低其读取压力最有效的方式。核心不是“加缓存”,而是把缓存前置到离用户最近、处理最快的位置——Nginx 本身。
静态页面与热点数据分离缓存
商品详情页、活动页等 HTML 内容变化频率低,但访问量极高。把这些页面生成静态文件或通过后端渲染后输出为纯 HTML,再由 Nginx 的 proxy_cache 模块缓存:
- 配置独立缓存区,如
keys_zone=seckill_html:20m,专用于秒杀页 - 对 /seckill/item/.* 路径设置缓存时间,例如
proxy_cache_valid 200 302 10m - 搭配
proxy_cache_lock on防止缓存失效时多个请求同时回源打爆后端 - 使用
proxy_cache_key包含商品 ID 和用户角色(如是否已登录),实现精准命中
利用 OpenResty + Lua 做动态内容本地缓存
纯静态页无法满足库存实时显示、用户限购状态等动态需求。此时用 OpenResty 运行 Lua 脚本,在 Nginx worker 进程内直接访问 Redis:
- Lua 脚本先查 Nginx 共享内存(shared_dict)中的本地热点数据,毫秒级响应
- 未命中则查 Redis,成功后写入 shared_dict 并设 TTL,避免重复查 Redis
- 库存变更时,通过消息队列通知所有 Nginx 节点清除对应 shared_dict 缓存项
- 关键逻辑如“是否可抢”“剩余库存数”全部在 Lua 中完成,不经过 Java 应用层
多级缓存协同与失效控制
Nginx 缓存不是孤立存在,需和 Redis、本地 JVM 缓存形成配合:
- Nginx 层缓存生命周期短(秒级到分钟级),专注扛住突发流量
- Redis 缓存存储结构化数据(如商品信息、库存值),TTL 设为业务允许的最大陈旧时间
- 当数据库数据更新时,通过 Canal 监听 binlog,触发 Redis 更新 + 向 Nginx 发送缓存清理指令(如 via HTTP POST 到内部管理接口)
- 对秒杀页设置分级过期策略:未开始时缓存 30 分钟;倒计时中缓存 10 秒;开抢后缓存 1 秒并启用 cache lock
缓存穿透与雪崩防护嵌入 Nginx 层
恶意构造不存在商品 ID 的请求会绕过缓存直击数据库。Nginx 可提前拦截:
- 用 Lua 脚本校验商品 ID 格式、长度,并查 Redis 中是否存在该商品元数据,不存在则直接返回 404
- 对高频无效请求 IP,结合
limit_req限流模块临时封禁 - 为热点 key 设置逻辑空值(如 {"code":200,"data":null})并缓存 1~2 分钟,防止反复穿透
- 缓存过期时间加入随机偏移(如 60s±10s),避免大量 key 同时失效引发雪崩











