CAP та інженерні компроміси
CAP стверджує: в умовах поділу мережі (Partition, P) розподілена система не може одночасно гарантувати і сильну узгодженість (Consistency, C), і доступність (Availability, A). При наявності P доводиться вибирати або CP, або AP. За відсутності поділів обмеження не діє, але з'являються інші компроміси - перш за все затримка (latency) і вартість.
Практична інженерія виходить за межі CAP: важливі PACELC (якщо P - вибираємо C або A; інакше - вибираємо між Latency і Consistency), моделі узгодженості, SLA/SLO, юзкейси і ризики бізнесу.
1) Базові визначення (без філософії)
Узгодженість (C): всі клієнти бачать один і той же результат «як ніби» операції виконувалися послідовно (лінійризованість/strong consistency).
Доступність (A): кожен запит до вузла, що не впав, завершується відповіддю в розумний час, навіть при поділі.
Розділення (P): втрата або значна деградація зв'язку між вузлами/регіональними кластерами; по суті - «неминуче» у великому масштабі.
PACELC: при P вибираємо C або A; else (коли P немає) вибираємо L (низьку затримку) або C (сильну узгодженість).
2) Інтуїтивна картинка вибору
CP (узгодженість важливіше): при поділі частину запитів відхиляємо/блокуємо, щоб не порушити інваріанти. Підходить для грошей, транзакцій, обліку залишків.
AP (доступність важливіше): відповідаємо завжди, але допускаємо тимчасову неузгодженість, потім схлопуємо конфлікти (CRDT/правила мерджа). Підходить для соц-фідів, лічильників лайків, кешованих профілів.
CA (одночасно C і A): можливо тільки за відсутності P - тобто поки мережа здорова. У реальній експлуатації «CA» - тимчасовий стан, а не властивість дизайну.
3) PACELC: не забуваємо про затримку
Коли P немає, вибір часто між низькою латентністю (L) і сильною узгодженістю (C):- Сильна консистентність між регіонами = міжконтинентальні кворуми ⇒ десятки-сотні мс до p95.
- Локальні читання (низька L) = слабші гарантії (read-my-writes, bounded staleness, eventual).
- PACELC допомагає пояснити, чому «швидко і строго» глобально - рідкість: світло - не миттєвий, а кворуми ростуть зі складністю мережі.
4) Моделі узгодженості (швидкий спектр)
Linearizable / Strong: ніби один послідовний порядок.
Serializable: еквівалентно деякому послідовному порядку транзакцій (вище рівня записів).
Read-your-writes / Monotonic reads: клієнт після власного запису читає нове значення.
Bounded staleness: читання відстають не більше N версій/ Δ t.
Eventual consistency: з часом всі копії сходяться; конфлікти потрібно вирішувати.
5) Патерни CP і AP в продуктах і протоколах (концептуально)
CP-підходи: кворумні журнали/лідерство (Raft/Paxos), суворі транзакції, глобальні локації лідера, синхронна реплікація. Ціна - відмова частини запитів при P і зростання затримок.
AP-підходи: мульти-майстер/мульти-лідер, CRDT, gossip-поширення, асинхронна реплікація, вирішення конфліктів (LWW, векторний годинник, доменні мердж-функції). Ціна - тимчасова неузгодженість і складність доменних правил.
6) Компроміси в мульти-регіоні
Глобальний лідер (CP): проста логіка, але «далекі» регіони платять латентністю; при P - блокування записів.
Локальні лідери + асинхрон (AP): запис швидкий локально, потім реплікація; конфліктуючі зміни вимагають мерджа.
Geo-partitioning: дані «живуть» ближче до користувача/юрисдикції; крос-регіон - тільки агрегати.
Dual-write заборонений без саг/CRDT: інакше виходять фантоми і подвійні списання.
7) Інженерні інваріанти та бізнес-рішення
Спочатку інваріанти: що ніколи не можна порушувати (подвійна витрата, негативний залишок, унікальність ключа), а що «переживає» eventual (лічильник переглядів, рекомендації).
Потім вибір:- Інваріант «жорсткий» → CP для відповідних операцій.
- Інваріант «м'який» → AP з подальшим схлопуванням.
8) Техніки пом'якшення компромісів
Кеш і CQRS: читання через близький кеш/проекції (AP), записи - в строгий журнал (CP).
RPO/RTO як мова компромісу: скільки даних можна втратити (RPO) і як швидко відновитися (RTO).
Узгоджені ID і годинник: монотонні таймстампи (Hybrid/TrueTime-підходи), ULID/Snowflake.
Саги/ТСС: бізнес-компенсації замість глобальних блокувань.
CRDT і доменний мердж: для колекцій, лічильників, «останніх перемог».
Bounded staleness: баланс UX і точності.
9) Спостережуваність, SLO і управління інцидентами
SLO по латентності (p50/p95/p99) окремо для читань/записів і регіонів.
SLO за доступністю з урахуванням фейловера регіону.
Lag реплікацій/конфліктність: частка конфліктів, середній час вирішення.
Алерти за ознакою P: сплеск таймаутів міжрегіональних каналів, зростання помилок кворуму.
Degrade-плани: read-only режим, локальне обслуговування з подальшим мерджем, відключення «дорогих» функцій.
10) Чек-лист вибору стратегії
1. Які інваріанти не можна порушувати? Що допускає eventual?
2. Чи потрібен крос-регіональний запис з низькою латентністю?
3. Які цільові SLO (латентність/доступність) і вартість (egress/реплікації)?
4. Чи допускаєте manual merge або тільки автомат (CRDT/правила)?
5. Який профіль відмови мережі: частота, тривалість, blast radius?
6. Чи є юридична локалізація даних (residency)?
7. Яка модель узгодженості прийнятна для кожного типу даних/операції?
8. Як будете спостерігати: лаги, конфлікти, стан кворумів?
9. Що робить система при P: блокує, деградує, розділяє трафік?
10. Який план відновлення і репатріації даних після P?
11) Типові помилки
Гонитва за «CA назавжди». При першому ж P доведеться вибирати - краще заздалегідь.
Глобальний мульти-майстер без правил мерджа. Конфлікти «з'їдають» дані і довіру.
Сильна консистентність «всюди». Надлишкові кворуми б'ють по p95/p99 і бюджету.
Dual-write без транзакцій/саг. Втрачені інваріанти і фантоми.
Ігнорування PACELC. У мирний час страждає латентність, в шторм - доступність.
Нульова телеметрія конфліктів і лагів. Проблеми видно тільки користувачеві.
12) Швидкі рецепти
Платіж/баланс: CP-сховище з кворумами; записи тільки через лідера; читання можуть бути кешовані, але в критичних UX - read-your-writes.
Контент/фід: AP-реплікація + CRDT/правила мерджа; при P - обслуговувати локально, потім схлопувати.
Глобальний SaaS: geo-partitioning по `tenant/region`; строгі операції в «домашньому» регіоні (CP), звіти/пошук - через асинхронні проекції (AP).
Реал-тайм сигналінг: Anycast/edge + AP-шина; критичні команди проходять через підтверджений канал (CP).
Аудит/журнал: єдине джерело істини (append-only) з CP-гарантіями, навколо - кеші і проекції.
13) Міні-еталон архітектури (словесно)
Write-core (CP): лідер + кворумна реплікація, строгі інваріанти, саги для міжсервісних ефектів.
Read-plane (AP): матеріалізовані уявлення, кеші, search-індекси, асинхронне оновлення.
Geo-routing: користувачі потрапляють в «домашній» регіон; при P - локальний режим + подальша реплікація.
Конфлікт-рушій: CRDT/правила; журнал конфліктів і засоби ручного врегулювання.
Спостережуваність: трейсинг кворумів, лаги, карта інцидентів мережі.
14) Практична математика затримок (проста оцінка)
Оптика ≈ 5 мс на 1000 км (RTT ще більше). Міжконтинентальні кворуми → p95 легко> 150-250 мс.
Будь-який «глобальний Strong» для запису - це дорогий запит. Якщо UX вимагає <100-150 мс, подумайте про локальний write-home + асинхронні наслідки.
15) Політики на випадок поділів
CP-шлях: блокувати записи поза кворумом; включати read-only; віддавати чесні статуси користувачеві.
AP-шлях: обслуговувати локально; маркувати версії; при відновленні - детермінований мердж; конфлікти піднімати в чергу розбору.
Висновок
CAP - не догма, а нагадування: поділу мережі неминучі, і проект повинен заздалегідь вибрати, ніж жертвувати в шторм - доступністю або суворою узгодженістю. PACELC додає ключову вісь затримки в ясну погоду. Комбінуйте стратегії: тримайте CP-ядро там, де інваріанти священні, і AP-площина там, де важливіше швидкість і стійкість. Закладайте телеметрію, плани деградації і процеси мерджа - і система збереже і дані, і довіру користувача.