- PVSM.RU - https://www.pvsm.ru -

Как мы NoSQL в «реляционку» реплицировали

В наши дни NoSQL продолжает набирать популярность, но мало кто знает, что нереляционные СУБД появились гораздо раньше даже самой реляционной алгебры. 40 и даже 50 лет назад в первичном «бульоне» зарождающейся IT индустрии «варились» только NoSQL-продукты. И что самое интересное – продукты, рожденные в те сложные времена, живы до сих пор и прекрасно себя чувствуют.
Одним из таких продуктов стала СУБД GT.m, разработанная компанией Graystone Tehnologies в 70-80-х годах прошлого века. СУБД нашла широкое применение в медицине, страховании и банковской сфере.

В нашем банке мы тоже используем GT.m, и этот инструмент прекрасно справляется с обработкой большого количества транзакций. Но… Есть одна проблема: GT.m никакой для аналитики, в нем нет SQL, аналитических запросов и всего того, что делает финансового аналитика счастливым. Поэтому мы разработали собственный «велосипед» для репликации данных из GT.m в «реляционные» СУБД.

Как мы NoSQL в «реляционку» реплицировали - 1
А вот здесь должна была быть картинка с летающим велосипедом

Всех заинтересованных приглашаем под кат.

Псс… Не хочешь еще немного GT.m? Уже в те доисторические времена GT.m имела (или имел) подержу ACID, сериализацию транзакций и наличие индексов и процедурного языка MUMPS. Кстати, MUMPS – это не просто язык, это целое направление, появившееся еще в 60-х годах 20 века!

Одной из самых успешных и популярных MUMPS-based СУБД стала Caché [1], и вы, скорее всего, слышали о ней.

Основой MUMPS СУБД являются иерархические структуры – глобалы. Представьте JSON, XML или структуру папок и файлов на вашем компьютере – примерно то же самое. И всем этим наши отцы и деды наслаждались до того, как это стало мейнстримом.
Один важный момент – в 2000 году СУБД стала Open Source.

Так вот, старушка GT.m надежна и, несмотря на свои преклонные года, обслуживает большое количество специфичных транзакций без каких-либо усилий в отличие, например, от своих SQL собратьев (фраза, конечно, холиварная, но для нас это факт: на определенной нагрузке NoSQL все же шустрее SQL). Однако все проблемы начинаются тогда, когда нам нужно сделать простейшую аналитику, передать данные в аналитические системы или, не дай бог, автоматизировать все это.

Долгое время решением данной проблемы были вездесущие «выгрузки». CSV файлы формировались процедурами, написанными на языке M (MUMPS), и каждая такая выгрузка разрабатывалась, тестировалась и внедрялась высококвалифицированными специалистами. Усилия, затрачиваемые на разработку каждой выгрузки, были огромными, а содержимое двух разных выгрузок могло существенно пересекаться между собой. Случалось такое, что заказчики требовали выгрузки, на несколько полей отличные от существующих, и приходилось делать все заново. При этом сам язык M код достаточно тяжелый для понимания и чтения, что влечет за собой дополнительные «расходы» как на разработку, так и на поддержку всего этого хардкода.

Как мы NoSQL в «реляционку» реплицировали - 2
Решение с выгрузками

ODS (Operational Data Store)

У нас уже был реализованный архитектурный паттерн под названием ODS (Operational Data Store [2]), в который мы реплицируем наши источники с минимальными отставаниями от 2 секунд до 15 минут.

Данные из ODS мы загружаем в хранилище данных (DWH) либо строим по ним оперативные отчеты. И с реляционными СУБД типа Oracle, MS SQL, Sybase и т.д. нет проблем – грузим таблицы источников в те же самые таблицы на ODS.

Как мы NoSQL в «реляционку» реплицировали - 3

Мы очень хотели реализовать подобную репликацию GT.m в ODS.
Но как же грузить NoSQL структуры в простые таблицы? Как, например, загрузить клиента, у которого может быть 2 телефона, а может и 22?

Как мы NoSQL в «реляционку» реплицировали - 4

