Тестирование производительности Drupal: MySQL vs PostgreSQL часть 1

Введение

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

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

Найденные тесты к Drupal относятся к односерверной конфигурации, но можно из Drupal выжать больше, если распределить БД, сервера приложений с php, кеш и поиск между несколькими серверами.

Я решил протестировать Drupal 7.34 и понять, когда у него возникают проблемы с масштабированием и получить какие-то опорные данные для сайзинга проектов на Drupal. Я сравню Drupal с MySQL vs. PostgreSQL. Есть важный нюанс: меня интересует результаты для авторизованных пользователей, поэтому такие эффективные средства как выдача кешированных блоков и страниц для анонимных пользователей, равно как и для авторизованных не применяются. Модуль Boost или кеширование ответов веб-серверами тоже не используются.

Тестовая конфигурация

1. Сервер БД 24 vCPU, 20 GB RAM, БД MariaDB 5.5.40 (XtraDB engine, innodb_buffer_pool_size=4G, query_cache_size=800M), БД PostgreSQL 9.4.0 (shared_buffers=4G)
2. Кешируюший сервер 2 vCPU, 6GB RAM,  Redis 2.8.12
3. Сервера приложений 5 шт. с конфигурацией 14 vCPU, 8 GB RAM,  php 5.4.16, php-fpm, Zend OPcache, APCu 4.0.7, nginx 1.6.2 (без кеширования ответов)
4. Балансировщик нагрузки 8 vCPU, 8 GB RAM, nginx 1.2.4 (без кеширования ответов)

Все диски на IBM DS5300 RAID6, пиковая производительность 2000 IOPS, типичная 400-800 IOPS.
Все процессоры Intel Xeon 3.2 GHz
Все ОС Linux CentOS7 x64.
Все виртуальные машины на VMware vSphere 5.1

Результаты Sysbench

Чтобы вы могли как-то экстраполировать мои результаты на вашу БД, надо измерить производительность БД стандартным тестом. Я выбрал sysbench и MariaDB в 600 потоков на одном миллионе записей:

sysbench --num-threads=600 --max-requests=100000 --oltp-table-size=1000000 --db-driver=mysql --test=oltp run

Результаты:
OLTP test statistics:
    queries performed:
        read:                            1400098
        write:                           500035
        other:                           200014
        total:                           2100147
    transactions:                        100007 (688.23 per sec.)
    deadlocks:                           0      (0.00 per sec.)
    read/write requests:                 1900133 (13076.34 per sec.)
    other operations:                    200014 (1376.46 per sec.)

Test execution summary:
    total time:                          145.3108s
    total number of events:              100007
    total time taken by event execution: 87083.1545
    per-request statistics:
         min:                                 54.52ms
         avg:                                870.77ms
         max:                              29007.16ms
         approx.  95 percentile:            1221.32ms

Threads fairness:
    events (avg/stddev):           166.6783/2.91
    execution time (avg/stddev):   145.1386/0.12

Методика тестирования

Тест проходил на MariaDB и PostgreSQL. Установлена свежая версия Drupal 7.34. Включены большинство стандартных модулей кроме views. Ноды в Drupal не генерировались, стандартная тема. Запросы создаются Apache Benchmark и направляются на страницу выводящую "hello world" в виде следующего модуля:
function test_perf_menu () {
  $items = array();
  $items['testperf/static'] = array(
    'title' => 'test perf static',
    'page callback' => 'static_test_perf',
    'type' => MENU_CALLBACK,
    'access callback' => TRUE,
  );
  return $items;
}
function static_test_perf() {
  return "hello world";
}
Такая методика означает, что полученные результаты оптимистичны для реальной нагрузки т.к. полезных запросов по загрузке контента в БД нет и кеширование запросов в БД используется очень эффективно. В связи с этим, результаты надо интерпретировать крайне осторожно и помнить, что тестирование измеряет максимальные возможности, которые можно получить от системы инициализации Drupal и работы его роутера.

Модуль Devel показал, что в использованной конфигурации выполняется 10 запросов:



Также надо иметь в виду, что балансировщик нагрузки выдает 500 ошибку в ApacheBench только если все сервера приложений ответили ему 500 ошибкой, т.е. фактическое время начала появления ошибок в БД наступает несколько раньше выявленного тестированием.
Кеширование страниц целиком для анонимных пользователей способно ОЧЕНЬ существенно снизить нагрузку на БД. В данном случае оно не использовалось, что связанно с особенностью моей задачи ради которой и проводилось тестирование.
Производительность CPU оценивалась визуально по htop. Производительность PostgreSQL измерялась pg_top.

Замечания по ходу тестов

