Apache 1

Цей контент є частиною серії:

Слідкуйте за виходом нових статей цієї серії.

Звичайний сценарій, до якого залучено, з одного боку - користувач з браузером, з іншого - віддалений веб-сервер, складається з наступних подій: користувач натискає в своєму браузері на посилання, надсилає запит на веб-сервер, який по ньому витягує певний документ і повертає вміст цього документа віддаленому клієнту.

1. Архітектура Apache 1.x

Клієнтський запит проходить в Apache кілька фаз:

Кожна фаза управляється власним модулем Apache.

Apache 1

Apache 1

На кожен запит ядро ​​Apache створює об'єкт структури request_rec, яку потім передає по черзі відповідного модуля і отримує її в модифікованому варіанті.

На наступному малюнку архітектура Apache представлена ​​більш детально. Є невеликі функціональні модулі - ap, regex, які використовуються як ядром, так і іншими базовими модулями. Окремий модуль OS реалізує кроссплатформенность Apache.

Apache 1

Apache 1

При найближчому розгляді дерева початкових кодів з'ясовується:

  1. Всі заголовки згруповані в каталозі include.
  2. Ядро лежить в каталозі main (libmain.a).
  3. Базові модулі лежать в каталозі modules (libstandard.a).
  4. Реалізація платформ знаходиться в каталозі os, який включає в себе відповідні підкаталоги, в кожному з яких лежить свій відповідний заголовок os.h. (Libos.a).
  5. Окремий бібліотечний компонент для роботи з регулярними виразами лежить в каталозі regex (libregex.a).
  6. Окремий компонент лежить в каталозі ap і включає набір різних функцій (libap.a).
  7. Окремий компонент лежить в каталозі support і включає в себе скрипти та код для допоміжних утиліт Apache, таких як ротація лог файлів, маніпуляція з файлами паролів і т.д.
  8. Каталог helpers включає скрипти, які використовуються при компіляції самого Apache.

Практично всі функції мають префікс ap_, це було введено в версії 1.3 для уникнення конфлікту імен при переході з версії 1.2.

2. Архітектура ядра Apache 1

Код ядра лежить в каталозі main. Ядро було розроблено з урахуванням того, що будь-який, хто хоче розширювати функціонал Apache, по можливості не чіпав код ядра, який вже включає всі можливості для такого розширення. Єдиний внутрішній компонент ядра, який може піддаватися зміни - це реалізація HTTP протоколу.

Apache 1

Apache 1

3. Модулі Apache

Модулі реалізують функціонал Apache. Модулі можуть безпосередньо спілкуватися з ядром, але не можуть безпосередньо спілкуватися один з одним. Кожен модуль фактично є набором оброблювачів (хендлерів) для різних фаз HTTP запиту. Наступний малюнок дає детальний огляд архітектури модуля. Модуль - це колекція функцій-обробників, що викликаються ядром. Кожен модуль має власну структуру під назвою module, в якій зберігаються покажчики на обробники, і об'єкт такої структури кожен модуль передає ядру.

Apache 1

Apache 1

Кожен модуль повинен бути ініціалізованим першим ядром. За ідеєю, будь-який модуль може використовувати команди, які користувач прописує в файлі конфігурації. Читанням файлу займається ядро, яке потім зіставляє їх з таблицею команд, отриманих від модуля в структурі module. Кожен рядок в цій таблиці складається з пари: тип контенту - покажчик на обробник, де тип контенту - це MIME type.

Обробники, які займаються безпосередньою відсиланням даних клієнта, називаються content handlers або response handlers. Для кожного типу об'єкта є свій власний обробник.

В Apache всі модулі згруповані в каталозі modules. Стандартні модулі згруповані в підкаталозі standard. реалізація проксі лежить в каталозі proxy. Демонстраційний модуль, який має всього один обробник, лежить в каталозі examples.

Всі стандартні модулі завантажуються статично, хоча можлива динамічне завантаження: їх можна слінковать з ядром і так, і так. При інсталяції Apache, коли ви запускаєте конфігурацію, створюється файл modules.c, в якому визначаються 2 масиву покажчиків на модульні структури:

При цьому всі перераховані модулі можна розбити на наступні групи:

4. Паралелізм

При старті Apache створює (fork) за замовчуванням 5 головних процесів, це мінімальне можливе число процесів. Кожен процес в свою чергу може підтримувати як мінімум 50 потоків (thread - якщо многопоточность підтримується операційною системою). На кожне клієнтське запит відводиться один процес. Існує спеціальна структура - scoreboard - яка зберігає стан всіх процесів. Число одночасних можливих процесів за замовчуванням - від 5 до 10. Максимальне число таких процесів - 256. Є також спеціальна чергу для запитів на очікування, яким поки немає місця в scoreboard. Максимальна довжина такої черги - 511.

Максимально можливе число одночасних клієнтських коннектов - 100.

5. Структури даних

На наступному малюнку показана тимчасова діаграма проходження різних фаз клієнтського запиту, при цьому основна робота виконується в ядрі, в файлі http_request.c.

Apache 1

Apache 1

При виклику обробника кожного модуля передається в якості параметра одна і та ж публічна структура - request_rec. При цьому може відбуватися зміна стану різних полів цієї структури. Responce handlers повертають контент клієнту. Оброблювач також може виконувати інший під-запит. Структура request_rec може включати покажчик на іншу структуру request_rec в тому випадку, коли відбувається редирект, а в разі під-запиту покажчик може вказувати на саму себе. Редирект означає виклик обробника картинки всередині документа або виклик CGI-скрипта. При цьому викликається обробник ap_internal_redirect, який створює новий об'єкт request_rec. Такий об'єкт може бути поміщений в зв'язний список request_recs.

