Привет, Хабр! Меня зовут Роман Аминов, я руковожу группой автоматизации бизнес-сценариев в команде СУБД Pangolin в СберТехе. Это специальная доработанная сборка PostgreSQL, целевая СУБД в Сбере и не только. СУБД — сложный продукт, обновление, настройка и другие рутинные действия, связанные с её сопровождением, сопряжены с риском потери данных. Чтобы облегчить жизнь пользователям (и вдобавок разгрузить нашу техподдержку) мы разработали инструмент для автоматизации кластеров СУБД, их настройки и конфигурирования, обновления версий компонентов в их составе и обслуживание. Решение уже прошло проверку на тысячах кластеров в Сбере и я готов поделиться тем, как всё это работает.

Уточню, что мы используем систему управления конфигурациями Ansible. Всё, что нужно для её работы — это возможность устанавливать SSH-соединения и Python на удалённых серверах.

Надеюсь, статья будет полезна или натолкнёт на свои мысли автоматизаторов и администраторов СУБД и вообще всех, кто связан с базами данных. 

В Platform V Pangolin DB входит большое количество компонентов, из которых можно собирать различные кластеры. Каждый кластер может быть сконфигурирован под разные цели и задачи. Все компоненты (где главный — сама СУБД) имеют большое количество параметров, активируя которые мы получаем ту или иную функциональность. С помощью тонкой настройки компонентов можно серьёзно увеличить производительность и надёжность как отдельных компонентов, так и кластера в целом. 

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

Какую пользу мы хотели получить от инструмента поддержки: 

  • ниже риск ошибок при развёртывании или обновлении СУБД;

  • меньше времени простоя СУБД при обслуживании кластера;

  • помощь в защите пользовательских данных (например, от потери) во время обслуживания кластера СУБД;

  • проще развёртывание, обновление и настройка компонентов кластера;

  • меньше трудозатрат при первичном развёртывании и при переходе на новые версии продукта.

В целом же нам было важно, чтобы решение помогло в первую очередь пользователям, у которых нет глубокой технической экспертизы в работе с СУБД. И вот как мы всё организовали.

Схемы развёртывания

Есть две наиболее часто встречающиеся схемы развёртывания.

Первая — это standalone: pangolin-dbms с pangolin-pooler — утилитой, управляющей пулом соединений СУБД (доработанный нами pgbouncer). 

Standalone pangolin-dbms с pangolin-pooler
Standalone pangolin-dbms с pangolin-pooler

Вторая — кластер с потоковой репликацией. 

Кластер с одной потоковой репликацией
Кластер с одной потоковой репликацией

Сейчас наши скрипты работают с этими двумя схемами. На самом деле, есть ещё две: это standalone только с одной СУБД и одноногий кластер, в его состав помимо СУБД входят pangolin-pooler, DCS и pangolin-manager. Однако такие схемы гораздо менее востребованы, потому на них не буду заострять внимание.

Pangolin-manager — это утилита, которую мы разработали на базе patroni, она нужна для создания высоконагруженных кластеров с потоковой репликацией. В роли DCS может выступать как стандартный etcd, так и наша разработка — Pangolin DCS. При работе наших сценариев можно использовать в том числе внешний кластер DCS, например, коммунальный.  Либо  можно развернуть и настроить DCS с помощью наших скриптов.

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

На картинке ниже  пример кластера с тремя потоковыми репликациями на базе DCS, pangolin-manager, pangolin-pooler и pangolin-dbms. Все реплики в данном случае наследуются от лидера. 

Кластер с тремя потоковыми репликациями от одного лидера
Кластер с тремя потоковыми репликациями от одного лидера

А это пример кластера с набором каскадных репликаций:

Кластер с набором каскадных репликаций
Кластер с набором каскадных репликаций

И наконец последний пример показывает возможность конфигурирования кластерных решений из отдельных атомарных кластеров. В роли таких кластеров можно рассматривать все ранее рассмотренные примеры конфигураций. При развёртывании и обновлении сложные конфигурации будут декомпозироваться на атомарные, для которых по отдельности и будут отрабатывать наши сценарии.

