Миграция витрины данных с СУБД Teradata в СУБД Greenplum

Миграция СУБД с одной технологии на другую — сложный процесс, который связан не только с конвертацией кода и переливкой данных из одной системы в другую. Хотя и здесь есть неочевидные нюансы. Часто это вопросы, связанные с совместимостью функциональности, производительностью, безопасностью данных, архитектурными особенностями новой системы и многими другими аспектами.

Меня зовут Станислав Свириденко и я DWH-разработчик AXENIX. В этой статье хочу рассказать об опыте миграции витрины данных с проприетарной СУБД Teradata на свободную СУБД GreenPlum. Поговорим о задачах, подводных камнях, на которые мы периодически натыкались, и способах решений, найденных  в процессе.

Описание задачи

Наш проект по миграции с дорогой проприетарной системы Teradata на более доступное Open Source решение начался в 2022 году. Это было вызвано необходимостью снизить риски, связанные с прекращением поддержки текущей системы из-за ухода IT-вендоров с российского рынка, а также желанием уменьшить расходы на обслуживание. Компании, осуществляющие подобный переход, стремятся удовлетворить требования информационной безопасности и соответствовать российскому законодательству относительно использования иностранного программного обеспечения.

В опыте миграции мы прошли ряд этапов:

1. Конвертация кода.

2. Подготовка среды Greenplum, включая создание схем, организацию ролевой политики, настройку ресурсных групп и создание объектов базы данных с учётом особенностей хранения и обработки данных.

3. Загрузка данных, включая промышленные данные и проведение проверки кода на этих данных.

4. Параллельный этап: организация взаимодействия между процессами — настройка оркестратора, DevOps-процесса и выгрузка данных с источников.

5. Итоговая сверка данных, включая параллельный запуск расчётов, проверку итоговых данных, нагрузочное тестирование и оптимизацию работы витрины.

6. Настройка систем мониторинга.

Сама витрина данных при этом была достаточно объёмной — 44 Тб, 2800 таблиц и 1100 процедур. Кластер Greenplum состоял из 40 физических узлов, из которых две мастер ноды и 38 рабочих. На каждой размещалось по 10 рабочих сегментов и 10 их зеркал. В целом кластер был достаточно производительным и пришел на смену кластеру Teradata, состоящему из 2024 amp«ов.

Конвертация кода

Для конвертации процедур и DDL-объектов мы написали свои конвертеры кода на Python. Некоторые сложные аспекты, вроде вложенных курсоров, рекурсивных запросов и использования различных агрегатных функций с qualify, пришлось обрабатывать вручную.

Кроме того, часть функций в Teradata и Greenplum работают по-разному. Например, в Teradata сортировка помещает значения null в начало списка, в то время как в Greenplum — в конец.

abe4f041876d757235c02a336cf4e470.png

Решение этой проблемы простое. Мы можем явно указать в Greenplum после имени атрибута конструкцию null first или null last, чтобы определить, где должны располагаться отсутствующие значения.

Одна из самых крутых особенностей Teradata, по моему мнению, заключается в том, что она позволяет переиспользовать алиасы внутри одного запроса. Это делает код более компактным и читаемым, поскольку результаты одних вычислений можно использовать в других вычислениях, в джойнах и т.д. В Greenplum так сделать нельзя, поэтому нам приходилось разбивать всё на множество вложенных запросов.

84c9c0a61553f1fc5f323debbba4c7b8.png

Также Teradata умеет неявно приводить типы данных при сравнении двух атрибутов. Например, если значение »123» хранится как текстовый, и как числовой атрибут, и в int, то Teradata автоматически выполнит необходимые операции для сравнения и вернёт true. В Greenplum для такого сравнения необходимо явно привести оба атрибута к одному типу данных, иначе операция объединения не сработает.

648712b0bdff873ff4675bf85ce2c37d.jpg

Ещё один важный момент: в Teradata используется банковское округление для чисел с плавающей точкой (numeric ()), в то время как в Greenplum применяется математическое. В банковском округлении числа приводятся к ближайшему чётному. Например, 1,5 и 2,5 округляются до 2. Это необходимо учитывать при проведении расчётов.

