Диплом: Повышение производительности веб-приложения за счет обратного проксирования с помощью NGINX

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам
42
сообщение и оно появлялось только после нажатия кнопки «Обновить
страницу». Такое поведение создавало впечатление неработоспособной.
Важную роль при кэшировании играет ключ страницы, задающийся
директивой proxy_cache_key. Можно заметить, что для каких-то страниц
используется комбинация $host$uri$is_args$args, а для других (все из локации
@fastcache) добавляется куки, идентифицирующий пользователя. Важно
делать так, чтобы кэш разных пользователей не пересекался. Соответственно,
персонифицированные страницы должны быть уникальны в кэше[7, 32].
Для распределения по локациям нельзя использовать директиву if. В
конфигурировании nginx ее использование для этих целей считается дурным
тоном, так как результаты ее использования порой бывают непредсказуемы.
Для этих целей следует использовать map и механизм, предоставляемый
средствами обработки ошибок, как сделано в этой работе[2,14].
Также следует отметить небольшой нюанс, связанный с ведением
журналов access_log. Не стоит логировать целиком запрос, который
находится в переменной @request, по крайней мере для таких целей, какие
преследовались в этой работе. Имеет смысл записывать отдельными полями
метод запроса $request_method, $request_uri и, если нужно, версию
протокола. Такой журнал легче обрабатывать, систематизировать и получать
статистику.
Во всех директивах proxy_pass помимо сервера бек-энда и порта, на
который нужно передать запрос был добавлен uri, который должен
передаваться. Это было сделано во всех локациях, кроме @midcache. По
умолчанию на сервер должно передаваться значение, соответствующее
$request_uri, но приложение в некоторых случаях вело себя неадекватно –
через раз вместо запрашиваемой страницы выдавало ту, которая должна
открываться без указания аргументов или если они неверно распознаны.
Добавление к адресу сервера переменных $uri,$is_args и $args исправило это
поведение (например, proxy_pass http://@rms/$uri$is_args$args;)
43
ГЛАВА 3. Дальнейшая оптимизация работы приложения
3.1. Оптимизация работы back-end сервера
3.1.1. Создание стека с тестовым приложением
Наиболее узким местом в приложении является архитектура БД.
Приложение разрабатывалось более 10 лет назад, об эффективности работы
БД разработчики не сильно беспокоились, а сильно выросшая за это время
база данных работать достаточно медленно. В данном случае, не прибегая к
серьезным изменениям, несколько оптимизировать работу бек-энда позволит
включение репликации master-master, что даст возможность равномерно
распределять запросы по двум серверам, не зависимо от запрашиваемого
метода. Сделать это можно, повторив процесс настройки, описанный в главе
2 в обеих направлениях. В контейнере db необходимо дополнительно
настроить мастер, внеся соответствующие изменения в файл conf/mysql-
rms.cnf. А на старом сервере с приложением, соответственно, понадобится
настроить слейв. После этого сервера смогут реплицировать изменения друг
с друга.
Однако наиболее широкие возможности оптимизации приложения
будут получены благодаря возможности использования SSI. SSI – server side
inclusion (включение на стороне сервера). Блоки SSI – это, по сути, простые
комментарии на языке html, содержащие в себе предписание о том, как их
должен обработать сервер. Грубо говоря, эта технология позволяет отдавать
на nginx шаблон html с расставленными в нем блоками ssi, содержимое
которых nginx получит из других мест[4,21,30,41].
Если параллельно с этим избавиться от некоторых уникальных для
пользователя элементов на одинаковом для всех контенте (например, цифры
в списках с задачами, означающие количество новых сообщений), можно
будет создавать разделяемый между пользователями кэш списков и задач.
Задачи в этом случае станет очень удобно кэшировать, если задействовать
очистку кэша (об этом в 3 разделе 3 главы).
44
Если добавить куки, в котором будет храниться роль пользователя в
системе и информация о доступах к проектам, можно будет использовать
кэш списков, разделяемый между определенными группами пользователей.
Например, группа управляющих сейчас видит одни и те же списки, однако на
страницах с ними присутствует уникальная для пользователя информация.
Рассмотрим по пунктам, что следует сделать, чтобы описанное стало
возможным:
1. Подготовить общий шаблон, который будет одинаков вообще для
всех пользователей. Его можно будет как угодно кэшировать, либо
он вообще может быть статическим html файлом, который nginx
будет отдавать из каталога с файлами приложения.
2. Подготовить скрипт index.php (основная и единственная точка входа
в приложение РМС) так, чтобы можно было получать отдельные
блоки страниц, в которых будет отсутствовать уникальное
содержимое, а не страницы целиком как сейчас. Это могут быть
сообщения внутри задач или списки задач, отобранные и
отсортированные по определенным признакам. Также нужно будет
создать возможность отдельно запросить уникальное для
пользователя содержимое для соответствующего общего блока.
3. Подготовить скрипт, который после загрузки страницы отдельным
запросом будет получать уникальное содержимое и заполнять им
нужные места. Это различные метаданные, отражающие количество
новых сообщений, непрочитанных сообщений, сообщений от
контрагентов, которые помечаются особым образом. Нет ни каких
проблем заполнять это после загрузки списка, создав в html шаблоне
списка пустые элементы с соответствующими идентификаторами.
4. Сконфигурировать nginx для работы с блоками ssi с помощью
директив в контексте сервера ssi on; и ssi_types, если в блоках ssi
будут использоваться типы помимо text/html
45
Для включения в блок ssi динамического содержимого используется
конструкция <!--# include virtual=page_uri -->, для включения статического
файла - <!--# include file=file_path -->
Из описанного может быть не совсем ясно, как это работает. Гораздо
лучше продемонстрировать работу этого механизма на небольшом примере.
Для применения технологий, которые описаны в этом и последующем
разделах, необходима длительная и дорогостоящая модификация
приложения. Для демонстрации работы технологий можно использовать
тестовый стенд.
Создадим простое приложение, для него будет создан отдельный стек с
помощью Docker Compose. Nginx будет отдавать одну страницу - простой
шаблон html, созданный на базе одного из списков задач реального
приложения. Вместо основного содержимого страницы в нее будет включен
блок ssi. Содержимое блока будет генерироваться php сценарием, для работы
которого будет запущен отдельный контейнер с веб-сервером Apache и php.
Он будет получать из базы mysql два элемента – задача 1 и задача 2. Каждый
элемент будет состоять из двух столбцов: название и время. Php будет
вписывать в колонку «время» текущие дату и время, это понадобится чтобы
идентифицировать взят блок из кэша или получен с бек-энда. В задачу
можно будет зайти, кликнув по названию, и увидеть список из нескольких
сообщений, также получаемых из базы данных. Сообщения можно будет
добавлять, отправляя POST запрос к странице с открытой задачей.
46
Рисунок 9. Структура стека тестового приложения app.
При добавлении информации в сообщения будет производиться запись
в базу данных app. Структура ее таблиц приведена в приложении 11.
Обратите внимание, на рисунке присутствуют два сервера СУБД.
Между ними настроена репликация master-master, примеры включаемых
конфигурационных файлов приведены в приложении 12. В данный момент
приложение может использовать для разрешения имени SQL сервера общий
для двух серверов псевдоним, но для простоты на данном этапе просто
используется mysql1. В следующем разделе будет продемонстрировано
использование модуля ngx_stream_module, который позволяет балансировать
нагрузку между mysql серверами с помощью nginx[12].
Приложение будет иметь всего два типа страниц. На главной странице
выводятся заголовки задач:
Рисунок 10. Главная страница тестового приложения.
47
По каждому из заголовков в колонке имя можно кликнуть и попасть на
страницу с сообщениями и формой для их отправки:
Рисунок 11. Страница с сообщениями.
Соответственно можно написать сообщение на страницу, вписав его в
текстовое поле и нажав кнопку «Написать».
Конфигурационный файл nginx, используемый в данном примере,
приведен в приложении 8. Настройка позволяет кэшировать на короткое
время содержимое таблицы с задачами, но предотвращает попадание к кэш
содержимого задач.
Статический index.html файл включает в себя несколько блоков ssi,
выбор которых зависит от аргумента show. Полный текст файла приведен в
приложении 6.
48
В зависимости от аргумента show скрипту render.php передаются
аргументы, в соответствии с которыми будет выглядеть страница. Текст
скрипта приведен в приложении 7.
Для того, чтобы шаблон index.html тоже кэшировался нужно сделать
небольшие изменения в конфигурационном файле – добавить директиву map,
определяющую переменную $bypass, и применение кэша для локации /
(конфигурационный файл в приложении уже содержит эти изменения).
В этом примере показано:
1. Для разгрузки бек-энд сервера Apache применяется кэширование
одного из видов динамических страниц. Это, в случае
рассматриваемого в основной части работы, приложения ощутимо
ускоряет приложение и часть нагрузки с сервера бек-энда;
2. Серверу бек-энда теперь нет необходимости каждый раз
генерировать основной шаблон страницы. Это занимает ничтожное
количество времени для php, но с учетом того, что это происходило
абсолютно каждый раз при обращении к любой странице, выигрыш
может быть существенным
3. После того, как шаблон html стал кэшироваться, пропала
необходимость получать его с сервера бек-энда. Это достаточно
весомо, так как операция также выполнялась каждый раз при
запросе пользователем страницы.
Для ознакомления приложение доступно по адресу
http://ssi.pictcut.com:8481
3.1.2. Анализ производительности после изменений
Для анализа производительности приложения будет использована
методика, примененная в главе 2. Разница будет заключаться в том, что с
тестовым приложением ни кто реально не работает и при сборе данных будет
здесь и в последующих разделах будет использован следующий паттерн,
49
описывающий перемещение пользователя по сайту. В начале кэш сервера
будет полностью очищен:
1. http://ssi.pictcut.com:8481/index.html?arg=tableзагрузка страницы
со списком задач с бек-энда, так как кэша еще нет;
2. http://ssi.pictcut.com:8481/index.html?show=messages&num=1
переход в первую задачу. Она не кэшируется на nginx, но есть еще
также кэш БД, в котором кэшируются результаты запросов. Вряд ли
с таким простым содержимым он значительно изменит время
отдачи, но все же стоит посмотреть;
3. http://ssi.pictcut.com:8481/index.html?show=messages&num=1 – POST
запрос, добавляющий сообщение. После добавления сообщения
происходит инвалидация кэша БД и последующая выборка
получается из БД заново. Так как после выполнения запроса
приложение направит пользователя на эту же страницу, все что
может на ней кэшироваться попадет в кэш;
4. http://ssi.pictcut.com:8481/index.html?arg=tableбудет возвращена
устаревшая страница из кэша и выполнено фоновое обновление;
5. http://ssi.pictcut.com:8481/index.html?show=messages&num=2
открытие страницы с задачей 2;
6. http://ssi.pictcut.com:8481/index.html?show=messages&num=2
добавление сообщения в задачу 2;
7. http://ssi.pictcut.com:8481/index.html?arg=tableвозврат на главную
страницу.
Последние 3 шага будут выполнены для сбора дополнительных
данных. Для наглядности работы кэша в скрипт render.php добавлены строки
14 и 30
sleep(1);
Это позволит затормозить работу сценария на секунду, иначе страницы
загружаются чрезвычайно быстро из-за их простоты.
Итак, журнал доступа будет выглядеть следующим образом:
50
Рисунок 12. Журнал доступа тестового приложения 1.
Как можно видеть, в первый раз главная страница отсутствует в кэше и
получается с сервера бек-энда за ~1 секунду. Запросы POST выполняются за
~20 миллисекунд. Время, указанное там, где статус кэша равен STALE – это
время, затраченное сервером на получение обновленной страницы с бекэнда.
Из кэша она отдается очень быстро:
Рисунок 13. Время получения страницы из кэша – 4мс.
Соответственно, с данном случае за 7 посещений страниц кэширование
позволило сэкономить около 2 секунд, что не так мало. В случае настоящего
приложения, рассматриваемого в работе, список – наиболее часто
используемая страница.
3.1.3. Анализ устойчивости при сбоях
Высокая доступность систем и устойчивость их к сбоям отдельных
узлов – крайне важное качество веб-приложений. Балансировщики нагрузки
позволяют распределять клиентские подключения между несколькими
серверами бек-энда и следить за их состоянием. В этом разделе будет
проанализировать устойчивость к сбоям приложения, работающего под
51
управлением Apache за балансировщиком nginx. Подробно структура стека
приложения рассмотрена в разделе 3.1.1.
Тестирование будет проводиться с «прогретым» кэшем, то есть
наполненным кэшируемыми страницами (на самом деле, для этого раздела
кэшируется всего одна страница). В этом и следующих разделах,
посвященных тестированию устойчивости, методика тестирования будет
заключаться в следующих действиях:
1. Для этого примера будет выключен контейнер с Apache, для
последующих примеров – с PHP-FPM. Затем будет выполнена
попытка загрузки главной страницы, с нее попытка перейти на
страницу задачи;
2. Если страница с сообщениями и формой отобразится, попытка
оставить сообщение;
3. Если после попытки оставить сообщение страница загрузилась,
попытка вернуться на главную страницу со списком сообщений.
Итак, для этого экземпляра приложения, необходимо переместиться в
папку со стеком, в которой находится файл docker-compose.yml и выполнить
команду sudo docker-compose pause apache.
После этого nginx загрузил главную страницу со списком из кэша, но
при попытке обратиться к странице с задачами после ожидания был получен
ответ 504 Gateway timeout, означающий превышение времени ожидания от
сервера бек-энда. В журнале ошибок при этом появилась запись:
2018/10/06 17:23:55 [error] 385#385: *2829 upstream timed out (110:
Connection timed out) while reading response header from upstream, client:
188.65.209.195, server: ssi.abelov.com, request: "GET
/index.html?show=messages&num=1 HTTP/1.1", upstream:
"http://192.168.16.55:8188/index.html?show=messages&num=1", host:
"ssi.pictcut.com:8481", referrer: http://ssi.pictcut.com:8481/index.html?arg=table

Смотрите также:

«Психологическое сопровождение персонала в организации на примере ООО «Крокус»
Cовершенствование деловой оценки персонала в организации (на примере ООО "Даймонд кейтеринг развитие")
PR-коммуникации в сфере общественного питания (на примере кафе-кондитерской «Cream Cheese»)
SMM как средство повышения эффективности работы учреждений социокультурной сферы (на примере Малого театра)
Value-based education: ценности в системе образования и способы их реализации на уроке английского языка. Опыт Европейских стран
Work-life balance подход в управлении рабочим временем молодых сотрудников (на примере ООО «МГТ-сервис»)
Актуализация контента, отражающего концепцию «диалога культур», при освоении английского языка взрослыми обучающимися
Актуализация приемов инсценирования и драматизации в рамках интерактивной модели обучения английскому языку в старших классах
Актуальные подходы в построении внутреннего pr строительной компании (на примере ООО "Ренессанспроект")
Анализ деловой активности и экономической эффективности деятельности организации (на примере АО «СГ-Транс»)