惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 叶小钗
D
Darknet – Hacking Tools, Hacker News & Cyber Security
S
SegmentFault 最新的问题
博客园 - 三生石上(FineUI控件)
雷峰网
雷峰网
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
博客园 - 【当耐特】
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
V
Visual Studio Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 聂微东
P
Proofpoint News Feed
Last Week in AI
Last Week in AI
U
Unit 42
W
WeLiveSecurity
博客园 - Franky
Recent Announcements
Recent Announcements
Hacker News - Newest:
Hacker News - Newest: "LLM"
Attack and Defense Labs
Attack and Defense Labs
月光博客
月光博客
The Cloudflare Blog
Spread Privacy
Spread Privacy
腾讯CDC
P
Privacy International News Feed
N
News and Events Feed by Topic
AWS News Blog
AWS News Blog
NISL@THU
NISL@THU
T
Troy Hunt's Blog
小众软件
小众软件
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Microsoft Security Blog
Microsoft Security Blog
L
Lohrmann on Cybersecurity
Webroot Blog
Webroot Blog
Y
Y Combinator Blog
量子位
P
Palo Alto Networks Blog
N
News and Events Feed by Topic
V
Vulnerabilities – Threatpost
K
Kaspersky official blog
IT之家
IT之家
T
Threat Research - Cisco Blogs
Cloudbric
Cloudbric
云风的 BLOG
云风的 BLOG
C
Check Point Blog
Blog — PlanetScale
Blog — PlanetScale
爱范儿
爱范儿
G
Google Developers Blog
S
Secure Thoughts

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Репликация по DDIA: что я понял, только когда сам сломал прод
Umidjon Tojiboyev · 2026-05-26 · via Все публикации подряд на Хабре

Средний

6 мин

6K

В понедельник утром бухгалтер из клиентской компании написала мне в Telegram: «У контрагента в SAP всё оплачено, а в Smartup долг 12 миллионов». Я открыл обе системы. Одна и та же накладная. Два разных состояния. Два источника правды — и оба врут.

Это было ровно то место в книге Designing Data-Intensive Applications, на котором я когда-то уверенно кивнул и пошёл дальше. Глава 5. Replication. «Ну да, master-slave, понятно». А когда через год сам построил систему с двумя ведущими — даже не назвав её так, — Клеппманн взял своё со штрафами и пенями.

Это история о том, как я понял пятую главу DDIA не из книги, а из логов.

Контекст: почему вообще двусторонняя синхронизация

Я работаю в SAP B1 партнёре в Ташкенте. У одного из клиентов параллельно живут две системы. SAP B1 — финансовый контур: главная книга, налоги, отчётность для аудита. Smartup — оперативка: продажи, склад, отгрузки, касса. Бизнес работает на обеих несколько лет. Выкинуть одну нельзя — обе глубоко вросли в процессы.

Задача звучала просто: «пусть данные синхронизируются». Партнёры, заказы, оплаты, накладные. На бумаге — типовой ETL. На практике — длинный урок про то, что «пусть синхронизируются» — это незаданное направление потока.

Первая версия дизайна была наивно симметричной. Псевдокод:

каждые 5 минут:
    для каждой сущности:
        если updated_at(SAP) > updated_at(Smartup):
            тянем из SAP в Smartup
        иначе если updated_at(Smartup) > updated_at(SAP):
            тянем из Smartup в SAP

Что я думал, когда это писал: «элегантно, симметрично, last-write-wins сам разрулит конфликты».

Что я НЕ думал: я только что построил multi-leader replication. Просто без этого названия.

Первый конфликт, который положил систему

Сценарий из логов (цифры близкие к реальным, имена и ID изменены):

  • 09:14:12 — бухгалтер в SAP B1 правит сумму НДС на накладной INV-2403-19. updated_at = 09:14:12.

  • 09:14:17 — менеджер в Smartup отмечает на этой же накладной частичную оплату. updated_at = 09:14:17.

  • 09:15:00 — крон забирает оба объекта. Smartup новее, он становится «правдой». Правка НДС теряется.

  • 09:16:00 — следующий крон. Сумма в Smartup всё ещё со старым НДС, но updated_at новее. SAP перезаписывается обратно. Цикл замыкается.

Что я увидел в логах: бесконечный пинг-понг с ошибками валидации (SAP не принимает дробные копейки от Smartup), а бухгалтер вручную правила одну и ту же сумму три раза за день, не понимая, почему она «возвращается».

Клеппманн в пятой главе ровно это и описывает: при асинхронной репликации между несколькими ведущими два независимых клиента могут обновить одну и ту же запись параллельно, и система обязана либо обнаружить конфликт, либо иметь правило разрешения, которое не теряет данные. Last-write-wins по часам — это правило, которое теряет данные. Каждый раз. По определению.

Я знал это в теории с момента, когда читал книгу. Я не узнал это в продакшене, пока не увидел свои собственные строчки в логах.

Часы врут — и не так, как ты думаешь

Дальше стало хуже. SAP B1 хранит updated_at в локальной зоне HANA. Smartup — в UTC. Я выровнял это в коде. Но даже после выравнивания вылезло: HANA-сервер у клиента под нагрузкой отстаёт от NTP на 2–4 секунды. Smartup живёт в облаке, и его сервер на секунду опережает реальное время.

Разница в 3–5 секунд между серверами — это то, о чём в восьмой главе DDIA отдельно предупреждают: не строй логику на timestamp-ах с разных машин. Они согласованы сами с собой, но не друг с другом. Монотонные часы хороши для измерения интервалов на одной машине и бесполезны через сеть.

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

Что я понял из главы 5, перечитав её после инцидента

