… простите, мигрировали куда? Туда!


CockroachDB — PostgreSQL-совместимая (по SQL-синтаксису DML) распределенная СУБД с открытым кодом (ну, почти). Ее название символизирует, что она, как таракан, выживает в любых экстремальных ситуациях. Лично мне крайне импонирует такая СУБД с привычным SQL-интерфейсом, настройка которой занимает 5 минут, которая хранит данные — как Kafka — на нескольких узлах в нескольких ЦОДах сразу, имеет настраиваемый replication factor на уровне конкретных таблиц, легко переживает потерю как одного узла, так и целого ЦОДа, использует для этого механизм распределенного консенсуса Raft и при этом еще и имеет строгую консистентность и уровень изоляции serializable. Разработчики CockroachDB — выходцы из компании Google, которые решили коммерциализировать архитектуру распределенной СУБД Spanner.



Недостатки тоже есть, не переживайте, но про них лучше в другой раз :)

Почему именно CockroachDB?


Среди распределенных SQL-СУБД есть альтернативы в виде Yugabyte и TiDB, и с прошлого месяца YDB. Вопрос «Почему?» связан в первую очередь с тем, зачем вообще нужна БД. Как мне кажется, БД нужна для того, чтобы надежно хранить данные и доставать их через стандартный язык SQL, а удобство ее использования — приятный, но вторичный фактор. Тут надо заметить, что я почти 9 лет проработал в техподдержке Oracle, и видел достаточно случаев порчи БД, как из-за дисковых сбоев и ошибок администраторов, так и из-за багов в приложении и даже в коде самой СУБД.

Ключевыми критериями выбора были:

  • многократно проверенный движок хранения данных. В CockroachDB используется RocksDB, в остальных — неизвестно кем, как и сколько тестированные альтернативы;
  • регулярное тестирование тестом Jepsen в рамках сборки релиза на наличие проблем безопасного хранения данных в распределенной БД. CockroachDB успешно прошли этот этап еще 5 лет назад;
  • совместимость с PostgreSQL для того, чтобы быстро мигрировать туда в случае серьезных проблем. TiDB совместимо с MySQL, YugaByte с Postgres, YDB пока что ни с чем;
  • простота настройки, отсутствие сложных decoupled-архитектур. Тут CockroachDB лидер: один бинарный файл, один конфигурационный файл, все изменения проходят либо в онлайне, либо с поочередной перезагрузкой узлов кластера.

Подытоживая, CockroachDB на мой вкус однозначно наиболее зрелая распределенная SQL-СУБД на рынке. YDB основана на тех же принципах, но отстаёт в технологическом развитии на 3-4 года. Я крайне рад отечественной разработке в критически важной отрасли транзакционной обработки данных. К сожалению, все презентации Яндекса по YDB, которые я посетил на конференции HighLoad++, были призваны привлекать в Яндекс разработчиков сложными задачами, а не продвигать YDB как готовое решение.

Зачем так сложно — распределенный SQL?


Суммарная стоимость владения (Total Cost of Ownership) решений по повышению отказоустойчивости PostgreSQL заметно выше CockroachDB. С одной стороны, эти решения (Patroni, Corosync) бесплатные, с другой стороны нет никаких гарантий, что они всегда будут отрабатывать как надо. У нас были прецеденты того, что правильно настроенное решение по автоматическому переключению ролей БД с основной на резервную и обратно приводило к зависаниям и неработоспособности сервиса, чего в нашем случае мы себе позволить не могли. В то же время CockroachDB разворачивается в среде k8s из коробки с минимальными усилиями. Я считаю, за распределенным SQL будущее. Этой же точки зрения придерживаются такие технологические гиганты как Twitter, которые сделали CockroachDB базой для разработки по умолчанию.



Как развивались события


Для первого запуска в промышленную эксплуатацию CockroachDB мы выбрали небольшой новый проект с крайне незначительной нагрузкой. Это позволило нам обкатать нюансы использования новой базы в наших CI/CD-потоках, придумать сценарии перехода на PostgreSQL в случае, если что-то сильно пойдет не так, и опробовать базовые преимущества проведения апгрейда БД и других операций планового обслуживания в онлайне без простоя.

После успешного завершения предыдущего этапа мы нашли mission critical схему данных, которая в Oracle нам сильно мешала, и стали думать над ее переносом в CockroachDB. Подчеркну, что основной причиной для миграции этой БД из Oracle в CockroachDB была отказоустойчивость.

Для миграции необходимо было решить следующие вопросы:
  • проверить синтаксис SQL-запросов на соответствие ANSI;
  • вынести хранимый код из PL/SQL в сервисы на Java/Kotlin;
  • правильно конвертировать схему данных;
  • выбрать подходящий способ переноса данных с учетом требований по доступности системы.

Конечно же, в наших SQL-запросах нашлись не входящие в ANSI стандарт конструкции вида "... and rownum <= X» — и их пришлось переписать. Для подготовки работы бизнес-логики с разными БД у нас уже были запланированы отдельные реализации Java-классов, поэтому система могла спокойно работать как с Oracle, так и с CockroachDB, в зависимости от текущих настроек, поэтому объем работы на данном этапе был незначительный. Из-за характера доступа к данным у нас получилось провернуть перенос данных без остановки, переключив приложение в read-only режим на время синхронизации данных в обеих БД.

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

