Поддержка динамических разделяемых объектов (DSO)
Сервер Apache HTTP — это модульная программа, в которой администратор может выбирать функциональность сервера, задавая набор модулей. Модули компилируются в виде динамических разделяемых объектов (DSO), существующих отдельно от основного двоичного файла httpd. Модули DSO можно скомпилировать при сборке сервера или скомпилировать и добавить позднее с помощью инструмента расширения Apache (apxs).
В качестве альтернативы модули можно статически скомпилировать в двоичный файл httpd при сборке сервера.
В этом документе описано, как использовать модули DSO, а также изложена теория, лежащая в основе их использования.
Реализация
| Связанные модули | Связанные директивы |
|---|---|
Поддержка загрузки отдельных модулей Apache httpd с помощью DSO основана на модуле с именем mod_so, который должен быть статически скомпилирован в ядро Apache httpd. Это единственный модуль, помимо core, который нельзя поместить в DSO. Практически все остальные распространяемые модули Apache httpd будут помещены в DSO. После компиляции модуля в DSO с именем mod_foo.so вы можете использовать директиву LoadModule модуля mod_so в файле httpd.conf, чтобы загрузить этот модуль при запуске или перезапуске сервера.
Сборку DSO для отдельных модулей можно отключить с помощью параметра --enable-mods-static модуля configure, как описано в документации по установке.
Для упрощения создания файлов DSO для модулей Apache httpd (особенно сторонних модулей) предусмотрена вспомогательная программа с именем apxs (APache eXtenSion). Её можно использовать для сборки модулей на основе DSO вне дерева исходного кода Apache httpd. Идея проста: при установке Apache HTTP Server процедура make install модуля configure устанавливает заголовочные файлы C для Apache httpd и записывает в программу apxs зависящие от платформы флаги компилятора и компоновщика, необходимые для сборки файлов DSO. Благодаря этому пользователь может использовать 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, или в путях, заданных переменной окружения LD_LIBRARY_PATH. Затем он разрешает все (ещё не разрешённые) символы исполняемой программы, доступные в 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 и для установки новой версии разрабатываемого модуля в работающий Apache HTTP Server достаточно выполнить командуapxs -i, а затемapachectl restart.
У 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