Привет, Хабр! Это снова мы — Павел Конотопов (@kakoka) и Михаил Жилин (@mizhka), сотрудники компании Postgres Professional. Напомню, что Павел занимается архитектурой построения отказоустойчивых кластеров, а я анализом производительности СУБД. У каждого из нас за плечами более десяти лет опыта в своей области.
Во второй части статьи «Мифы и реалии «Мультимастера» в архитектуре СУБД PostgreSQL» мы говорили о гарантии согласованности данных и разрешение конфликтов. Разобрали как выявлять и разрешать конфликты, используя разные способы. Теперь пришла пора одной из самых важных характеристик хранения данных — надёжности.
Часть 3. Производительность: почему Мультимастер замедляет транзакции?
И вот мы подошли к самому вкусному — к производительности. Всё, что было сказано выше — хорошие и надёжные механизмы по обеспечению консистентности данных и разрешению конфликтов. Однако любые механизмы по обеспечению надёжности, как известно, отражаются на производительности.
Описав механизм глобального коммита, разрешения конфликтов, возникают вопросы: «Насколько всё это быстро происходит?», «Где стоит применить «Мультимастер?», потому что он точно не про «скорость без границ».
Представим, что к нам пришел заказчик с требованиями:
необходим кластер «Мультимастера» из двух или трёх узлов;
кластер предназначен OLTP-процессингу;
закрытая модель нагрузки в десятки параллельных потоков;
требования к средней задержке фиксации транзакции (commit average latency) — 300 мс;
транзакционная нагрузка — процессинг JSON-файлов, размер каждого около 20 Мб.
В первых тестах с «Мультимастера» для этой задачи результат был катастрофически медленным, всё работало в 3-4 раза медленнее по сравнению с одиночным экземпляром СУБД:
«Мультимастер», 3 узла — 800 мс;
Postgres Pro Enterprise, 1 узел — 250 мс;
Заказчик выразил мнение, что такая низкая скорость — из-за надёжности «Мультимастера» и его супер возможностей. «Да ваш «Мультимастер» — просто черепаха!» — сказал нам заказчик. И мы пошли разбираться, где же он притормаживает.
Почему может тормозить «Мультимастер»?
Настройка объёма информации, записываемой в WAL-журналы. При включении дополнительного уровня логирования данных в WAL-файлы с информацией для логического декодирования, получили замедление в три раза. Хотя при таком уровне логирования в журналы добавляется всего пара записей, и WAL-файлы не раздуваются в размерах.
Проигрывание изменений на всех узлах. Изменения данных с первого узла применяются на втором узле, а следом применяются и на третьем. Но на третьем узле мы применим изменения за то же время, да и изменения на обоих узлах применяются параллельно. Откуда возникло замедление в 3 раза?
Глобальный коммит. Все узлы при применении изменений должны проголосовать по протоколу PAXOS, договориться о согласованном применении изменений: это требует дополнительные временные затраты, но они невелики.
В ходе разбирательства нашлись проблемы как в настройках «Мультимастера», так и в способах работы с ним со стороны приложения.
Проблема №1. Таблицы без Primary Key
Если на узел кластера приходит строка изменения без первичного ключа, то приходится делать полное сканирование таблицы и искать, в какой строке появились изменения. В «Мультимастере» Postgres Pro есть специальная настройка: если есть таблицы без первичного ключа, то их можно игнорировать. Тогда они будут реплицироваться: multimaster.ignore_tables_without_pk.
Конечно, эта опция выглядит, как опция для параноиков. Главное, чтобы не было сильной просадки производительности. Поэтому, если мы хотим реплицировать все таблицы, нужно обязательно создавать для всех таблиц первичные ключи.
Проблема №2. Время фиксации при глобальном коммите
Далее стали разбираться, что происходит с фиксацией транзакций в кластере: извлекли информацию из WAL-файлов, когда происходили изменения, когда начинался и заканчивался распределенный коммит. Выяснилось, что множество транзакций изменяли всего лишь одну строку, но при этом время глобального коммита было в 10 раз больше, чем время самой транзакции.
Просмотрели информацию о нескольких транзакциях: везде одна и та же картина. Поинтересовались у разработчиков, что именно фиксируется в транзакциях. Логично было собирать небольшие изменения JSON (пусть и размером в 20 Мб) в «пачку» и фиксировать их одним коммитом. Оказалось, что на стороне Java-приложения был включен автокоммит, то есть каждая DML-операция создавала распределённый глобальный коммит. После рекомендации выключить автокоммит, ситуация нормализовалась:
«Мультимастер» стал работать очень быстро, время глобального коммита резко сократилось и стало занимать не 99% времени от всей транзакции, а всего лишь 28%, а это уже сравнимо с работой обычной физической репликации.
Проблема №3. Производительность сети виртуальной машины
Кластер «Мультимастера» был развёрнут в среде виртуализации. У виртуальной машины QEMU был виртуальный сетевой интерфейс virtio-net-pci, драйвер которого по умолчанию работает в однопоточном (или одноочередном) режиме.
Чтобы глобальный коммит происходил быстро, требуется, чтобы сеть отвечала практически мгновенно. Скорость глобального коммита при решении Проблемы №2 хоть и уменьшилась, но так и не достигла требуемых значений. При дальнейших исследованиях причин мы заметили, что скорость коммита зависит от производительности сетевого устройства. Мы переключили драйвер virtio-net-pci в многопоточный (многоочередный) режим, включили multiqueue на всех узлах кластера и выставили количество очередей в значение 4. После этих манипуляций время выполнения коммита уменьшилось и достигло требуемых заказчиком значений.
Аварийное нарушение работы логической репликации
В кластере «Мультимастера» произошла аварийная ситуация. Общую картину может дать фрагмент журнала работы сервера (отредактирован и сокращен для лучшего понимания):
14:52:07 – нарушение работы логической репликации, «узел-2» не забирает изменения от «узла-1»
15:48:52 – диск pg_wal на «узле-1» полностью заполняется WAL-файлами и уходит в перезагрузку
15:49:28 – «узел-1» запускается и переходит в catchup. Рабочая нагрузка переходит на «узел-2»
16:29:50 – диск pg_wal на «узле-2» полностью заполняется WAL-файлами
В один прекрасный момент логическая репликация, которая выбирала данные для узла-2, перестала работать. Причина: на стороне приёмника «узла-2» что-то пошло не так. На «узле-1» начали копиться WAL-файлы. Они копились до тех пор, пока дисковое пространство выделенное под хранение WAL-файлов, не закончилось. Как только оно закончилось, «узел-1» ушёл в перезагрузку, а затем перешёл в режим восстановления. «Узел-2» ждёт, когда «узел-1» вернётся в нормальное состояние и тоже накапливает WAL-файлы для этого узла. Накапливает он их до тех пор, пока и у него не заканчивается дисковое пространство — так весь кластер «Мультимастера» перешёл в неработоспособное состояние.
У этой проблемы есть довольно простое решение: в PostgreSQL есть настройка, с помощью которой можно указать, какое количество WAL-файлов необходимо хранить до того момента, пока слот репликации не остановится: max_slot_wal_keep_size — ограничение размера слотов репликации. Если вдруг WAL-файлов накопилось больше указанного размера, то следует найти слот, который заставляет держать WAL-файлы, и удалить его. Пусть лучше остановится работа логической репликации, но «Мультимастер» продолжит работать. Поэтому ограничиваем размер хранимых WAL-файлов, предотвращая возможное возникновение аварийной ситуации. Теперь обратимся к вопросу производительности.
Производительность: рекомендации
Чтобы добиться производительности «Мультимастера» можно применить следующие рекомендации:
обязательно наличие первичного ключа (primary key) на реплицируемых таблицах;
делать более объемные транзакции, чтобы глобальный коммит стал «дешевле». Чем объёмнее транзакция — тем меньше время её фиксации (commit);
настроить сеть виртуальных машин под требуемую сетевую нагрузку;
выставить max_slot_wal_keep_size, чтобы кластер «Мультимастера» не уходил в отказ из-за переполнения диска.
Дополнительно можно принять во внимание такие замечания:
Стремитесь избегать конфликтов на уровне кода на разных узлах: разрешение конфликтов — «дорогая» операция. Какой способ разрешения будет выбран, настолько «дорогим» и долгим будет время этой операции.
Синхронизируйте время на узлах кластера. «Мультимастер» использует глобальные распределенные коммиты, построенные на протоколе распределённого консенсуса PAXOS. Этот консенсус использует временные метки. Время должно быть синхронизировано с одним источником времени на всех узлах кластера. Если будет расхождение времени на узлах, то возникнут дополнительные задержки при фиксации транзакций, что сильно снижает производительность.
Внимательно отнеситесь к требованиям со стороны службы безопасности. Антивирус отслеживает сетевую активность между узлами кластера и изменения в каталоге БД, auditd-правила следят за бинарными файлами экземпляра СУБД. Эта активность со стороны ПО, обеспечивающего безопасность, всегда отражается на производительности СУБД, и не в лучшую сторону. Одним из требований со стороны ДБА к службе ИБ может быть исключение сетевой активности внутри кластерного трафика и каталога БД из области наблюдения средств безопасности.
Крупные миграции данных следует делить на части. Если у вас есть огромная миграция (сотни, а то и тысячи миллиардов строчек), то постарайтесь разделить её на части. Когда вы сделаете одну большую транзакцию, её нужно потом логически декодировать в памяти: это зачастую приводит к срабатыванию OOM-киллера или повышенной нагрузке на все узлы кластера.
Итоги
Сначала о том, чем закончился реальный кейс с заказчиком: время транзакции упало с 800 мс до 300 мс, система успешно прошла все тесты и перешла в промышленную эксплуатацию. Мы получили ценный опыт и знаем теперь, какие настройки надо обязательно сделать сразу, чтобы кластер «Мультимастера» работал стабильно.
Исходные показатели производительности:
Фиксация транзакций в кластере «Мультимастер» — 800 мс;
Фиксация транзакций в одиночном экземпляре Postgres Pro Enterprise —250 мс.
Достигнутые результаты:
Фиксация транзакций в кластере «Мультимастер» — 300–350 мс;
Система в промышленной эксплуатации на Postgres Pro Enterprise Multimaster;
Все приобрели ценный опыт.
Подведем итоги нашей статьи. В начале нее мы говорили о мифах «Мультимастера». Напомним, что «Мультимастер»:
не про масштабирование записи, но масштабирование чтения;
не про пиковую производительность, но для нагруженных систем;
не про надёжность;
не про доступность;
не для промышленного применения.
В итоге можно уверенно утверждать, что реальность «Мультимастера» (от Postgres Pro):
не про масштабирование записи, а про масштабирование чтения;
не про пиковую производительность, а для нагруженных систем;
не про надёжностьнадежен;не про доступностьуровень доступности может достигать 99,99*%;не для промышленного примененияпроверенное промышленное решение.
Реализация технологии «Мультимастер» в Postgres Pro Enterprise позволяет добиться высокой доступности («AlwaysOn» архитектура, база данных доступна всегда). Период недоступности классического кластерного ПО («Active-Passive» архитектура) можно рассчитать, как сумму времён, затраченных на определение кластерным ПО сбоя мастер-узла, выборы нового мастера, переключение роли выбранного узла, перенастройку (пусть и автоматическую), TCP-прокси, переподключение приложения к новому «мастеру».
В кластере «Мультимастера» приложение просто подключится к другому узлу кластера. Время на такое переподключение может отличаться на один-два порядка в меньшую сторону от времени переподключения при использовании классического кластерного решения.
Надёжность, по сравнению с любым кластерным решением, основанным на физической репликации, обеспечивается встроенными протоколами распределенного консенсуса при глобальной фиксации транзакций.
Решения на базе «Мультимастера» уже внедрены в промышленную эксплуатацию весьма серьезными заказчиками (рассказали бы, но, увы, вынуждены соблюдать NDA). Кластер «Мультимастера» уверенно можно использовать в промышленных решениях!
Материалы для изучения
«Мультимастер» последней версии — проверенное решение, которое можно использовать в продуктиве. Раньше мы упоминали, что Postgres Pro Multimaster — продукт с закрытым кодом, но это не значит, что прежде чем решить, нужен он вам или нет, вы не можете о нем ничего узнать.
Для изучения технологии и ее реализации есть:
Вы можете загрузить себе учебную виртуальную машину, запустить «Мультимастер» и попробовать всё, о чём мы рассказали в данной статье. Кроме того, Postgres Pro Enterprise может быть выдан и бесплатно для тестирования (необходимо связаться с отделом продаж компании).
Материалы для более вдумчивого изучения технологии «Мультимастер» и связанными с ней темами: