Highload-оптимизация stolplit.ru

Компания «Столплит» была основана более 15 лет назад и сегодня занимает лидирующее положение на мебельном рынке. Купить мебель «Столплит» можно не только через интернет, но и в фирменных магазинах в десятках регионов России и ближнего зарубежья. Сейчас их уже более двух тысяч.

Интаро осуществляет техническое сопровождение сайта с середины 2012 года.

ЗАДАЧА

Оптимизация серверной и программной части под высокие нагрузки.

ЧТО МЫ ДЕЛАЛИ

  • High-load оптимизация

Насколько все плохо?

Для ответа на этот вопрос в «цифрах» нужно провести аудит. Критичными показателями для нас на первом этапе аудита являются время генерации страницы на сервере и время рендеринга (отображения) в браузере. Хорошим суммарным показателем является время менее 1 секунды. Для простого аудита показателем «насколько все плохо» является суммарное время отображения страницы поделенное на 1 секунду.

Ниже приведен график Яндекс.Метрики, по которому видно, что у ресурса есть проблемы с производительностью. Время полного получения страницы может достигать 8 секунд. Есть большая вероятность, что пользователь не дождется открытия этой страницы и уйдет.

График Яндекс.Метрики

Еще одним немаловажным показателем является запас производительности, который можно получить, проведя нагрузочное тестирование на работающем проекте. Нужно иметь в виду, что целью нагрузочного тестирования является получение значения максимальной производительности, т.е. значений, при которых мы получим отказ в обслуживании. Именно поэтому нагрузочное тестирование нужно производить с особой аккуратностью, чтобы не допустить реального отказа в обслуживании. Обычно показателем нагрузочного тестирования является RPS (Requests per second) — количество запросов в секунду, которое способен обработать ваш сервер. Полученный показатель можно сравнить с текущим средним количеством запросов в секунду и получить доступный запас производительности вашего проекта.

Ниже приведен пример нагрузочного тестирования Яндекс.Танком. Тестирование проводилось на «боевом» проекте в час-пик. Видно, что RPS достигал значений близких к 30. Но фактический отказ в обслуживании начался с 17 RPS. Если принять во внимание среднюю нагрузку на сайт около 100 RPS, то можно считать этот запас критически низким, а сервис — потенциальной жертвой DDoS (атака, целью которой является отказ в обслуживании).

График нагрузочного тестирования Яндекс.Танком.

Кто виноват?

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

Что делать?

В любом случае никогда не поздно привести все в порядок. И хочу отметить, что как приведение к хаосу, так и установление порядка в проекте — это слаженный труд разработчиков, системных администраторов, контент-менеджеров и других специалистов. Именно поэтому нужно выделить узкие места проекта, разделить зоны ответственности и комплексно решать проблемы.

Серверы — наше все!

Существует поверье, что если купить достаточно мощный сервер, то можно перестать волноваться и забыть про апгрейд на ближайшие пару лет. Возможно это и верно для проектов со средней посещаемостью, не планирующих прироста пользователей на ближайшее время. Ведь на первый взгляд это удобно: оплачивать и администрировать 1 сервер. Но для проектов с высокой посещаемостью, с ее возможными всплесками это в корне не так.

Критически важным для таких проектов является время простоя во время технических работ и сведение к минимуму времени восстановления в случае аварии. Здесь применимо выражение «время — деньги». Именно поэтому нужно создать такую архитектуру, которая обеспечит нужный уровень отказоустойчивости и масштабируемости.

Три кита правильной конфигурации

1.
Масштабируемость
2.
Отказоустойчивость
3.
Безопасность

Рассмотрим каждый пункт подробнее.

Масштабируемость

Под масштабируемостью подразумевается способность быстро и просто добавлять вычислительные мощности в проект. Именно по этой причине нужно разделить серверы на выполняемые роли. Нужно четко понимать, что много «маленьких» серверов лучше, чем один «большой». Все серверы одной роли должны быть идентичной конфигурации. Это дает нам возможность для простого горизонтального масштабирования. В случаях отказа одного «маленького» сервера, мы имеем пропорциональную просадку производительности. В случае отказа одного «большого», мы скорее всего имеем отказ в обслуживании.

Много маленьких коробок лучше, чем одна большая!
Илья Безрукавников
РУКОВОДИТЕЛЬ ОТДЕЛА DEVOPS, INTARO

Если рассматривать типовой веб-сайт на PHP и СУБД MySQL, то разделение на роли примерно такое: балансировщик запросов, сервер приложения, сервер баз данных.