Для конвертации схемы данных из Oracle в CockroachDB я выбрал утилиту с открытым исходным кодом Ora2Pg , до этого она была неоднократно проверена в задачах миграции с Oracle на PostgreSQL.

Немножко деталей про использование ora2pg


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

Мы проделали следующие шаги:

1. Инсталлировали Perl, DBI, DBD:Oracle и ora2pg, каждый по соответствующей документации.
2. Создали четыре файла конфигурации для ora2pg.

Помимо параметров коннекта и конвертируемой схемы, в каждом из них были установлены параметры
DISABLE_SEQUENCE = 1  
DROP_FKEY = 0 


Эти файлы конфигурации отличались параметром TYPE, установленном соответственно в

SEQUENCE
TABLE
VIEW
COPY


3. Запуск утилиты ora2pg с этими параметрами сгенерировал 4 sql-файла.

После этого определения внешних ключей были перенесены в 5-й файл, с нюансом того, что CockroachDB пока что не поддерживает инструкцию DEFERRABLE .

grep -v -i "FOREIGN KEY" table.sql > table1.sql
grep -i FOREIGN table.sql| sed -e 's/NOT DEFERRABLE INITIALLY IMMEDIATE//g' > fk.sql
mv table1.sql table.sql


4. Далее в определения таблиц мы внесли изменения, аналогичные триггерам для заполнения полей из sequence. Это достигается использованием синтаксиса "… default nextval('sequence')", см. ниже.

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

С учетом вышесказанного про sequence, синтаксис создания таблицы выглядит примерно так:

CREATE TABLE some_table (
   id bigint NOT NULL default nextval('some_sequence'),
   value varchar(300) NOT NULL,
   value_lower VARCHAR(300) NULL AS (lower(value)) STORED   
)


После этого вычисляемый столбец можно индексировать:
CREATE UNIQUE INDEX some_uk2 ON some_table (id, value_lower);


5. Пришлось убрать из файлов инструкции set search_path и обработчики ошибок.

Далее я просто применил к базе CockroachDB файлы sequence.sql, table.sql и view.sql и получил требуемую структуру данных.

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

6. Заполнение таблиц CockroachDB большим количеством данных оказалось не самой тривиальной задачей, и быстрее всего оказалась команда PostgreSQL вида COPY. Для ее использования пришлось дополнительно инсталлировать клиентский драйвер psql, генерация файлов для команды COPY также производилась утилитой ora2pg.

Можно было заморочиться с использованием команды IMPORT из csv-файла, однако по скорости и качеству в подходе с ora2pg лично меня всё устраивало, и csv-подход опробован не был. Вариант с генерацией команд INSERT оказался провальным, в какой-то момент после массовой вставки трёх тысяч строк этот процесс зависал.

7.После этого из файла fk.sql были созданы внешние ключи. Это последний технический шаг в миграции БД.

8. Провели тест работоспособности приложения с новой базой.

9. После успешного теста мы просто заменили JDBC-строки подключения к БД на использование CockroachDB и включили режим read/write.

10. Сценарий обратной миграции данных из CockroachDB в Oracle через генерацию INSERT был также отработан на 100%. Обычно такие сценарии не то что не тестируют, а даже не рассматривают, но наша система слишком важна для бизнеса, и эти риски нам нужно было отработать.

Суммарно исследование методов миграции и подготовка к работам заняли неделю, изменения кода Java/Kotlin — два спринта одного разработчика, сами работы были полностью проведены от начала до конца за час. Объем перенесенных данных составлял порядка 10 млн строк, генерация скрипта переноса данных заняла 2 минуты, а вставлял этот скрипт данные в CockroachDB примерно 3 минуты.

Если бы мы не укладывались в наше получасовое тех.окно в режиме read-only, то, скорее всего, мы бы использовали Oracle GoldenGate в связке с Kafka для промежуточной синхронизации данных между Oracle и CockroachDB.

