# ngx.shared.DICT 非隊列性質
執行階段和主要函數請參考[維基百科 HttpLuaModule#ngx.shared.DICT](http://wiki.nginx.org/HttpLuaModule#ngx.shared.DICT)
### 非隊列性質
ngx.shared.DICT的實現是采用紅黑樹實現,當申請的緩存被占用完后如果有新數據需要存儲則采用LRU算法淘汰掉“多余”數據。
這樣數據結構的在帶有隊列性質的業務邏輯下會出現的一些問題:
我們用shared作為緩存,接納終端輸入并存儲,然后在另外一個線程中按照固定的速度去處理這些輸入,代碼如下:
~~~
-- [ngx.thread.spawn](http://wiki.nginx.org/HttpLuaModule#ngx.thread.spawn) #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](http://wiki.nginx.org/HttpLuaModule#ngx.thread.spawn) #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
~~~
在上述業務邏輯下會出現由生產者生產的某些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來暫存隊列性質的數據
- 序
- Lua簡介
- Lua環境搭建
- 基礎數據類型
- 表達式
- 控制結構
- if/else
- while
- repeat
- 控制結構for的使用
- break,return
- Lua函數
- 函數的定義
- 函數的參數
- 函數的返回值
- 函數回調
- 模塊
- String庫
- Table庫
- 日期時間函數
- 數學庫函數
- 文件操作
- 元表
- 面向對象編程
- FFI
- LuaRestyRedisLibrary
- select+set_keepalive組合操作引起的數據讀寫錯誤
- redis接口的二次封裝(簡化建連、拆連等細節)
- redis接口的二次封裝(發布訂閱)
- pipeline壓縮請求數量
- script壓縮復雜請求
- LuaCjsonLibrary
- json解析的異常捕獲
- 稀疏數組
- 空table編碼為array還是object
- 跨平臺的庫選擇
- PostgresNginxModule
- 調用方式簡介
- 不支持事務
- 超時
- 健康監測
- SQL注入
- LuaNginxModule
- 執行階段概念
- 正確的記錄日志
- 熱裝載代碼
- 阻塞操作
- 緩存
- sleep
- 定時任務
- 禁止某些終端訪問
- 請求返回后繼續執行
- 調試
- 調用其他C函數動態庫
- 我的lua代碼需要調優么
- 變量的共享范圍
- 動態限速
- shared.dict 非隊列性質
- 如何添加自己的lua api
- 正確使用長鏈接
- 如何引用第三方resty庫
- 使用動態DNS來完成HTTP請求
- 緩存失效風暴
- Lua
- 下標從1開始
- 局部變量
- 判斷數組大小
- 非空判斷
- 正則表達式
- 不用標準庫
- 虛變量
- 函數在調用代碼前定義
- 抵制使用module()函數來定義Lua模塊
- 點號與冒號操作符的區別
- 測試
- 單元測試
- API測試
- 性能測試
- 持續集成
- 灰度發布
- web服務
- API的設計
- 數據合法性檢測
- 協議無痛升級
- 代碼規范
- 連接池
- c10k編程
- TIME_WAIT問題
- 與Docker使用的網絡瓶頸
- 火焰圖
- 什么時候使用
- 顯示的是什么
- 如何安裝火焰圖生成工具
- 如何定位問題