Lua in Redis and Nginx
Prerequisites: Environments and sandboxing
Redis: atomic scripts
Redis runs Lua scripts atomically — no other command runs while a script executes — which makes multi-step operations safe without transactions.
-- illustrative
-- rate_limit.lua: allow `limit` requests per `window` seconds
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local current = redis.call("INCR", key)
if current == 1 then
redis.call("EXPIRE", key, window)
end
if current > limit then
return 0
end
return 1
$ redis-cli --eval rate_limit.lua ratelimit:user:42 , 5 60
(integer) 1
KEYSandARGVhold the keys and arguments passed toEVAL.redis.callruns Redis commands (and raises errors);redis.pcallreturns them instead.- Keep scripts short — while one runs, the whole server waits.
- Redis 7 adds Functions (
FUNCTION LOAD), named Lua libraries stored on the server.
OpenResty: Lua inside Nginx
OpenResty bundles Nginx with LuaJIT, so request handling can be scripted — API gateways, authentication, routing, and caching, at Nginx speed.
# nginx.conf
http {
lua_shared_dict counters 10m;
server {
listen 8080;
location /hello {
default_type application/json;
content_by_lua_block {
local cjson = require "cjson"
local name = ngx.var.arg_name or "world"
local counters = ngx.shared.counters
local visits = counters:incr("visits", 1, 0)
ngx.say(cjson.encode({message = "Hello, " .. name, visits = visits}))
}
}
}
}
$ curl "localhost:8080/hello?name=Ada"
{"message":"Hello, Ada","visits":1}
- Each request runs in its own coroutine; network calls (
ngx.socket,lua-resty-http,lua-resty-redis) yield instead of blocking, so one worker handles thousands of connections. ngx.shareddictionaries share data between workers.- Kong and APISIX, two popular API gateways, are built on OpenResty.
Other servers with Lua scripting include HAProxy, Envoy, and Apache
(mod_lua).