硬件配置
tomcat运行环境
-
cpu:AMD Ryzen 7 4800H with Radeon Graphics 8核16线程
-
内存:32G
-
网络带宽:886Mbps
openresty运行环境
- cpu:1核2线程
- 内存:5GB
WEB服务
web服务采用《微服务架构下的国内航班查询与预定系统》
测试功能
机票查询
请求方式
post
测试结果
OpenResty
使用jemter工具,开始500线程数,循环次数100进行压测,观察压测数据
在硬件资源低配置的情况下,openresty发挥除了不俗的性能,平均响应时间达到25ms,中位数 为10ms,最小响应时间为0ms,吞吐量为12251QPS
Tomcat
使用jemter工具,开始500线程数,循环次数100进行压测,观察压测数据
在硬件资源低配置的情况下,openresty发挥除了不俗的性能,平均响应时间达到49ms,中位数为47ms,最小响应时间为0ms,吞吐量为9473QPS
对比
最小响应时间 | 中位数 | 平均响应时间 | QPS | |
---|---|---|---|---|
openresty | 0ms | 47ms | 49ms | 12251 |
tomcat | 0ms | 10ms | 25ms | 9473 |
在硬件条件差这么多的情况下,能做到这么高的吞吐量和这么低的响应时间,可见openresty的性能有多强。
下面我来讲解一下实现方案。
实现方案
本次测试采用了openresty+lua实现了缓存,请求实现经openresty,openresty对请求做处理,提取请求中的uri,请求体,以及请求数据,并对其做相应的处理。将用户请求的数据提取出来作为缓存的key,将该数据查询到的结果为value存在缓存中。如果2022-09-02 长沙到上海的机票再次被查询则可直接从openresty返回,请求就不需要访问到后台WEB服务,减少后台服务器的压力,提升响应速度。
用户请求数据
{
"start":"长沙",
"end":"上海",
"startTime":"2022-09-02",
"price1":0,
"price2":0,
"section":"",
"mid":false
}
接下来我将讲解我是如何使用openresty+lua脚本实现代理服务器缓存的。
NGINX配置
在http模块中使用"lua_shared_dict my_cache 128m;"声明一块共享内存空间
我们的请求路径是/http,如果是/http请求调用http_example.lua脚本文件对请求进行处理
http_example
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by Administrator.
--- DateTime: 2022/8/17 21:47
---
-- 引入http包与cache包
local http = require("resty.http")
local lrucache = require("resty.lrucache")
-- 缓存函数
function get_from_cache(key)
local cache_ngx = ngx.shared.my_cache
local value = cache_ngx:get(key)
return value
end
function set_to_cache(key, value, exptime)
if not exptime then
exptime = 0
end
local cache_ngx = ngx.shared.my_cache
local succ, err, forcible = cache_ngx:set(key, value, exptime)
return succ
end
-- 缓存key
local key = nil
local s=nil
local x=nil
--local arg = ngx.req.get_uri_args()
--
--for k,v in pairs(arg) do
-- s = k
-- x = v
-- key = k..v
-- ngx.say(k..":"..v)
--end
ngx.req.read_body()
local post_args = ngx.req.get_post_args()
for k, v in pairs(post_args) do
if type(v) == "table" then
ngx.say(k,":",v)
else
key = k
end
end
if get_from_cache(key) ~= nil then
ngx.say("命中缓存:",get_from_cache(key))
return
end
local httpc = http.new()
local res, err = httpc:request_uri("http://192.168.217.1:11000/airroute/query/airroute", {
method = "POST",
body = key,
headers = {
["Content-Type"] = "application/json",
},
keepalive_timeout = 60,
keepalive_pool = 10
})
set_to_cache(key,res.body)
ngx.say(res.body)
if not res or res.status then
ngx.log(ngx.ERR, "request error#", err)
return
end
引入http包与lrucache包
-- 引入http包与cache包
local http = require("resty.http")
local lrucache = require("resty.lrucache")
缓存函数
-- 缓存函数
-- 获取key的值
function get_from_cache(key)
local cache_ngx = ngx.shared.my_cache
local value = cache_ngx:get(key)
return value
end
-- 设置key的值
function set_to_cache(key, value, exptime)
if not exptime then
exptime = 0
end
local cache_ngx = ngx.shared.my_cache
local succ, err, forcible = cache_ngx:set(key, value, exptime)
return succ
end
局部变量
-- 缓存key
local key = nil -- 作为缓存的key使用,在后续解析http请求会将请求数据拼接成key
local s=nil -- 如果是get请求,用来记录请求字段 如:/hello?name=123 s用来记录name
local x=nil -- 如果是get请求,用来记录请求字段值 如:/hello?name=123 s用来记录123
获取请求体
ngx.req.read_body() -- 获取请求题
local post_args = ngx.req.get_post_args() -- 获取post请求参数
for k, v in pairs(post_args) do -- 遍历参数
if type(v) == "table" then -- 如果是table类型则打印输出
ngx.say(k,":",v)
else
-- 将请求数据赋值给key
key = k
end
end
判断缓存
-- 如果该key存在,则直接返回value
if get_from_cache(key) ~= nil then
ngx.say("命中缓存:",get_from_cache(key))
return
end
创建http请求
local httpc = http.new() -- 创建http请求
-- 请求地址
local res, err = httpc:request_uri("http://192.168.217.1:11000/airroute/query/airroute", {
method = "POST",
body = key, -- 前面说了,请求的数据用key存放,这个key可以用来做缓存的key,也能在这里进行发送数据
-- 请求头信息
headers = {
["Content-Type"] = "application/json",
},
keepalive_timeout = 60,
keepalive_pool = 10
})
-- 如果失败,则记录错误日志并返回
if not res or res.status then
ngx.log(ngx.ERR, "request error#", err)
return
end
-- 将以key为key,res.body(请求接口的响应数据)为value,存在缓存中
set_to_cache(key,res.body)