# ============================================================ # Nginx lua_shared_dict 共享字典配置示例 # ============================================================ # # 功能说明: # - 跨请求共享数据 # - 实现缓存、计数器、限流 # - 进程间通信 # # Lolly 对应配置: # lolly 内置 Lua 沙箱,支持共享字典功能 # 相关文档: docs/lua-nginx-module/05-shdict.md # ============================================================ http { # 定义共享字典 # lua_shared_dict name size; # size: 内存大小,支持 k, m 单位 lua_shared_dict cache 10m; # 缓存存储 lua_shared_dict rate_limit 5m; # 限流计数 lua_shared_dict sessions 10m; # 会话存储 lua_shared_dict config 1m; # 配置存储 server { listen 80; server_name shdict.example.com; # 缓存示例 location /api/cached { content_by_lua_block { local cjson = require "cjson.safe" local cache = ngx.shared.cache local key = ngx.var.arg_key or "default" -- 尝试从缓存获取 local value, flags = cache:get(key) if value then ngx.header["X-Cache"] = "HIT" ngx.say(value) return end -- 生成数据(模拟) local data = { key = key, value = "generated_value_" .. key, timestamp = ngx.now() } local json = cjson.encode(data) -- 存入缓存,60 秒过期 local success, err, forcible = cache:set(key, json, 60) if not success then ngx.log(ngx.WARN, "failed to set cache: ", err) end -- 检查是否 LRU 强制淘汰 if forcible then ngx.log(ngx.WARN, "cache LRU eviction occurred") end ngx.header["X-Cache"] = "MISS" ngx.say(json) } } # 限流示例 location /api/limited { access_by_lua_block { local limit = ngx.shared.rate_limit local ip = ngx.var.remote_addr local key = "limit:" .. ip -- 获取当前计数 local count, err = limit:incr(key, 1, 0, 60) # 60 秒窗口 if not count then ngx.log(ngx.ERR, "failed to incr: ", err) count = 0 end -- 设置过期时间(仅首次) if count == 1 then limit:expire(key, 60) end -- 检查限制 local max_requests = 100 if count > max_requests then ngx.status = 429 ngx.header["X-RateLimit-Limit"] = max_requests ngx.header["X-RateLimit-Remaining"] = 0 ngx.header["X-RateLimit-Reset"] = 60 ngx.say('{"error": "Rate limit exceeded"}') ngx.exit(429) end -- 设置响应头 ngx.header["X-RateLimit-Limit"] = max_requests ngx.header["X-RateLimit-Remaining"] = math.max(0, max_requests - count) } content_by_lua_block { ngx.say('{"status": "ok"}') } } # 会话存储示例 location /api/session { content_by_lua_block { local cjson = require "cjson.safe" local sessions = ngx.shared.sessions local session_id = ngx.var.cookie_session_id if ngx.req.get_method() == "GET" then -- 获取会话 if not session_id then ngx.status = 401 ngx.say('{"error": "No session"}') ngx.exit(401) end local session_data = sessions:get("session:" .. session_id) if not session_data then ngx.status = 401 ngx.say('{"error": "Session expired"}') ngx.exit(401) end ngx.say(session_data) elseif ngx.req.get_method() == "POST" then -- 创建会话 ngx.req.read_body() local data = cjson.decode(ngx.req.get_body_data()) -- 生成 session ID local session_id = ngx.md5(ngx.now() .. math.random()) -- 存储会话,30 分钟过期 sessions:set("session:" .. session_id, cjson.encode(data), 1800) -- 设置 Cookie ngx.header["Set-Cookie"] = "session_id=" .. session_id .. "; Path=/; HttpOnly" ngx.say(cjson.encode({session_id = session_id})) end } } # 配置管理示例 location /admin/config { content_by_lua_block { local cjson = require "cjson.safe" local config = ngx.shared.config local method = ngx.req.get_method() if method == "GET" then local keys = config:get_keys() local result = {} for _, key in ipairs(keys) do result[key] = config:get(key) end ngx.say(cjson.encode(result)) elseif method == "POST" then ngx.req.read_body() local data = cjson.decode(ngx.req.get_body_data()) for k, v in pairs(data) do config:set(k, v) end ngx.say(cjson.encode({success = true})) end } } # 统计信息 location /admin/stats { content_by_lua_block { local cjson = require "cjson.safe" local function get_stats(dict_name) local dict = ngx.shared[dict_name] return { capacity = dict:capacity(), free_space = dict:free_space(), keys = #dict:get_keys() } end local stats = { cache = get_stats("cache"), rate_limit = get_stats("rate_limit"), sessions = get_stats("sessions"), config = get_stats("config") } ngx.header["Content-Type"] = "application/json" ngx.say(cjson.encode(stats)) } } } } # lua_shared_dict API 说明: # # 1. 基础操作: # - get(key): 获取值 # - set(key, value, exptime?, flags?): 设置值 # - add(key, value, exptime?, flags?): 仅当 key 不存在时设置 # - replace(key, value, exptime?, flags?): 仅当 key 存在时替换 # - delete(key): 删除 # # 2. 计数操作: # - incr(key, value?, init?, init_ttl?): 增加 # - decr(key, value?): 减少 # - flush_all(): 清空所有 # - flush_expired(max_count?): 清理过期 # # 3. 过期管理: # - expire(key, exptime): 设置过期时间 # - ttl(key): 获取剩余过期时间 # # 4. 统计: # - capacity(): 总容量(字节) # - free_space(): 剩余空间(字节) # - get_keys(max_count?): 获取所有 key # # 5. 特点: # - 所有 worker 共享 # - LRU 淘汰策略 # - 原子操作 # - 支持过期时间