OpenResty终极优化:引入L1本地缓存,实现微秒级响应

张开发
2026/4/20 6:33:00 15 分钟阅读

分享文章

OpenResty终极优化:引入L1本地缓存,实现微秒级响应
在上一篇文章中我们实现了OpenResty查询Redis的架构。虽然Redis很快但它毕竟是一个远程服务每次查询都需要经过网络I/O即使是本地回环网络也有协议解析和上下文切换的开销。在超高并发场景下如秒杀我们追求的是极致的性能。有没有比Redis更快的方法答案是肯定的——Nginx本地缓存。今天我们将引入架构中的L1缓存构建“本地内存 → Redis → Tomcat”的三级缓存体系将响应速度推向微秒级什么是Nginx本地缓存Nginx本地缓存在OpenResty中被称为共享字典它利用共享内存来存储数据。核心特性极速数据就在Nginx进程的内存中读取无需网络交互速度是微秒级。共享性通过lua_shared_dict定义的内存区域可以在Nginx的多个Worker进程之间共享。局限性它仅限于当前Nginx实例。如果你有多个OpenResty节点它们之间的本地缓存是不互通的这与Redis集群完全不同。配置与实战开启L1缓存1. 开启共享字典首先需要在nginx.conf的http模块中定义一块共享内存区域。http { # 定义一个名为 item_cache大小为 150MB 的共享内存区域 lua_shared_dict item_cache 150m; # ... 其他配置 ... }2. 操作共享字典在Lua脚本中我们可以通过ngx.shared来获取这个字典对象并进行读写。-- 获取缓存对象 local item_cache ngx.shared.item_cache -- 存储数据key, value, 过期时间(秒) -- 0 表示永不过期 item_cache:set(my_key, hello world, 0) -- 读取数据 local val item_cache:get(my_key)业务实现三级缓存查询链路现在我们需要修改item.lua将查询逻辑升级为三级漏斗L1 本地缓存查Nginx内存最快。L2 远程缓存查Redis次之。L3 数据库查Tomcat最慢。代码实现要点-- 获取共享字典对象 local item_cache ngx.shared.item_cache -- 封装多级查询函数 local function read_data(key, path, params) -- 1. 优先查询本地缓存 (L1) local resp item_cache:get(key) if resp then ngx.log(ngx.INFO, 命中本地缓存, key: , key) return resp end -- 2. 本地未命中查询Redis (L2) resp read_redis(127.0.0.1, 6379, key) if resp then ngx.log(ngx.INFO, 命中Redis缓存, key: , key) -- 数据回写将Redis的数据写入本地缓存 item_cache:set(key, resp, 1800) return resp end -- 3. Redis未命中查询Tomcat (L3) ngx.log(ngx.ERR, 缓存全未命中查询Tomcat, key: , key) resp read_http(path, params) -- 数据回写将Tomcat的数据写入本地缓存 if resp then item_cache:set(key, resp, 1800) end return resp end -- 业务调用 local id ngx.var[1] -- 注意Key的设计要统一这里假设Redis和本地缓存Key格式一致 local itemJson read_data(item:id: .. id, /item/ .. id, nil)关键设计缓存有效期的权衡在代码中我们设置了1800秒30分钟的过期时间。但在实际业务中不同数据的策略是不同的商品基本信息变更频率极低如标题、详情图可以设置较长的过期时间如30分钟。库存信息非常敏感变更频繁。普通商品可以设置较短时间如1分钟允许短暂的不一致。秒杀商品严禁使用本地缓存因为本地缓存无法在多节点间同步会导致超卖。秒杀应直接走Redis利用Lua脚本或分布式锁。验证与总结验证方法启动所有服务。访问商品页面。查看error.log日志第一次访问显示“缓存全未命中查询Tomcat”。第二次访问显示“命中本地缓存”。极端测试关闭Redis服务。刷新页面依然能访问因为数据已经在Nginx本地内存中了。总结通过引入Nginx本地缓存我们构建了坚不可摧的三级防御体系。性能L1缓存挡住了绝大多数读请求响应速度达到极致。高可用即使Redis宕机本地缓存依然能支撑一段时间的服务为系统恢复争取了时间。架构至此已臻完善但随之而来的是数据一致性的挑战。如何保证本地缓存、Redis和数据库的数据一致这将是我们下一阶段探讨的重点。知识点核心总结表格知识点核心内容考试重点/易混淆点难度系数Nginx本地缓存实现通过lua_shared_dict指令开启共享词典使用set/get方法操作缓存数据缓存更新策略到期更新 vs 主动更新多级缓存架构请求流程Nginx本地缓存 → Redis → Tomcat集群缓存穿透/雪崩的预防措施shared dict特性1. Worker进程间共享2. 不支持多节点共享3. 需配置内存大小示例150MB与Redis集群的数据一致性区别缓存有效期设置商品信息30分钟 vs 库存信息1分钟敏感数据如秒杀库存不建议缓存API使用方法ngx.shared.DICT.get(key)ngx.shared.DICT.set(key,value,expire)时间单位秒与永久缓存0的区分调试技巧通过error.log观察缓存命中情况日志记录格式需包含ngx.ERR级别

更多文章