Структура request_rec містить в собі такі поля:

  • покажчики на інші request_rec;
  • покажчик на пул ресурсів;
  • об'єкти запиту:
    • URI
    • filename
    • path
  • інформація про контент:
    • тип контенту
    • кодування
  • MIME headers;
  • інформація про запит:
    • протокол
    • метод

Нижче дано вибіркове представлення структури request_rec з найбільш часто використовуваними полями:

Apache використовує пул ресурсів - pool - структуру даних, в якій зберігається список всіх виділених ресурсів для запиту. Коли обробка запиту закінчується, всі ресурси, витрачені на цей запит, звільняються. У модулів можуть бути свої власні пули на свої потреби.

Як вже було сказано, ядро ​​зберігає таблицю конфігураційних команд. Також і кожен модуль може мати свою власну командну таблицю. Кожна команда представляє об'єкт структури command_struct і включає:

  • ім'я команди;
  • покажчик на функцію-обробник;
  • переданий аргумент;
  • умови ініціалізації;
  • тип і число аргументів;
  • опис аргументів;

Структура scoreboard зберігає список оброблюваних запитів. Зберігається статус запиту та його id. Для кожного створюваного процесу в scoreboard додається запис, яка після обробки запиту видаляється. Статус процесу в цій структурі змінюється самим процесом. Статус запиту може набувати таких значень:

6. Обробник response

Результат роботи більшості оброблювачів зводиться до банального зміни значення полів структури request_rec, або до повернення спеціальних кодів. Даний же обробник відсилає реальні дані клієнта. Спочатку клієнтові відсилається HTTP-заголовок за допомогою функції send_http_header. Якщо у запиту є мітка header_only, то клієнту більш нічого не висилається. В іншому випадку, клієнту надсилається саме повідомлення, для цього використовуються спеціальні примітиви rputc, rprintf, send_fd. Наступний код показує обробку GET-запиту і відсилання даних клієнта:

Ця функція може повернути або код помилки, або OK, у другому випадку викликається редирект на інший обробник за допомогою internal_redirect.

Основна проблема, яка розв'язується за допомогою пулу - pool - це запобігання витокам пам'яті.

Пул в Apache розроблений таким чином, що звільнення всіх ресурсів - пам'яті, дескрипторів і т.д. - відбувається автоматично, після завершення обробки клієнтського запиту. Кожному такому запиту виділяється свій власний пул, представлений структурою pool. Після обробки цей пул видаляється.

При старті Apache виділяться спеціальний пул - конфігураційний. При перезапуску сервера цей пул також очищається.

Пам'ять виділяється за допомогою palloc, що швидше, ніж malloc. Ця функція має 2 аргументу - покажчик на пул і кількість виділеної пам'яті:

Функція pfree відсутня, оскільки звільнення пам'яті йде автоматично тоді, коли звільняється пул. Є спеціальні прикладні функції, які виділяють пам'ять. наприклад, в наступному прикладі функція pstrcat виділяє пам'ять під 8 байтовий строковий модуль:

Аналогічно відбувається відкриття файлів:

На відміну від роботи з пам'яттю, тут є відповідна закриває функція pfclose.

Загальним недоліком цієї моделі виділення пам'яті є вкладені пули. Можна змоделювати таку ситуацію, при якій батьківський пул звільняється раніше дочірнього, при якому можливий витік пам'яті для останнього. Наприклад, можна навести як приклад лістинг каталогу сервера з великим рівнем вкладеності. В цьому випадку для створення вкладених пулів потрібно використовувати make_sub_pool.

Пул також можна звільнити в будь-який момент за допомогою clear_pool або destroy_pool.

У разі підзапитів для надійного очищення пам'яті використовується destroy_sub_request.

8. Конфігурація

Перший Apache розроблявся з прицілом на максимальну сумісність зі своїм попередником - вебсервер NCSA 1.3 - в плані читання конфігураційних файлів. Було поставлено завдання винести максимально весь функціонал з ядра в модулі. Для цього в ядрі була створена спеціальна таблиця команд. Визначення типу файлу по суффиксу робиться на основі конфігураційних директив AddType і DefaultType.

Робота з файловою системою виконується за допомогою директив Aliases і Redirect.

Робота з вкладеними файлами виконується на базі файлів .htaccess.

Коли сервер читає в файлі директиву , він створює структуру mime_dir_config:

Команди AddType і AddEncoding зазвичай присутні в .htaccess.

Для створення такої структури потрібні 2 параметра - пул і ім'я каталогу:

Якщо в нашому серверному каталозі, який ми тільки що прочитали, є вкладений каталог, і там є свій власний .htaccess, нам доведеться об'єднувати дві структури:

висновок

Архітектура першого Apache має свої особливості - всі функції мають префікс ap_, реалізація платформ зроблена на основі окремих модулів, модулі не можуть спілкуватися один з одним, а тільки з ядром, всі модулі можна розбити на 7 основних груп: трансляція, аутентифікація, MIME, fix -ups, генератори контента, логирование, проксі. Управління пам'яттю реалізовано на основі пулів. Система конфігурація має широкі можливості для попереднього налаштування сервера.

Ресурси для скачування

Схожі теми

Схожі статті