Мы понимали, что правильнее будет организовать репликацию на основе бинарных логов СУБД (в других СУБД они называются WAL, Redo, transaction log и т.п.), благо, GT.m журналирует каждую транзакцию, изменяемую данные. При этом на рынке уже существовали готовые продукты, одним из которых является Evolve Replicator от компании CAV systems [3].

Evolve CAV systems

Evolve читает журналы транзакций, трансформирует их и записывает строки в таблицы уже на реляционном приемнике.

Но была одна совсем маленькая проблема – это решение нам не подходило… В наших структурах имелось большое количество вычисляемых значений (Computed Data Items или CDI).

Попробую объяснить на пальцах. Это чем-то напоминает «виртуальное поле» в таких СУБД, как Oracle, в которых значение не хранится, а вычисляется на момент обращения к этому полю. При этом CDI может иметь достаточно сложную логику и базироваться на данных из дочерних узлов и т.д. И, как вы наверно уже догадались, такие Computed Data Items невозможно реплицировать из журналов СУБД, так как информация по ним там не хранится, потому что в журналы записываются только изменения физических полей. Но такие поля-призраки нам очень нужны для аналитики, в них сложная логика, и иметь аналитическую реплику без этих полей было бы бессмысленно.

Реализовать подобную логику с вычисляемыми полями в реплике – нереально. Во-первых, по причине производительности, во-вторых – переписывать весь этот хардкод с языка М на SQL – дело неблагодарное.

Как мы NoSQL в «реляционку» реплицировали - 5

FIS Profile

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

Таким приложением является FIS Profile (далее Profile) – это автоматизированная банковская система, полностью интегрированная с GT.m. Кроме функций автоматизации банковской деятельности, Profile обеспечивает следующий функционал:
1. Простейший SQL (select * from table where id=1)
2. Доступ к данным по JDBC
3. Представление глобалов в табличный вид, при этом один глобал может быть представлен в несколько разных таблиц
4. Триггеры
5. Секьюрность
По сути, мы имеем еще одну СУБД поверх другой СУБД. При этом одна из них будет реляционной, а другая – NoSQL.

Profile является полностью проприетарным ПО, но есть и Open Source аналоги, например, Vista Fileman [4].

Как мы NoSQL в «реляционку» реплицировали - 6
Логические уровни нашей GT.m-системы.

Реализация концепции

Для репликации NoSQL-структур данных в SQL СУБД в первую очередь необходимо:

1. Представить глобалы в табличном виде.
При этом один узел «дерева» может быть представлен в виде нескольких, связанных между собой таблиц. Такую возможность уже предоставляет Profile, и все, что нам необходимо, – это правильно настроить такие табличные представления. Задача хоть и сложная, но вполне решаемая.

2. Захват изменений.
К сожалению, наличие CDI в нашей системе не позволяет сделать «правильную репликацию» из журналов СУБД. Единственный возможный вариант – логическая репликация триггерами. Изменилось значение в таблице – триггер это отловил и записал изменение в журнальную таблицу. Кстати, журнальная таблица – это тот же самый глобал. Сейчас все сами увидите!

Вот так выглядит типичный глобал:

Как мы NoSQL в «реляционку» реплицировали - 7

Понимаем, выглядит как минимум… странно, но в те далекие годы понятия красоты были совершенно другими. Структура глобала также называется «многомерным разреженным массивом». И ключ – это как бы координата данных, которые в нем лежат.
Кстати, по «данным» можно также строить индексы, что бывает очень удобно для табличного представления.

Собственно, из такого глобала мы можем получить 2 таблицы:

TABLE_HEADER:

Как мы NoSQL в «реляционку» реплицировали - 8

TABLE_SHED — лог изменений:

Как мы NoSQL в «реляционку» реплицировали - 9

Кстати, числовые значения преобразовались в даты, например, для поля TJD.

По имеющимся таблицам выполняется запрос.

Как мы NoSQL в «реляционку» реплицировали - 10
где:
:STARTPOINT – дата последнего запуска;
'Т' – текущая дата (выглядит как минимум странно, но эта функция – аналог sysdate() или now() в нормальных других СУБД)