86f6f921d2af24b3e4566691a05b169a.png

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

8160d7bbe1c24eb800005b0f49899eaf.png

Кроме того, в Teradata прямо в DDL таблицах можно задать признак для атрибутов case-insensitive. Сначала в процедурах сравнения двух текстовых атрибутов мы добавляли «обёртку» из lower (). Но такие ручные правки влекли за собой увеличение времени на конвертацию процедур. А так как их было очень много, то использовали другой подход:   переконвертировали DDL объекты на основе объектов Teradata и для таких атрибутов использовали тип данных citext, который при сравнении автоматически переводит все значения в нижний регистр.

a950ac781d33bd30035b1477d9d730e9.jpg

И последний момент касается того, что Greenplum v6 использует Postgres SQL v9, внутри которого нет процедур. Есть только функции, которые представляют собой единую транзакцию. В них нельзя использовать коммиты roll back для отдельных операций. Это приводило к тому, что если функция завершается с ошибкой, то откатывается всё, включая запись в журнал отладки. Из-за этого нам пришлось переделать процедуры, добавив туда эксепшены, отслеживать ошибки по ним и вывод в output.

Создание схем, организация ролевой политики

На этапе создания схем возникли проблемы в настройке ролевых групп в особых условиях. В Greenplum DDL объекты требуют, чтобы операции над ними выполнял только владелец. В качестве решения мы создали отдельные роли для бизнес-пользователей и технических пользователей, из-под которых осуществляются различные ETL-процессы, запуски расчётов и DevOps-операции.

c72f45004dc1fbe1d9efaab074e597bb.jpg

Также мы настроили роли для запуска функций, выделение ресурсов в зависимости от времени суток и дня недели. А также организовали структуру витрины данных, включив наименования атрибутов, объектов, схем и параметров переменных в функциях.

Создание объектов БД

На ранних этапах работы с БД мы индивидуально настраивали каждую таблицу, включая выбор метода хранения данных и ключей распределения по сегментам. В основном они соответствовали настройкам в Teradata, но частично отличались. Например, для всех справочников мы использовали метод Distributed Replicated, чтобы сократить лишние motion при джойнах с этими справочниками. Ещё мы определили методы партиционирования данных, ориентацию данных (колоночную или строковую), а также тип и степень сжатия данных в партициях с учётом их температуры.

Загрузка промышленных данных

Для загрузки промышленных данных использовали последовательную переливку. Сначала извлекали данные из Teradata и, используя QueryGrid, заливали их в HDFS. Затем, через PXF переносили данные в отдельную схему в Greenplum, где они использовались в качестве эталонных и копировались в различные схемы Greenplum для проведения тестовых расчётов.

d1c24b32632c782e18122b4c9bb66076.jpg

Сверка кода на данных

Для сверки кода мы использовали Python. Сначала загружали в Python данные из Teradata и Greenplum при помощи двух JDBC-коннекторов. Затем брали исходный и сконвертированный код, помещали результат каждого из них в отдельные датафреймы Pandas и начинали сравнение. Сначала сравнивались агрегаты атрибутов, затем — поатрибутно, с учётом заданного ключа. При этом возникали сложности с поиском уникального ключа для сопоставления, а также при сверке некоторых типов данных, таких как float, numeric или timestamp.

2e88d06e82b3cbe98cb28b0f9e5bc85c.jpg

Настройка DevOps процесса и оркестратора

Для настройки оркестратора мы разработали самописное решение, которое взаимодействовало с Greenplum и, при необходимости, с HDFS через специальные учётные записи с использованием Kerberos. Сценарии оркестратора хранились в специальных таблицах Greenplum и включали последовательный или параллельный запуск функций, а также выполнение команд в Hive. Параллельно мы также настраивали процесс DevOps. Он был нужен, чтобы развернуть модели ресурсов и ролей, артефактов Greenplum и запустить сценарии.

Технологический стек для DevOps-процесса: Jenkins, Bitbucket CI и Nexus.

f6369f3b12452ef61c0cb8669a3dd2f7.jpg