Перечитал главу не как студент, а как человек, у которого она в проде. То, что раньше было параграфами, стало списком ошибок, которые я уже совершил:

Single-leader было правильным выбором, а я его обошёл. Не потому что он не подходил, а потому что симметричный дизайн казался «честнее». Multi-leader оправдан только когда есть одно из трёх: геораспределённая запись с низкой задержкой, работа оффлайн с последующей синхронизацией, или разная семантика записи в разных регионах. Ни одно из этих условий у меня не выполнялось. Я выбрал сложную модель из эстетических соображений.

Replication lag — это не баг, это свойство системы. В моей конфигурации lag был 5 минут (период крона). Любой UI, который сразу после записи возвращался читать ту же запись через другую систему, видел старые данные. Read-your-own-writes consistency — это не магия, а явная фича, которую надо проектировать. У меня её не было.

LWW не разрешает конфликты, он их прячет. Каждый раз, когда last-write-wins «разруливает» конфликт, кто-то теряет данные. Иногда это допустимо — счётчик просмотров, лайк, последняя выбранная тема интерфейса. В финансах — никогда.

Conflict detection важнее conflict resolution. Если ты не можешь увидеть, что произошёл конфликт, ты не можешь его починить. У меня не было ни одной метрики «записи разъехались». Только жалоба бухгалтера в Telegram через два дня после факта.

Что я переделал

После недели логов и одной перечитки главы я переписал интеграцию по правилам, которые сегодня выглядят почти очевидными.

Owner per field, а не per record. Накладная — общий объект, но у каждого поля есть владелец. Сумма НДС — owner SAP B1 (бухгалтерия). Статус оплаты и остаток — owner Smartup (касса). Поля от не-owner системы игнорируются на приёме. Это не классический single-leader, но это и не multi-leader: каждое отдельное поле имеет ровно один источник правды.

Поток в одну сторону за раз. Никаких «если updated_at новее». Просто: SAP → Smartup для бухгалтерских полей, Smartup → SAP для операционных. Направление зафиксировано в схеме, а не определяется в рантайме.

Idempotency keys на каждое сообщение. Каждое изменение получает UUID. Принимающая сторона хранит таблицу применённых ключей за последние 7 дней. Если сообщение пришло дважды — второе игнорируется. Простое, но впервые я мог безопасно ретраить без страха задвоить запись.

Conflict logging вместо conflict resolution. Если по какой-то причине пришло обновление поля от не-owner системы — лог плюс алерт в Telegram. Не «разрулим автоматически». Не «перезапишем». Лог плюс человек. За полгода в этот лог попало 17 записей, и каждая оказалась реальным багом в одной из систем — например, скрипт миграции дёргал не то API, или менеджер кликнул не туда. Без лога это бы тихо сожрало данные.

Метрика расхождения. Раз в час join по ключевым полям. Если суммы по накладной в SAP и Smartup отличаются больше чем на 0.01 — алерт. Это та самая видимость конфликтов, которую я не построил с первого раза. Если её нет — у тебя в системе уже есть тихие конфликты, ты их просто не видишь.

`Выводы, которые я бы сказал себе год назад

Если ты пишешь «пусть данные синхронизируются» — ты пишешь репликацию. Назови её правильно. Multi-leader replication — это не «распределённый ETL», это известный класс систем с известным списком проблем, описанных три десятилетия. Не называя проблему по имени, ты лишаешь себя готовых решений.

Симметрия — антипаттерн. Когда обе стороны равноправны и обе могут писать произвольные поля — у тебя multi-leader. Multi-leader дороже single-leader на порядки в плане сложности. Платить эту цену стоит только если симметрия даёт реальное преимущество. В 90% enterprise-интеграций — не даёт.

DDIA читается дважды. Первый раз — чтобы знать слова. Второй раз — после своего первого инцидента, чтобы понять, что эти слова значат.

Если у вас в продакшене есть интеграция между двумя системами с двусторонней записью — откройте две метрики прямо сейчас. Первая: «расхождение часов между серверами». Вторая: «количество объектов, у которых обе стороны изменили один и тот же ключ в окне репликации». Если этих метрик нет — у вас есть скрытый multi-leader, и пятая глава DDIA уже ждёт. Я бы предпочёл встретиться с ней до инцидента, а не после.

Источники и дополнительное чтение

  • Martin Kleppmann. Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems. — O'Reilly Media, 2017. Главы 5 (Replication) и 8 (The Trouble with Distributed Systems) — основная теоретическая канва этой статьи. На русском вышла в издательстве «Питер» в 2018 под названием «Высоконагруженные приложения. Программирование, масштабирование, поддержка» — ISBN 978-5-4461-0512-0.

  • dataintensive.net — официальный сайт книги с актуальным списком источников по главам и обновлениями автора.

  • martin.kleppmann.com — блог Клеппманна, где он дописывает то, что не вошло в книгу: критика CAP, разборы свежих incidents, заметки про CRDT и local-first software.

  • Kyle Kingsbury (aphyr), Jepsen — анализы того, как реальные распределённые СУБД (PostgreSQL, MongoDB, Kafka, etcd, Cassandra) ломают свои же гарантии под сетевыми разделениями. Лучшее лекарство от веры в маркетинговые странички про «strong consistency».

  • Marc Shapiro, Nuno Preguiça, Carlos Baquero, Marek Zawirski. Conflict-free Replicated Data Types. — INRIA, 2011. Если после статьи захочется разрешать конфликты не логом, а структурой данных.

  • Eric Brewer. CAP Twelve Years Later: How the «Rules» Have Changed. — IEEE Computer, 2012. Сам автор CAP-теоремы объясняет, почему её обычно понимают неправильно — ровно то, что я описал в разделе про симметрию.