Вы когда-нибудь задумывались о том, чтобы перенести крупномасштабное программное решение с Oracle на PostgreSQL, а затем развернуть его в общедоступном облаке? Если Вы планируете реализовать подобное, возможно, Вам поможет наш опыт. Данная статья подробно рассказывает о нашем опыте настройки облачного хранилища, используемого PostgreSQL и оптимизации его производительности.

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

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

  2. Oracle также имеет автоматическое управление хранилищем (ASM), которое управляет группами дисков для хранения файлов и может делать умные вещи, такие как равномерное распределение файлов данных по дискам для избежания хот-спотов.

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

Теперь давайте рассмотрим последствия перехода в общедоступное облако. Мы больше не покупаем дисковые массивы для хранения данных, а пользуемся стандартными услугами нашего облачного провайдера. Итак, все, что нам нужно сделать, это выбрать объем и скорость хранения из выпадающего списка, верно? Не совсем. Оказывается, один блок хранилища не способен обеспечить пропускную способность и задержку, необходимые для наших тестируемых приложений.

Независимо от выбранного IOPS, задержка увеличивается с увеличением объема трафика. У каждой системы хранения будет момент, когда она не сможет удовлетворить спрос, и задержка будет увеличиваться; использование более быстрого хранилища просто сдвигает момент, в который это произойдет. Реальный вопрос заключается в том, можем ли мы поднять планку достаточно высоко, чтобы PostgreSQL стабильно получал хорошее время отклика от носителя при обработке требуемой рабочей нагрузки?

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

Как и во всех RDBMS, PostgreSQL использует кэширование данных в памяти, это дополнительно поддерживается Linux, использующим доступную свободную память для буферизации метаданных файловой системы и кэширования содержимого файлов данных, но в конечном итоге, если информация, которую мы хотим прочитать или изменить, не находится в любом из этих мест, то нам нужно прочитать ее из хранилища. Чем дольше выполняется чтение, тем больше времени требуется PostgreSQL для возврата данных приложению. Это можно улучшить, добавив памяти для увеличения коэффициента попаданий в буфер, но в конечном итоге, если вся база данных не будет помещаться в память, нам в какой-то момент придется считывать некоторые данные из хранилища.

Записи журнала WAL об обновлениях/вставках/удалениях

DML, который изменяет данные, хранящиеся в базе данных, делает это, манипулируя данными в общем буфере. Однако для надежности в момент фиксации данных PostgreSQL записывает сведения об изменениях в журнал WAL на диск. Это синхронная запись, и поэтому она является частью времени транзакции. Если хранилище, содержащее WAL, имеет чрезмерную задержку записи, то транзакция занимает больше времени, чем нужно.

Записи, влияющие на чтение из хранилища

В целом записи в хранилище из PostgreSQL (кроме журнала WAL) являются асинхронными и отделены от времени, необходимого для выполнения запроса. Однако низкая производительность записи и большие объемы записей могут привести к перенасыщению емкости хранилища IOPS, что приведет к замедлению времени чтения, что повлияет на время запросов PostgreSQL.

Контрольные точки

У нас есть похожие проблемы с контрольными точками (когда PostgreSQL хочет отметить точку в журнале WAL, где все транзакции до этой точки были записаны на диск). Это может потребовать записи больших объемов данных в хранилище перед записью контрольной точки, низкая задержка хранилища может замедлить этот процесс.

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

Тестирование

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

Рассматриваемое приложение изначально создавалось только для Oracle, но за последние несколько лет оно было преобразовано для работы на PostgreSQL. Мы знаем реальный профиль нагрузки и его же будем симулировать на тесте. Приложение будет считывать огромное количество данных из одной единственной таблицы, которую мы назовем Таблица A (750 миллионов строк в этом тестовом наборе). А также будет записывать большие объемы данных в две другие таблицы, назовем их B и C. Чтобы не увязнуть в специфике приложения, достаточно сказать, что при тестировании оно читает из нескольких таблиц, включая таблицу А, выполняет некие преобразования в памяти, а затем выводит результаты своей работы в несколько других таблиц, включая таблицы В и С, генерируя большое количество IOPS.

Этот тест проводился с использованием PostgreSQL 11, размещенного на хосте 16-vCPU и 117 ГБ оперативной памяти в облаке Oracle (VM.Standard2.8, два потока на ядро, каждый поток представлен как vCPU). Мы сгенерировали нагрузку от приложений, работающих в кластере Kubernetes, состоящем из 4 узлов с той же спецификацией, что и сервер базы данных, допуская более чем достаточно ресурсов, чтобы гарантировать, что это не будет проблемой.