Схема взаимодействия между балансировщиком запросов, сервером приложения и сервером баз данных

Балансировщик — сервер с Nginx на борту:

  • занимается балансировкой запросов к серверам приложений (см. ниже);
  • занимается обработкой и кэшированием статики (картинки, стили, javascript и т.д.);
  • занимается реврайтами;
  • может выполнять регулярные «тяжелые» задачи по cron.

Сервер приложения — сервер, на котором выполняется бизнес-логика проекта. В нашем случае это код PHP. На сервере такой роли лучше использовать php-fpm вместо Apache, если нет прямых противопоказаний. Все-таки хороший веб-сервер у нас уже есть. Nginx очень хорошо справляется со своими обязанностями. Главная причина, по которой системные администраторы не спешат отказываться от Apache в качестве бекэнда на «живых» проектах — это наличие файлов .htaccess и, соответственно, куча реврайтов в них. Настоятельно рекомендую потратить время и переписать все реврайты под Nginx. Он делает это гораздо быстрее по своей природе.

Как уже само собой разумеющееся на сервере, выполняющем бизнес-логику должно быть много кэша. Кэшировать нужно все, что можно. У PHP должен быть OPcache или аналог. Использование memcaсhe в проекте всегда приветствуется.

Синхронизировать файлы проекта между серверами приложений можно любым удобным способом. Например lsyncd.

Забегу вперед и скажу, что на серверах приложений обязательно должен быть реализован функционал распределения нагрузки на БД.

Сервер баз данных — сервер с СУБД MySQL на борту. Рекомендую отказаться от использования чистой MySQL и посмотреть в сторону форков, таких как Mariadb и Percona. Для придания отказоустойчивости БД предлагаю посмотреть в сторону кластеризации. У чистой MySQL есть встроенный механизм реализации master-slave репликации. По сути, с его помощью можно реализовать master-master репликацию. Но советовать этого я не буду. Вместо этого предлагаю рассмотреть решение от Percona под названием percona xtradb cluster. Оно реализует настоящую master-master репликацию и полноценный кластер. К тому же он очень прост в управлении, масштабировании и восстановлении в случае сбоя, оснащен встроенным движком xtradb, полностью совместимым с InnoDB. К тому же есть возможность делать резервные копии, которые быстро восстанавливаются, причём гораздо быстрее обычного восстановления из sql дампа. А ребята из Mariadb разработали прекрасную утилиту maxscale для распределения нагрузки между серверами.

Отказоустойчивость

Главное правило отказоустойчивости — не допускать наличия единой точки отказа. Т.е. не допускать наличия недублированных узлов. Таким образом, серверов каждой роли у нас должно быть как минимум два. Что касается сервера-балансировщика, то его можно собрать в отказоустойчивый кластер или реализовать Round-robin DNS между несколькими балансировщиками.

По сути, реализуя схему с возможностью горизонтального масштабирования, представленную выше, мы получаем определенный уровень отказоустойчивости. Повышение уровня отказоустойчивости достигается дальнейшим горизонтальным масштабированием, добавляя серверы в нужную роль.

Безопасность

Безопасности много не бывает! Хочу остановиться на базовых моментах:

  • Исключить парольный доступ по SSH/SFTP. Насколько стойким бы ни был ваш пароль, хороший бот-нет обязательно его подберет. Самый удобный, на мой взгляд, способ авторизации — это RSA сертификаты. Просто и удобно.
  • WAF (Web Application Firewall) — незаменимый инструмент на защите вашего сервиса от XSS и SQL-инъекций. При правильной настройке поможет сэкономить много времени и душевных сил.
  • На каждом из серверов обязательно должен быть настроенный Firewall с политикой по умолчанию «Запрещено». Наружу должны быть открыты только необходимые порты.

Для защиты от DDoS атак существует масса способов. Она может осуществляться на уровне хостинга. Некоторые маршрутизаторы обладают возможностью интеллектуальной обработки трафика и очистки его от «мусора». Обычно такая услуга предоставляется провайдерами на платной основе. Тюнинг ядра Linux может помочь устоять перед другими видами сетевых атак.


Результаты

На примере реального проекта можно проследить, как описанный выше подход может привести в порядок даже очень запущенную систему.

Цель оптимизации

Задачей является крупный интернет-магазин мебели, построенный на CMS Bitrix.