Пример комплексного кластера на основе атомарных кластеров
Пример комплексного кластера на основе атомарных кластеров

На предыдущих скринах были примеры новых схем конфигурирования, а сейчас рассмотрим сам механизм их создания. С точки зрения Ansible-проекта обязательно должен быть файл inventory, где указаны IP/FQDN хостов, с которыми мы будем работать, а также параметры подключения к ним. Для каждого хоста с помощью специально зарезервированных слов в рамках нашего проекта указываем его роль в кластере (см. картинку ниже). А именно:

  • leader — это текущий хост мастера, сейчас он может быть только один;

  • replica — потоковые репликации, которые синхронизируются напрямую с мастером;

  • replica_cascade – набор каскадных репликаций;

  • dcs — хосты, выделенные под распределённую систему хранения конфигурации. 

После такого специального слова сначала идёт символ нижнего подчеркивания, а сразу после — число от 0 до N, которое для replica и DCS обозначает номер узла в рамках его роли. А в случае каскадной реплики это число указывает номер потоковой репликации, которая синхронизируется напрямую с мастером. И от которой должна наследоваться эта каскадная реплика. Если при эксплуатации кластера нужно добавить ещё одну реплику, то достаточно запустить специальный сценарий. 

Пример заполнения файла inventory
Пример заполнения файла inventory

Рассмотрим сам пользовательский конфигурационный файл. Мы определились с ролями в рамках всего кластера для каждого хоста, но нужно также понять, какие компоненты должны быть установлены на этих хостах. Для этого мы используем три абстракции: leader_group, replica_group и dcs_group, для каждой из них указываем те компоненты, которые будут инсталлированы и настроены на хостах в одной из этих групп. Leader_group содержит в себе leader‑хост из inventory. Replica_group соответствует всем replica и replica_cascade‑хостам. Dcs_group содержит в себе все DCS‑хосты.

Пример конфигурирования пользовательского конфига в части определения схемы развёртывания кластера

Сценарии автоматизации

В первую очередь мы автоматизировали  сценарий первичного развёртывания СУБД. При развёртывании или в рамках отдельных сценариев можно включить или настроить ту или иную функциональность. Например, сюда можно отнести сценарий настройки и включения средств защиты информации (СЗИ) — это шифрование хранимых данных, защита данных от привилегированных пользователей и secure config (хранение конфигурационных файлов в специальном удалённом VAULT‑хранилище). Также мы автоматизировали тюнинг параметров СУБД в зависимости от профилей нагрузки — на текущий момент это 1С, OLAP, OLTP.

В состав Pangolin входят разработанные или доработанные нами утилиты. Это утилиты для работы с шифрованным хранилищем паролей, перешифрованием данных, ротации сертификатов и многие другие. Их нужно корректно устанавливать, конфигурировать и обновлять. При разработке метода обновления мы придерживались подхода, где обновление только обновляет (но не исправляет и не переконфигурирует СУБД и компоненты). Ведь обновление СУБД — само по себе дело трудоёмкое и ответственное, и нагружать этот сценарий дополнительными требованиями мы не хотели. Для этого есть другие сценарии. Зато теперь всё работает просто и надёжно.

Обновление кластера СУБД

Этот сценарий состоит из двух частей.

Разведка — здесь пользователь получает всю нужную информацию о состоянии текущего стенда с СУБД. И непосредственно обновление — его можно запускать, когда таможня в виде разведчика даёт добро (выдаёт success-сообщение). 

Обновление кластера СУБД
Обновление кластера СУБД

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

Обновление СУБД с помощью pg_upgrade
Обновление СУБД с помощью pg_upgrade

