Вышел 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 изначально поддерживал динамические модули, для этого он и создавался, потому что фича очень нужная.
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 19

      +1
      Отлично! Я уже честно устал пересобирать свежие выпуски nginx с нужными мне модулями, теперь можно единожды (в общем случае) собрать модули, а пакетирование самого nginx оставить на совести мейнтейнеров дистрибутива.
        +1
        Ну и возможно понизит порог вхождения для новичков.

        Хотя именно с фразы в мануале «для этого вам придется пересобрать nginx с требуемым вам модулем» и началось мое увлекательное путешествие в кроличью нору *nix
          +1
          Пересобирать всё равно придётся, во всяком случае в ближайшем будущем.

          > We've been looking at whether this would let us offer a precompiled
          > ngx_pagespeed module, though, and it looks to me like this might be
          > pretty tricky? In order to load a module, it looks like it has to
          > have been compiled for that specific point release of nginx and with a
          > matching signature? So we would need to make binaries for 1.9.11,
          > 1.9.12, 1.9.13 etc and for each of those we would need to make ones
          > for each of the common signatures [1]. That's a lot of binaries to
          > prepare!

          Yes. We don't maintain a stable ABI between versions, and not
          even API between mainline versions. So preparing different
          binaries for different nginx versions is unavoidable for now.

          As of now general idea is that it should be possible to compile
          module that can be loaded into an nginx binary built on a
          particular OS with particular configure arguments. That is, you
          can prepare binaries targeting particular nginx distributions.

          In the future we are likely to review and reduce number of various
          options that change nginx internal structures and hence are
          included in the signature. This should improve compatibility
          between different builds.

          http://mailman.nginx.org/pipermail/nginx-devel/2016-February/007879.html
            0
            Поэтому я и упомянул «в общем случае» :) В принципе, задача сборки нужных модулей тоже можно возложить на мейнтейнеров, тогда просто нужно будет поставить nginx + необходимые модули, а не все скопом из пакета или собственноручно собираемые при каждом обновлении.
              0
              Но есть надежда, что спустя какое-то время этот функционал станет доступен по-умолчанию. Ну или, хотя бы, пока что один раз собрать с динамическими модулями, а потом их просто добавлять «на лету».
            –3
            Интересный ход. Но я не уверен, что понимаю подоплеку. Ведь сейчас каждый за два вечера сможет собрать Nginx Plus на базе модулей!
              0
              Люди умные, люди сишные, сделайте пожалуйста, расширение для получения уникального идентификатора запроса, который можно пробросить в upstreams? Или хотя бы получение хеш-суммы из произвольно конкатенированных переменных?
              Детали проблемы
              :)
                +1
                А в сторону lua не смотрели? Nginx же её умеет.
                  0
                  Не только lua, но и javascript. Правда, опять же, не из коробки
                    0
                    Там можно и перл вызывать. Но мне нужно только одно небольшое улучшение, не хочется тянуть слишком много для этого.
                      0
                      В общем случае, с lua ничего тянуть не придется, и все должно выглядеть проще, по крайней мере на debian/ubuntu, достаточно доставить nginx-extras:

                      aptitude install nginx-extras
                      

                      И lua в Nginx должен взлететь.

                      Центось я не уверен, не помню, но вроде там тоже можно просто сделать yum install nginx-extras.
                      Ну и я lua предложил только потому, что мы активно пользуем его в nginx, на довольно нагруженных участках, и оно хорошо себя ведет. А так, свет клином не сошелся, конечно.
                    0
                    Например github.com/streadway/ngx_txid не поможет?
                      0
                      Требует --configure, в этом и загвоздка. Собирать из исходников ради этого весь nginx не хочется.
                      0
                      https://github.com/hhru/nginx_requestid
                        0
                        Аналогично вышесказанному, это не динамический модуль и именно этим он и плох. Нужно компилировать, что в продакшн-среде очень некомфортно. Ради одной маленькой фичи не хочется это делать. Пока что меня больше устраивают длинные request-id, зато можно ставить в любой среде nginx из пакетов и решение продолжает стабильно работать.
                          +1
                          Его легко сделать динамическим путем исправления config к такому виду:

                          ngx_addon_name=ngx_http_requestid_filter_module

                          if [ $ngx_module_link = DYNAMIC ]; then
                          ngx_module_name=«ngx_http_requestid_filter_module»
                          ngx_module_srcs="$ngx_addon_dir/ngx_http_requestid_module.c"
                          . auto/module
                          elif [ $ngx_module_link = YES ]; then
                          ngx_module_type=HTTP
                          ngx_module_name=ngx_http_requestid_filter_module
                          ngx_module_incs=
                          ngx_module_deps=
                          ngx_module_srcs="$ngx_addon_dir/ngx_http_requestid_module.c"
                          . auto/module
                          fi
                            0
                            Спасибо, попробую ваш рецепт!
                      0
                      Эх, как же жалко, что перестали собирать под Debian и armhf :(
                        0
                        Динамические модули, как же долго я этого ждал.
                        Сколько матерных сов было высказано при необходимости каждый раз перекомпилировать )

                        Only users with full accounts can post comments. Log in, please.