Время генерации некоторых страниц на сайте достигало 200 секунд. Понятно, что при таких условиях пользователь никогда не дождется открытия страницы. Также на некоторых страницах количество запросов на хит достигало 20 000! На серверах, которым была отведена роль выполнения бизнес- логики, были установлены разные версии PHP интерпретатора. Была реализована master-slave репликация, но по факту балансировка не была реализована и работал только один мастер. Данный факт говорил о том, что деньги, выплачиваемые за аренду мощного сервера, не приносили никакой пользы. Серверы БД находились в ДЦ, удаленном от всех других серверов проекта, что накладывало задержку на время соединения более 10 мс. Memcached, установленный на мастер-сервере БД использовался только для хранения сессий, а весь кэш хранился в файлах.

Конфигурация серверов в начале

Парк серверов состоял из 5 довольно мощных машин. Под сервер, несущий на себе Nginx и выполняющий роль мастера для бизнес-логики, был выбран вариант с параметрами Dell PowerEdge R730, снаряженный Intel Xeon E5-2600 v3 2.10GHz Octa-Core, 128 ГБ DDR4 ECC RAM. Этот сервер обрабатывал 90% всех запросов и, судя по значению Load Average, должен был гореть ярким факелом от перегрева. Мастер и слейв БД MySQL находились в виртуальных контейнерах на 1 физическом сервере Dell PowerEdge R730. Как отмечалось ранее, слейв сервер просто реплицировал мастер и не нес никакой нагрузки, а значит ресурсы сервера, отведенные контенеру со слейвом попросту не использовались. Под слейв серверы, выполняющие бизнес-логику использовались две машины с параметрами Intel Core i7-4770, 32 ГБ DDR3 и, можно сказать, не справлялись со своими обязанностями. Также довольно мощный сервер использовался для простого хранения бекапов. На всех серверах использовались SATA диски 6 Гбит/с 7200 об/мин.

В конечном итоге на большинстве серверов не было задействовано и 10% доступных вычислительных ресурсов.

Что было сделано

Было решено использовать новый парк серверов и развернуть там новую архитектуру. После тестирования «переехать» на новые серверы, а от старых отказаться. Оптимальный выбор серверов под каждую роль смог сократить расходы на их аренду. Серверы получились дешевле используемых ранее. Проанализировав размеры данных проекта, было принято решение использовать SSD диски. Они быстрее SATA аналогов и заметно ускоряют файловые операции. Особенно это важно на серверах баз данных. Под хранение бекапов был выделен отдельный сервер-хранилище в соседнем ДЦ. Каждый сервер являлся физической машиной. Виртуализация не использовалась.

Тезисно остановимся на каждой роли:

Балансировщик

  • Собрана последняя стабильная версия nginx с дополнительными модулями
  • Жестко структурированы файлы конфигураций
  • Удален «мусор» и «мертвые» виртуальные хосты
  • Реализована балансировка нагрузки на сервера приложений. В случае аварии на сервере приложения все «клиенты» передаются другому серверу. Если авария на 2-х серверах приложений то некоторый трафик направляется на собственный сервер приложений балансировщика и система продолжает обслуживание.
  • Установлен WAF (Web Application Firewall) для защиты от XSS и SQL-инъекций
  • Настроена поддержка SSL
  • Все выгрузки и обмены происходят на балансировщике, т.к. его ресурсы не заняты при штатном функционировании системы.
  • Полностью перенесены, переписаны и оптимизированы правила реврайтов из файлов .htaccess.
  • Балансировщик занимается изменением размеров, кэшированием картинок и добавлением водных знаков «на лету».

Серверы приложений

  • В качестве fastCGI для php был выбран php5-fpm
  • Используется новая (совместимая) версия php
  • Используется прекомпилятор/кэшер кода php-OpCache
  • Тонко настроена конфигурация production пула
  • На каждом сервере приложений свой memcached, sphinxsearch и maxscale

Серверы БД:

  • Серверы БД перенесены в один ДЦ с серверами приложений, что уменьшило накладные расходы на связь.
  • Сделана тонкая настройка конфигурации серверов. Появился большой запас производительности.
  • На серверах настроена master-master репликация. Т.к. используется 2-е ноды вместо 3-х, то отключен кворум. Для избежания split-brain используется maxscale на серверах приложений. С его помощью реализуется логика master-slave. Slave является горячей заменой master'y и по сути не знает, что он Slave.

Все основные параметры серверов контролируются через систему мониторинга zabbix с оповещениями о нештатных ситуациях дежурному администратору. Параметры выполнения PHP контролируются через Pinboard.

Были переработаны нагружающие страницы и переписана часть компонентов системы. А в целом был проведен большой объем работы по оптимизации кода проекта.