Вышел Nginx 1.9.11 с поддержкой динамических модулей
9 февраля состоялся выпуск nginx 1.91.11 с долгожданной поддержкой динамических модулей, которую анонсировали разработчики nginx на Хабре в апреле 2015 г.
Список изменений
- Добавление: теперь resolver поддерживает TCP.
- Добавление: динамические модули.
- Исправление: при использовании HTTP/2 переменная $request_length не учитывала размер заголовков запроса.
- Исправление: в модуле ngx_http_v2_module.
Динамические модули компилируются как отдельные файлы .so и подгружаются в процессе работы nginx, в любой момент. Не нужно заново компилировать nginx каждый раз при добавлении модуля.
В документации сказано, что не каждый статичный модуль можно конвертировать в динамический. Не следует делать такую конвертацию для модулей, которые патчат исходный код nginx, они не будут работать. И рекомендуют использовать только те вызовы API, которые непосредственно предназначены для модулей.
Вдобавок, если модули должны были устанавливаться в определённом порядке, то для динамических модулей нужно будет указать значение ngx_module_order
.
API остались одинаковыми как для оригинальных статичных модулей, так и для динамических.
Компиляция динамического модуля
Появилась новая опция в конфиге для добавления модуля в качестве динамического. Вместо использования --add-module
пишем --add-dynamic-module
. Например:
$ ./configure --add-dynamic-module=/opt/source/ngx_my_module/
После компиляции будет создан бинарный модуль в файле .so
(Shared Object). Этот файл затем переносится в поддиректорию modules
в папке установки nginx.
Загрузка динамического модуля
Модули можно загружать в nginx с помощью новой директивы load_module
. Например:
load_module modules/ngx_my_module.so;
По умолчанию установлен максимальный лимит в 128 одновременно загружаемых динамических модулей. Это значение можно изменить в переменной NGX_MAX_DYNAMIC_MODULES
в исходном коде nginx.
Преобразование конфигурационного файла
Ниже пример конфига в старом стиле для стороннего модуля ngx_http_response_module:
ngx_addon_name=ngx_http_response_module
HTTP_MODULES="$HTTP_MODULES ngx_http_response_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_response_module.c"
Теперь для настройки многих вещей используется скрипт сборки auto/module
, так что новые конфиги подходят и для статичных, и для динамических модулей. Для того же ngx_http_response_module
будет выглядеть следующим образом:
ngx_addon_name=ngx_http_response_module
if test -n "$ngx_module_link"; then
ngx_module_type=HTTP
ngx_module_name=ngx_http_response_module
ngx_module_incs=
ngx_module_deps=
ngx_module_srcs="$ngx_addon_dir/ngx_http_response_module.c"
ngx_module_libs=
. auto/module
else
HTTP_MODULES="$HTTP_MODULES ngx_http_response_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_response_module.c"
fi
Как видим, в него включён старый файл config
, поэтому старые версии nginx будут совместимы с этим модулем.
Более подробно о новом формате конфига см. здесь.
Пример сложного модуля
Наконец, в документации nginx приводится пример сложносоставного модуля, которые в реальности вмещают несколько модулей в одном пакете. Их немного сложнее конвертировать. Такие модули придётся разбить на несколько модулей при компиляции в качестве статичных модулей, но можно оставить единым файлом .so
при компиляции в качестве динамических модулей. Вот пример модуля ngx_rtmp_module, который содержит модули CORE и HTTP.
Результат преобразования выглядит следующим образом:
ngx_addon_name="ngx_rtmp_module"
RTMP_CORE_MODULES=" \
ngx_rtmp_module \
ngx_rtmp_core_module \
ngx_rtmp_cmd_module \
ngx_rtmp_codec_module \
ngx_rtmp_access_module \
ngx_rtmp_record_module \
ngx_rtmp_live_module \
ngx_rtmp_play_module \
ngx_rtmp_flv_module \
ngx_rtmp_mp4_module \
ngx_rtmp_netcall_module \
ngx_rtmp_relay_module \
ngx_rtmp_exec_module \
ngx_rtmp_auto_push_module \
ngx_rtmp_notify_module \
ngx_rtmp_log_module \
ngx_rtmp_limit_module \
ngx_rtmp_hls_module \
ngx_rtmp_dash_module \
"
RTMP_HTTP_MODULES=" \
ngx_rtmp_stat_module \
ngx_rtmp_control_module \
"
RTMP_DEPS=" \
$ngx_addon_dir/ngx_rtmp_amf.h \
$ngx_addon_dir/ngx_rtmp_bandwidth.h \
$ngx_addon_dir/ngx_rtmp_cmd_module.h \
$ngx_addon_dir/ngx_rtmp_codec_module.h \
$ngx_addon_dir/ngx_rtmp_eval.h \
$ngx_addon_dir/ngx_rtmp.h \
$ngx_addon_dir/ngx_rtmp_version.h \
$ngx_addon_dir/ngx_rtmp_live_module.h \
$ngx_addon_dir/ngx_rtmp_netcall_module.h \
$ngx_addon_dir/ngx_rtmp_play_module.h \
$ngx_addon_dir/ngx_rtmp_record_module.h \
$ngx_addon_dir/ngx_rtmp_relay_module.h \
$ngx_addon_dir/ngx_rtmp_streams.h \
$ngx_addon_dir/ngx_rtmp_bitop.h \
$ngx_addon_dir/ngx_rtmp_proxy_protocol.h \
$ngx_addon_dir/hls/ngx_rtmp_mpegts.h \
$ngx_addon_dir/dash/ngx_rtmp_mp4.h \
"
RTMP_CORE_SRCS=" \
$ngx_addon_dir/ngx_rtmp.c \
$ngx_addon_dir/ngx_rtmp_init.c \
$ngx_addon_dir/ngx_rtmp_handshake.c \
$ngx_addon_dir/ngx_rtmp_handler.c \
$ngx_addon_dir/ngx_rtmp_amf.c \
$ngx_addon_dir/ngx_rtmp_send.c \
$ngx_addon_dir/ngx_rtmp_shared.c \
$ngx_addon_dir/ngx_rtmp_eval.c \
$ngx_addon_dir/ngx_rtmp_receive.c \
$ngx_addon_dir/ngx_rtmp_core_module.c \
$ngx_addon_dir/ngx_rtmp_cmd_module.c \
$ngx_addon_dir/ngx_rtmp_codec_module.c \
$ngx_addon_dir/ngx_rtmp_access_module.c \
$ngx_addon_dir/ngx_rtmp_record_module.c \
$ngx_addon_dir/ngx_rtmp_live_module.c \
$ngx_addon_dir/ngx_rtmp_play_module.c \
$ngx_addon_dir/ngx_rtmp_flv_module.c \
$ngx_addon_dir/ngx_rtmp_mp4_module.c \
$ngx_addon_dir/ngx_rtmp_netcall_module.c \
$ngx_addon_dir/ngx_rtmp_relay_module.c \
$ngx_addon_dir/ngx_rtmp_bandwidth.c \
$ngx_addon_dir/ngx_rtmp_exec_module.c \
$ngx_addon_dir/ngx_rtmp_auto_push_module.c \
$ngx_addon_dir/ngx_rtmp_notify_module.c \
$ngx_addon_dir/ngx_rtmp_log_module.c \
$ngx_addon_dir/ngx_rtmp_limit_module.c \
$ngx_addon_dir/ngx_rtmp_bitop.c \
$ngx_addon_dir/ngx_rtmp_proxy_protocol.c \
$ngx_addon_dir/hls/ngx_rtmp_hls_module.c \
$ngx_addon_dir/dash/ngx_rtmp_dash_module.c \
$ngx_addon_dir/hls/ngx_rtmp_mpegts.c \
$ngx_addon_dir/dash/ngx_rtmp_mp4.c \
"
RTMP_HTTP_SRCS=" \
$ngx_addon_dir/ngx_rtmp_stat_module.c \
$ngx_addon_dir/ngx_rtmp_control_module.c \
"
ngx_module_incs=$ngx_addon_dir
ngx_module_deps=$RTMP_DEPS
ngx_module_libs=
if [ $ngx_module_link = DYNAMIC ] ; then
ngx_module_name="$RTMP_CORE_MODULES $RTMP_HTTP_MODULES"
ngx_module_srcs="$RTMP_CORE_SRCS $RTMP_HTTP_SRCS"
. auto/module
elif [ $ngx_module_link = YES ] ; then
ngx_module_type=CORE
ngx_module_name=$RTMP_CORE_MODULES
ngx_module_srcs=$RTMP_CORE_SRCS
. auto/module
ngx_module_type=HTTP
ngx_module_name=$RTMP_HTTP_MODULES
ngx_module_incs=
ngx_module_deps=
ngx_module_srcs=$RTMP_HTTP_SRCS
. auto/module
fi
USE_OPENSSL=YES
Значение $ngx_module_link
установлено DYNAMIC
для динамического модуля и YES
для статического модуля. Во втором случае скрипт сборки auto/module
вызывается дважды.
P.S. Кстати, один из форков Tengine изначально поддерживал динамические модули, для этого он и создавался, потому что фича очень нужная.