Как мы видим, происходит соединение «таблиц»; по факту соединение локальное, в пределах каждого узла, что не создает существенной нагрузки.

3. Выборка данных из журнальных таблиц и последующая их передача в ODS.
Существовавший на тот момент данных JDBC-драйвер прекрасно работал с атомарными запросами, но вызывал утечки памяти во время массированных операций Select. Имеющийся драйвер пришлось значительно переписать.

4. Доставка и применение изменений.
Очень важный аспект – быстрое применение данных на приемнике. Если GT.m успешно справляется с большим количеством атомарных транзакций, то для реляционных СУБД типа Oracle это несет большую нагрузку. При этом в наш ODS льются данные из большого количества других источников (всего около 15).
Для решения этой проблем, необходимо собирать все такие операции в пачки и применять их группой. Такие операции называются Bulk и полностью зависят от специфики СУБД приемника.

Как мы NoSQL в «реляционку» реплицировали - 11
Текущая архитектура репликации

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

5. Пункт управления.
Для удобного администрирования мы сделали веб-мордочку для запуска и остановки потоков репликации. Да и вообще, вся основная логика была написала на Java, что позволило использовать уже готовые Open Source компоненты для решения каких-то специфичных кейсов.

Задачи, решаемые SQL репликой

1. Избавление от разрозненных выгрузок. Мы получили единое окно для всех потребителей данных.
2. Аудит. Упрощается процедура аудита за счет того, что данные лежат в удобном виде, а мощь SQL позволяет удобно и быстро этими данными оперировать.
3. Качество данных. Например, в GT.m всего 2 типа данных – числовой и строковый. Когда данные прилетают в ODS, они преобразуется в другие типы, в том числе и в даты. Если дата в неправильном формате, мы можем легко отлавливать такой инцидент и улучшать качество данных уже на источнике.
4. Вычисление инкремента для дальнейшей загрузки в DWH.

Дальнейшие пути развития

На будущее планируем реализовать следующее:
1. Полностью избавиться от существующих CSV-выгрузок. Сейчас они все еще живы, но мы их будем потихоньку «отстреливать».
2. Оптимизировать некоторые проблемы с производительностью.
3. Поделиться идеями с заинтересованным сообществом, возможно и поддерживать проект в OpenSource.
4. Попробовать интеграцию с Oracle GoldenGate на уровне доставки изменений.
5. Возможно, сделать обратную реплику (дополнительную, не ODS) Replica -> GT.m, для сервисных процессов повышения качества данных.
6. Развивать оперативную отчетность поверх ODS.

Резюме

В статье мы рассказали о нашем детище – Profile Loader и о том, как NoSQL данные можно анализировать в SQL СУБД. Данное решение возможно не совсем правильное и элегантное, но оно прекрасно работает и выполняет возложенные на него обязательства.

Если вы решитесь реплицировать свою NoSQL БД в «реляционку» для удобной аналитики, в первую очередь оцените объемы изменений, модель данных и возможности тех технологий, которые все это будут обеспечивать.

Желаем успехов в ваших начинаниях!
Всегда готовы ответить на ваши вопросы.

P.S. Также выражаем благодарность коллегам, участвовавшим и активно помогавшим в проекте: Шевелеву Дмитрию, Чебанову Николаю, Бубону Роману, Быстрову Денису, Бейспекову Кайсару, Люфко Андрею, Кудюрову Павлу, Воробьёву Сергею, Лысых Сергею, Кулешову Денису, Никитчик Елене, Мушкет Ольге, Чечёткиной Юлии, Пасынкову Юрию и коллегам из CAV Systems и FIS.

Автор: Банк «Ренессанс Кредит»

Источник [5]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/oracle/166439

Ссылки в тексте:

[1] Caché: https://ru.wikipedia.org/wiki/Caché

[2] Operational Data Store: https://en.wikipedia.org/wiki/Operational_data_store

[3] CAV systems: http://www.cavsystems.com/en/

[4] Vista Fileman: http://www.hardhats.org/fileman/FMmain.html

[5] Источник: https://habrahabr.ru/post/306954/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best