CI/CD для DWH
Введение в непрерывную интеграцию при разработке систем хранения данных
Постоянно появляющиеся новые источники данных и приложения продолжают стимулировать неуклонное расширение систем хранения данных, таких как DWH, Data Lake и аналитических платформ. Процессы управления данными также должны соответствовать неуклонно растущим требованиям. Нередко небольшие BI-приложения перерастают в крупные проекты, в которых участвуют несколько команд разработчиков. Во многих отраслях ситуация обостряется необходимостью внесения корректировок быстрее, чем когда-либо прежде. Это, в свою очередь, требует быстрого реагирования и высокой гибкости от команд и от инфраструктуры.
Непрерывная интеграция для удовлетворения растущих требований к разработке программного обеспечения
Для того, чтобы справиться с растущими требованиями к размеру и количеству групп разработчиков, а также к параллельным процессам разработки в системе, уже давно используются и успели зарекомендовать себя такие принципы, как непрерывная интеграция (CI). CI стремится гарантировать, что код и другие объекты разработки регулярно интегрируются и тестируются с помощью автоматических заданий. Изменения интегрируются в центральный репозиторий под контролем версий. Фиксация этих изменений запускает автоматические сборки, которые включают различные тесты и проверки согласованности. Если какой-либо тест не пройден, разработчика автоматически уведомляют об этом.
Для обработки систем баз данных в качестве серверных частей приложений в процесс сборки могут быть включены дополнительные шаги, такие как обновления базы данных и тесты. Поскольку проектирование и совершенствование систем хранилищ данных (DWS) сосредоточено на разработке систем баз данных, особенности CI должны быть описаны в отношении разработки баз данных с учетом разработки приложений. Для этого сначала описывается базовая функциональность CI, а также представляются общие ключевые практики. Затем на основе ключевых практик показаны основные различия и предложены решения.
Обзор непрерывной интеграции
Непрерывная интеграция не требует использования ни определенного набора инструментов, ни каких-либо отдельных инструментов. В рамках CI предлагаются исключительно практики, позволяющие устранить многие проблемы, связанные с параллельной разработкой в одной системе. Наиболее подходящим для введения в эту тему является рабочий процесс разработки в сфере CI:
Рабочий процесс на рис. 1 представляет разработку функции в упрощенной среде разработки с мастером и системой контроля версий (VCS), в которой происходит непрерывная интеграция с помощью операций фиксации. Как показано на рисунке 1, разработка новой функции начинается с того, что разработчик создает или обновляет свою рабочую копию базы кода. После этого можно разработать новую функцию и связанный с ней тест. Тест помогает обеспечить соответствие спецификациям во время разработки и может использоваться в качестве регрессионного теста после разработки. После того, как вся кодовая база будет успешно развернута вместе с новой разработкой в локальной среде, а тесты, касающиеся измененных объектов, окажутся успешными, база должна быть проверена на предмет возможных изменений и, при необходимости, обновлена, чтобы предвидеть потенциальные конфликты при интеграции. Наконец, изменения интегрируются в общую кодовую базу в системе контроля версий. Это инициирует выполнение автоматической сборки, включая автоматические тесты. Этот шаг имеет решающее значение, поскольку созданные для него тестовые среды больше напоминают производственную конфигурацию, чем это было бы возможно только при локальной разработке. Если все результаты тестов положительные, работа разработчика считается завершенной. В противном случае оставшиеся ошибки устраняются, и цикл СI повторяется.
Ключевые практики для эффективной непрерывной интеграции
Для того, чтобы такой подход стал возможным в сочетании с различными тестами во время разработки, должны быть выполнены определенные предварительные условия. Уже в 2006 году Мартин Фаулер описал ряд ключевых практик (КП), которые следует соблюдать для обеспечения эффективной непрерывной интеграции:
КП 1 |
|
KП 2 |
|
КП 3 Сделать сборку самопроверяемой |
|
KP 4 Ежедневный коммит каждого участника в основную ветку |
|
КП 5 Сборка основной ветки на интеграционном сервере после каждого коммита |
|
КП 6 Быстрое исправление сломанных сборок |
|
КП 7 Сборка должна быть быстрой |
|
КП 8 Тестирование на копии боевой среды |
|
KP 9 Простота получения последнего исполняемого файла для каждого участника |
|
KP 10 Каждый может видеть, что происходит |
|
KP 11 Автоматическое развертывание |
|
В случае систем хранения данных рассмотренные ключевые практики могут иметь разные последствия, как и в случае создания программного обеспечения. Тем не менее, многие принципы могут быть применены практически в соотношении 1:1. В случае применения других ключевых практик необходимо учитывать особые обстоятельства или находить компромиссы. Далее предлагаем более подробно рассмотреть основные сложности:
Сложности при использовании непрерывной интеграции во время разработки базы данных
Полное развертывание vs. Дельта-развертывание
Хотя код может быть полностью перезаписан во время выпуска программного приложения (полное развертывание), при работе с системами баз данных необходимо иметь в виду, что повторное развертывание объектов обычно приводит к потере содержащихся в них постоянных данных. Системы баз данных также используются в традиционной разработке программного обеспечения, но в основном только в качестве серверной части для программного обеспечения или веб-приложения. В таких случаях они оптимизируется для небольших транзакций, изменения в модели данных происходят редко и обычно являются чисто аддитивными.
Кроме того, над системой баз данных, как правило, трудиться меньшее количество разработчиков. Большинство изменений можно создать с помощью простых скриптов или DB Diff, особое внимание к данным требуется только в определенных случаях. Однако в системах хранения данных большая часть работы должна быть посвящена базе данных, при этом структурные изменения, миграция данных, архивирование и обновления являются частью повседневной деятельности.
Поэтому изменения в данном случае не могут быть созданы и развернуты просто через DB Diff. Для релиза должен быть доступен специальный сценарий перехода/обновления, который учитывает манипуляции данными (DML) в дополнение к определению данных (DDL). Здесь важно сделать все необходимое для того, чтобы данные не были потеряны или фальсифицированы. Дополнительную проблему создают большие объемы данных (по сравнению с транзакционными системами). Для облегчения процессов были созданы различные инструменты, такие как Liquibase и Flyway.
Однако создание только лишь сценариев обновления может привести к проблемам. Если совокупность структурных изменений и файлы конфигурации всех сценариев обновления всегда реализуются последовательно, чтобы развернуть текущий этап разработки в пустой среде, это может быстро привести к возникновению узких мест, что нарушает ключевую практику 7.
Кроме того, сам по себе код не дает возможности определить, какие объекты и в какой форме существуют на текущем этапе разработки, поскольку они присутствуют в разных сценариях обновления. Это лишь некоторые из причин для создания «моментального снимка» текущей конфигурации разработки. Однако хотим Вас предостеречь: если поддерживаются два артефакта, необходимо убедиться (например, с помощью DB Diff), что они не расходятся между собой.
Зависимости внутри сборки
В базе данных существуют зависимости между объектами, которые не всегда легко разрешаются. Например, представление может обращаться к функции, но также и наоборот. Проблемы могут возникнуть особенно в случае, если «моментальные снимки» используются по причинам, упомянутым выше, а последний этап разработки должен быть развернут в пустой среде. В традиционной разработке программного обеспечения стандартной процедурой на этом этапе будет анализ системы и ее загрузчиков по аналогии с развертыванием категорий объекта. Однако ввиду обстоятельств, указанных выше, недостаточно просто развернуть категории объекта, строящиеся друг на друге в системе хранения данных (сначала все таблицы, затем все представления и т. д.). Вероятно, самым простым, но не очень изящным решением было бы принять зависимости и управлять ими с помощью стандартов кодирования. Более изящным, но при этом и более дорогостоящим решением будет анализ зависимостей перед развертыванием и построение оптимального потока.
Неоднородная рабочая среда
При использовании непрерывной интеграции многие проблемы могут быть обнаружены и устранены на ранней стадии за счет автоматизации и тестирования отдельных шагов вплоть до продуктивной среды. При разработке программного обеспечения среда непрерывной интеграции, как правило, достаточно точно отражает рабочую среду. Однако целесообразность данного факта для разработки баз данных ограничена по следующим причинам:
- Для хранения полной копии производственной среды может потребоваться гигантское место на диске;
- Клонирование (или импорт резервной копии) рабочей среды может занять слишком много времени;
- Согласно Общему регламенту по защите данных, в целях тестирования данные нельзя использовать в соотношении 1:1;
- По финансовым соображениям несколько экземпляров оборудования и лицензий не всегда могут быть доступны.
Балансирование на этом этапе состоит в том, чтобы обеспечить максимально реалистичную среду тестирования (см. ключевую практику 8) и одновременно быструю сборку (см. ключевую практику 7), несмотря на все выше описанные ограничения. Упомянутые проблемы можно решить только с помощью компромиссов, особенно для больших рабочих сред в системах хранения данных. Соответственно, среда, разработанная специально для тестов, может быть загружена более старой версией данных и использоваться совместно всеми разработчиками (предварительная подготовка). В данном случае разработчики должны осуществлять очень точную координацию в целях оптимизации использования ресурсов и избегания конфликтов. Ввиду более длительного ожидания обновления среды разработчики должны поддерживать ее «чистоту» и осторожно обращаться с данными.
Автоматизированные тесты
В отличие от разработки приложений, где отдельные модули можно тестировать изолированно, а интерфейсы - просто моделировать, на системы хранения данных накладываются различные ограничения. Поскольку данные фактически копируются в базу данных для значимых тестов, отдельные тесты не могут быть легко распараллелены. В противном случае любой тест может быть перезаписан / изменен посредством параллельной ссылки на данные другого теста до его завершения. Помимо параллелизма тестов внутри сборки те же причины препятствуют одновременному запуску нескольких сборок с тестами, если они развернуты для одной и той же среды. Кроме того, последовательное выполнение отдельных тестов также означает длительный период работы. Действительно, период выполнения можно сократить, создав скрипты из зависимостей для оптимальной последовательности во время выполнения теста (сначала Тест 1, затем параллельно Тест 2 и Tест 3, затем Тест 4 и т. д.). Однако в данном случае сборка может быть ускорена лишь до определенной степени, а полный охват возможен лишь условно, потому что не все зависимости легко считываются автоматически. По этим причинам все тесты не могут быть выполнены с каждой сборкой. Более сложным решением было бы выполнение только тех тестов, для которых объекты действительно изменились. Однако из-за одного только динамичного SQL полный охват в данном случае реализовать будет сложно, так что придется снова идти на компромиссы. Например, ночные сборки, выполняемые в фиксированное время, можно настроить для автоматических тестов. Кроме того, тесты также можно разделить, чтобы легкие модульные тесты выполнялись, например, при каждой сборке, а более обширные и трудоемкие – во время ночных сборок.
Заключение
Использование непрерывной интеграции может значительно повысить качество инкрементов перед доставкой в рабочую среду. Помимо возможности повторного создания локальной среды разработки в любое время и обнаружению конфликтов на ранней стадии непрерывная интеграция представляет собой дополнительную обучающую ценность: благодаря коротким циклам обратной связи разработчик автоматически обучается работать более упорядоченно и осторожно, чтобы результаты автоматической сборки реже содержали "красные лампочки".
Большинство ключевых практик можно перенять из традиционной разработки программного обеспечения. На другие ключевые практики влияют естественные различия между программным обеспечением и разработкой системой хранения данных, они не могут применяться по принципу 1:1. Существенным отличием в данном случае является то, что большинство ошибок в системах хранения данных невозможно найти до момента импорта в тестовую среду и запуска процессов управления данными (run-time), тогда как при традиционной разработке ПО более обширное тестирование возможно уже на этапе компиляции.
Различные компромиссы между охватом тестирования, преимуществами, временем работы и затратами позволяют работать с конкретными характеристиками баз данных и пользоваться преимуществами непрерывной интеграции.