Первоначальные измерения

Pg_profile показал что ~50% времени занимает считывание из таблицы A, в то же время как вставки в B и C занимают всего 5-7% на таблицу. Учитывая профиль продукта, мы не ожидаем, что большая часть данных в таблице A будет находиться в буфере во время теста (в реальности данные собираются целый месяц, а потом за раз обсчитываются) создавая большое количество операций ввода-вывода для тестирования дисковых конфигураций.

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

  • sda — содержит загрузочный диск;

  • sdb — содержит большую часть файлов данных для базы данных;

  • sdc — содержит журнал WAL;

  • sdd — содержит таблицу A.

Каждый блок хранения представлял собой облачное сбалансированное хранилище Oracle объемом более 600 Гб, что должно обеспечивать пропускную способность 200 МБ/с.

Первоначальное тестирование
Первоначальное тестирование

Мы получили реальную отправную точку для исследования проблем с задержкой. Как показано на диаграмме выше, перемещение таблицы A на отдельный диск позволило нам отслеживать задержку на работу именно с этой таблицей. Нужно ли говорить, что время чтения 15 мс для извлечения данных с диска для таблиц в общем хранилище и 6 мс для чтения таблицы A, которая будет обслуживаться почти исключительно с диска, не оправдало наших ожиданий. Следует отметить, что мы увеличивали нагрузку до тех пор, пока не достигли ограничения системы; при меньших объемах хранилище имело результат в диапазоне 1 мс. Мы попытались использовать диск с более высокой производительностью, и это несколько улучшило ситуацию, как показано на графике ниже.

WAL и таблица A имеют собственный блок хранения
WAL и таблица A имеют собственный блок хранения

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

Мы экспериментировали с добавлением в систему новых томов хранилища и переносом самых горячих таблиц (A, B, C) на новые диски за счет использования табличных пространств, указывающих на места присоединения новых дисков. Это отделило горячие таблицы от остальных данных и позволило остальным таблицам иметь меньшую задержку (1–2 мс). Это также позволило нам измерить задержку каждого диска, содержащего горячие таблицы. По мере улучшения производительности хранилища мы добавили дополнительные параллельные экземпляры тестируемого приложения, чтобы попытаться достичь более высокой пропускной способности. Пропускная способность увеличилась, однако мы снова достигли точки, в которой хранилище, содержащее A, имело задержку 20 мс. У нас была таблица, для которой требовалось больше операций ввода-вывода в секунду, чем мог обеспечить любой блок хранилища, и у нас все еще не было недостатка в CPU или памяти.

Мы решили разбить таблицу A на несколько блоков хранения, используя хеш-секционирование*, что значительно улучшило время чтения для таблицы A до такой степени, что записи в таблицы B и C стали относительно намного больше в отчете pg_profile, поэтому мы решили также секционировать таблицы разделов B и C на тех же дисках.

* Следует отметить, что использование логического тома, распределенного по нескольким дискам, является традиционным подходом к равномерному распределению данных по файловой системе (и тем, который мы используем сегодня). Однако частью объема работы было изучение новых способов работы с PostgreSQL, а использование логического тома не позволило нам протестировать новую функцию PostgreSQL, которую мы раньше не использовали. Для справки, создание LVM против хеш-секционирования показало, по-видимому, эквивалентную производительность в наших тестах.

  • sda — содержит загрузочный диск;

  • sdb — содержит большую часть файлов данных для базы данных;

  • sdc — содержит журнал WAL;

  • sdd, sde, sdf, sdg, sdh содержат таблицы A B и C, секционированные по HASH-методу на 5 блоков хранения.

Разделение горячих таблиц на 5 блоков хранения
Разделение горячих таблиц на 5 блоков хранения

После внесения этих изменений, записи в журнал WAL постоянно были ниже 1 мс. Чтение из всех таблиц занимает около 1 мс. У нас есть случайный рост записей, но они не критичны.

Основные выводы:

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

Журнал WAL всегда должен находиться в отдельном хранилище и должен быть самым быстрым из доступных. Это может быть логический том, состоящий из нескольких устройств хранения, чтобы обеспечить требуемое количество операций ввода-вывода в секунду.

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

Автор статьи: Duncan Paul Walker

Оригинал: How does migrating from Oracle to PostgreSQL in the cloud impact storage?

Комментарии (1)


  1. emaxx
    22.02.2022 15:59
    +1

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

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