У серверов БД кеша хватало чтобы не было обращений к диску. Это означает, что файловая система не является ограничивающим фактором. Также не допускалась ситуация исчерпания ОЗУ на любых серверах. Все сервера настроены на достаточно большую нагрузку. Ошибок связанных с работай сети, исчерпанием файловых дескрипторов и т.п. ни на одном сервере не появлялось.

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

Поведение Redis

При 1000 конкурентных подключений Redis нагружает 4 vCPU примерно на 50-60%. Не смотря на простые операции кеширования, под кеш надо покупать отдельный от основной БД сервер и с числом ядер не менее 4. Желательно с максимальной доступной частотой т.к. возможности горизонтального масштабирования Redis ограничены (судя по увиденной мною загрузки CPU).

Поведение PostgreSQL

PostgreSQL выходит на пиковую производительность 15 000 tps (транзакций в секунду) уже при 100 конкурентных подключений. Начиная со 100 конкурентных подключений общее время выполнение тестов ApacheBench не зависит от числа конкурентных подключений. С выходом на пиковую производительность, все 24 процессора оказываются загружены.

При числе серверов приложений > 2, суммарное время исполнение теста 37 секунд для 40 000 запросов с погрешностью менее 10%. Я интерпретирую ситуацию следующим образом: БД выполняет свои 15 000 запросов в секунду и ее производительность не зависит от числа конкурентных подключений (в пределах нагрузки). 200 конкурентных подключений обрабатываются БД в два раза медленнее 100 подключений, но, если производительность уперлась в БД, то 40 000 запросов она обработает за постоянное время т.к. вычислительная сложность фиксирована.



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

Высокая нагрузка на процессор PostgreSQL позволяет рекомендовать покупку сервера под БД с максимальной производительностью и большим числом ядер.

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


Интерпретация:

При использовании двух нод вместо одной можно почти в два раза уменьшить время ответа, однако, дальнейшее увеличение числа нод слабо влияет на время генерации страницы. То что в диапазоне конкурентных запросов от 50 до 400 время генерации страницы для двух и пяти нод одинаково говорит о том, что производительность уперлась в БД и даже у двух нод хватает производительности процессора для обработки данных.
Если бы мы уперлись только в БД и производительность процессоров нод не имела значения, то все кривые находились бы на одной кривой. Соответственно, начиная с уровня конкуренции 450 запросов, производительность нод серверов приложений начинает влиять на время генерации и повышение числа нод серверов приложений начинает давать вклад во время генерации страницы.

Итак: надо иметь один сервер приложений для уровня конкуренции до 50 запросов, два сервера приложений на уровне конкуренции до 400 запросов и можно подумать о большем числе если уровень конкуренции больше 400 запросов.

Поведение MariaDB (MySQL)

MariaDB дает существенно меньшую нагрузку на CPU чем PostgreSQL. Даже при 1000 конкурентных подключений максимальная загрузка процессора не превышает 28% и загружены на эти проценты не все из 24 vCPU. Это означает ограниченные возможности вертикального и горизонтального масштабирования MariaDB и его большую "вычислительную экономичность". Выход на пиковую производительность в 24 тыс запросов в секунду (qps) происходит позднее PostgreSQL - на 250 конкурентных подключениях. Аналогично с PostgreSQL, с некоторого момента общее время выполнение ApacheBench не зависит от числа конкурентных подключений и составляет 32 секунды для 40 000 запросов. Насыщение происходит при 150 конкурентных подключений, что больше PostgreSQL.



Общий вывод такой: по аналогии с PostgreSQL, производительность упирается в БД. При этом, на простой нагрузке MariaDB раз в 6 меньше нагружает CPU и работает быстрее минимум на 40%. В виду отсутствия 100% загрузки CPU, гнаться за большим числом ядер на малых БД не следует.

Давайте посмотрим на зависимость времени ответа от числа вычислительных нод и для MariaDB. Напомню: по оси абсцисс - число конкурентных подключений, по оси ординат - в какое время ответа уложилось половина запросов.


Интерпретация:

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

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

Замечания по настройке серверов

В процессе выполнения тестирования оказалось:
1) Следует использовать подключение php-fpm по tcp/ip, а не через сокеты т.к. при работе с сокетами начинаются ошибки таймаута ожидания со стороны nginx при уровне конкуренции в 400-500 запросов.
2) Следует установить параметр backlog в php-fpm, nginx, и в ядре (sysctl). По умолчанию и nginx и php-fpm должны использовать системный backlog, но по факту оказалось что лучше эти параметры установить руками.

Заключение

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

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

Читайте вторую часть...

Популярные сообщения из этого блога

Как оживить корпоративный сайт?

Мастерим компьютер для прямых интернет трансляций и записи с видеокамеры или системы ВКС

Тестирование производительности Drupal: MySQL vs PostgreSQL часть 2