Мажорное обновление. Этот сценарий требует миграции всех данных при переходе на новую версию — и для этого мы используем утилиту pg_upgrade (см. картинку выше). И здесь нам нужно создавать локальную резервную копию всей СУБД, при мажорных обновлениях всегда есть потенциальный риск потери данных (ввиду того что в процессе они изменяются). В случае ошибки обновления резервная копия будет использована для автоматического восстановления кластера к его исходному состоянию. Также при мажорном обновлении уже смигрированные на мастере данные будут переноситься на его реплики с помощью утилиты rsync. После чего автоматически собирается новая статистика и при необходимости пересчитываются индексы. На всё время обновления компонента СУБД недоступна для пользователей, так как весь внешний трафик блокируется.

Минорное обновление. Или обновление исполняемых файлов СУБД.

Обновление исполняемых файлов СУБД
Обновление исполняемых файлов СУБД

В этом случае нет рисков потери данных, а значит, не нужна полная локальная резервная копия. Старая и новая версии СУБД здесь полностью обратно совместимы и в том числе не меняется формат WAL‑записей. При обновлении такого кластера сначала обновляется реплика, после чего происходит switchover и старая реплика становится новым мастером. В это время обновляется уже новая реплика и снова switchover, чтобы вернуть роли кластера к исходному состоянию. Так происходит последовательное обновление всех узлов кластера. Блокировки трафика в этом случае нет, потому кластер доступен для использования на протяжении всего обновления. Интересная особенность: даже при полном отказе текущего мастера в момент обновления реплики на текущую реплику сохраняются все WAL с мастера (даже когда она не работает какое‑то время). Копирование происходит с помощью утилиты pg_receivewal, так реплика всегда консистентна с мастером.

Обновление СУБД с помощью утилиты inplace_upgrade
Обновление СУБД с помощью утилиты inplace_upgrade

Обновление данных системного каталога. Или минорно‑мажорное обновление. Этот сценарий разработала наша команда. Всё строится вокруг нашей утилиты inplace_upgrade. Это решение позволило нам отказаться от мажорных обновлений при изменении только данных системного каталога, то есть когда меняются только системные данные, но не сами физические объекты системного каталога — таблицы, столбцы, индексы, ключи и т. д. О том, как устроен бэкенд утилиты inplace_upgrade ранее мой коллега Николай Литковец рассказал в своей статье. А наш девопс Кристина Демидович подробно написала о том, как автоматизирует сценарий обновления. Вкратце: с помощью inplace_upgrade кластер обновляется так же быстро, как и в миноре. И не требует предварительного создания полной резервной копии: ввиду отсутствия работы с данными, бэкапируются только данные системного каталога. При этом, как и при мажорном обновлении, СУБД недоступна для пользователей во время обновления.

Каждый из сценариев обновления идёт по своему алгоритму и со своими ограничениями и требованиями.  Но пользователю не обязательно знать все нюансы. Ему достаточно запустить разведчика, выполнить все рекомендации (если они будут), повторно запустить разведчика — убедиться, что больше нет препятствий, а после этого начать обновление. Все проверки и выбор нужного метода  пройдут под капотом скриптов. 

Приятный бонус: при любой внештатной ситуации во время любого нашего обновления кластер автоматически восстановится до исходного состояния. 

Пользовательские сообщения: скрипты → пользователь

Примеры сообщений
Примеры сообщений

Вернёмся к разведчику обновления. Выше я вскользь упомянул, что он выполняет какие-то там проверки. Какие именно? И как он взаимодействует с пользователем? Перед обновлением разведчик должен проверить, что обновляемый кластер находится в полностью рабочем состоянии, нет недостатка в ресурсах, в том числе для хранения данных. Ещё на этом шаге он определяет тип обновления. При мажорном обновлении разведчик дополнительно проверяет, хватает ли свободного места для создания резервной копии, не используются ли deprecated типы данных и так далее. Затем он сообщает в человекочитаемом виде о том, что разведка прошла успешно и можно запустить playbook обновления. Или же пишет, почему обновление недоступно и его нужно отложить. У таких сообщений собственные уникальные коды, они делятся на четыре группы: WARNING, ERROR, INFO и SUCCESS. Допустим разведчик обнаружил, что в БД используются deprecated типы данных, которые после обновления перестанут поддерживаться. Он не просто сообщит об этом, но и предложит альтернативу. Когда пользователь сконвертирует свои данные из deprecated в альтернативные, ещё раз проверит, что все ошибки устранены и можно начинать обновление. 

