D-07 · Декомпозиция данных#
- Версия: 1.0 · 2026-09-17 · по мастер-шаблону v6.0
- Известно также как: разделение данных, база на сервис, database per service, где лежит истина, сколько копий
- Этап: W3 · Данные: модель и хранилище · граница сервисов проверяется на W4, транзакционная — на W6
- Стадия: гринфилд · работающая — на гринфилде вопрос «сколько копий уже есть» читается как «сколько заведём»
- Профиль: дорого изменить · высокое влияние → полная форма, двусторонняя
- Не решает: какой продукт взять под конкретное хранилище — это D-01; где границы сервисов — D-02 и D-05; как участники разговаривают — D-04; как переехать, не останавливаясь — это D-08; что отдавать, когда одна из разделённых частей недоступна, — D-06
- Не путать с: D-02 — там границы сервисов, здесь границы данных. Они часто совпадают и обязаны быть согласованы, но решаются порознь: сервисы можно разделить, оставив базу общей, и это отдельный выбор с отдельной ценой
- Карточки: DATA-16 целостность и сверка · DATA-19 retention, удаление, приватность · DATA-15 OLTP и OLAP · DATA-18 мультитенантность · DATA-17 миграции схемы без простоя · MSG-07 outbox и CDC · SEC-13 классификация данных · PERF-06 пулы соединений
Решение двустороннее по построению. Вопрос здесь ровно «делить или держать вместе», и однонаправленного ответа у него не бывает: силы разделения взвешиваются против сил интеграции, и перевес считается, а не объявляется.
Область решения — одна сущность или одна связная группа данных, а не «данные в системе». Вторая группа — второе применение документа.
Документ собран из реестра пилота И0′. Шесть записей из семи вошли вопросами, осями и дисквалификаторами; седьмая — удаление персональных данных — вошла частным случаем первой, а не отдельной темой.
1. Что выяснить#
| Вопрос | Где смотреть | Заполняет |
|---|---|---|
| О каких данных речь и кто сегодня их пишет? | Схема, код, права доступа | Область; сила «управление изменениями» |
| Сколько копий этих данных уже существует? | Индексы, кэши, витрины, журналы событий, выгрузки, архивы | Реестр копий — см. ниже |
| Какие запросы основного сценария соединяют их с данными других владельцев? | Основные сценарии, медленные запросы | Сила интеграции «отношения в данных» |
| Какие инварианты требуют атомарности между ними и соседними? | Инварианты W0 | Дисквалификатор |
| Что перестанет работать при отказе этого хранилища и сколько независимых частей это затронет? | Карта зависимостей | Сила «отказоустойчивость» |
| Есть ли среди этих данных требующие особого режима — и какого именно? | Требования W0, закон, договор | Сила «режим защиты», дисквалификатор |
| Сколько независимых потребителей держат соединения к этому хранилищу? | Пулы соединений, предел хранилища | Сила «управление соединениями» |
Реестр копий — позвоночник решения#
Второй вопрос важнее остальных, и отвечать на него надо письменно. Каждая копия — место, куда обязано дойти изменение. Пока список не составлен, все рассуждения о разделении идут про одну копию из семи.
| Куда | Как туда попадает | Доходит ли изменение | Можно ли удалить |
|---|---|---|---|
| Основное хранилище | Запись | — | Да |
| Поисковый индекс | ? | ? | ? |
| Кэш | ? | ? | ? |
| Витрина отчётности | ? | ? | ? |
| Журнал событий | ? | ? | Часто нет |
| Архивная копия | ? | ? | Часто нет |
Удаление — это изменение, которое обязано дойти до всех копий. Ничего особенного в нём нет, кроме того, что невыполнение замечает юрист, а не пользователь. Отдельной темы оно не образует: если реестр копий составлен и путь изменения по нему прослежен, путь удаления прослеживается тем же способом. Механика — DATA-19: карта распространения, мягкое и жёсткое удаление, крипто-шреддинг там, где стереть нельзя.
Строка «часто нет» — не оговорка. Неизменяемая по построению копия превращает вопрос удаления в вопрос шифрования, и решать его надо до разделения, а не после.
2. Силы, дисквалификаторы и встречная половина#
Силы разделения — оси сравнения#
Шесть. Первые пять — из Ford, Richards, гл. 6, шестая пришла из разбора и в их списке отсутствует.
| Сила | Что записывать в ячейку |
|---|---|
| Управление изменениями | Сколько независимых частей задевает изменение схемы этих данных |
| Отказоустойчивость | Сколько частей перестанет работать при отказе хранилища |
| Масштабируемость | Различаются ли требования к масштабу у этих данных и у соседних — и на сколько порядков |
| Управление соединениями | Число независимых потребителей против предела хранилища |
| Тип хранилища | Выигрывают ли эти данные от другого типа — и насколько измеримо |
| Режим защиты | Требуют ли эти данные режима, которого не требуют соседние: шифрование на диске, аудит доступа, локализация, ограниченный круг лиц |
Силы интеграции — встречная половина#
Сила интеграции — не балл, а счёт, который разделение выставляет. Как и в D-02: либо оплачена названной ценой, либо отменяет линию.
| Сила | Чем измеряется | Оплатить можно так | Когда отменяет линию |
|---|---|---|---|
| Отношения в данных | Внешние ключи, соединения, представления, пересекающие линию | Соединение в приложении · материализованное представление по событиям · денормализация со сверкой | Целостность обеспечивается связью на уровне БД и требуется инвариантом |
| Транзакции | Нужна ли атомарность поперёк линии | — | Всегда: дисквалификатор ниже |
| Число копий | Сколько мест придётся синхронизировать после разделения | Единственный источник порядка — журнал, из которого читают все | Синхронизировать нечем, кроме записи в оба места: см. первый дисквалификатор |
Третья сила в списке Форда и Ричардса отсутствует, и это неслучайно: их две силы интеграции — про связи между данными, а эта про связи между копиями. Разделение не только разрывает соединения, но и размножает истину, и второе дороже первого, потому что невидимо.
Дисквалификаторы#
- Разделение порождает запись в два места без единого источника порядка. Расхождение при этом неизбежно по двум независимым причинам — гонка и частичный отказ — и не порождает ошибок, поэтому обнаруживается месяцами позже (Kleppmann). Двойная запись — не вариант с недостатками, а дефект. Либо журнал как единственный источник порядка (MSG-07), либо разделения нет.
- Есть копия, из которой нельзя удалить, и в ней оседают данные, подлежащие стиранию. Решать надо до разделения: после — придётся переписывать архивы.
- Разделение размазывает защищаемые данные по нескольким владельцам. Каждый попадает в периметр аудита и обязан держать режим целиком; стоимость режима умножается на число мест. Если линия проходит сквозь класс защищаемых данных — её двигают, а не оплачивают.
- Атомарность требуется поперёк линии и следует из бизнес-инварианта. Дисквалифицирована линия, а не требование.
- Отказ остаётся общим. Разделили логически, база физически одна — ни одна сила разделения не сработала, а сложность выросла. Проверка: сколько частей ляжет вместе с этим хранилищем после разделения.
Первые три обычно не отменяют разделение, а добавляют работу до него — и этим отличаются от последних двух, которые отменяют линию.
3. Матрица оценки#
Колонки — формы из раздела 4, применимые к этим данным. В ячейках факты с пометкой источника, не баллы.
Словарь пометок. [схема] — из схемы данных и кода · [замер] · [расчёт] · [требования] — из инвариантов и обязательств W0 · [режим] — из требований к защищаемым данным: закон, договор, внутренняя политика · [нет данных].
Пометка [нет данных] здесь редка и подозрительна. Почти всё считается по схеме, коду и конфигурации за часы. Пустая ячейка обычно означает не «не померили», а «не нашли все копии» — то есть незаполненный реестр из раздела 1.
| Ось | Что записывать | Оставить как есть | Разделить владение внутри одной базы | База на сервис |
|---|---|---|---|---|
| Управление изменениями | Сколько частей задевает изменение схемы | 3 [схема] |
1 — остальные через интерфейс [схема] |
1 [схема] |
| Отказоустойчивость | Сколько частей ляжет с хранилищем | 3 | 3 — база та же | 1 |
| Масштабируемость | Разница требований, в порядках | Неприменимо | Неприменимо | Порознь |
| Управление соединениями | Потребителей против предела | 3 пула | 3 пула | 1 пул на базу |
| Тип хранилища | Выигрыш от другого типа | — | — | Возможен |
| Режим защиты | Что обязывает класс данных и сколько мест его держит | 1 место, режим целиком [режим] |
1 место [режим] |
2 места — режим удваивается [режим] |
| Сила интеграции: отношения | Связи через линию и чем оплачены | нет | нет | 4 внешних ключа → соединение в приложении [схема] |
| Сила интеграции: копии | Сколько мест синхронизировать | 2 | 2 | 4 [схема] |
Нулевой вариант обязателен, и здесь он выигрывает чаще, чем в других решениях: у данных цена разделения выше, чем у кода, а обратимость ниже.
«Разделить владение внутри одной базы» — колонка, которую забывают. Отдельная схема, единственный писатель, чтение остальных через интерфейс: связность разработки падает, а физического разделения ещё нет. Промежуточная форма, и обычно правильная первая.
4. Типовые формы разделения данных#
Рынка здесь нет. Место рыночного слоя занимают формы — они не устаревают, даты съёмки у раздела нет.
| Форма | Что делаем | Когда верна | Чем оборачивается при ошибке | Статус у нас |
|---|---|---|---|---|
| Оставить как есть | Ничего | Силы разделения не набрали перевеса; связи плотные | Связность разработки останется — но это честная цена, а не поломка | заполняется в проекте |
| Разделить владение внутри одной базы | Схема на владельца, единственный писатель, чтение через интерфейс | Первый шаг почти всегда | Владение объявлено и нарушается: технически-то доступ есть | |
| База на сервис | Физическое разделение | Силы разделения перевесили и соединения через линию оплачены | Соединения уезжают в приложение, копий становится больше | |
| Вынести класс данных отдельно | Защищаемые или особые по типу данные — в своё хранилище | Класс требует режима, которого не требуют соседние | Режим удваивается, если класс вынесен не целиком | |
| Копия только для чтения из журнала | Витрина, индекс, поисковый слой | Нужен другой способ доступа к тем же данным | Копия становится вторым источником истины — и расходится | |
| Разделить по времени | Горячее и холодное порознь | Доступ к старому редок и другой по характеру | Граница «горячего» подобрана на глаз и уезжает | |
| Разделить по арендатору или региону | Данные по границе клиента или юрисдикции | Локализация обязательна или радиус поражения важен (DATA-18) | Кросс-арендаторские запросы становятся невозможны |
Колонка «статус у нас» — те же три значения, что в рыночном слое: используем · не используем, потому что… · не рассматривали.
Формы применяются лесенкой, а не по выбору. Обычный порядок — владение внутри одной базы, потом база на сервис, потом вынос класса. Перепрыгивать можно, но тогда стоит записать, почему промежуточная ступень пропущена.
Источники раздела: Ford, Richards — Software Architecture: The Hard Parts, гл. 6 · Richardson — Database per service · Richardson — Shared database · Kleppmann — логи и почему двойная запись плоха · реестр пилота И0′
5. Эвристики#
Начинать с реестра копий, а не с линии. Пока не выписаны все места, где эти данные оседают, разделение обсуждается на одной копии из семи, и все оценки занижены.
Двойная запись — не компромисс, а дефект. Её не «принимают с оговоркой»: расхождение неизбежно и невидимо. Если после разделения она возникает — либо появляется журнал как источник порядка, либо линия не проводится.
Логическое разделение перед физическим. Отдельная схема и единственный писатель дают большую часть выигрыша за малую часть цены, и они обратимы. Физическое разделение — почти нет.
Защищаемые данные сначала сужают, потом делят. Чем меньше мест, где они лежат, тем дешевле режим. Линия, рассекающая класс защищаемых данных, удваивает стоимость аудита и почти никогда не окупается.
Отказ, оставшийся общим, обнуляет разделение. Самая частая полумера: сервисы разные, база одна. Проверять надо не намерение, а число частей, которые лягут вместе.
«Нет данных» здесь подозрительно. В D-01 пустая ячейка значит «не померили». Здесь — почти всегда «не нашли все копии»: всё остальное считается по схеме и коду за часы.
Согласовать с границами сервисов, но не выводить одно из другого. Данные можно разделить, оставив сервисы едиными, и наоборот. Совпадение линий — цель, а не данность; расхождение записывается как осознанная цена, а не обнаруживается через полгода.
6. Запись в ADR#
| Поле ADR | Чем заполняется |
|---|---|
| Контекст | Данные, их писатели, реестр копий целиком и инварианты, требующие атомарности |
| Дисквалификаторы | Какие линии отсечены и почему; отдельно — что превратилось в работу до разделения |
| Рассмотренные варианты | Матрица раздела 3 снимком, включая нулевой вариант и обе силы интеграции |
| Решение | Форма разделения, новый единственный писатель для каждой части, способ распространения изменений |
| Обоснование | Какие силы перевесили и чем оплачена каждая сила интеграции |
| Последствия | Что придётся построить: журнал или захват изменений, сверка, соединение в приложении, путь удаления по всем копиям |
| Условия пересмотра | Раздел 7 |
| Метод | D-07 v<версия> · шаблон ADR v<версия> — рыночного снимка нет |
Обязательная строка записи — реестр копий на момент решения. Он и есть «условия момента»: через год копий станет больше, и вопрос «что перепроверить» начинается именно отсюда.
7. Условия пересмотра#
- Появилась копия, которой не было в реестре. Каждая новая копия — новое место, куда обязано доходить изменение, и повод пересчитать силу «число копий».
- Появился инвариант, требующий атомарности поперёк линии.
- Класс защищаемых данных изменился: то, что не требовало режима, стало требовать, или наоборот.
- Число независимых потребителей выросло так, что упёрлось в предел по соединениям.
- Отказ хранилища затронул больше частей, чем считалось при решении.
- Сверка стала показывать расхождение, которого раньше не было, — значит распространение изменений сломалось, и молча.
- Границы сервисов изменились по D-02, и линии данных разошлись с ними.
Проверка перед тем, как считать решение принятым — пять пунктов в шаблоне. Шестой, местный: реестр копий выписан целиком, и по нему прослежен путь удаления. Без этого решение принято на одной копии из семи, какой бы аккуратной ни была матрица.
Источники: Ford, Richards — Software Architecture: The Hard Parts, гл. 6 · Kleppmann — Using logs to build a solid data infrastructure · Richardson — Database per service · GitHub — разбор инцидента 21 октября 2018 · 00-workflow.md, шаг W3
История версий#
| Версия | Дата | Изменение |
|---|---|---|
| 1.0 | 2026-09-17 | Первая версия. Собрана из реестра пилота И0′. 7 вопросов, 6 сил разделения, 3 силы интеграции, 5 дисквалификаторов, 7 типовых форм вместо рыночного слоя. Первый документ, построенный на двусторонней форме целиком. Удаление персональных данных вошло частным случаем согласованности, а не отдельной темой; третья сила интеграции — «число копий» — в источниках отсутствует и добавлена по разбору |