Поддержка динамических общих объектов (DSO)
Сервер Apache HTTP — это модульная программа, где администратор может выбирать функциональность, включаемую в сервер, выбирая набор модулей. Модули будут компилироваться как динамические общие объекты (DSO), которые существуют отдельно от основного httpd двоичного файла. Модули DSO могут быть скомпилированы во время сборки сервера, или они могут быть скомпилированы и добавлены в более позднее время с помощью инструмента Apache Extension Tool (apxs).
В качестве альтернативы, модули могут быть статически скомпилированы в httpd двоичный файл во время сборки сервера.
Этот документ описывает, как использовать модули DSO, а также теорию, лежащую в основе их использования.
Реализация
| Связанные модули | Связанные директивы |
|---|---|
Поддержка DSO для загрузки отдельных модулей Apache httpd основана на модуле, названном mod_so, который должен быть статически скомпилирован в ядро Apache httpd. Это единственный модуль помимо core, который нельзя поместить в DSO. Практически все другие распределённые модули Apache httpd будут размещены в DSO. После компиляции модуля в DSO под названием mod_foo.so вы можете использовать директиву mod_so's LoadModule в вашем файле httpd.conf, чтобы загрузить этот модуль при запуске или перезапуске сервера.
Сборка DSO для отдельных модулей может быть отключена с помощью опции configure's --enable-mods-static, как описано в документации по установке.
Чтобы упростить создание файлов DSO для модулей Apache httpd (особенно для модулей сторонних разработчиков), доступна программа поддержки под названием apxs (APache eXtenSion). Её можно использовать для построения модулей на основе DSO вне дерева исходных кодов Apache httpd. Идея проста: при установке Apache HTTP Server процедура configure's make install устанавливает заголовочные файлы Apache httpd C и помещает платформозависимые флаги компилятора и компоновщика для построения файлов DSO в программу apxs. Таким образом, пользователь может использовать apxs для компиляции исходных кодов своего модуля Apache httpd без дерева исходных кодов дистрибутива Apache httpd и без необходимости вносить изменения в платформозависимые флаги компилятора и компоновщика для поддержки DSO.
Краткое руководство по использованию
Для обзора возможностей DSO в Apache HTTP Server 2.x приведён краткий и лаконичный обзор:
-
Скомпилируйте и установите распределённый модуль Apache httpd, например
mod_foo.c, в свой DSOmod_foo.so:$ ./configure --prefix=/path/to/install --enable-foo $ make install
-
Настройте Apache HTTP Server со всеми включенными модулями. Только базовый набор будет загружен во время запуска сервера. Вы можете изменить набор загруженных модулей, активировав или деактивировав директивы
LoadModuleвhttpd.conf.$ ./configure --enable-mods-shared=all $ make install
-
Некоторые модули полезны только для разработчиков и не будут включены при использовании набора модулей all. Для построения всех доступных модулей, включая модули разработчиков, используйте reallyall. Кроме того, директивы
LoadModuleдля всех построенных модулей могут быть активированы через опцию конфигурации--enable-load-all-modules.$ ./configure --enable-mods-shared=reallyall --enable-load-all-modules $ make install
- Скомпилируйте и установите модуль стороннего разработчика Apache httpd, например
mod_foo.c, в свой собственный DSOmod_foo.soвне дерева исходных кодов Apache httpd с помощьюapxs:$ cd /path/to/3rdparty $ apxs -cia mod_foo.c
Во всех случаях после компиляции общего модуля необходимо использовать директиву LoadModule в httpd.conf, чтобы сообщить Apache httpd об активации модуля.
Для получения дополнительной информации см. документацию по apxs.
Обзор
В современных Unix-подобных системах существует механизм динамической загрузки/подключения динамических общих объектов (DSO), который предоставляет способ компиляции части программного кода в специальном формате для загрузки его во время выполнения в адресное пространство исполняемого файла.
Загрузка обычно может выполняться двумя способами: автоматически программой системы под названием ld.so при запуске исполняемого файла или вручную изнутри исполняемой программы через программируемый системный интерфейс к загрузчику Unix посредством системных вызовов dlopen()/dlsym().
В первом случае DSO обычно называют общими библиотеками или библиотеками DSO и называют их libfoo.so или libfoo.so.1.2. Они находятся в системном каталоге (обычно /usr/lib) и ссылка на исполняемый файл устанавливается во время компиляции путём указания -lfoo команде компоновщика. Это жёстко задаёт ссылки на библиотеки в файле исполняемого файла, чтобы в момент запуска загрузчик Unix мог найти libfoo.so в /usr/lib, в путях, жёстко заданных через параметры компоновщика, или в путях, заданных переменной среды -R. Затем он разрешает любые (ещё не разрешённые) символы в исполняемом файле, которые доступны в DSO.
Символы в исполняемом файле обычно не ссылаются на DSO (поскольку это повторно используемая библиотека общего кода), и поэтому дальнейшего разрешения делать не нужно. Исполняемому файлу нет необходимости делать что-либо самостоятельно, чтобы использовать символы из DSO, потому что полное разрешение выполняется загрузчиком Unix. (Фактически, код вызова ld.so является частью кода запуска во время выполнения, который связан с каждым исполняемым файлом, который был связан не статически). Преимущество динамической загрузки общего кода библиотеки очевидно: код библиотеки нужно хранить только один раз, в системной библиотеке, как libc.so, что экономит дисковое пространство для каждой программы.
Во втором случае DSO обычно называют объектами или файлами DSO и могут иметь произвольное расширение (хотя каноническое имя — foo.so). Эти файлы обычно находятся внутри каталога, специфичного для программы, и нет автоматически установленной связи с исполняемым файлом, где они используются. Вместо этого исполняемый файл вручную загружает DSO в своё адресное пространство во время выполнения с помощью dlopen(). В этот момент не выполняется разрешение символов из DSO для исполняемого файла. Вместо этого загрузчик Unix автоматически разрешает любые (ещё не разрешённые) символы в DSO из набора символов, экспортированных исполняемым файлом и уже загруженными библиотеками DSO (особенно все символы из повсеместной libc.so). Таким образом, DSO получает знания о наборе символов исполняемого файла, как если бы он был статически связан с ним в первом случае.
Наконец, для использования API DSO исполняемый файл должен разрешить определённые символы из DSO с помощью dlsym() для последующего использования внутри таблиц обработки и т. д. Другими словами: исполняемый файл должен вручную разрешать каждый символ, который он должен использовать. Преимущество такого механизма заключается в том, что необязательные части программы не загружаются (и, следовательно, не тратят память) до тех пор, пока они не потребуются конкретной программе. При необходимости эти части программы могут быть загружены динамически для расширения функциональности основной программы.
Хотя этот механизм DSO кажется простым, есть по крайней мере одна трудная задача: разрешение символов из исполняемого файла для DSO при использовании DSO для расширения программы (второй способ). Почему? Потому что «обратное разрешение» символов DSO из набора символов исполняемого файла противоречит дизайну библиотеки (где библиотека не знает о программах, в которых она используется) и не доступно на всех платформах, а также не стандартизировано. На практике глобальные символы исполняемого файла часто не повторно экспортируются и, следовательно, не доступны для использования в DSO. Нахождение способа заставить компоновщик экспортировать все глобальные символы — основная проблема, которую необходимо решить при использовании DSO для расширения программы во время выполнения.
Подход с общей библиотекой является типичным, поскольку именно для этого был разработан механизм DSO, поэтому он используется для почти всех типов библиотек, предоставляемых операционной системой.
Преимущества и недостатки
Вышеупомянутые функции на основе DSO имеют следующие преимущества:
- Пакет сервера более гибкий во время выполнения, потому что процесс сервера может быть собран во время выполнения через директивы конфигурации
LoadModulehttpd.confвместо опцийconfigureво время компиляции. Например, таким образом можно запустить разные экземпляры сервера (стандартный и SSL, минималистичный и динамичный [mod_perl, mod_php] и т. д.) с помощью одной установки Apache httpd. - Пакет сервера легко расширяется модулями сторонних разработчиков даже после установки. Это большая выгода для поставщиков пакетов, которые могут создать пакет ядра Apache httpd и дополнительные пакеты, содержащие расширения, такие как PHP, mod_perl, mod_security и т. д.
- Проще прототипировать модули Apache httpd, так как с парой DSO/
apxsвы можете работать вне дерева исходных кодов Apache httpd и вам нужна только командаapxs -iвместе сapachectl restart, чтобы добавить новую версию вашего текущего модуля в работающий Apache HTTP Server.
DSO имеет следующие недостатки:
- Сервер примерно на 20% медленнее при запуске из-за накладных расходов на разрешение символов, которые теперь должен выполнять загрузчик Unix.
- Сервер примерно на 5% медленнее во время выполнения на некоторых платформах, потому что позиционно-независимый код (PIC) иногда требует сложных ассемблерных трюков для относительного адресования, которые не обязательно так же быстры, как абсолютное адресование.
- Поскольку модули DSO не могут быть связаны с другими DSO-библиотеками (
ld -lfoo) на всех платформах (например, платформы a.out обычно не предоставляют этой функциональности, в то время как платформы ELF — да), вы не можете использовать механизм DSO для всех типов модулей. Или другими словами, модули, скомпилированные как файлы DSO, ограничены только использованием символов из ядра Apache httpd, из библиотеки C (libc) и всех других динамических или статических библиотек, используемых ядром Apache httpd, или из архивов статических библиотек (libfoo.a) содержащих позиционно-независимый код. Единственные возможности использования другого кода — либо убедиться, что само ядро httpd уже содержит ссылку на него, либо загрузить код самостоятельно с помощьюdlopen().
© 2018 The Apache Software Foundation
Licensed under the Apache License, Version 2.0.
https://httpd.apache.org/docs/2.4/en/dso.html