Загрузка данных с источников

При разработке витрины данных мы создавали новые ETL-процессы для загрузки данных с источников. В то время, что параллельно с миграцией нашей витрины данных происходила миграция источников и получателей данных, чтобы обработка и хранение осуществлялись в основном на HDFS-серверах. Поэтому мы проработали взаимодействие с источниками с помощью PXF-серверов через external table. Одна из основных проблем на этом этапе заключалась в том, что загрузка через Hive была довольно быстрой, за исключением случаев загрузки из вьюшек. Порой от выгрузки из вьюшек избавиться не получалось, и в таком случае данные переливались достаточно медленно.

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

Выгрузка данных

При переходе к выгрузке данных в HDFS у нас возникли сложности. В первую очередь, выгрузка через PXF была возможна только с использованием профиля HDFS Parquet. Это нас ограничивало, потому что через этот профиль данные о партициях таблиц доступны только на уровне файловой системы. Например, для записи данных из Greenplum в определённую партицию Hadoop необходимо было явно указывать полный путь к местоположению внешней таблицы в самом DDL, включая каталоги партиций. Это было сложно и не всегда применимо на практике.

В результате мы воспользовались альтернативным подходом, при котором данные из Greenplum сначала загружались в непартиционированную таблицу Hadoop. Затем мы настроили автоматическую конвертацию данных из этих таблиц в партиционированные, что помогло избежать проблем.

de1b70dd693173f37f6da88f553a38be.jpg

Ещё один момент, который следует упомянуть относительно выгрузки данных, связан с тем, что при использовании PXF формировалось большое количество маленьких файлов, а это негативно сказывалось на производительности HDFS. В итоге нам пришлось объединять эти файлы в более крупные после каждой выгрузки.

9117da844a44590b5f780a92dfe5cba6.png

Нагрузочное тестирование и оптимизация работы витрины

В ходе нагрузочного тестирования и оптимизации работы витрины на Greenplum выявились несколько технических проблем.

●        Неоптимальность конвертированного кода из Teradata.

При параллельном запуске процедур на Teradata и Greenplum мы обнаружили, что сконвертированный код из Teradata в Greenplum иногда вызывал ошибки или работал значительно медленнее. Это могло быть связано с неоптимальностью запросов Teradata для оптимизатора Greenplum, а также настройками самого кластера. Мы обратились к DBI, чтобы они помогли оптимизировать настройки кластера с учётом специфики нашей витрины.

●        Ошибки при обработке большого количества партиций.

●        Проблемы при большом числе соединений.

Также возникли сложности при обработке процедур с большим количеством джойнов, особенно при наличии множества соединений. Например, когда мы пытались объединить около 50 различных таблиц при помощи джойнов в Greenplum, процессы становились медленными, что приводило к ошибкам типа OutOfMemory или Recovery Mode на сегментах. С этим мы разобрались, поменяв логику работы процедур и логически разбив таблицы, участвующие в джойнах, на части. Далее, прикапывали данные в промежуточные таблицы таким образом, чтобы итоговый селект состоял не из 50 таблиц, а, например, одной основной и пяти промежуточных. Это позволило сильно ускорить работу подобных процедур в Greenplum.

Так как Greenplum — MVCC система, при изменении данных таблицы постоянно увеличиваются в размерах, и команда delete не приводит к физической очистке данных. Поэтому мы использовали команду truncate вместо delete без условий where и настроили запуск Vacuum раз в неделю.

Отдельно отмечу по оптимизации Greenplum — очень важно производить сбор статистик для изменяемых таблиц. Это позволяет существенно ускорить работу.

Настройка систем мониторинга

В отличии от очень удобного ViewPoint в Teradata, для ванильного Greenplum мы не смогли найти хорошую систему мониторинга. Поэтому сначала пользовались логами работы нашего оркестратора, записью в логи из критических мест процедур, а также системными таблицами Greenplum (PG-каталог). Для мониторинга общей производительности кластера мы использовали Grafana.

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

Заключение

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

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

Моё выступление на конференции HighLoad++ 2023 в Москве:

© Habrahabr.ru