Проблема M×N: ад точечных интеграций
Урок про главную инфраструктурную боль, ради которой и появилась Kafka: комбинаторный взрыв связей между системами.
Проблема M×N — когда каждый из N источников данных нужно напрямую соединить с каждым из M потребителей, число интеграций растёт как произведение M×N и быстро становится неуправляемым.
Зачем это нужно
Представьте растущую компанию. Есть источники данных: база заказов, профиль пользователя, платёжный сервис, мобильное приложение. И потребители: аналитическое хранилище, поисковый индекс, система рекомендаций, антифрод, рассылки. Каждому потребителю нужны данные из каждого источника. Если соединять напрямую, вы пишете отдельный коннектор на каждую пару.
Считаем связи
При 4 источниках и 5 потребителях это 4×5 = 20 интеграций. Добавили один источник — плюс 5 связей. Добавили потребителя — плюс 4. Каждая связь — это код, формат, мониторинг, обработка сбоев. Схема прямых связей выглядит как паутина:
Источники Потребители
--------- -----------
Заказы ----+----+----+----o Хранилище
| | | o Поиск
Профиль ----+----+----+----o Рекомендации
| | | o Антифрод
Платежи ----+----+----+----o Рассылки
(каждый источник тянется к каждому: M x N линий)
Каждая линия — это отдельный, хрупкий конвейер. Меняется формат в источнике — чините все нисходящие связи.
Лог-посредник: M+N вместо M×N
Решение — поставить в центр единый лог. Источники пишут события в него один раз; потребители читают из него независимо. Источнику не нужно знать, кто читает; потребителю — кто пишет. Связей становится M+N:
Заказы ---+
Профиль ---+===[ KAFKA: единый лог ]===+--- Хранилище
Платежи ---+ +--- Поиск
+--- Рекомендации
+--- Антифрод
(N записей в лог) + (M чтений из лога) = M + N
При 4 источниках и 5 потребителях это 4+5 = 9 связей вместо 20. И что важнее — рост линейный: новый потребитель просто подписывается на лог, не трогая источники.
Как работает под капотом
Ключ к развязке — инверсия зависимости через посредника. Источник не вызывает потребителя (это создаёт жёсткую связь), а публикует факт в лог. Лог хранит события, поэтому потребители читают в своём темпе: один — в реальном времени, другой — батчем раз в час, третий — переигрывая историю с нуля. Источник от этого не зависит вообще. Kafka здесь — не транзитная труба (как классическая очередь, где сообщение исчезает после прочтения), а хранилище-журнал, из которого можно читать многократно и разными скоростями.
Частые ошибки
- Считать Kafka «просто шиной». Главная ценность — не транспорт, а развязка: производители и потребители ничего не знают друг о друге.
- Дублировать логику на каждом потребителе. Если все нормализуют один и тот же формат, лучше вынести это в общий слой (Kafka Connect / Streams).
- Возвращаться к точечным связям «по-быстрому». Один прямой коннектор в обход лога ломает всю выгоду — снова появляется скрытая M×N-связь.
Итоги
- Прямые интеграции дают M×N связей и квадратичный рост сложности.
- Лог-посредник снижает это до M+N и делает рост линейным.
- Развязка важнее транспорта: источники и потребители независимы и читают в своём темпе.