多级缓存架构(三)OpenResty Lua缓存
文章目录
- 一、nginx服务
- 二、OpenResty服务
- 1. 服务块定义
- 2. 配置修改
- 3. Lua程序编写
- 4. 总结
- 三、运行
- 四、测试
- 五、高可用集群
- 1. openresty
- 2. tomcat
通过本文章,可以完成多级缓存架构中的Lua缓存。


一、nginx服务
在docker/docker-compose.yml中添加nginx服务块。
nginx:container_name: nginximage: nginx:stablevolumes:- ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf- ./nginx/conf/conf.d/default.conf:/etc/nginx/conf.d/default.conf- ./nginx/dist:/usr/share/nginx/distports:- "8080:8080"networks:multi-cache:ipv4_address: 172.30.3.3
删除原来docker里的multiCache项目并停止springboot应用。
nginx部分配置如下,监听端口为8080,并且将请求反向代理至172.30.3.11,下一小节,将openresty固定在172.30.3.11。
upstream nginx-cluster {server 172.30.3.11;
}server {listen 8080;listen [::]:8080;server_name localhost;location /api {proxy_pass http://nginx-cluster;}
}
重新启动multiCache看看nginx前端网页效果。
docker-compose -p multi-cache up -d
访问http://localhost:8080/item.html?id=10001查询id=10001商品页

这里是假数据,前端页面会向/api/item/10001发送数据请求。
二、OpenResty服务
1. 服务块定义
在docker/docker-compose.yml中添加openresty1服务块。
openresty1:container_name: openresty1image: openresty/openresty:1.21.4.3-3-jammy-amd64volumes:- ./openresty1/conf/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf- ./openresty1/conf/conf.d/default.conf:/etc/nginx/conf.d/default.conf- ./openresty1/lua:/usr/local/openresty/nginx/lua- ./openresty1/lualib/common.lua:/usr/local/openresty/lualib/common.luanetworks:multi-cache:ipv4_address: 172.30.3.11
2. 配置修改
前端向后端发送/api/item/10001请求关于id=10001商品信息。
根据nginx的配置内容,这个请求首先被nginx拦截,反向代理到172.30.3.11 (即openresty1)。
upstream nginx-cluster {server 172.30.3.11;
}server {location /api {proxy_pass http://nginx-cluster;}
}
openresty1收到的也是/api/item/10001,同时,openresty将/api/item/(\d+)请求代理到指定lua程序,在lua程序中完成数据缓存。

因此,openresty的conf/conf.d/default.conf如下
upstream tomcat-cluster {hash $request_uri;server 172.30.3.4:8081;
# server 172.30.3.5:8081;
}server {listen 80;listen [::]:80;server_name localhost;# intercept /item and join lualocation ~ /api/item/(\d+) {default_type application/json;content_by_lua_file lua/item.lua;}# intercept lua and redirect to back-endlocation /path/ {rewrite ^/path/(.*)$ /$1 break;proxy_pass http://tomcat-cluster;}error_page 500 502 503 504 /50x.html;location = /50x.html {root /usr/share/nginx/dist;}
}
conf/nginx.conf在http块最后添加3行,引入依赖。
#lua 模块lua_package_path "/usr/local/openresty/lualib/?.lua;;";#c模块lua_package_cpath "/usr/local/openresty/lualib/?.so;;";#本地缓存lua_shared_dict item_cache 150m;
3. Lua程序编写
common.lua被挂载到lualib,表示可以被其他lua当做库使用,内容如下
-- 创建一个本地缓存对象item_cache
local item_cache = ngx.shared.item_cache;-- 函数,向openresty本身发送类似/path/item/10001请求,根据conf配置,将被删除/path前缀并代理至tomcat程序
local function read_get(path, params)local rsp = ngx.location.capture('/path'..path,{method = ngx.HTTP_GET,args = params,})if not rsp thenngx.log(ngx.ERR, "http not found, path: ", path, ", args: ", params);ngx.exit(404)endreturn rsp.body
end-- 函数,如果本地有缓存,使用缓存,如果没有代理到tomcat然后将数据存入缓存
local function read_data(key, expire, path, params)-- query local cachelocal rsp = item_cache:get(key)-- query tomcatif not rsp thenngx.log(ngx.ERR, "redis cache miss, try tomcat, key: ", key)rsp = read_get(path, params)end-- write into local cacheitem_cache:set(key, rsp, expire)return rsp
endlocal _M = {read_data = read_data
}return _M
item.lua是处理来自形如/api/item/10001请求的程序,内容如下
-- include
local commonUtils = require('common')
local cjson = require("cjson")-- get url params 10001
local id = ngx.var[1]
-- redirect item, 缓存过期时间1800s, 适合长时间不改变的数据
local itemJson = commonUtils.read_data("item:id:"..id, 1800,"/item/"..id,nil)
-- redirect item/stock, 缓存过期时间4s, 适合经常改变的数据
local stockJson = commonUtils.read_data("item:stock:id:"..id, 4 ,"/item/stock/"..id, nil)
-- json2table
local item = cjson.decode(itemJson)
local stock = cjson.decode(stockJson)
-- combine item and stock
item.stock = stock.stock
item.sold = stock.sold
-- return result
ngx.say(cjson.encode(item))
4. 总结
- 这里
lua对item(tb_item表)和stock(tb_stock表)两个信息都有缓存,并使用cjson库将两者合并后返回到前端。 - 关于
expire时效性的问题,如果后台改变了数据,但是openresty关于此数据的缓存未过期,前端得到的是旧数据。 - 大致来说openresty = nginx + lua,不仅具有
nginx反向代理的能力,还能介入lua程序进行扩展。
三、运行
到此为止,docker-compose.yml应该如下
version: '3.8'networks:multi-cache:driver: bridgeipam:driver: defaultconfig:- subnet: 172.30.3.0/24services:mysql:container_name: mysqlimage: mysql:8volumes:- ./mysql/conf/my.cnf:/etc/mysql/conf.d/my.cnf- ./mysql/data:/var/lib/mysql- ./mysql/logs:/logsports:- "3306:3306"environment:- MYSQL_ROOT_PASSWORD=1009networks:multi-cache:ipv4_address: 172.30.3.2nginx:container_name: nginximage: nginx:stablevolumes:- ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf- ./nginx/conf/conf.d/default.conf:/etc/nginx/conf.d/default.conf- ./nginx/dist:/usr/share/nginx/distports:- "8080:8080"networks:multi-cache:ipv4_address: 172.30.3.3openresty1:container_name: openresty1image: openresty/openresty:1.21.4.3-3-jammy-amd64volumes:- ./openresty1/conf/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf- ./openresty1/conf/conf.d/default.conf:/etc/nginx/conf.d/default.conf- ./openresty1/lua:/usr/local/openresty/nginx/lua- ./openresty1/lualib/common.lua:/usr/local/openresty/lualib/common.luanetworks:multi-cache:ipv4_address: 172.30.3.11
启动各项服务
docker-compose -p multi-cache up -d
启动springboot程序。

四、测试
清空openresty容器日志。
访问http://localhost:8080/item.html?id=10001
查看openresty容器日志,可以看到两次commonUtils.read_data都没有缓存,于是代理到tomcat,可以看到springboot日志出现查询相关记录。
2024-01-12 11:45:53 2024/01/12 03:45:53 [error] 7#7: *1 [lua] common.lua:99: read_data(): redis cache miss, try tomcat, key: item:id:10001, client: 172.30.3.3, server: localhost, request: "GET /api/item/10001 HTTP/1.0", host: "nginx-cluster", referrer: "http://localhost:8080/item.html?id=10001"
2024-01-12 11:45:53 2024/01/12 03:45:53 [error] 7#7: *1 [lua] common.lua:99: read_data(): redis cache miss, try tomcat, key: item:stock:id:10001 while sending to client, client: 172.30.3.3, server: localhost, request: "GET /api/item/10001 HTTP/1.0", host: "nginx-cluster", referrer: "http://localhost:8080/item.html?id=10001"
2024-01-12 11:45:53 172.30.3.3 - - [12/Jan/2024:03:45:53 +0000] "GET /api/item/10001 HTTP/1.0" 200 486 "http://localhost:8080/item.html?id=10001" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0"
再次访问此网址,强制刷新+禁用浏览器缓存+更换浏览器
间隔超过4s但小于1800s时,日志如下,只出现一次miss。
2024-01-12 11:48:04 2024/01/12 03:48:04 [error] 7#7: *4 [lua] common.lua:99: read_data(): redis cache miss, try tomcat, key: item:stock:id:10001, client: 172.30.3.3, server: localhost, request: "GET /api/item/10001 HTTP/1.0", host: "nginx-cluster", referrer: "http://localhost:8080/item.html?id=10001"
2024-01-12 11:48:04 172.30.3.3 - - [12/Jan/2024:03:48:04 +0000] "GET /api/item/10001 HTTP/1.0" 200 486 "http://localhost:8080/item.html?id=10001" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0"
再次访问此网址,强制刷新+禁用浏览器缓存+更换浏览器
间隔小于4s,日志如下,未出现miss。
2024-01-12 11:49:16 172.30.3.3 - - [12/Jan/2024:03:49:16 +0000] "GET /api/item/10001 HTTP/1.0" 200 486 "http://localhost:8080/item.html?id=10001" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0"
五、高可用集群
1. openresty

对于openresty高可用,可以部署多个openresty docker实例,并在nginx的docker/nginx/conf/conf.d/default.conf的upstream nginx-cluster将多个openresty地址添加进去即可。比如
upstream nginx-cluster {hash $request_uri;# hash $request_uri consistent;server 172.30.3.11;server 172.30.3.12;server 172.30.3.13;
}
多个openresty 无论是conf还是lua都保持一致即可。
并且使用hash $request_uri负载均衡作为反向代理策略,防止同一请求被多个实例缓存数据。
2. tomcat

对于springboot程序高可用,也是类似。可以部署多个springboot docker实例,并在openresty 的docker/openresty1/conf/conf.d/default.conf的upstream nginx-cluster将多个springboot地址添加进去即可。比如
upstream tomcat-cluster {hash $request_uri;server 172.30.3.4:8081;server 172.30.3.5:8081;
}
相关文章:
多级缓存架构(三)OpenResty Lua缓存
文章目录 一、nginx服务二、OpenResty服务1. 服务块定义2. 配置修改3. Lua程序编写4. 总结 三、运行四、测试五、高可用集群1. openresty2. tomcat 通过本文章,可以完成多级缓存架构中的Lua缓存。 一、nginx服务 在docker/docker-compose.yml中添加nginx服务块。…...
写点东西《Docker入门(上)》
写点东西《Docker入门(上)》 环境变量 Docker 镜像 Docker CMD 与 ENTRYPOINT 有什么区别 Docker 中的网络: Docker 存储: Docker 是一个工具,允许开发人员将他们的应用程序及其所有依赖项打包到一个容器中。然后&…...
chatgpt实用技巧之二反问式提示
大家好,今天跟大家讲实用gpt的小技巧二、反问式提示 有时候不知道怎么给 GPT 提示词,这时候,就可以反问 GPT 如何更好地给提示词。如图片所示 更详细内容可以看下这篇: 按照 GPT 给出的:故事设定角色故事发展主题结局…...
【数据结构和算法】奇偶链表
其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 2.1 方法一:分离节点后合并 三、代码 3.1 方法一:分离节点后合并 四、复杂度分…...
MVC框架
文章目录 JSP 和 ServletMVC 的演进1. JSP Model 12. JSP Model 23. MVC 的一般化4. MVC 的变体 总结 JSP 和 Servlet 如果你有使用 Java 作为主要语言开发网站的经历,那么你一定听过别人谈论 JSP 和 Servlet。其中,Servlet 指的是服务端的一种 Java 写…...
学习笔记之——3D Gaussian Splatting及其在SLAM与自动驾驶上的应用调研
之前博客介绍了NeRF-SLAM,其中对于3D Gaussian Splatting没有太深入介绍。本博文对3D Gaussian Splatting相关的一些工作做调研。 学习笔记之——NeRF SLAM(基于神经辐射场的SLAM)-CSDN博客文章浏览阅读967次,点赞22次࿰…...
Github Copilot 的使用方法和快捷键
Github Copilot是一个基于人工智能技术的代码自动补全工具,它可以为开发者提供实时的代码建议和自动生成代码片段。本文将详细介绍如何安装、设置和使用Github Copilot,并提供一些常用的快捷键来提高开发效率。 1. 安装和设置 1.1 下载并安装VS Code …...
开源iMES工厂管家 - 详细安装部署指南(图解)- 全网独稿
目录 一、服务器环境: 二、部署构成总览: 三、下载 node-v16.17.1-win-x64:Index of /download/release/v16.17.1/ 四、绿色安装 node-v16.17.1-win-x64 五、配置环境变量 六、检查 node-v16.17.1-win-x64 是否成功 七、执行命令组,安装组库与各种依赖 vue3环境配置…...
Codeforces Round 919 (Div. 2)
Problem - A - Codeforces n个约束条件 a x 求出满足n个约束条件的整数的个数 大于等于x,取最大的 小于等于x,取最小的 然后不等于x的,记录在区间范围内的个数,减去这些 #include<bits/stdc.h> #define endl \n #define …...
面向经验丰富的开发人员的最佳 Linux 发行版
在深入研究最佳 Linux 发行版之前,让我们回顾一下历史。到 2021 年,Linux 操作系统已经有 30 年的历史了,从作为开发者 Linus Torvalds 的个人项目开始,它已经走过了很长一段路。最初发布时,其源代码被分发给用户&…...
Rust-借用检查
Rust语言的核心特点是:在没有放弃对内存的直接控制力的情况下,实现了内存安全。 所谓对内存的直接控制能力,前文已经有所展示:可以自行决定内存布局,包括在栈上分配内存,还是在堆上分配内存;支…...
xcode安装及运行源码
抖音教学视频 目录 1、xcode 介绍 2、xcode 下载 3、xocde 运行ios源码 4、快捷键 1、xcode 介绍 Xcode 是运行在操作系统Mac OS X上的集成开发工具(IDE),由Apple Inc开发。Xcode是开发 macOS 和 iOS 应用程序的最快捷的方式。Xcode 具有…...
x-cmd pkg | czg - git commit 智能生成工具
目录 简介首次用户功能特点竞品和相关作品进一步探索 简介 czg 源于 commitizen/cz-cli 交互插件中 cz-git 的延伸项目,重新使用 TypeScript 编写的零依赖独立的 Node.js 命令行工具。旨在使用交互友好的方式,辅助用户生成规范的 git commit message 约…...
Go的并发练习题目
经典并发题目 现在有4个协程,分别对应编号为1,2,3,4,每秒钟就有一个协程打印自己的编号,要求编写一个程序,让输出的编号总是按照1,2,3,4,1,2,3,4这样的规律一直打印下去 type Token struct { }func newWorker(id int, ch chan Token, nextC…...
Python 网络编程之粘包问题
【一】粘包问题介绍 【1】粘包和半包 粘包: 定义: 粘包指的是发送方发送的若干个小数据包被接收方一次性接收,形成一个大的数据包。原因: 通常是因为网络底层对数据传输的优化,将多个小数据包组合成一个大的数据块一次…...
旧衣回收小程序搭建:降低企业成本,提高回收效率!
在人们环保意识提升下,旧衣回收行业受到了大众的关注,同时旧衣回收具有门槛低、利润大的优势。在我国,回收行业不仅帮助普通人就业获利,还对环保做出了较大贡献。因此,旧衣回收行业成为了当下的热门商业模式࿰…...
Jmeter后置处理器——JSON提取器
目录 1、简介 2、使用步骤 1)添加线程组 2)添加http请求 3) 添加JSON提取器 1、简介 JSON是一种简单的数据交换格式,允许互联网应用程序快速传输数据。JSON提取器可以从JSON格式响应数据中提取数据、简化从JSON原始数据中提取特定…...
[SWPUCTF 2022 新生赛]奇妙的MD5
[SWPUCTF 2022 新生赛]奇妙的MD5 wp 题目页面: 提示:可曾听过ctf 中一个奇妙的字符串。 奇妙的字符串 奇妙的字符串,又跟 MD5 有关,我只知道两个: 一个是 MD5 加密后弱比较等于自身,这个字符串是 0e215…...
MHFormer 论文解读
目录 Multi-Hypothesis Transformer 结果 Introduction & Related work 多假设 为什么作者提出这个模型? 3.Multi-Hypothesis Transformer 3.1 Preliminary 3.2 MultiHypothesis Generation 3.3 Temporal Embedding 3.4. SelfHypothesi…...
Python列表append()函数使用详解
在Python中,列表是一种可变序列类型,可以用来存储多个元素。列表的append()函数是用于在列表末尾添加新元素的内置方法。本文将详细介绍Python列表的append()函数及其使用方法。 一、append()函数的基本语法 append()函数的语法非常简单,只…...
Ostrakon-VL-8B构建智能相册:基于自然语言的照片检索与回忆生成
Ostrakon-VL-8B构建智能相册:基于自然语言的照片检索与回忆生成 你有没有过这样的经历?手机里存了几千张照片,想找一张去年夏天在山上拍的照片,却要翻上十几分钟,甚至最后也没找到。或者,看着一堆旅行照片…...
“AI 辅助数据库优化 - 从慢查询分析到索引自动推荐“
AI 辅助数据库优化 - 从慢查询分析到索引自动推荐 问题场景 数据库优化的常见挑战: 慢查询排查依赖 DBA 经验,门槛高索引创建盲目,有时反而降低性能SQL 改写凭感觉,缺乏系统方法执行计划看不懂,不知道优化方向性能问题…...
小白程序员必看:收藏这份LangChain Agent开发指南,轻松入门大模型时代!
本文以LangChain框架为核心,详细介绍了如何开发AI Agent。内容涵盖模型调用、工具封装、会话记忆保存等基础功能,通过实操案例帮助读者理解Agent开发流程。LangChain简化了模型集成和工具调用,并提供了记忆模块支持多轮对话。文章适合想要入门…...
告别复杂操作!Wan2.2-I2V-A14B一键生成480P高清视频
告别复杂操作!Wan2.2-I2V-A14B一键生成480P高清视频 1. 视频创作新体验:简单三步生成专业级视频 你是否曾经为制作一段简单的视频而头疼?传统视频制作需要学习复杂的剪辑软件,花费大量时间调整参数,甚至需要专业的拍…...
Flux Sea Studio 海景摄影生成工具:AIGC内容创作革命——海景摄影从拍摄到生成的范式转变
Flux Sea Studio 海景摄影生成工具:AIGC内容创作革命——海景摄影从拍摄到生成的范式转变 想象一下,你脑海中浮现出一幅画面:史前时代的海洋,巨大的沧龙在泛着磷光的海浪中游弋;或者,一颗遥远星球的海岸线…...
openclaw 配置教程:本地安装、网关接入与模型 API 配置完整说明
如果你在折腾 openclaw 配置,通常会发现真正影响使用体验的,不是把程序装上去,而是后面的模型来源怎么接、网关怎么起、控制面板怎么进,以及默认模型如何切换。只要这些环节没有理顺,就算安装完成,后续也很…...
免费Figma中文界面插件终极指南:3分钟告别英文设计工具
免费Figma中文界面插件终极指南:3分钟告别英文设计工具 【免费下载链接】figmaCN 中文 Figma 插件,设计师人工翻译校验 项目地址: https://gitcode.com/gh_mirrors/fi/figmaCN 你是否曾经因为Figma的英文界面而感到困惑?每天在设计时不…...
华硕笔记本终极优化指南:用GHelper彻底释放硬件潜能
华硕笔记本终极优化指南:用GHelper彻底释放硬件潜能 【免费下载链接】g-helper Lightweight, open-source control tool for ASUS laptops and ROG Ally. Manage performance modes, fans, GPU, battery, and RGB lighting across Zephyrus, Flow, TUF, Strix, Scar…...
Janus-Pro-7B在CNN图像识别中的增强应用
Janus-Pro-7B在CNN图像识别中的增强应用 1. 引言 图像识别技术正在经历一场革命性的变革。传统的CNN模型虽然在图像分类任务上表现出色,但在复杂场景和多模态理解方面仍存在局限。今天我们要介绍的Janus-Pro-7B,作为一个统一的多模态理解和生成框架&am…...
18年产品经理生涯精华:从交付到规划,项目管理、解决方案、业务理解深度解析!
本期访谈只有1位老师,大海老师,18年工作经验,从干交付,到项目管理,再到资深技术专家、解决方案专家,目前做的更多的是业务规划、产品规划,是从一线实战走到真正的专家层面,老师分享的…...
