nginx proxy cache 缓存
- nginx 反向代理前置
- 依靠文件系统存索引级的文件
- nginx讲一个请求当做一个 文件存储在本地,当下一个请求来时,看本地有没有一个文件,来决定proxycache是否启用
- 依靠内存缓存文件地址
- 缓存的内容是以文件存在磁盘中。但是缓存的key是存储在内存中,其值是文件在磁盘上的地址。
nginx.conf
#申明一个cache缓存节点的内容
proxy_cache_path /uar/local/openresty/nginx/tmp_cache levels=1:2 keys_zone=tmp_cache:100m inactive=7d max_size=10g;
levels说明对应文件的级别,可以在temp_cache目录下,将getid=6的url作为文件名,也可以做二级目录,减少磁盘寻址时间。将url做hash,取最后一位做一级目录,取倒数二位做二级目录。100m空间放key,inactive文件存储七天,文件系统最多10g。超过10g采用淘汰算法。
location / {
proxy_pass http://backend_server;
proxy_cache tmp_cache;
proxy_cache_key $uri;
proxy_cache_valid 200 206 304 302 7d;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
其实读取的还是本地磁盘文件。
所以回滚配置;
nginx lua
lua协程机制
协程机制,线程空间站中的一个执行单元,有自己独立的运行空间,基于用户态模拟出来的运行空间。
nginx协程机制
niginx lua 插载点
OpenResty
协程机制
- 依附于线程的内存模型,切换开销小
- 遇阻塞及归还执行权,代码同步
- 无需加锁
lua协程
-
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio > function foo (a) >> print("foo函数输出",a) >> return coroutine.yield(2 * a) >> end > > co = coroutine.create(function(a,b) >> print("第一次协程执行输出", a, b) >> local r = foo(a + 1) >> >> print("第二次协程执行输出", r) >> local r,s=coroutine.yield(a+b, a-b) >> >> print("第三次协程执行输出",r,s) >> return b,"结束协程" >> end) > > > print("main", coroutine.resume(co,1,10)) 第一次协程执行输出 1 10 foo函数输出 2 main true 4 > print("main",coroutine.resume(co,"r")) 第二次协程执行输出 r main true 11 -9 > print("main",coroutine.resume(co,"x","y")) 第三次协程执行输出 x y main true 10 结束协程 > > print("main",coroutine.resume(co,"x","y")) main false cannot resume dead coroutine >
ngInx的每一个 Worker进程都是在epol或 kqueue这种事件模型之上,封装成协程。
nginx协程机制
ngInX每个工作进程创建一个lua虚拟机
工作进程内的所有协程共享同一个vm
每个外部请求由一个lua协程处理,之间数据隔离
lua代码调用io等异步接口时,协程被挂起,上下文数据
自动保存,不阻塞工作进程
io异步操作完成后还原协程上下文,代码继续执行
nginx处理阶段
NGX_HTTP_ POST READ PHASE=0,/读取请求头
NGX_HTTP_ ServEr RewriTe PhasE, //执行rewrite ->rewrite handler
NGX_HTTP_ Find_ CONFIG PHASE,/根据uri替换 location
NGX_HTTP_ REWRITE_ PHASE//根据替换结果继续执行 rewrite--》 rewrite handler
NGX_HTTP_ Post RewriTe Phase,/行 rewrite后处理
NGX_HTTP_ PreacCess_ PHASE,/八认证预处理请求限制,连接限制→ limit conn hander
limit_req_ handler
NGX_HTTP_ AccesS PhasE,//认证处理→ auth basic handler, access handler
NGX_HTTP_ POST_ACCESS_ PHASE,//认证后处理,认证不通过,丢包
NGX_HTTP_ Try FileS Phase,∥尝试try标签
NGX_HTTP_ ConteNt Phase,∥内容处理→ static handler
NGX_HTTP_ Log Phase//日志处理→ g_handler
nginx lua插载点
init_by_lua:系统启动时调用
init_worker_by_lua: worker进程启动时调用
set _ by_lua: ngInx变量用复杂 lua return
rewrite_ by_lua:重写url规则
access_by_ua:权限验证阶段
content_by_lua:内容输出节点
openresty实践
- openresty hello world
- shared dic:共享内存字典,所有 worker进程可见,lru淘汰
- openresty redis支持
在openresty目录下新建lua文件夹,编写staticitem.lua
内容是ngx.say("hello static item lua");
在 nginx.conf配置中
location /staticitem/get{
default_type "text/html";
content_by_lua_file ../lua/staticitem.lua;
}
当浏览器访问 ..../staticitem/get 时,输出hello static item lua.这句话
在openresty目录下新建lua文件夹,编写helloworld.lua
内容是ngx.exec(".item/get?id=6");
在 nginx.conf配置中
location /helloworld{
content_by_lua_file ../lua/helloworld.lua;
}
当浏览器访问 ..../helloworld 时,会跳转连接
、、
itemsharedic.lua
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
local args = ngx.req.get_uri_args()
local id = args["id"]
local item_model get_from_cache("item_"..id)
if item_model == nil then
local resp = ngx.location.capture("/item/get?id="..id)
item_model = resp.body
set_to_cache("item_"..id,item_model,1*60)
end
ngx.say(item_model)
~
~
nginx.conf中
lua_shared_dict my_cache 128m
location /luaitem/get{
default_type "application/json";
content_by_lua_file ../lua/itemsharedic.lua;
}
nginx内存保存了热点数据,但是对于一些非热点,但是访问量大的,需要使用openresty的redis支持
编写 itemredis.lua
local args = ngx.req.get_uri_args()
local id = args["id"]
local redis = require "resty.redis"
local cache = redis:new()
local ok,err = cache:connect("127.0.0.1", 6379)
local item_model = cache:get("item_"..id)
if item_model == ngx.null or item_model == nil then
local resp = ngx.location.capture("/item/get?id="..id)
item_model = resp.body
end
~
~
~
location /luaitem/get{
default_type "application/json";
content_by_lua_file ../lua/itemredis.lua;
}
总结:share dic热点本地缓存 和tomcat使用guava本地缓存,都可以是QPS,PS上3500+,响应时间100ms以内的高性能。
但是这些热点数据吃内存,更新不方便。如果数据不是很热,但是涉及更新的时候,使用openresty对redis的支持,或者tomcat对redis的支持。