# *lua*: Поддержка скриптов Lua для NGINX
## Установка
Вы можете установить этот модуль в любой дистрибутив на базе RHEL, включая, но не ограничиваясь:
* RedHat Enterprise Linux 7, 8, 9 и 10
* CentOS 7, 8, 9
* AlmaLinux 8, 9
* Rocky Linux 8, 9
* Amazon Linux 2 и Amazon Linux 2023
=== "CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023+"
```bash
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-lua
```
=== "CentOS/RHEL 7 и Amazon Linux 2"
```bash
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-lua
```
Включите модуль, добавив следующее в начало файла `/etc/nginx/nginx.conf`:
```nginx
load_module modules/ngx_http_lua_module.so;
Этот документ описывает nginx-module-lua v0.10.31 выпущенный 29 мая 2026 года.
-
Видео на YouTube "Hello World HTTP Example with OpenResty/Lua"
-
Видео на YouTube "Write Your Own Lua Modules in OpenResty/Nginx Applications"
-
Видео на YouTube "OpenResty's resty Command-Line Utility Demo"
-
Видео на YouTube "Measure Execution Time of Lua Code Correctly in OpenResty"
-
Видео на YouTube "Precompile Lua Modules into LuaJIT Bytecode to Speedup OpenResty Startup"
Вы можете подписаться на наш официальный YouTube канал, OpenResty.
Синопсис
# установить пути поиска для чистых внешних библиотек Lua (';;' - это путь по умолчанию):
# установить пути поиска для внешних библиотек Lua, написанных на C (можно также использовать ';;'):
server {
location /lua_content {
# MIME тип определяется по default_type:
default_type 'text/plain';
content_by_lua_block {
ngx.say('Hello,world!')
}
}
location /nginx_var {
# MIME тип определяется по default_type:
default_type 'text/plain';
# попробуйте доступ к /nginx_var?a=hello,world
content_by_lua_block {
ngx.say(ngx.var.arg_a)
}
}
location = /request_body {
client_max_body_size 50k;
client_body_buffer_size 50k;
content_by_lua_block {
ngx.req.read_body() -- явно прочитать тело запроса
local data = ngx.req.get_body_data()
if data then
ngx.say("body data:")
ngx.print(data)
return
end
-- тело может быть буферизовано во временный файл:
local file = ngx.req.get_body_file()
if file then
ngx.say("body is in file ", file)
else
ngx.say("no body found")
end
}
}
# прозрачный неблокирующий ввод-вывод в Lua через подзапросы
# (на самом деле, лучший способ - использовать cosockets)
location = /lua {
# MIME тип определяется по default_type:
default_type 'text/plain';
content_by_lua_block {
local res = ngx.location.capture("/some_other_location")
if res then
ngx.say("status: ", res.status)
ngx.say("body:")
ngx.print(res.body)
end
}
}
location = /foo {
rewrite_by_lua_block {
res = ngx.location.capture("/memc",
{ args = { cmd = "incr", key = ngx.var.uri } }
)
}
proxy_pass http://blah.blah.com;
}
location = /mixed {
rewrite_by_lua_file /path/to/rewrite.lua;
access_by_lua_file /path/to/access.lua;
content_by_lua_file /path/to/content.lua;
}
# используйте переменную nginx в коде
# ВНИМАНИЕ: содержимое в переменной nginx должно быть тщательно отфильтровано,
# в противном случае возникнет серьезный риск безопасности!
location ~ ^/app/([-_a-zA-Z0-9/]+) {
set $path $1;
content_by_lua_file /path/to/lua/app/root/$path.lua;
}
location / {
client_max_body_size 100k;
client_body_buffer_size 100k;
access_by_lua_block {
-- проверьте, находится ли IP-адрес клиента в нашем черном списке
if ngx.var.remote_addr == "132.5.72.3" then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
-- проверьте, содержит ли URI плохие слова
if ngx.var.uri and
string.match(ngx.var.request_body, "evil")
then
return ngx.redirect("/terms_of_use.html")
end
-- тесты пройдены
}
# настройки proxy_pass/fastcgi_pass/etc.
}
}
Описание
Этот модуль встраивает LuaJIT 2.0/2.1 в Nginx. Он является основным компонентом OpenResty. Если вы используете этот модуль, то по сути вы используете OpenResty.
Начиная с версии v0.10.16 этого модуля, стандартный интерпретатор Lua
(также известный как "PUC-Rio Lua") больше не поддерживается. Этот
документ взаимозаменяемо использует термины "Lua" и "LuaJIT" для обозначения
интерпретатора LuaJIT.
Используя подзапросы Nginx, этот модуль позволяет интегрировать мощные потоки Lua (известные как "корутины" Lua) в модель событий Nginx.
В отличие от mod_lua Apache и mod_magnet Lighttpd, код Lua, выполняемый с помощью этого модуля, может быть на 100% неблокирующим по сетевому трафику, если используется Nginx API для Lua, предоставляемый этим модулем, для обработки запросов к upstream-сервисам, таким как MySQL, PostgreSQL, Memcached, Redis или upstream HTTP веб-сервисам.
По крайней мере, следующие библиотеки Lua и модули Nginx могут быть использованы с этим модулем:
- lua-resty-memcached
- lua-resty-mysql
- lua-resty-redis
- lua-resty-dns
- lua-resty-upload
- lua-resty-websocket
- lua-resty-lock
- lua-resty-logger-socket
- lua-resty-lrucache
- lua-resty-string
- ngx_memc
- ngx_postgres
- ngx_redis2
- ngx_redis
- ngx_proxy
- ngx_fastcgi
Практически любые модули Nginx могут быть использованы с этим модулем ngx_lua с помощью
ngx.location.capture или
ngx.location.capture_multi, но рекомендуется использовать
библиотеки lua-resty-* вместо создания подзапросов для доступа к модулям Nginx upstream,
поскольку первые обычно гораздо более гибкие и экономичные по памяти.
Интерпретатор Lua (также известный как "Lua State" или "экземпляр LuaJIT VM") делится между всеми запросами в одном рабочем процессе Nginx для минимизации использования памяти. Контексты запросов разделяются с помощью легковесных корутин Lua.
Загруженные модули Lua сохраняются на уровне рабочего процесса Nginx, что приводит к небольшому объему памяти в Lua даже при высокой нагрузке.
Этот модуль подключается к "http" подсистеме Nginx, поэтому он может говорить только на протоколах связи downstream в семействе HTTP (HTTP 0.9/1.0/1.1/2.0, WebSockets и т.д.). Если вы хотите выполнять общие TCP-коммуникации с клиентами downstream, то вам следует использовать ngx_stream_lua модуль вместо этого, который предлагает совместимый Lua API.
Типичные Использования
Просто чтобы назвать несколько:
- Объединение и обработка выходных данных различных upstream Nginx (proxy, drizzle, postgres, redis, memcached и т.д.) в Lua,
- выполнение произвольно сложного контроля доступа и проверок безопасности в Lua перед тем, как запросы фактически достигнут upstream бэкендов,
- манипулирование заголовками ответа произвольным образом (с помощью Lua)
- получение информации о бэкенде из внешних хранилищ (таких как redis, memcached, mysql, postgresql) и использование этой информации для выбора, к какому upstream бэкенду обращаться на лету,
- разработка произвольно сложных веб-приложений в обработчике контента с использованием синхронного, но все же неблокирующего доступа к бэкендам баз данных и другим хранилищам,
- выполнение очень сложной маршрутизации URL в Lua на этапе переписывания,
- использование Lua для реализации продвинутого механизма кэширования для подзапросов Nginx и произвольных местоположений.
Возможности безграничны, так как модуль позволяет объединять различные элементы внутри Nginx, а также раскрывать мощь языка Lua для пользователя. Модуль предоставляет полную гибкость скриптов, предлагая при этом уровни производительности, сопоставимые с программами на родном языке C как по времени ЦП, так и по объему памяти благодаря LuaJIT 2.x.
Другие реализации языков сценариев обычно испытывают трудности с достижением этого уровня производительности.
Совместимость с Nginx
Последняя версия этого модуля совместима со следующими версиями Nginx:
- 1.29.x (последняя проверка: 1.29.8)
- 1.29.x (последняя проверка: 1.29.2)
- 1.27.x (последняя проверка: 1.27.1)
- 1.25.x (последняя проверка: 1.25.1)
- 1.21.x (последняя проверка: 1.21.4)
- 1.19.x (последняя проверка: 1.19.3)
- 1.17.x (последняя проверка: 1.17.8)
- 1.15.x (последняя проверка: 1.15.8)
- 1.14.x
- 1.13.x (последняя проверка: 1.13.6)
- 1.12.x
- 1.11.x (последняя проверка: 1.11.2)
- 1.10.x
- 1.9.x (последняя проверка: 1.9.15)
- 1.8.x
- 1.7.x (последняя проверка: 1.7.10)
- 1.6.x
Ядра Nginx старше 1.6.0 (исключительно) не поддерживаются.
Репозиторий кода
Репозиторий кода этого проекта размещен на GitHub по адресу openresty/lua-nginx-module.
Поддержка байт-кода LuaJIT
Смотрите видео на YouTube "Measure Execution Time of Lua Code Correctly in OpenResty"
Начиная с релиза v0.5.0rc32, все директивы конфигурации *_by_lua_file (такие как content_by_lua_file) поддерживают загрузку сырых файлов байт-кода LuaJIT 2.0/2.1 напрямую:
/path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc
Опция -bg может быть использована для включения отладочной информации в файл байт-кода LuaJIT:
/path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.ljbc
Пожалуйста, обратитесь к официальной документации LuaJIT по опции -b для получения дополнительных сведений:
https://luajit.org/running.html#opt_b
Обратите внимание, что файлы байт-кода, сгенерированные LuaJIT 2.1, не совместимы с LuaJIT 2.0, и наоборот. Поддержка байт-кода LuaJIT 2.1 была впервые добавлена в ngx_lua v0.9.3.
Попытки загрузить стандартные файлы байт-кода Lua 5.1 в экземпляры ngx_lua, связанные с LuaJIT 2.0/2.1 (или наоборот), приведут к сообщению об ошибке Nginx, подобному следующему:
[error] 13909#0: *1 failed to load Lua inlined code: bad byte-code header in /path/to/test_file.luac
Загрузка файлов байт-кода через примитивы Lua, такие как require и
dofile, всегда должна работать как ожидается.
Поддержка системных переменных окружения
Если вы хотите получить доступ к системной переменной окружения, скажем, foo, в Lua через стандартный API Lua os.getenv, тогда вам также следует указать это имя переменной окружения в вашем файле nginx.conf через директиву env. Например,
env foo;
Поддержка HTTP 1.0
Протокол HTTP 1.0 не поддерживает фрагментированный вывод и требует явного заголовка Content-Length, когда тело ответа не пустое, чтобы поддерживать HTTP 1.0 keep-alive.
Таким образом, когда выполняется запрос HTTP 1.0 и директива lua_http10_buffering включена, ngx_lua будет буферизовать
вывод вызовов ngx.say и ngx.print и также отложит отправку заголовков ответа до тех пор, пока не будет получен весь вывод тела ответа.
В это время ngx_lua может вычислить общую длину тела и сформировать правильный заголовок Content-Length, чтобы вернуть его клиенту HTTP 1.0.
Если заголовок ответа Content-Length установлен в выполняемом коде Lua, однако, это буферизование будет отключено, даже если директива lua_http10_buffering включена.
Для больших потоковых ответов важно отключить директиву lua_http10_buffering, чтобы минимизировать использование памяти.
Обратите внимание, что общие инструменты бенчмаркинга HTTP, такие как ab и http_load, по умолчанию выполняют запросы HTTP 1.0.
Чтобы заставить curl отправлять запросы HTTP 1.0, используйте опцию -0.
Статическая компоновка чистых модулей Lua
С LuaJIT 2.x можно статически связывать байт-код чистых модулей Lua с исполняемым файлом Nginx.
Вы можете использовать исполняемый файл luajit для компиляции файлов модулей Lua .lua в объектные файлы .o, содержащие экспортированные данные байт-кода, а затем напрямую связывать файлы .o в вашей сборке Nginx.
Ниже приведен тривиальный пример, чтобы продемонстрировать это. Предположим, что у нас есть следующий файл .lua, названный foo.lua:
-- foo.lua
local _M = {}
function _M.go()
print("Hello from foo")
end
return _M
А затем мы компилируем этот файл .lua в файл foo.o:
/path/to/luajit/bin/luajit -bg foo.lua foo.o
Что имеет значение здесь, так это имя файла .lua, которое определяет, как вы будете использовать этот модуль позже в Lua. Имя файла foo.o не имеет значения, кроме расширения .o (которое говорит luajit, какой формат вывода используется). Если вы хотите удалить информацию отладки Lua из полученного байт-кода, вы можете просто указать опцию -b выше вместо -bg.
Затем, при сборке Nginx или OpenResty, передайте опцию --with-ld-opt="foo.o" в скрипт ./configure:
./configure --with-ld-opt="/path/to/foo.o" ...
Наконец, вы можете просто сделать следующее в любом коде Lua, выполняемом ngx_lua:
local foo = require "foo"
foo.go()
И этот кусок кода больше не зависит от внешнего файла foo.lua, так как он уже был скомпилирован в исполняемый файл nginx.
Если вы хотите использовать точку в имени модуля Lua при вызове require, как в
local foo = require "resty.foo"
то вам нужно переименовать файл foo.lua в resty_foo.lua перед компиляцией его в файл .o с помощью командной строки luajit.
Важно использовать точно ту же версию LuaJIT при компиляции файлов .lua в файлы .o, что и при сборке nginx + ngx_lua. Это связано с тем, что формат байт-кода LuaJIT может быть несовместим между различными версиями LuaJIT. Когда формат байт-кода несовместим, вы увидите ошибку выполнения Lua, сообщающую о том, что модуль Lua не найден.
Когда у вас есть несколько файлов .lua для компиляции и связывания, просто укажите их файлы .o одновременно в значении опции --with-ld-opt. Например,
./configure --with-ld-opt="/path/to/foo.o /path/to/bar.o" ...
Если у вас слишком много файлов .o, то может быть нецелесообразно называть их все в одной команде. В этом случае вы можете создать статическую библиотеку (или архив) для ваших файлов .o, как в
ar rcus libmyluafiles.a *.o
тогда вы можете связать архив myluafiles целиком с вашим исполняемым файлом nginx:
./configure \
--with-ld-opt="-L/path/to/lib -Wl,--whole-archive -lmyluafiles -Wl,--no-whole-archive"
где /path/to/lib - это путь к каталогу, содержащему файл libmyluafiles.a. Следует отметить, что опция компоновщика --whole-archive требуется здесь, потому что в противном случае наш архив будет пропущен, поскольку ни один символ в нашем архиве не упоминается в основных частях исполняемого файла nginx.
Обмен данными между рабочими процессами Nginx
Чтобы глобально обмениваться данными между всеми запросами, обрабатываемыми одним и тем же рабочим процессом Nginx, инкапсулируйте общие данные в модуль Lua, используйте встроенный Lua require для импорта модуля, а затем манипулируйте
общими данными в Lua. Это работает, потому что требуемые модули Lua загружаются только один раз, и все корутины будут делить одну и ту же копию модуля (как его кода, так и данных).
Обратите внимание, что использование глобальных переменных Lua категорически не рекомендуется, так как это может привести к неожиданным условиям гонки между параллельными запросами.
Вот небольшой пример обмена данными между рабочими процессами Nginx через модуль Lua:
-- mydata.lua
local _M = {}
local data = {
dog = 3,
cat = 4,
pig = 5,
}
function _M.get_age(name)
return data[name]
end
return _M
а затем доступ к нему из nginx.conf:
location /lua {
content_by_lua_block {
local mydata = require "mydata"
ngx.say(mydata.get_age("dog"))
}
}
Модуль mydata в этом примере будет загружен и выполнен только при первом запросе к местоположению /lua,
и все последующие запросы к тому же рабочему процессу Nginx будут использовать повторно загруженный экземпляр
модуля, а также ту же копию данных в нем, пока не будет отправлен сигнал HUP к главному процессу Nginx для принудительной перезагрузки.
Эта техника обмена данными является важной для высокопроизводительных приложений Lua, основанных на этом модуле.
Обратите внимание, что этот обмен данными осуществляется на уровне рабочего процесса, а не на уровне сервера. То есть, когда под управлением главного процесса Nginx имеется несколько рабочих процессов, обмен данными не может пересекать границу процессов между этими рабочими.
Обычно рекомендуется делиться данными только для чтения таким образом. Вы также можете делиться изменяемыми данными между всеми параллельными запросами каждого рабочего процесса Nginx, при условии, что в ваших вычислениях нет никаких неблокирующих операций ввода-вывода (включая ngx.sleep). Пока вы не передаете управление обратно в цикл событий Nginx и планировщик легких потоков ngx_lua (даже неявно), не может быть никаких условий гонки между ними. По этой причине всегда будьте очень осторожны, когда хотите поделиться изменяемыми данными на уровне рабочего процесса. Ошибочные оптимизации могут легко привести к трудным для отладки условиям гонки под нагрузкой.
Если требуется обмен данными на уровне сервера, то используйте один или несколько из следующих подходов:
- Используйте API ngx.shared.DICT, предоставляемый этим модулем.
- Используйте только один рабочий процесс Nginx и один сервер (это, однако, не рекомендуется, когда в одной машине имеется многоядерный ЦП или несколько ЦП).
- Используйте механизмы хранения данных, такие как
memcached,redis,MySQLилиPostgreSQL. Официальные релизы OpenResty поставляются с набором дополнительных модулей Nginx и библиотек Lua, которые предоставляют интерфейсы с этими механизмами хранения данных.
Известные проблемы
Проблемы с операцией подключения TCP-сокета
Метод tcpsock:connect может указывать на success несмотря на сбои подключения, такие как ошибки Connection Refused.
Тем не менее, последующие попытки манипулировать объектом cosocket будут завершаться неудачей и возвращать фактическое сообщение об ошибке, сгенерированное неудачной операцией подключения.
Эта проблема связана с ограничениями в модели событий Nginx и, как правило, затрагивает Mac OS X.
Возобновление/приостановка корутин Lua
- Поскольку встроенные функции Lua
dofileиrequireв настоящее время реализованы как функции C в LuaJIT 2.0/2.1, если файл Lua, загружаемый с помощьюdofileилиrequire, вызывает ngx.location.capture*, ngx.exec, ngx.exit или другие функции API, требующие приостановки в верхнем уровне файла Lua, то будет вызвана ошибка Lua "попытка приостановить через границу C-вызова". Чтобы избежать этого, поместите эти вызовы, требующие приостановки, в свои собственные функции Lua в файле Lua вместо верхнего уровня файла.
Область видимости переменных Lua
При импорте модулей необходимо быть осторожным, и следует использовать следующую форму:
local xxx = require('xxx')
вместо старой устаревшей формы:
require('xxx')
Вот причина: по замыслу, глобальная среда имеет точно такой же срок жизни, как и обработчик запроса Nginx, связанный с ним. Каждый обработчик запроса имеет свой собственный набор глобальных переменных Lua, и это идея изоляции запросов. Модуль Lua фактически загружается первым обработчиком запроса Nginx и кэшируется встроенной функцией require() в таблице package.loaded для последующего обращения, а встроенная функция module() используется некоторыми модулями Lua и имеет побочный эффект установки глобальной переменной в загруженную таблицу модуля. Но эта глобальная переменная будет очищена в конце обработчика запроса, и каждый последующий обработчик запроса будет иметь свою собственную (чистую) глобальную среду. Таким образом, вы получите исключение Lua за доступ к значению nil.
Использование глобальных переменных Lua в контексте ngx_lua обычно не рекомендуется, так как:
- неправильное использование глобальных переменных Lua имеет негативные побочные эффекты на параллельные запросы, когда такие переменные должны быть локальными по области видимости,
- глобальные переменные Lua требуют поиска таблиц Lua в глобальной среде, что является вычислительно затратным, и
- некоторые ссылки на глобальные переменные Lua могут содержать ошибки ввода, что делает их трудными для отладки.
Поэтому категорически рекомендуется всегда объявлять такие переменные в соответствующей локальной области видимости.
-- Избегайте
foo = 123
-- Рекомендуется
local foo = 123
-- Избегайте
function foo() return 123 end
-- Рекомендуется
local function foo() return 123 end
Чтобы найти все экземпляры глобальных переменных Lua в вашем коде Lua, запустите инструмент lua-releng по всем исходным файлам .lua:
$ lua-releng
Проверка использования глобальных переменных Lua в файле lib/foo/bar.lua ...
1 [1489] SETGLOBAL 7 -1 ; содержит
55 [1506] GETGLOBAL 7 -3 ; setvar
3 [1545] GETGLOBAL 3 -4 ; varexpand
Вывод показывает, что строка 1489 файла lib/foo/bar.lua записывает в глобальную переменную с именем contains, строка 1506 читает из глобальной переменной setvar, а строка 1545 читает глобальную переменную varexpand.
Этот инструмент гарантирует, что локальные переменные в функциях модуля Lua все объявлены с помощью ключевого слова local, в противном случае будет выброшено исключение времени выполнения. Это предотвращает нежелательные условия гонки при доступе к таким переменным. Смотрите Обмен данными между рабочими процессами Nginx для причин, стоящих за этим.
Места, настроенные другими модулями с помощью подзапросов
Директивы ngx.location.capture и ngx.location.capture_multi не могут захватывать места, которые включают директивы add_before_body, add_after_body, auth_request, echo_location, echo_location_async, echo_subrequest, или echo_subrequest_async директивы.
location /foo {
content_by_lua_block {
res = ngx.location.capture("/bar")
}
}
location /bar {
echo_location /blah;
}
location /blah {
echo "Success!";
}
$ curl -i http://example.com/foo
не будет работать как ожидалось.
Cosockets недоступны везде
Из-за внутренних ограничений в ядре Nginx API cosocket отключен в следующих контекстах: set_by_lua*, log_by_lua*, header_filter_by_lua*, и body_filter_by_lua.
Cosockets в настоящее время также отключены в контекстах init_by_lua* и init_worker_by_lua*, но мы можем добавить поддержку для этих контекстов в будущем, поскольку в ядре Nginx нет ограничений (или ограничения могут быть обойдены).
Тем не менее, существует обходной путь, когда оригинальный контекст не требует ожидания результатов cosocket. То есть создание таймера с нулевой задержкой через API ngx.timer.at и выполнение результатов cosocket в обработчике таймера, который работает асинхронно по отношению к оригинальному контексту, создающему таймер.
Специальные последовательности экранирования
ПРИМЕЧАНИЕ После релиза v0.9.17 эту ловушку можно избежать, используя директивы конфигурации *_by_lua_block {}.
Последовательности PCRE, такие как \d, \s или \w, требуют особого внимания, потому что в строковых литералах символ обратной косой черты \ удаляется как парсером языка Lua, так и парсером конфигурационного файла Nginx перед обработкой, если он не находится внутри директивы *_by_lua_block {}. Таким образом, следующий фрагмент не будет работать как ожидалось:
# nginx.conf
? location /test {
? content_by_lua '
? local regex = "\d+" -- ЭТО НЕПРАВИЛЬНО ВНЕ ДИРЕКТИВЫ *_by_lua_block
? local m = ngx.re.match("hello, 1234", regex)
? if m then ngx.say(m[0]) else ngx.say("not matched!") end
? ';
? }
# оценивается как "not matched!"
Чтобы избежать этого, двойное экранирование обратной косой черты:
# nginx.conf
location /test {
content_by_lua '
local regex = "\\\\d+"
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
';
}
# оценивается как "1234"
Здесь \\\\d+ преобразуется в \\d+ парсером конфигурационного файла Nginx, а затем это дополнительно преобразуется в \d+ парсером языка Lua перед выполнением.
В качестве альтернативы, шаблон регулярного выражения может быть представлен как строковой литерал Lua с длинными скобками, заключив его в "длинные скобки", [[...]], в этом случае обратные косые черты должны быть экранированы только один раз для парсера конфигурационного файла Nginx.
# nginx.conf
location /test {
content_by_lua '
local regex = [[\\d+]]
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
';
}
# оценивается как "1234"
Здесь [[\\d+]] преобразуется в [[\d+]] парсером конфигурационного файла Nginx, и это обрабатывается корректно.
Обратите внимание, что более длинная форма длинной скобки, [=[...]=], может потребоваться, если шаблон регулярного выражения содержит последовательности [...].
Форма [=[...]=] может использоваться в качестве формы по умолчанию, если это необходимо.
# nginx.conf
location /test {
content_by_lua '
local regex = [=[[0-9]+]=]
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
';
}
# оценивается как "1234"
Другой подход к экранированию последовательностей PCRE заключается в том, чтобы убедиться, что код Lua помещен в внешние файлы скриптов и выполняется с помощью различных директив *_by_lua_file.
С этим подходом обратные косые черты удаляются только парсером языка Lua и, следовательно, должны быть экранированы только один раз.
-- test.lua
local regex = "\\d+"
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
-- оценивается как "1234"
Внутри внешних файлов скриптов последовательности PCRE, представленные как строковые литералы Lua с длинными скобками, не требуют модификации.
-- test.lua
local regex = [[\d+]]
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
-- оценивается как "1234"
Как уже упоминалось ранее, последовательности PCRE, представленные внутри директив *_by_lua_block {} (доступные после релиза v0.9.17), не требуют модификации.
# nginx.conf
location /test {
content_by_lua_block {
local regex = [[\d+]]
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
}
}
# оценивается как "1234"
ПРИМЕЧАНИЕ Рекомендуется использовать by_lua_file, когда код Lua очень длинный.
Смешивание с SSI не поддерживается
Смешивание SSI с ngx_lua в одном запросе Nginx вообще не поддерживается. Просто используйте ngx_lua исключительно. Все, что вы можете сделать с SSI, можно сделать на основе ngx_lua, и это может быть более эффективно при использовании ngx_lua.
Режим SPDY не полностью поддерживается
Некоторые API Lua, предоставляемые ngx_lua, еще не работают в режиме SPDY Nginx: ngx.location.capture, ngx.location.capture_multi и ngx.req.socket.
Пропущенные данные в коротких запросах
Nginx может преждевременно завершить запрос с (по крайней мере):
- 400 (Неверный запрос)
- 405 (Не разрешено)
- 408 (Таймаут запроса)
- 413 (Слишком большой объем запроса)
- 414 (Слишком длинный URI запроса)
- 494 (Слишком большие заголовки запроса)
- 499 (Клиент закрыл запрос)
- 500 (Внутренняя ошибка сервера)
- 501 (Не реализовано)
Это означает, что фазы, которые обычно выполняются, пропускаются, такие как фаза переписывания или доступа. Это также означает, что последующие фазы, которые выполняются независимо от этого, например, log_by_lua, не будут иметь доступа к информации, которая обычно устанавливается в этих фазах.
Изменения
Изменения, внесенные в каждую версию этого модуля, перечислены в журналах изменений пакета OpenResty:
https://openresty.org/#Changes
Тестовый набор
Для запуска тестового набора требуются следующие зависимости:
-
Версия Nginx >= 1.4.2
-
Модули Perl:
- Test::Nginx: https://github.com/openresty/test-nginx
-
Модули Nginx:
- ngx_devel_kit
- ngx_set_misc
- ngx_auth_request (это не требуется, если вы используете Nginx 1.5.4+).
- ngx_echo
- ngx_memc
- ngx_srcache
- ngx_lua (т.е. этот модуль)
- ngx_lua_upstream
- ngx_headers_more
- ngx_drizzle
- ngx_rds_json
- ngx_coolkit
- ngx_redis2
Порядок, в котором эти модули добавляются во время конфигурации, важен, поскольку позиция любого фильтрующего модуля в цепочке фильтрации определяет окончательный вывод, например. Правильный порядок добавления показан выше.
-
Библиотеки Lua третьих сторон:
-
Приложения:
- mysql: создайте базу данных 'ngx_test', предоставьте все привилегии пользователю 'ngx_test', пароль 'ngx_test'
- memcached: слушает на порту по умолчанию, 11211.
- redis: слушает на порту по умолчанию, 6379.
Смотрите также скрипт сборки разработчика для получения дополнительных сведений о настройке тестовой среды.
Чтобы запустить весь тестовый набор в режиме тестирования по умолчанию:
cd /path/to/lua-nginx-module
export PATH=/path/to/your/nginx/sbin:$PATH
prove -I/path/to/test-nginx/lib -r t
Чтобы запустить конкретные тестовые файлы:
cd /path/to/lua-nginx-module
export PATH=/path/to/your/nginx/sbin:$PATH
prove -I/path/to/test-nginx/lib t/002-content.t t/003-errors.t
Чтобы запустить конкретный блок тестов в определенном тестовом файле, добавьте строку --- ONLY в блок тестов, который вы хотите запустить, а затем используйте утилиту prove для запуска этого .t файла.
Существуют также различные режимы тестирования на основе mockeagain, valgrind и т.д. Смотрите документацию Test::Nginx для получения дополнительных сведений о различных продвинутых режимах тестирования. Смотрите также отчеты о тестах для тестового кластера Nginx, работающего на Amazon EC2: https://qa.openresty.org.
Смотрите также
Записи в блогах:
- Введение в графики CPU Flame для Lua-Land
- Как OpenResty и Nginx выделяют и управляют памятью
- Как зоны общей памяти OpenResty и Nginx потребляют ОЗУ
- Фрагментация памяти в OpenResty и зонах общей памяти Nginx
Другие связанные модули и библиотеки:
- ngx_stream_lua_module для официального порта этого модуля для подсистемы Nginx "stream" (выполнение общих TCP-коммуникаций downstream).
- lua-resty-memcached библиотека на основе cosocket ngx_lua.
- lua-resty-redis библиотека на основе cosocket ngx_lua.
- lua-resty-mysql библиотека на основе cosocket ngx_lua.
- lua-resty-upload библиотека на основе cosocket ngx_lua.
- lua-resty-dns библиотека на основе cosocket ngx_lua.
- lua-resty-websocket библиотека как для сервера, так и для клиента WebSocket, на основе cosocket ngx_lua.
- lua-resty-string библиотека на основе LuaJIT FFI.
- lua-resty-lock библиотека для неблокирующего простого API блокировки.
- lua-resty-cookie библиотека для манипуляции HTTP-куками.
- Маршрутизация запросов к различным MySQL запросам на основе аргументов URI
- Динамическая маршрутизация на основе Redis и Lua
- Использование LuaRocks с ngx_lua
- Введение в ngx_lua
- ngx_devel_kit
- echo-nginx-module
- drizzle-nginx-module
- postgres-nginx-module
- memc-nginx-module
- Пакет OpenResty
- Nginx Systemtap Toolkit
Директивы
- lua_load_resty_core
- lua_capture_error_log
- lua_use_default_type
- lua_malloc_trim
- lua_code_cache
- lua_thread_cache_max_entries
- lua_regex_cache_max_entries
- lua_regex_match_limit
- lua_package_path
- lua_package_cpath
- init_by_lua
- init_by_lua_block
- init_by_lua_file
- init_worker_by_lua
- init_worker_by_lua_block
- init_worker_by_lua_file
- exit_worker_by_lua_block
- exit_worker_by_lua_file
- set_by_lua
- set_by_lua_block
- set_by_lua_file
- precontent_by_lua_block
- precontent_by_lua_file
- content_by_lua
- content_by_lua_block
- content_by_lua_file
- server_rewrite_by_lua_block
- server_rewrite_by_lua_file
- rewrite_by_lua
- rewrite_by_lua_block
- rewrite_by_lua_file
- access_by_lua
- access_by_lua_block
- access_by_lua_file
- header_filter_by_lua
- header_filter_by_lua_block
- header_filter_by_lua_file
- body_filter_by_lua
- body_filter_by_lua_block
- body_filter_by_lua_file
- log_by_lua
- log_by_lua_block
- log_by_lua_file
- balancer_by_lua_block
- balancer_by_lua_file
- balancer_keepalive
- lua_need_request_body
- ssl_client_hello_by_lua_block
- ssl_client_hello_by_lua_file
- ssl_certificate_by_lua_block
- ssl_certificate_by_lua_file
- ssl_session_fetch_by_lua_block
- ssl_session_fetch_by_lua_file
- ssl_session_store_by_lua_block
- ssl_session_store_by_lua_file
- proxy_ssl_certificate_by_lua_block
- proxy_ssl_certificate_by_lua_file
- proxy_ssl_verify_by_lua_block
- proxy_ssl_verify_by_lua_file
- lua_shared_dict
- lua_socket_connect_timeout
- lua_socket_send_timeout
- lua_socket_send_lowat
- lua_socket_read_timeout
- lua_socket_buffer_size
- lua_socket_pool_size
- lua_socket_keepalive_timeout
- lua_socket_log_errors
- lua_ssl_ciphers
- lua_ssl_crl
- lua_ssl_protocols
- lua_ssl_certificate
- lua_ssl_certificate_key
- lua_ssl_trusted_certificate
- lua_ssl_verify_depth
- lua_ssl_key_log
- lua_ssl_conf_command
- lua_upstream_skip_openssl_default_verify
- lua_http10_buffering
- rewrite_by_lua_no_postpone
- access_by_lua_no_postpone
- precontent_by_lua_no_postpone
- lua_transform_underscores_in_response_headers
- lua_check_client_abort
- lua_max_pending_timers
- lua_max_running_timers
- lua_sa_restart
- lua_worker_thread_vm_pool_size
Основные строительные блоки скриптов Nginx с Lua - это директивы. Директивы используются для указания, когда выполняется пользовательский код Lua и как будет использоваться результат. Ниже приведена диаграмма, показывающая порядок выполнения директив.

lua_load_resty_core
синтаксис: lua_load_resty_core on|off
по умолчанию: lua_load_resty_core on
контекст: http
Эта директива устарела с релиза v0.10.16 этого
модуля. Модуль resty.core из
lua-resty-core теперь обязательно
загружается во время инициализации Lua VM. Указание этой директивы не будет иметь
никакого эффекта.
Эта директива была впервые введена в релизе v0.10.15 и
использовалась для необязательной загрузки модуля resty.core.
lua_capture_error_log
синтаксис: lua_capture_error_log size
по умолчанию: нет
контекст: http
Включает буфер указанного size для захвата всех сообщений об ошибках Nginx (не только тех, которые производятся
этим модулем или подсистемой http Nginx, но и всего остального) без обращения к файлам или дискам.
Вы можете использовать единицы, такие как k и m в значении size, например
lua_capture_error_log 100k;
Как правило, буфер размером 4 КБ может обычно содержать около 20 типичных сообщений об ошибках. Так что считайте!
Этот буфер никогда не растет. Если он заполнен, новые сообщения об ошибках заменят самые старые в буфере.
Размер буфера должен быть больше максимальной длины одного сообщения об ошибке (которая составляет 4K в OpenResty и 2K в стандартном NGINX).
Вы можете читать сообщения в буфере на стороне Lua через get_logs() функцию модуля ngx.errlog библиотеки lua-resty-core. Эта функция API Lua вернет захваченные сообщения об ошибках и также удалит эти уже прочитанные из глобального буфера захвата, освобождая место для любых новых данных об ошибках. По этой причине пользователь не должен настраивать этот буфер слишком большим, если пользователь быстро читает данные об ошибках в буфере.
Обратите внимание, что уровень журнала, указанный в стандартной директиве error_log действительно влияет на эту функцию захвата. Она захватывает только сообщения журнала уровня не ниже указанного уровня журнала в директиве error_log. Пользователь все еще может выбрать установку еще более высокого уровня фильтрации журнала на лету через функцию API Lua errlog.set_filter_level. Таким образом, это более гибко, чем статическая директива error_log.
Стоит отметить, что нет способа захватить отладочные логи
без сборки OpenResty или Nginx с опцией ./configure
--with-debug. Включение отладочных логов
категорически не рекомендуется в производственных сборках из-за высокой нагрузки.
Эта директива была впервые введена в релизе v0.10.9.
lua_use_default_type
синтаксис: lua_use_default_type on | off
по умолчанию: lua_use_default_type on
контекст: http, server, location, location if
Указывает, следует ли использовать MIME-тип, указанный директивой default_type в качестве значения по умолчанию для заголовка ответа Content-Type. Отключите эту директиву, если не требуется заголовок ответа Content-Type по умолчанию для обработчиков запросов Lua.
Эта директива включена по умолчанию.
Эта директива была впервые введена в релизе v0.9.1.
lua_malloc_trim
синтаксис: lua_malloc_trim <количество запросов>
по умолчанию: lua_malloc_trim 1000
контекст: http
Запрашивает у библиотеки времени выполнения libc освободить свою кэшированную свободную память обратно в операционную систему каждые N запросов, обработанных ядром Nginx. По умолчанию N равно 1000. Вы можете настроить количество запросов, используя свои собственные числа. Меньшие числа означают более частые освобождения, что может привести к большему потреблению времени ЦП и меньшему объему памяти, в то время как большие числа обычно приводят к меньшим накладным расходам на ЦП и относительно большему объему памяти. Просто настройте число для своих собственных случаев использования.
Настройка аргумента на 0 фактически отключает периодическое освобождение памяти полностью.
lua_malloc_trim 0; # полностью отключить обрезку
Текущая реализация использует обработчик фазы журнала Nginx для подсчета запросов. Таким образом, появление директив log_subrequest on в nginx.conf
может ускорить подсчет, когда участвуют подзапросы. По умолчанию учитываются только "основные запросы".
Обратите внимание, что эта директива не влияет на память, выделенную собственным аллокатором LuaJIT на основе системного вызова mmap.
Эта директива была впервые введена в релизе v0.10.7.
lua_code_cache
синтаксис: lua_code_cache on | off
по умолчанию: lua_code_cache on
контекст: http, server, location, location if
Включает или отключает кэш кода Lua для кода Lua в директивах *_by_lua_file (таких как set_by_lua_file и
content_by_lua_file) и модулях Lua.
При отключении каждый запрос, обслуживаемый ngx_lua, будет выполняться в отдельном экземпляре Lua VM, начиная с релиза 0.9.3. Таким образом, файлы Lua, на которые ссылаются set_by_lua_file,
content_by_lua_file, access_by_lua_file,
и т.д. не будут кэшироваться, и все используемые модули Lua будут загружаться с нуля. Это позволяет разработчикам применять подход редактирования и обновления.
Обратите внимание, однако, что код Lua, написанный встраиваемым способом в nginx.conf
таким образом, как это указано директивами set_by_lua, content_by_lua,
access_by_lua, и rewrite_by_lua, не будет обновляться, когда вы редактируете встроенный код Lua в вашем файле nginx.conf, потому что только парсер конфигурационного файла Nginx может правильно разобрать файл nginx.conf, и единственный способ - перезагрузить конфигурационный файл,
отправив сигнал HUP или просто перезапустив Nginx.
Даже когда кэш кода включен, Lua файлы, которые загружаются с помощью dofile или loadfile
в *_by_lua_file не могут быть кэшированы (если вы не кэшируете результаты самостоятельно). Обычно вы можете либо использовать директиву init_by_lua
или init_by_lua_file для загрузки всех таких файлов или просто сделать эти файлы Lua настоящими модулями Lua
и загружать их через require.
Модуль ngx_lua не поддерживает режим stat, доступный с модулем Apache mod_lua (пока).
Отключение кэша кода Lua настоятельно не рекомендуется для производственного использования и должно использоваться только в процессе разработки, так как это значительно негативно сказывается на общей производительности. Например, производительность примера "hello world" на Lua может упасть на порядок величины после отключения кэша кода Lua.
lua_thread_cache_max_entries
синтаксис: lua_thread_cache_max_entries <num>
по умолчанию: lua_thread_cache_max_entries 1024
контекст: http
Указывает максимальное количество записей, разрешенных в кэше объектов потоков Lua на уровне рабочего процесса.
Этот кэш перерабатывает объекты GC потоков lua среди всех наших "легких потоков".
Значение <num> равное нулю отключает кэш.
Обратите внимание, что эта функция требует LuaJIT OpenResty с новым C API lua_resetthread.
Эта функция была впервые введена в версии v0.10.9.
lua_regex_cache_max_entries
синтаксис: lua_regex_cache_max_entries <num>
по умолчанию: lua_regex_cache_max_entries 1024
контекст: http
Указывает максимальное количество записей, разрешенных в кэше скомпилированных регулярных выражений на уровне рабочего процесса.
Регулярные выражения, используемые в ngx.re.match, ngx.re.gmatch, ngx.re.sub и ngx.re.gsub, будут кэшироваться в этом кэше, если опция регулярного выражения o (т.е. флаг компиляции один раз) указана.
Максимальное количество записей, разрешенных по умолчанию, составляет 1024, и когда этот предел достигнут, новые регулярные выражения не будут кэшироваться (как если бы опция o не была указана), и в файле error.log будет одно, и только одно, предупреждение:
2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ...
Если вы используете реализацию ngx.re.* библиотеки lua-resty-core путем загрузки модуля resty.core.regex (или просто модуля resty.core), то для кэша регулярных выражений, используемого здесь, используется кэш LRU.
Не активируйте опцию o для регулярных выражений (и/или аргументов строк замены для ngx.re.sub и ngx.re.gsub), которые генерируются на лету и приводят к бесконечным вариациям, чтобы избежать достижения указанного предела.
lua_regex_match_limit
синтаксис: lua_regex_match_limit <num>
по умолчанию: lua_regex_match_limit 0
контекст: http
Указывает "предел соответствия", используемый библиотекой PCRE при выполнении ngx.re API. Цитируя страницу man PCRE, "предел ... имеет эффект ограничения объема обратного отслеживания, которое может иметь место."
Когда предел достигнут, строка ошибки "pcre_exec() failed: -8" будет возвращена функциями ngx.re API.
При установке предела на 0 используется значение "предел соответствия" по умолчанию при компиляции библиотеки PCRE. И это значение по умолчанию для этой директивы.
Эта директива была впервые введена в релизе v0.8.5.
lua_package_path
синтаксис: lua_package_path <lua-style-path-str>
по умолчанию: Содержимое переменной окружения LUA_PATH или встроенные значения Lua.
контекст: http
Устанавливает путь поиска модуля Lua, используемого скриптами, указанными в set_by_lua,
content_by_lua и других. Строка пути имеет стандартный формат пути Lua, и ;;
может использоваться для обозначения оригинальных путей поиска.
Начиная с релиза v0.5.0rc29, специальная нотация $prefix или ${prefix} может использоваться в строке пути поиска, чтобы указать путь к server prefix, обычно определяемый опцией командной строки -p PATH при запуске сервера Nginx.
lua_package_cpath
синтаксис: lua_package_cpath <lua-style-cpath-str>
по умолчанию: Содержимое переменной окружения LUA_CPATH или встроенные значения Lua.
контекст: http
Устанавливает путь поиска C-модуля Lua, используемого скриптами, указанными в set_by_lua,
content_by_lua и других. Строка cpath имеет стандартный формат cpath Lua, и ;;
может использоваться для обозначения оригинального cpath.
Начиная с релиза v0.5.0rc29, специальная нотация $prefix или ${prefix} может использоваться в строке пути поиска, чтобы указать путь к server prefix, обычно определяемый опцией командной строки -p PATH при запуске сервера Nginx.
init_by_lua
синтаксис: init_by_lua <lua-script-str>
контекст: http
фаза: loading-config
ПРИМЕЧАНИЕ Использование этой директивы не рекомендуется после релиза v0.9.17. Вместо этого используйте директиву init_by_lua_block.
Похоже на директиву init_by_lua_block, но принимает исходный код Lua напрямую в строковом литерале Nginx (что требует специального экранирования символов).
Например,
init_by_lua '
print("I need no extra escaping here, for example: \r\nblah")
'
Эта директива была впервые введена в релизе v0.5.5.
init_by_lua_block
синтаксис: init_by_lua_block { lua-script }
контекст: http
фаза: loading-config
Когда Nginx получает сигнал HUP и начинает перезагрузку конфигурационного файла, Lua VM также будет воссоздана, и init_by_lua_block будет выполнен снова на новой Lua VM. В случае, если директива lua_code_cache отключена (по умолчанию включена), обработчик init_by_lua_block будет выполняться при каждом запросе, потому что в этом специальном режиме всегда создается отдельная Lua VM для каждого запроса.
Обычно вы можете предварительно загрузить модули Lua при запуске сервера с помощью этого хука и воспользоваться оптимизацией копирования по записи (COW) современных операционных систем. Вот пример предварительной загрузки модулей Lua:
# это выполняется перед разветвлением процессов рабочих процессов nginx:
init_by_lua_block { require "cjson" }
server {
location = /api {
content_by_lua_block {
-- следующий require() просто вернет
-- уже загруженный модуль из package.loaded:
ngx.say(require "cjson".encode{dog = 5, cat = 6})
}
}
}
Вы также можете инициализировать хранилище shm lua_shared_dict на этой фазе. Вот пример для этого:
```nginx
lua_shared_dict dogs 1m;
init_by_lua_block { local dogs = ngx.shared.dogs dogs:set("Tom