Журнал работы скриптов автоматизации

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

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

Журнал работы сценариев автоматизации
Журнал работы сценариев автоматизации

Запуск сценариев: Ansible или утилита для запуска

Рассмотрим вызов сценариев напрямую из Ansible. Как видно из примеров, строка запуска довольно большая и с дополнительными параметрами. Отмечу, что мы имеем две точки пользовательского конфигурирования — inventory и пользовательский конфигурационный файл. Запустим сценарий развёртывания. 


Да, конечно, строка запуска может быть и проще, ну а может быть и такой.

Запуск сценария развёртывания БЕЗ утилиты запуска
Запуск сценария развёртывания БЕЗ утилиты запуска
Запуск сценария развёртывания с помощью утилиты запуска
Запуск сценария развёртывания с помощью утилиты запуска

На втором скрине — запуск того же сценария развёртывания кластера СУБД, но уже с помощью нашей утилиты. Запуск плэйбуков напрямую больше подходит для инженеров, он нативнее и может использоваться, скажем, при интеграции в работу собственных сценариев. А запуск с помощью нашей утилиты адресован пользователям, которые хотят максимально упростить всё и не вникать в тонкости. Здесь много писать не буду — свой текст на Хабр о приложении для установки и обновления СУБД уже дописывает его разработчик — наш DevOps Дмитрий Озолин. Вкратце: мы постарались продумать решение таким, чтобы пользователю было всё интуитивно понятно и не требовалось делать никаких дополнительных шагов перед запуском сценариев, помимо установки самой утилиты (а это делается с помощью пакетного менеджера).

Итак, утилита установлена. Теперь нужно проинициализировать пользовательский конфигурационный файл, то есть создать его (утилита сделает это сама по команде init). Далее через конфигурационный файл пользователь задаст требования к сценарию: на каких хостах развернуть, обновить или настроить кластер, какую функциональность включить и в каких режимах. И просто нажмёт «Запуск». Кстати, в ходе выполнения, с помощью прогресс-бара он будет видеть статус всех этапов в сценарии.

Утилиту мы планируем развивать. Интересно было бы добавить собственный GUI. И совместимый интерфейс для автоматизации с помощью REST API, на случай если у пользователя есть собственный GUI.  В том числе здесь мы имеем уже одну точку конфигурирования вместо двух обозначенных ранее. На скрине ниже пример вывода информации о ходе развёртывания кластера СУБД.

Пример вывода результата работы утилиты запуска
Пример вывода результата работы утилиты запуска

На картинке ниже показана вторая часть вывода информации о развёртывании кластера. 

Пример вывода результата работы утилиты запуска
Пример вывода результата работы утилиты запуска

Ещё утилита выводит информацию о rpm/deb-пакетах: какие пакеты установлены в ходе работы сценария, их версии и на каких хостах.

Результаты: как всё это сработало 

Расскажу об опыте использования наших инструментов в Сбере за прошедший год. Pangolin — это целевая СУБД в Сбере, основа для миграции всех существующих приложений и разработки новых. У нас есть команда поддержки уровня L3, которая помогает пользователям по любым сложным вопросам. Наши инженеры включаются в помощь по обновлениям и развёртыванию СУБД. И в какое‑то время эти обращения были самыми частыми. Изменилось ли что‑то после того, как мы выдали пользователям наши скрипты? Да, результаты радуют:

  • 100 % кластеров СУБД развёрнуто вообще без обращений в нашу поддержку;

  • 98 % кластеров СУБД обновлено без обращений, 2 % — c обращениями.

