Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Библиотека Warp

Глава 11 из книги "Производительность приложений с открытым исходным кодом".

Оригинал: Warp
Авторы: Kazu Yamamoto, Michael Snoyman, Andreas Voellmy
Перевод: Н.Ромоданов

Композер HTTP-ответа

В этом разделе описывается композер HTTP-ответа библиотеки Warp. Ответ Response в WAI имеет три конструктора:

ResponseFile Status ResponseHeaders FilePath (Maybe FilePart)
ResponseBuilder Status ResponseHeaders Builder
ResponseSource Status ResponseHeaders (Source (ResourceT IO) (Flush Builder))

Конструктор ResponseFile используется для отправки статического файла, тогда как конструкторы ResponseBuilder и ResponseSource предназначены для отправки динамического содержимого, созданного в памяти. В состав каждого конструктора входят составляющие Status и ResponseHeaders. ResponseHeaders определяется как список пар заголовка ключ/значение.

Композер заголовка HTTP-ответа

Старый композер собирал заголовок ответа HTTP с использованием структуры Builder, структуры данных, работа с которой походила на плетение веревки. Во-первых, Status и каждый элемент ResponseHeaders он преобразовывался в Builder. Каждое преобразование работает за O(1). Затем с помощью добавления еще одного Builder происходило их объединение их друг к другу. Благодаря свойствам Builder, каждая операция добавления также выполнялась за время O(1). Наконец, за время O(N) при помощи копирования данных из структуры Builder в буфер происходила упаковка заголовка HTTP-ответа.

Во многих случаях, производительность структуры Builder была достаточной. Но на практике мы убедились, что ее недостаточно для высокопроизводительных серверов. Для устранения накладных расходов, связанных с Builder, мы для заголовков HTTP-ответов реализовали специальный композер, в котором используется memcpy(), очень хорошо настроенная функция языка С, предназначенная для копирования байтов.

Композер тела HTTP-ответа

Для конструкторов ResponseBuilder и ResponseSource, значения Builder, передаваемые приложением, упакованы в список строк типа ByteString. Собранный заголовок добавляется к началу списка и для того, чтобы отправить список в буфер. используется команда send().

В случае конструктора ResponseFile, Warp для того, чтобы отправить заголовок и тело HTTP-ответа, использует команды send() и sendfile(), соответственно. На рис.11.7 проиллюстрирована эта ситуация. Опять же, благодаря механизму кэширования, описанному в разделе «Таймеры дескрипторов файлов» можно не выполнять некоторые системные вызовы open(), stat(), close() и другие. В следующем подразделе описывается еще один вариант настройки производительности в случае использования конструктора ResponseFile.

Совместная отсылка заголовка и тела

Когда мы измеряли производительность Warp при отправке статических файлов, мы всегда выполняли это с высокой степенью распараллеливания (несколько подключений одновременно) и достигали хороших результатов. Однако, когда мы установили значение распараллеливания, равным 1, мы обнаружили, что Warp работает очень медленно.

Наблюдая за результатами работы команды tcpdump, мы поняли, что это происходит из-за того, что первоначально в Warp используется комбинация команды writev(), применяемой для заголовка HTTP, и команды sendfile(), применяемой для тела HTTP. В этом случае заголовок и тело HTTP посылаются в отдельных пакетах TCP (рис. 11.11).

Рис.11.11: Последовательность пакетов в старом варианте библиотеки Warp

Для того, чтобы отправить их в одном пакете TCP (когда это возможно), в новой версии Warp мы перешли от команды writev() к команде send(). В новом варианте для запоминания заголовка используется команда send() с флагом MSG_MORE, а для отправки запомненного заголовка и файл используется команда sendfile(). Это сделало пропускную способность, по крайней мере, в 100 раз выше в сравнении с пропускной способностью нашего первоначального варианта.


Продолжение статьи: Очистка с помощью таймеров.