Ответ
В распределенных системах, которые я проектировал и поддерживал, выбор модели консистентности — это всегда компромисс между доступностью, скоростью отклика и корректностью данных.
1. Строгая консистентность (Strong Consistency)
- Гарантия: Все узлы видят одни и те же данные в один момент времени. Любое чтение возвращает результат самой последней завершенной записи.
- Примеры и применение: Классические реляционные БД (PostgreSQL, MySQL) в конфигурации с синхронной репликацией. Используем, когда критически важна абсолютная корректность, например, в финансовых транзакциях. Цена — более высокая задержка записи и риск недоступности при потере кворума реплик.
2. Согласованность в конечном счете (Eventual Consistency)
- Гарантия: Если не поступает новых обновлений, то со временем все узлы придут к согласованному состоянию. Это не означает, что чтение в произвольный момент вернет устаревшие данные, но такая вероятность есть.
- Примеры и применение: Системы, где доступность и скорость записи важнее мгновенной согласованности: DNS, CDN, многие NoSQL БД (Apache Cassandra, DynamoDB). В Cassandra мы настраивали уровень консистентности для каждой операции:
-- На уровне сессии можно задать CONSISTENCY QUORUM; -- Для записи и чтения требуется ответ от большинства реплик -- Или в приложении (драйвер Cassandra) session.execute("INSERT INTO data (key, value) VALUES (?, ?)").setConsistencyLevel(ConsistencyLevel.LOCAL_ONE);
3. Модели на основе causal consistency (причинно-следственная согласованность)
- Read-your-writes: После того как клиент выполнил запись, его последующие чтения всегда увидят это обновление. Это базовая гарантия для хорошего UX, которую мы обеспечивали через "sticky sessions" или хэширование клиента на конкретную реплику.
- Monotonic Reads: Клиент не увидит более старые данные после того, как уже видел более новые. Это предотвращает "откат во времени" при переключении между разными репликами.
Практический выбор в DevOps: При настройке кластера, например, PostgreSQL с репликацией, мы выбирали между:
- Синхронной репликацией (
synchronous_commit = on) для строгой консистентности (риск: запись блокируется, если реплика недоступна). - Асинхронной репликацией для большей доступности и производительности записи (риск: потеря данных при аварии мастера).
Для распределенного кэша (Redis Cluster) мы использовали модель eventual consistency, так как потеря нескольких устаревших значений кэша предпочтительнее, чем недоступность всего сервиса.