Что в итоге


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

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


  1. zxweed
    06.06.2022 18:18
    +5

    10 млн строк сможет обработать Nokia 3110, у вас нет случайно опыта переноса, например, 10 трлн строк с оракла хоть куда-нибудь?


    1. PeterBobrov Автор
      06.06.2022 19:22

      Горечь в Ваших словах слышу я. Могу посоветовать Hadoop. 10 млрд строк из Oracle в Hadoop мы переносили аж два раза. Впрочем, CockroachDB не аналитическая БД, а также use case немножко другой, так что сравнение с Nokia 3110 неуместно. Для начала попробуйте утопить Нокию в сортире, а потом обработать ей 10 млн строк.


      1. arheops
        07.06.2022 21:28

        10млн строк mysql пробегает в среднем за минуту. На дешевом хостинге.


  1. Roman2dot0
    06.06.2022 18:59
    +7

    Как мы мигрировали критичную БД с Oracle в CockroachDB

    Ожидания:
    Терабайты данных, миллиарды записей в таблицах, десятки-сотни таблиц.

    Реальность:
    Можно было заморочиться с использованием команды IMPORT из csv-файла. 3 минуты вставляли данные


    1. AndrewJD
      06.06.2022 20:50
      +4

      Добавлю к ожиданиям: тысячи или десятки тысяч хранимок и вьюх.


    1. mnbck
      07.06.2022 13:21

      Справедливости ради стоит отметить, что тут по сути не описан процесс миграции кода (кроме упоминания, что требуется «вынести хранимый код из PL/SQL в сервисы на Java/Kotlin»).
      А иногда это и есть самый сложный и затратный этап из всей миграции.


  1. krabdb
    06.06.2022 19:38
    -1

    Парни, вы проедаете деньги инвесторов с такими "задачами".


  1. Dansoid
    06.06.2022 19:40
    +1

    Думаю из минусов CockroachDB, все упрется в аналитические выборки. Конечно, это может и не ваш вариант, но как бы хотелось чтобы база и считала быстро.

    Стоит также посмотреть и сюда https://www.singlestore.com. Такой же непотопляемый черт, петабайт ready, но с чертовски скоростной аналитикой. Платный однако. Накормить его данными можно кучей способов и очень быстро.


    1. PeterBobrov Автор
      06.06.2022 19:47
      +1

      Соглашусь с Вами. Типы нагрузки по личному опыту лучше не смешивать, а всё что декларирует совместимость с разными типами нагрузки, сразу вызывает кучу вопросов и подозрений. Мы же не пишем, что это универсальная база общего назначения, а рассматриваем конкретный use case. В нем она мега-хороша.


    1. creker
      06.06.2022 20:58
      +3

      Дык, таракан не аналитическая же база. Конечно упрется, это OLTP база. Под каждый тип нагрузок нужно свой сторадж иметь. Хотя бы разные движки, если база позволяет. Singlestore, судя по документации, имеет сомнительную консистентность, когда в списке неподдерживаемых MySQL фич видишь foreign keys и referential integrity. А поддерживаемый уровень изоляции - read committed. Я сторадж с такими же гарантиями на какой-нить касандре смогу собрать. Хочется аналитику - кликхуаз, пожалуйста.


      1. Dansoid
        06.06.2022 21:20

        Хочется аналитику - кликхуаз, пожалуйста.

        Ой что-то я сомневаюсь в текущих способностях CH, слишком молодой. Пишем для него провайдер для linq2db, ограничений пока хватает, может и поборем часть ограничений эмуляцией.


        1. PeterBobrov Автор
          06.06.2022 21:54
          +1

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


          1. EvgenyVilkov
            08.06.2022 18:02

            Плюсану за Вольт. По сути MPP OLTP


        1. neenik
          06.06.2022 22:21

          Тем не менее, задачу OLAP он полноценно закрывает (а иногда даже и не только OLAP).


  1. AndrewJD
    06.06.2022 20:54
    +2

    При упоминании тестов Jepsen, неплохо все же предостережения из этих тестов указывать:

    Like Spanner, Cockroach’s correctness depends on the strength of its clocks. If any node drifts beyond the clock-offset threshold (by default, 250 ms), all guarantees are basically out the window. Unlike Spanner, CockroachDB users are likely deploying on commodity hardware or the cloud, without GPS and atomic clocks for reference. Their clocks may drift due to VM, IO, or GC pauses, NTP misconfiguration or faults, network congestion, and so on, especially in certain cloud environments.


    1. PeterBobrov Автор
      06.06.2022 21:01
      +1

      В одной статье же нельзя объять необъятное, если копнуть, то узел кластера CockroachDB при дрифте времени в <параметр> миллисекунд просто выводит себя из состава кластера ("падает"). Это приводит к регулярным "падениям" узлов, если вы держите узлы на гипервизоре, который по тем или иным причинам решает мигрировать свою "виртуалку"


  1. akhkmed
    07.06.2022 13:08
    +1

    Вы упомянули, что Postgres оказался недостаточно надёжным. Опишите подробнее ваш опыт, который показал проблемы при переключениях мастера в Postgres.


    1. PeterBobrov Автор
      07.06.2022 15:03

      Может быть в следующий раз)


  1. yoshka
    07.06.2022 15:48

    Один из недостатков CockroachDB - маркетинг, ассоциированный с тараканами. Сейлзы CockroachDB те еще жуки. Ты их в бан, они с другого адреса пишут: "Где-то скучает одинокий таракан". Ты им пишешь "спасибо-не-надо", они через неделю интересуются "а может сейчас уже надо?".

    Даже интересно, сколько раз в день им угрожают тапком или диклофосом за навязчивость.


  1. vooft
    07.06.2022 16:31

    Кокроач изо всех сил пытается выглядеть обычной RDBMS, но на деле не является такой. В итоге на какой-нибудь очень простой запрос в специальных условиях задержка улетает в небо.

    Ну и отсутствие привычного READ_COMMITTED ломает многие привычные паттерны проектирования.


    1. PeterBobrov Автор
      07.06.2022 18:02

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