Что такое неконсистентность данных
Консистентность данных
Консистентность данных
Консистентность данных (англ. data consistency или data validity) — это согласованность данных друг с другом, целостность данных, а также внутренняя непротиворечивость. Множество всех условий, налагаемых на данные определяется моделью (структурой) данных.
Содержание
Условия консистентности данных в ER-модели
Если данные представляют собой связанные отношениями узлы различного типа, в которых хранятся какие-то данные, то в модели данных могут быть оговорены условия: какие именно данные там могут хранится, и узлы каких типов могут быть связаны заданными в модели отношениями (связями) (см. w:en:Entity-relationship model, ER-модель данных).
Например, в базе данных людей, отношение «родитель» направленное от узла X к узлу Y подразумевает, что узел Y связан с X либо отношением «дочь» либо отношением «сын», причём это непосредственно зависит от значения атрибута «пол» узла X. Другим очевидным условием консистентности базы данных людей является требование, чтобы один узел был связан не более, чем с двумя другими узлами отношением «родитель», причём атрибут «пол» у этих узлов должен различаться.
Условия консистентности могут включать в себя указание того, какие значения могут принимать атрибуты узлов, какие отношения могут устанавливаться между узлами, каково минимальное и максимальное число отношений определённого типа, в котором может участвовать один узел, а также другие типы условий.
Консистентность в базах данных
Понятие консистентности впервые появилось в области систем управления базами данных.
Условия целостности данных (integrity constraints) стали записывать в виде правил и ввели триггеры — процедуры, которые вызывались до и после выполнения запроса. До запроса (триггер типа BEFORE) проходила проверка того, что данные имеют состояние, которое позволяет осуществить данный тип запроса. А после выполнения запроса (триггер типа AFTER) проверялось, что состояние базы данных удовлетворяет условим целостности. Если один из триггеров не срабатывал (возвращал НЕУСПЕХ или срабатывал с ошибкой), то транзакция откатывалась (отменялась).
Kонсистентность является важнейшим понятием теории управления данными (data management) и входит в четвёрку ACID (Atomicity, Consistency, Isolation, и Durability) — Атомарность, Консистентность, Замкнутость и Живучесть (стойкость).
Консистентность в теории алгоритмов и структур данных
Консистентность структуры данных в теории алгоритмов имеет важное значение.
Задачи, решаемые алгоритмистами и программистами, в большей части связаны с поиском эффективной структуры данных и реализацией механизмов поддержки её консистентности.
Например, условие консистентности двоичного дерева поиска — это возрастание ключей в узлах дерева слева направо, а именно ключ в корневом узле должен быть меньше ключей узлов правого поддерева и больше ключей узлов левого поддерева. Если в каждом узле дерева поиска хранится также указатель parent на родительский узел, то возникает дополнительное условие консистентности двоичного дерева поиска: в каждом узле X указатель на родительский узел должен указывать на такой узел, в котором ровно один из указателей на детей (left или right) указывает на узел X.
Проблема поддержки консистентности данных
Проблема поддержки консистентности данных остро стоит в задачах управления большими базами данных. Одним из способов избавится от проблем, связанных с поддержкой консистентности, является устранения дублирования информации. Одна и та же информация может быть записана с базе данных в нескольких местах (но, возможно в разном виде) или частично повторяться. Это требует синхронизации кусочков повторяющейся информации друг с другом.
С другой стороны, дублирование информации в различных местах позволяет писать более простые и эффективные алгоритмы поиска данных (алгоритмы выполнения различных запросов). При решении проблемы поддержки консистентности данных необходим разумный баланс между скоростью (сложностью алгоритмов) извлечения данных и скоростью (сложностью алгоритмов) хранения и модификации данных.
Что такое ACID в базах данных?
В частности, ACID имеет отношение к тому, как БД может восстанавливаться после ошибок, возникающих в процессе выполнения транзакции.
В базах данных, следующих принципу ACID, данные остаются целостными и консистентными, несмотря на любые ошибки.
Определение ACID
Atomicity (атомарность)
Атомарность гарантирует, что каждый запрос в транзакции будет выполнен успешно, либо вообще никакой, в случае ошибки одного. Не получится так, что часть запросов выполнятся успешно, а часть с ошибкой. Если хоть одна часть транзакции выполнится с ошибкой, вся транзакция не выполнится. Другими словами под атомарностью можно понимать «всё или ничего».
Consistency (консистентность, согласованность)
Это свойство даёт гарантию того, что все данные будут целостны. Данные будут корректны в соотвествии со всеми предопределёнными правилами, ограничениями, каскадами и триггерами, применёнными к БД.
Isolation (изолированность)
Гарантирует, что все транзакции будут выполняться изолированно. Ни одна транзакция не зааффектит на другую транзакцию. Другими словами, одна транзакция не сможет прочитать данные второй транзакции, которая ещё не выполнилась.
Durability (стойкость)
Durability означает, что когда транзакция будет применена, она останется в системе, даже если БД упала сразу после выполнения этой транзакции. Любые изменения, внесённые транзакцией, должны оставаться навсегда. Если БД сообщила об успешном выполнении транзакции, то она должна быть действительно применена.
Когда пригодится ACID?
Свойства ACID спроектированы для transaction-ориентированные баз данных.
ACID предлагает принципы, которым должны придерживаться базы данных, чтобы быть уверенным в том, что данные не будут повреждены в результате какой нибудь ошибки.
Транзакция это единая логическая операция, которая может состоять из одного или нескольких шагов. Например, транзакцией может быть перевод денежных средств между банковскими аккаунтами (снятие денег из одного и пополнение другого). Если в середине такой транзакции возникнет ошибка, может возникнуть большая неконсистентность в данных. Деньги будут вычтены с одного счёта, но не зачислены в другой.
Вот тут и должны быть применены принципы ACID.
Следуя принципу ACID, база данных будет целостна тогда и только тогда, когда она будет содержать все результаты успешно выполненных запросов, выполненных в транзакции. Любая ACID совместимая БД гарантирует, что будут применены изменения только успешных транзакций. В случае ошибки в транзакции, данные не будут изменены.
Таким образом, СУБД, совместимые с ACID, дают организациям уверенность в том, что данные в их базе данных будут целостны, даже если произойдёт какой-либо сбой в середине выполнения транзакции.
Типы сбоев
Ошибка транзакции
Эта ошибка может произойти из-за некорректных входных данных или любых других нарушений целостности. Она так же возникает в результате тайм-аута, либо в результате deadlock.
Системный сбой
Системный сбой может быть из-за ошибки в коде СУБД, либо аппаратного сбоя.
Медийные сбои
Эти сбои случаются, когда запись или чтение из хранилища невозможны (например сбой в работе жёсткого диска, либо ошибки в работе операционной системе). Эти ошибки возникают намного реже, чем первые 2 типа.
Следование ACID принципам
Все популярные реляционные базы данных следуют принципам ACID. Все они имеют инструменты, обеспечивающие целостность данных при сбоях программного и аппаратного обеспечения, а также при любых неудачных транзакциях.
Но с NoSQL базами данных ситуация обстоит немного по-другому. Эти базы данных часто предназначены для обеспечения высокой доступности в кластере, а обычно это означает, что в некоторой степени жертвуют консистентностью и/или стойкостью. Однако большинство NoSQL баз данных в некоторой степени могут обеспечить атомарность.
Но всё же, большинстве NoSQL баз данных заложены основы целостности данных, что означает, что данные могут быть не синхронизированы какое-то время, но в конечном итоге они всё таки будут синхронизированы.
Вдобавок, некоторые разработчики, такие как MarkLogic, OrientDB и Neo4j, предлагают ACID-совместимые системы управления базами данных NoSQL.
Консистентность и ACID-гарантии в распределенных системах хранения данных
Распределенные системы используют, когда возникает необходимость в горизонтальном масштабировании, чтобы обеспечить повышенные показатели производительности, которые не способна обеспечить за адекватные деньги вертикально масштабированная система.
Как и переход с однопоточной парадигмы на многопоточную, миграция на распределенную систему требует своего рода погружения и понимания того, как это работает внутри, на что нужно обращать внимание.
Одна из проблем, которая встает перед человеком, который хочет мигрировать проект на распределенную систему или начать на ней проект, — какой продукт выбрать.
Мы, как компания, которая «собаку сьела» в разработке систем такого рода, помогаем нашим клиентам взвешенно принимать такие решения применительно к распределенным системам хранения. Также мы выпускаем серию вебинаров для более широкой аудитории, которые посвящены базовым принципам, рассказанным простым языком, и безотносительно каких-то конкретных продуктовых предпочтений помогают составить карту значимых характеристик, чтобы облегчить выбор.
Эта статья основана на наших материалах по консистентности и ACID-гарантиям в распределенных системах.
Что это такое и зачем это нужно?
«Согласованность данных (иногда консистентность данных, англ. data consistency) — согласованность данных друг с другом, целостность данных, а также внутренняя непротиворечивость.» (Wikipedia)
Согласованность подразумевает, что в любой момент времени приложения могут быть уверены, что работают с корректной, технически актуальной версией данных, и могут расчитывать на нее при принятии решений.
В распределенных системах обеспечивать согласованность становится сложнее и дороже, потому что появляется целый ряд новых вызовов, связанных с сетевым обменом между различными узлами, возможностью отказа отдельных узлов и — зачастую — отсутствием единой памяти, которая может служить для верификации.
Например, если у меня есть система из 4 узлов: A, B, C и D, которая обслуживает банковские транзакции, и узлы C и D отделились от A и B (скажем, из-за сетевых проблем), вполне возможно, я теперь не имею доступа к части транзакций. Как мне действовать в этой ситуации? Разные системы принимают разные подходы.
На верхнем уровне есть 2 ключевых направления, которые выражены в CAP-теореме.
«Теорема CAP (известная также как теорема Брюера) — эвристическое утверждение о том, что в любой реализации распределённых вычислений возможно обеспечить не более двух из трёх следующих свойств:
Когда CAP-теорема говорит о консистентности, она подразумевает достаточно строгое определение, включающее линеаризацию записей и чтений, и оговаривает только консистетность при записи отдельных значений. (Martin Kleppman)
CAP-теорема говорит о том, что если мы хотим быть устойчивы к сетевым проблемам, то мы в целом должны выбрать, чем жертвовать: консистентностью или доступностью. Есть также расширенная версия этой теоремы — PACELC (Wikipedia), которая дополнительно рассказывает о том, что даже в отсутствии сетевых проблем мы должны выбирать между скоростью отклика и консистетностью.
И хотя, на первый взгляд выходца из мира классических СУБД, кажется, что выбор очевиден, и консистетность — самое главное, что у нас есть, это далеко не всегда так, что ярко иллюстрирует взрывной рост целого ряда NoSQL СУБД, которые сделали другой выбор и, несмотря на это, получили огромную пользовательскую базу. Apache Cassandra с ее знаменитой eventual consistency является хорошим примером.
Все из-за того, что это выбор, который подразумевает, что мы чем-то жертвуем, и далеко не всегда мы этим жертвовать готовы.
Часто проблема консистентности в распределенных системах решается просто отказом от этой консистентности.
Но нужно и важно понимать, когда отказ от этой консистентности допустим, а когда она является бизнес-критичным требованием.
Например, если я проектирую компонент, который отвечает за хранение пользовательских сессий, здесь мне, скорее всего, консистентность не так важна, да и потеря данных некритична, если она происходит только в проблемных случаях — очень редко. Худшее, что случится, — пользователю нужно будет перелогиниться, и для многих бизнесов это практически никак не повлияет на их финансовые показатели.
Если я делаю аналитику на потоке данных с датчиков, во многих случаях мне совсем некритично потерять часть данных и получить на небольшом промежутке времени пониженную дискретизацию, особенно, если «eventually» данные я все-таки увижу.
Но если я делаю банковскую систему, консистентность денежных проводок критична для моего бизнеса. Если я начислил пеню на кредит клиента из-за того, что просто не увидел в срок внесенный платеж, хотя он был в системе — это очень-очень плохо. Как и если клиент может несколько раз снять все деньги с моей кредитной карты, потому что у меня в момент проведения транзакции возникли сетевые проблемы, и на часть моего кластера информация о снятии не дошла.
Если вы оформляете дорогостоящую покупку в интернет-магазине, вы не хотите, чтобы о вашем заказе забыли, несмотря на рапортующую об успехе веб-страницу.
Но если вы делаете выбор в пользу консистентности, вы жертвуете доступностью. И зачастую это ожидается, скорее всего, вы не раз сталкивались с этим лично.
Лучше, если корзина интернет-магазина скажет «попробуйте позднее, распределенная СУБД недоступна», чем если отрапортует об успехе и забудет заказ. Лучше получить отказ в транзакции из-за недоступности сервисов банка, чем отбивку об успехе и потом разбирательства с банком из-за того, что он забыл, что вы внесли платеж по кредиту.
Наконец, если мы смотрим на расширенную, PACELC теорему, то мы понимаем, что даже в случае штатной работы системы, выбирая консистентность, мы можем жертвовать низкими задержками, получая потенциально более низкий уровень максимальной производительности.
Поэтому, отвечая на вопрос «зачем это нужно?»: это нужно, если для вашей задачи критично иметь актуальные, целостные данные, и альтернатива принесет вам существенные потери, большие, чем временная недоступность сервиса на период инцидента или его более низкая производительность.
Как это обеспечить?
Соответственно, первое решение, которое вам нужно принять — где вы находитесь в CAP-теореме, вы хотите консистентность или доступность в случае инцидента.
Далее нужно понять, на каком уровне вы хотите проводить изменения. Возможно, вам хватит обычных атомарных записей, затрагивающих единственный объект, как умела и умеет MongoDB (сейчас она расширяет это дополнительно поддержкой полноценных транзакций). Напомню, что CAP-теорема ничего не говорит о консистентности операций записи, затрагивающих множественные объекты: система вполне может быть CP (т.е. предпочитать консистентность доступности) и при этом предоставлять только атомарные одиночные записи.
Если вам этого не хватает, мы начинаем подходить к концепции полноценных распределенных ACID-транзакций.
Замечу, что даже переходя в дивный новый мир распределенных ACID-транзакций, мы зачастую вынуждены чем-то жертвовать. Так например, ряд распределенных систем хранения имеет распределенные транзакции, но только в рамках одной партиции. Или, например, система может не поддерживать «I»-часть на нужном вам уровне, не имея изоляции, либо имея недостаточное количество уровней изоляции.
Эти ограничения зачастую были сделаны по какой-то причине: либо для упрощения реализации, либо, например, для повышения производительности, либо для чего-то еще. Они достаточны для большого количества кейсов, поэтому не стоит рассматривать их как минусы сами по себе.
Нужно понять, являются ли эти ограничения проблемой для вашего конкретного сценария. Если нет, — у вас есть более широкий выбор, и вы можете больший вес дать, например, показателям производительности или способности системы обеспечивать катастрофоустойчивость и т.д. Наконец, нужно не забывать, что у ряда систем эти параметры могут настраиваться вплоть до того, что система может быть CP или AP в зависимости от конфигурации.
Если наш продукт стремится быть CP, то обычно у него есть либо кворумный подход к выбору данных, либо выделенные узлы, которые являются основными владельцами записей, через них проходят все изменения данных, и в случае сетевых проблем, если эти мастер-узлы не могут дать ответ, считается, что данные в принципе, невозможно получить, либо арбитраж, когда внешний высокодоступный компонент (например, кластер ZooKeeper) может говорить, какой из сегментов кластера является основным, содержит актуальную версию данных и может эффективно обслуживать запросы.
Наконец, если нас интересует не просто CP, но поддержка полноценных распределенных ACID-транзакций, то зачастую или используется все же единый источник истины, например, централизованное дисковое хранилище, где наши узлы, по сути, выступают лишь кешами к нему, которые можно инвалидировать в момент коммита, или применяется протокол многофазового коммита.
Первый подход с единым диском также упрощает реализацию, дает низкие задержки на распределенных транзакциях, но торгует взамен очень ограниченной масштабируемостью на нагрузках с большими объемами записи.
Второй подход дает намного больше свободы в масштабировании, и, в свою очередь, делится на двухфазный (Wikipedia) и трехфазный (Wikipedia) протоколы коммита.
Рассмотрим на примере двухфазного коммита, который использует, например, Apache Ignite.