Что же, мы довольны, воодушевлены продолжать и автоматизировать ещё больше ручной работы.

Что дальше?

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

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

Вот список компонентов, для которых мы хотим сделать возможность независимого развёртывания и обновления:

  • pangolin‑dbms — СУБД;

  • pangolin‑pooler — утилита, управляющая пулом соединений СУБД;

  • pangolin‑manager — утилита для создания высокодоступных кластеров с потоковыми репликациями;

  • pangolin‑backup‑tools — набор утилит для создания резервных копий БД;

  • pangolin‑certs‑rotate — утилита для ротации сертификатов;

  • pangolin‑auth‑reencrypt — утилита для восстановления работоспособности узла кластера при смене параметров сервера;

  • pangolin‑security‑utilities — набор утилит для настройки СЗИ;

  • pangolin‑docs — документация продукта Pangolin;

  • pangolin‑diagnostic‑tool — утилиты для получения диагностической информации о СУБД;

Хотим создать отдельные сценарии для активации уже реализованной и новой функциональности. Вот у пользователя есть ранее развёрнутый и настроенный стенд. Ему нужно внести туда какие‑либо изменения. Скажем, поменять значения параметров в конфигурационном файле СУБД. Мы создадим систему, где ему достаточно запустить сценарий настройки параметров СУБД и указать новые значения для тех параметров, которые надо изменить. Концепция заключается в том, что мы уйдем от монолитной архитектуры (когда в один сценарий могла закладываться даже какая‑то бизнес‑логика и он мог объединять в себе сразу несколько типов действий, различных с точки зрения логики, например, развёртывание кластера, его настройка и активация отдельных фич) в сторону декомпозиции, где каждый сценарий отвечает только за решение одной логической задачи. Отдельно — развёртывание, отдельно — настройка конфигурационных файлов компонентов кластера. Доконфигурирование текущей схемы развёртывания, активация отдельных фич (настройка ssl, pkcs12 и тд) и многое другое. И можно будет отдельным сценарием установить/обновить расширение, которое не входит в ядро СУБД (postgis, timescaledb и пр.).

Планируем реализовать идемпотентность не только на уровне встроенных Ansible‑модулей, но и на уровне Ansible‑ролей и сценариев. Сценарий автоматизации требует проведения большого количества операций, и они тоже могут длиться долго. Хотим, чтобы при возникновении ошибки в ходе сценария обновления у пользователя была возможность устранить эту ошибку, а после просто перезапустить его и продолжить сразу с той самой роли, на которой было падение. Минуя все предыдущие шаги. На практике это будет так: пользователь разворачивает кластер с большим набором компонентов, допустим, развёртывание проходит благополучно, но на последнем шаге проверки лагает сеть и сценарий падает. Ему не нужно будет всё удалять и ставить по новой. Достаточно перезапустить сценарий, который доделает оставшиеся шаги и выдаст сообщение о том, что развёртывание прошло успешно.

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

Хотим сделать так, чтобы скрипты автоматизации могли работать со всеми версиями компонентов в составе Platform V Pangolin DB и в любом сочетании этих версий.

Собираемся разработать разные скрипты для поддержания документации Ansible‑сценариев в актуальном состоянии. Хочется сделать механизм для автоматической генерации/перегенерации документации. Можно в markdown‑формате. А также на основании документации автоматически создавать инструкции по ручному воспроизведению работы каждого нашего сценария,.

Интересно реализовать магазин коллекций в Ansible. Это аналог репозиториев Linux для распространения rpm/deb‑пакетов, только в роли пакетов здесь выступают коллекции Ansible.

Вместо заключения

Если вы автоматизируете работу с СУБД, буду рад узнать о вашем опыте и ответить на вопросы. Если вы пользователь, расскажите, каких инструментов вам не хватает? Прошу в комментарии.

P.S. Если интересно узнать больше о том, как мы развиваем решение, приходите в наше сообщество. Скоро расскажем про наши новые доработки. 

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