Why OpenResty Achieves High Performance: Inside Nginx, Cosockets, and LuaJIT
This article explains how OpenResty leverages Nginx's event‑driven architecture, the cosocket non‑blocking I/O model, and LuaJIT's just‑in‑time compilation to deliver high‑throughput web services, detailing their inner workings, APIs, and performance trade‑offs.
OpenResty architecture on top of Nginx
OpenResty runs as Nginx master and worker processes. Each process embeds a LuaJIT VM; all coroutines in a worker share this VM and execute Lua code inside it.
Each worker handles a single request at a time, i.e., one coroutine runs per request. Nginx uses epoll‑based event‑driven I/O, minimizing idle waiting and allowing high throughput. A thread‑per‑request model would exhaust resources under the C10K scenario.
cosocket
cosocket is the core mechanism that enables non‑blocking network I/O for Lua libraries such as lua‑resty‑redis and lua‑resty‑memcached. Early OpenResty versions required C modules (e.g., redis2‑nginx‑module, memc‑nginx‑module) to talk to external services; after cosocket was introduced these were superseded by pure‑Lua implementations.
The term combines “coroutine” and “socket”. When a cosocket function is called, the coroutine yields, the network event is registered with Nginx’s event loop, and the coroutine is resumed once the event fires.
cosocket API overview
Create object: ngx.socket.tcp Set timeout: tcpsock:settimeout or tcpsock:settimeouts Connect: tcpsock:connect Send data: tcpsock:send Receive data: tcpsock:receive, tcpsock:receiveany, tcpsock:receiveuntil Connection pool: tcpsock:setkeepalive Close: tcpsock:close These APIs are usable in phases such as rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua, and ssl_session_fetch_by_lua*. They are unavailable in phases like init_by_lua or log_by_lua*. See the OpenResty lua‑nginx‑module documentation for details (https://github.com/openresty/lua-nginx-module#cosockets-not-available-everywhere).
LuaJIT
LuaJIT provides a tracing JIT compiler that turns hot Lua code into native machine code, while falling back to interpretation for cold paths.
Position in OpenResty
Worker processes are forked from the master; the master’s LuaJIT VM is also forked, so all coroutines in a worker share the same VM.
LuaJIT vs standard Lua
Standard Lua compiles source to bytecode and interprets it. LuaJIT adds a JIT compiler that records execution statistics while interpreting; when a function or loop becomes hot, the JIT translates the bytecode to an intermediate representation (IR) and then generates architecture‑specific machine code.
FFI (Foreign Function Interface)
LuaJIT’s FFI allows Lua code to call external C functions and manipulate C data structures directly, without the overhead of the traditional Lua/C API. This is used by the lua‑resty‑core library to call Nginx and OpenSSL functions efficiently.
Why JIT is not full‑time compilation
Compiling every piece of code would waste CPU time and increase memory usage. JIT needs runtime profiling information to decide which code paths are worth compiling. Therefore only hot code is compiled, while the rest remains interpreted.
Time: short‑lived workloads may not benefit from compilation.
Space: compiled code occupies additional memory.
Data: optimisation requires execution statistics.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Open Source Tech Hub
Sharing cutting-edge internet technologies and practical AI resources.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