Процедура коммита делится на 2 фазы: prepare и commit.
На фазе prepare рассылается сообщение о подготовке к коммиту, и каждый участник при необходимости делает блокировку, выполняет все операции вплоть до фактического commit не включительно, рассылает prepare на свои реплики, если это предполагается продуктом. Если хотя бы один из участников ответил по какой-то причине отказом или оказался недоступен — данные фактически не поменялись, коммита не было. Участники откатывают изменения, снимают блокировки и возвращаются на исходное состояние.
На фазе commit отправляется фактическое выполнение commit на узлах кластера. Если по какой-то причине часть узлов была недоступна или ответила ошибкой, то к этому времени данные занесены в их redo-лог (поскольку prepare был выполнен успешно), и коммит в любом случае может быть завершен хотя бы в отложенном состоянии.
Наконец, если отказывает координатор, то на prepare-этапе коммит будет отменен, на commit-этапе может быть выбран новый координатор, и, если все узлы выполнили prepare, он может проверить и обеспечить выполнение этапа commit.
Разные продукты имеют свои особенности реализации и оптимизации. Так, например, некоторые продукты умеют в отдельных случаях сводить 2-х фазный коммит к 1-фазному, значительно выигрывая по производительности.
Выводы
Ключевой вывод: распределенные системы хранения данных — это достаточно развитый рынок, и продукты на нем могут обеспечивать высокую консистентность данных.
При этом продукты этой категории находятся на разных точках шкалы консистентности, от полностью AP-продуктов без какой-либо транзкционности, до CP-продуктов, которые дополнительно дают еще и полноценные ACID-транзакции. Часть продуктов может быть настроена в одну или в другую сторону.
Когда вы выбираете, что нужно вам, нужно учитывать потребности вашего кейса и хорошо понимать, на какие жертвы и компромиссы вы готовы пойти, потому что ничего не бывает бесплатно, и выбирая одно, вы, скорее всего, откажетесь от чего-то другого.
Оценивая продукты с этой стороны, стоит обращать внимание на то:
Интеграция информационных систем. Борьба с неконсистентными данными.
Коллеги, привет! Меня зовут Бравин Илья, и сегодня я хочу поделиться с вами своим опытом использования Open Source решения Apache Zeppelin для упрощения и ускорения процесса выявления неконсистентных данных в интегрированных системах с различными базами данных.
Также расскажу, как мы выстроили процесс работы с неконсистентными данными.
О чем будет статья
Кому будет полезен материал?
В первую очередь бизнес-аналитикам и системным аналитикам из IT-индустрии, работающими с Энтерпрайз системами в разрезе данных там, где присутствует одно или сразу оба условия одновременно:
а) Все системы/модули/сервисы интегрированы между собой через синхронизацию данных
б) Данные в системах хранятся в различных БД (например, MySQL и PostgreSQL или Oracle Database, Elasticsearch)
Вводная часть
Для начала, хотел бы немного рассказать о себе и о компании. На данный момент у меня более 6 лет опыта аналитической и консалтинговой работы.
На прошлом месте я в составе консалтинговой команды в течение четырех лет внедрял систему управления активами предприятия от IBM на 10 теплоэлектростанциях в различных регионах России, а на данный момент я на протяжении 2,5 лет являюсь системным аналитиком в логистической компании СДЭК в блоке CRM (отвечаю за модули Контрагент, Договор, Отчет менеджера продаж во внутренней ERP).
Я, как и многие коллеги, работающие в компаниях, существующих более 10 лет, помогаю переводить функциональность и данные из старой монолитной системы в новую микросервисную.
Для понимания масштабов компании приведу несколько метрик:
В дальнейшем для термина «неконсистентные данные» я буду применять сокращение — «НКД».
Проблематика
Как показывает опыт общения с коллегами, во многих проектах данные могут стекаться из разных источников, храниться в разных базах, кто-то может пользоваться дополнительно сторонними сервисами аналитики. Соответственно, перед аналитиками порой встают задачи “подружить” такой зверинец между собой.
В данной статье мы рассмотрим ситуацию, когда причиной, по которой необходимо “подружить” зоопарк систем в разрезе данных, является выявленная или пока потенциальная НКД между связанными системами.
Для наглядности, представьте, что у вас есть две системы “А” (монолит) и “Б” (микросервисы).
Большая часть пользователей работает в новой системе, а меньшая — в старой. Часть работает и там, и там.
Часть модулей имеют уже только одностороннюю миграцию ( из новой системы в старую), но большая часть — двустороннюю.
В новой системе отсутствует часть модулей, которые есть в старой ( например, Финансы) — они в процессе “переезда”.
Неконсистентные данные
Консистентность данных — согласованность данных друг с другом, целостность данных.
Если сказать простыми словами, то неконсистентность в данных — это различие в данных между системами в разрезе конкретного объекта или атрибута.
Как вы думаете, чем вообще грозит неконсистентность между двумя и более связанными Энтерпрайз системами?
Представьте, что у вас 50 тыс. договоров в старой системе имеют верный номер договора, а в новой системе — отличающийся.
Тогда все взаиморасчеты с клиентами по данным договорам могут “встать”, когда другие модули, которым для работы нужен номер Договора, начнут брать данные из новой системы. Причем с учетом массовости проблемы, это может просто остановить бизнес в целом на какое-то время!
Или, например, адреса доставки возвратов разные для 1% заказов (что для нас около 3 тыс. заказов) или телефон у клиента разный в разных системах, а на него приходят все уведомления и смс — насколько велики будут потери в деньгах и репутации?
4 причины возникновения НКД
Проработав более 6 месяцев по задачам связанным с НКД, мы выявили следующие причины их возникновения:
1. Ошибки в маппинге между моделями данных в любом из направлений миграции
Пример: статусы или любые другие списочные данные конвертируются неверно при миграции сущностей из одной БД в другую ( особенно, если статусные модели разные или списки давно не актуализировались в одной из систем).
2. Различаются обязательные атрибуты между системами (из-за этого сущности могут зависать в миграторе, не переходя в другую систему).
Пример: в старой системе есть необязательное поле “Адрес”, а в новой оно обязательное. Тогда миграция сущности, у которой оно не заполнено, из старой в новую систему не произойдет, а зависнет с ошибкой. Потенциально это может привести к НКД уже в разрезе сущностей, а не атрибутов.
3. Отсутствует событие на миграцию в другую систему (потерялось или вообще не создавалось)
Пример: событие на миграцию из старой системы в новую создавалось только при стандартном сохранении объекта через пользовательский интерфейс.
Т.е. изначально не заложили, что при изменении какого-то атрибута объекта не через пользовательский интерфейс (например, триггер или техподдержка делает запись напрямую в БД) создавалось событие на миграцию в новую систему.
4. Массовые ручные обновления боевых данных в БД
Пример: такие обновления часто нужно выполнять сразу во всех связанных системах, что при ручном исполнении приводит к постепенному росту неконсистентности данных из-за человеческого фактора.
Рекомендация: если вы выявили неконсистентность данных у себя в проекте, пройдите по этому чек-листу. Велика вероятность, что ваша причина здесь уже есть!
Первый случай с НКД
Однажды я разбирал уже третий однотипный тикет в jira от пользователей, которые жаловались, что в существующем долгое время договоре «слетели данные» по подразделению в новой системе.
Первое, с чего я начал — убедился, что в старой системе данные верные. Тогда я решил сравнить значения этого поля по всем договорам между двумя системами.
Итак, что у нас было перед началом выгрузок:
а) Две разные системы “А” и “Б” с различными БД (MySQL и PostgreSQL).
б) Модуль “Договор” существует и в старой системе, и в новой, люди работают и там, и там, миграция данных двусторонняя синхронная.
в) Договоров — 500 тыс.
г) Сервера стоят в Новосибирске — мы в СПБ.
Что пришлось делать:
а) разработчик делал выгрузку из 2-х БД в локальный PostgreSQL
б) разработчик конвертировал модели и сопоставлял данные из двух систем в разрезе Договора
в) я работал с выборкой данных (искал паттерны)
г) я согласовывал решение проблемы с бизнесом
д) разработчик повторял выгрузки с учетом новых вводных от бизнеса
Из-за того, что у нас разные типы бд, сделать запрос в одном окне программы для запросов в БД (например, в DataGrip) не представлялось возможным.
Поэтому разработчику пришлось выгружать две выборки по 500 тыс. договоров из двух баз. Только выгрузка заняла в сумме около 4 часов!
После этого разработчик конвертировал и сопоставлял данные из двух выборок в локальном DataGrip, что заняло еще более 30 мин.
И только после этого к работе приступал я. По сути, первично, меня интересовал масштаб проблемы, так как в зависимости от него и способы решения были различные.
Наш выгрузка показала около 1 тыс. договоров с разными Подразделениями. Явного тренда или зависимости я не обнаружил, поэтому быстрого решения тут не было, требовалось привлекать бизнес.
Когда бизнес увидел выборку, ему было нужно несколько дополнительных атрибутов в ней, чтобы разобраться, а в какой же из систем верные данные, что потребовало повторения процедуры выгрузки.
Резюме: у нас ушло более 8 часов времени разработчика и аналитика на то, чтобы предоставить бизнесу такую выборку, которая сможет дать ему необходимые данные для принятия решения.
Требования к инструменту
После нескольких таких выборок, мы решили найти инструмент, который позволит ускорить нахождение НКД для систем с различными БД, а также позволит привлекать разработчиков только при особо сложных случаях.
Наши требования были следующими:
а) Инструмент хотелось бесплатный, так как не было понятно, насколько он нам реально нужен (может все закончится на 10 выборках), поэтому искали в open source.
б) Инструмент должен позволять один раз настроив подсоединение к различным БД, более не повторять настройки. Также он должен упростить и автоматизировать конвертацию и сопоставление данных из различных БД.
в) С учетом предварительной настройки разработчиком инструмент должен обладать возможностью работы с SQL (для автономной работы аналитика)
г) Инструмент должен обладать интуитивно понятным интерфейсом, а также возможностью визуализации данных для того, чтобы можно было безболезненно привлекать бизнес к решению.
Apache Zeppelin
Просмотрев несколько вариантов решений, остановились на двух Zeppelin и Jupiter notebook:
Нашу задачу можно было решить и с Jupiter Notebook, но потребовалось бы больше прослоек и дополнительных настроек, а также времени, так как из коробки там работа основана на Python или языке R, а нам нужен был SQL.
Почему выбрали Apache Zeppelin
В итоге оказалось, что Apache Zeppelin удовлетворяет всем нашим требованиям, описанным выше.
Различные источники данных
Zeppelin из коробки, через Apache Spark, позволяет работать с различными источниками данных (MySQL, PostgreSQL, Cassandra, Elasticsearch, Python и пр. ).
Визуализация данных
Все стандартные виды визуализации данных присутствуют, но особых изысков нет)
Для нашей цели, как оказалось, не нужна даже такая визуализация, так как она практически не помогает бизнесу в принятии решения. Проще и быстрее при необходимости использовать стандартные возможности Excel.
Работа с SQL из коробки
За счет Apache Spark из коробки работает сервис Spark SQl, позволяющий работать с запросами в интерфейсе всем, кто может их писать.
Примеры реальной работы с Zeppelin
Ноутбуки и параграфы
Ноутбук в Zeppelin — это аналог страницы с набором данных по отдельному бизнесовому запросу. На скриншоте вы можете увидеть ноутбук по атриубу “Подразделение» в сущности «Договор».
Каждый ноутбук состоит из нескольких параграфов (окон).
В большинстве случаев стандартный ноутбук состоит из следующих параграфов:
а) Настройки подключения (здесь необходимо прописывать базовые настройки для подключения к бд и базовые запросы к ним) — рассмотрим его чуть позже
б) Выгрузка по кол-ву НКД между системами (нас всегда интересует масштаб проблемы!)
в) По необходимости, визуализация распределения НКД по времени или другому разрезу
г) Результирующая выгрузка по данным для анализа (здесь нужно выводить все сопутствующие данные по проблемным сущностям — чтобы бизнес мог прямо или косвенно понять, в какой из систем данные верные)
Каждый параграф (кроме настроек подключения) состоит из двух разделов: code section, в который помещается исходный SQL запрос, и result section, где можно увидеть результат выполнения запроса. Code section для удобства скрывается автоматически.
Также у вас есть возможность запускать каждый из параграфов в отдельности (чтобы сэкономить время) или запустить сразу все параграфы внутри одного ноутбука одной кнопкой.
В целом, вы можете проводить стандартные действия с каждым из параграфов:
Теперь кратко представлю алгоритм работы аналитика по получению выгрузки по НКД:
1. Настроить подключение ко всем необходимым источникам данных.
2. Составить SQL запрос для выгрузки исходного дата сета для каждого источника данных.
3. Дать наименование каждой временной таблице, куда будет сохраняться датасет каждого источника данных.
4. Добавить новый параграф и в нем написать SQL запрос, который сравнивает полученные датасеты из временных таблиц в разрезе равенства необходимого атрибута.
5. Запустить параграф из п.4.
Далее более подробно обсудим каждый шаг.
Параграф “Настройки подключения”
Сначала идет SQL запрос на выборку данных из новой базы ( «Договор» в PostreSQL).
Этот запрос может формировать аналитик. Обычно это запрос с минимальными фильтрами. Но в нем должны выводится все необходимые косвенные данные.
Далее настройка для подключения к этой базе («Договор» в PostreSQL).
Далее идет SQL запрос на выборку данных из старой базы ( «Договор» в MYSQL).
Далее настройка для подключения к этой базе («Договор» в MYSQL).
Настройки подключения к БД (url, драйвер, логин, пароль) заполняются один раз для каждого источника данных — с этим могут помочь администраторы/разработчики.
После того как вы прописали первичный SQL и настройки подключение к БД необходимо назвать временную таблицу, которая будет хранить результаты выборки.
В последующем финальном запросе необходимо будет использовать именно это новое наименование таблицы!
Далее для каждого источника данных требуется повторить процедуру.
Количество источников данных не ограничено (в своей практике мы не использовали более 6).
Сравнение датасетов и результат
Как я говорил ранее, параграф состоит из двух разделов: code section, в который помещается исходный SQL запрос, и result section, где можно увидеть результат выполнения запроса.
Ранее в параграфе “Настройки подключения” мы инициировали создание двух временных таблиц с данными из разных БД.
Теперь нам необходимо составить условие для проверки на консистентность конкретного атрибута в разрезе сущности Договора из разных БД.
В сode section — запрос, который сравнивает два датасета из разных БД и должен выдать все договоры, у которых поле “Подразделение” отличается между датасетами.
Финальная выгрузка
После выполнения параграфа с финальной выгрузкой и начинается аналитика данных (поиск паттернов и гипотез).
Масштаб проблемы удобнее оценивать по отдельному параграфу с численным отображением найденных сущностей с НКД.
Можно скачать файл в CSV или в TSV (рекомендую, когда у вас в выборке много данных со знаками препинания).
С этой таблицей при необходимости может работать бизнес по прямой ссылке.
Если повезло, и все данные по выборке верные в одной из систем, то ссылка на этот ноутбук копируется в jira, когда аналитик ставит задачу на проведение апдейта в БД.
Ролевая политика и совместная работа в команде
Нам удалось легко настроить разделение возможностей у пользователей, выдав им соответствующие роли, например:
а) Бизнес — могут только просматривать
б) Аналитики — могут просматривать «ноутбуки» и запускать их
в) Разработчики — могут создавать «ноутбуки» и перезагружать сервис
г) Администраторы — могут все
Мы используем 3 общие роли — нам достаточно. Можно работать совместно (но желательно не над одним проектом, это некомфортно).
LDAP и Active Directory
Zeppelin через Appach Shiro поддерживает эти распространенные способы аутентификации пользователей, так что при необходимости вы сможете быстро их настроить и упростить жизнь своим пользователям, не заставляя их придумывать новые логины и пароли.
Результаты после полугода работы с инструментом
а) кратно уменьшился срок поиска НКД
б) появилась возможность визуализировать и делиться результатом
в) сильно увеличилась автономность работы аналитика
г) появилась возможность повторить выборку нажатием кнопки «Run all»
Также сформировался новый алгоритм работы аналитика по работе с НКД:
а) Формулировка бизнес-задачи
б) Формирование SQL запросов в 2 БД для получения базовых датасетов
в) Клонирование и актуализация существующего ноутбука
г) Актуализация условий сравнения датасетов из разных БД и нужных столбцов в выборке
д) Получение данных
ж) Согласование и верификация решения с бизнесом
з) Создание задачи на апдейт в Jira со ссылкой на ноутбук в Zeppelin
*Разработчики привлекаются только для составления сложных запросов ( в 10-15% случаев)
При выявлении НКД мы запускаем (часто параллельно) два процесса — устранение последствий (определение в какой из систем данные верные, апдейт данных в другой системе), поиск и исправление причин, чтобы неконсистентные данные больше не появлялись.
Что делать в первую очередь, зависит от потенциальных последствий, которые требуется обсуждать с Product Owner и PM.
Требуется оценить, что принесет больше проблем/убытков — продолжать создавать новую неконсистентность, начав с исправления НКД (однако после исправления причины, придется править данные еще раз) или сначала найти и исправить причину НКД, а только после этого исправить НКД?
Очень часто по выявленным случаям НКД необходимо отрабатывать вручную с разработчиком, раскапывая старый код, логику миграторов или маппинга моделей.(см. чек-лист причин НКД выше). В большинстве случаев это занимает продолжительное время (от 4-6 часов и до недели, в зависимости от того, нужно ли лезть в логику монолита)
У вас может возникнуть следующий вопрос: “Зачем так много лишних действий?” — как только выявили НКД и определили, где данные верные — просто копируете полностью все данные из одной системы в разрезе атрибута в другую!
И это действительно может сработать, но только при выполнении одного условия:
вы уверены, что данные портились всегда только в одной из систем?
В нашей практике в 85% случаев, данные оказывались верными в старой системе, но пожертвовать 15% это очень ответственное решение, у которого много негативных последствий, с учетом высокой связности модулей.
Кейсы, когда Apache Zeppelin может быть полезен
Самое главное — Apache Zeppelin помогает только в поиске НКД. Он не решает причин возникновения неконсистентности!
Рекомендуем использовать Apache Zeppelin:
а) при внедрении нового/переносе существующего крупного
функционала или большого массива данных в одной из связанных систем, если у систем используются различные БД
Выделив несколько ключевых полей, вы сможете отслеживать практически в режиме реального времени, что данные мигрируют во все системы корректно.
Для этого потребуется произвести дополнительные настройки и например, подключить алерты, при появлении НКД.
Такой подход позволит минимизировать риски того, что проблема вскроется, когда уже станет критической. Глазами, вы не сможете отслеживать неконсистентность сотен тысяч атрибутов единовременно.
б) если вы никогда не проверяли системы с различными БД на НКД
Наш опыт показывает, что в таких случаях неконсистентность также может быть. У нас, например, проблема не успела “выстрелить” из-за того, что другие модули в новой системе, которые получают информацию от “Договора”, еще не вышли на prod. и не успели получить некорректные данные.
в) При необходимости сравнения выборок данных из разных БД
Это просто удобный инструмент для такого типа задач ( у нас часто им пользуются разработчики).
Заключение
А вы проверяете свои системы на НКД?! Если у вас есть опыт настройки других инструментов для выявления НКД — прошу поделиться опытом в комментариях.
Ссылки на полезные материалы
Здесь подобраны ссылки на полезные материалы как для разработчиков, так и для аналитиков, чтобы развернуть Apache Zeppelin у себя и начать им пользоваться.