-
序
- 入门篇
- Lua 入门
-
Nginx
-
Nginx 新手起步
-
location 匹配规则
-
静态文件服务
-
日志
-
反向代理
-
负载均衡
-
陷阱和常见错误
- 环境搭建
-
Hello World
-
与其他 location 配合
-
获取 uri 参数
-
获取请求 body
-
输出响应体
-
日志输出
-
简单API Server框架
-
使用 Nginx 内置绑定变量
-
子查询
-
不同阶段共享变量
-
防止 SQL 注入
-
如何发起新 HTTP 请求
-
访问有授权验证的 Redis
-
select+set_keepalive 组合操作引起的数据读写错误
-
redis 接口的二次封装(简化建连、拆连等细节)
-
redis 接口的二次封装(发布订阅)
-
pipeline 压缩请求数量
-
script 压缩复杂请求
-
动态生成的 lua-resty-redis 模块方法
-
Nginx 新手起步
- LuaCjsonLibrary
- PostgresNginxModule
- LuaNginxModule
- LuaRestyDNSLibrary
- LuaRestyLock
- 测试
- Web 服务
- 火焰图
ngx.shared.DICT
非队列性质
===========
执行阶段和主要函数请参考HttpLuaModule#ngx.shared.DICT
非队列性质
ngx.shared.DICT
的实现是采用红黑树实现,当申请的缓存被占用完后如果有新数据需要存储则采用 LRU 算法淘汰掉“多余”数据。
这样数据结构的在带有队列性质的业务逻辑下会出现的一些问题:
我们用 shared 作为缓存,接纳终端输入并存储,然后在另外一个线程中按照固定的速度去处理这些输入,代码如下:
-- [ngx.thread.spawn](https://github.com/openresty/lua-nginx-module#ngxthreadspawn) #1 存储线程 理解为生产者
....
local cache_str = string.format([[%s&%s&%s&%s&%s&%s&%s]], net, name, ip,
mac, ngx.var.remote_addr, method, md5)
local ok, err = ngx_nf_data:safe_set(mac, cache_str, 60*60) --这些是缓存数据
if not ok then
ngx.log(ngx.ERR, "stored nf report data error: "..err)
end
....
-- [ngx.thread.spawn](https://github.com/openresty/lua-nginx-module#ngxthreadspawn) #2 取线程 理解为消费者
while not ngx.worker.exiting() do
local keys = ngx_share:get_keys(50) -- 一秒处理50个数据
for index, key in pairs(keys) do
str = ((nil ~= str) and str..[[#]]..ngx_share:get(key)) or ngx_share:get(key)
ngx_share:delete(key) --干掉这个key
end
.... --一些消费过程,看官不要在意
ngx.sleep(1)
end
copy
在上述业务逻辑下会出现由生产者生产的某些 key-val 对永远不会被消费者取出并消费,原因就是 shared.DICT
不是队列,ngx_shared:get_keys(n)
函数不能保证返回的 n 个键值对是满足 FIFO 规则的,从而导致问题发生。
问题解决
问题的原因已经找到,解决方案有如下几种:
1.修改暂存机制,采用 Redis 的队列来做暂存;
2.调整消费者的消费速度,使其远远大于生产者的速度;
3.修改 ngx_shared:get_keys()
的使用方法,即是不带参数;
方法 3 和 2 本质上都是一样的,由于业务已经上线,方法 1 周期太长,于是采用方法 2 解决,在后续的业务中不再使用 shared.DICT
来暂存队列性质的数据