Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Чому в розподіленій системі не можна покладатися на годинник для порядку подій і що робити замість цього?

Інтуїтивно здається: у кожної події є мітка часу, тож порядок подій очевидний. У розподіленій системі це не так.

Чому годинник ненадійний:

  • годинники різних серверів розходяться - на мілісекунди чи більше навіть з NTP;
  • годинник може стрибати назад при синхронізації NTP чи переході віртуальної машини;
  • мітка часу ставиться в різних місцях: на клієнті, на сервері при отриманні, в базі при записі;
  • мережа змінює порядок: повідомлення, відправлене раніше, може прийти пізніше.

Типова помилка:

Сервіс A о 10:00:00.120: ProfileUpdated(name="Оля")
Сервіс B о 10:00:00.100: ProfileUpdated(name="Олена")   ← годинник B відстає на 50 мс

Правило «перемагає пізніша мітка часу» (last write wins) тихо втрачає справжню останню зміну.

Що використовують замість фізичного часу:

1. Версії сутності - лічильник, що збільшується з кожною зміною в джерелі істини:

CustomerRenamed { customer_id: 7, version: 15, name: "Оля" }

Споживач застосовує подію, лише якщо version більша за збережену, - запізнілі й дубльовані події ігноруються.

2. Логічні годинники Лампорта - лічильник, який кожен вузол збільшує при події й синхронізує з отриманими повідомленнями (max(local, received) + 1). Дають порядок, узгоджений з причинністю: якщо подія A спричинила B, лічильник A менший.

3. Векторні годинники - виявляють конкурентні зміни (жодна не спричинила іншу) - тоді конфлікт треба розв'язати явно, а не мовчки перезаписати.

4. Гібридні логічні годинники (HLC) - поєднують фізичний час із логічним лічильником; використовуються в розподілених базах (CockroachDB).

5. Порядок у брокері повідомлень: Kafka гарантує порядок у межах партиції - події однієї сутності публікують з тим самим ключем (order_id), і вони обробляються послідовно.

6. Одне джерело істини для порядку - послідовність у базі власника даних (автоінкремент, sequence) чи запис усіх змін однієї сутності через один сервіс.

Практичні правила:

  • мітки часу - для показу людям і приблизного аналізу, а не для вирішення конфліктів;
  • для конкурентних змін однієї сутності - оптимістичне блокування з версією (WHERE version = ?);
  • події, що мають застосовуватися в порядку, - з ключем партиціювання за сутністю й номером версії.

Докладніше в документації: Patterns of Distributed Systems: Lamport Clock

Схожі питання