MidТеория5 min

CAP теорема

Consistency, Availability, Partition tolerance: теорема, ограничения, примеры CP и AP систем

Формулировка

CAP теорема (теорема Брюера, 2000) утверждает, что распределённая система может обеспечить только два из трёх свойств одновременно:

  • C (Consistency) -- согласованность: каждое чтение возвращает результат последней записи
  • A (Availability) -- доступность: каждый запрос получает ответ (не ошибку)
  • P (Partition Tolerance) -- устойчивость к разделению сети

Почему только 2 из 3

Сетевые разделения (partition) неизбежны. Поэтому P -- обязательное свойство. Выбор сводится к: CP или AP.

Клиент A --> [Узел 1]     [Узел 2] <-- Клиент B
                    РАЗРЫВ СЕТИ

Клиент A записал x=1 на Узел 1.
Клиент B читает x с Узла 2.

CP: Узел 2 отвечает ошибкой (не может гарантировать актуальность)
AP: Узел 2 отвечает старым значением x=0 (доступность важнее)

CP vs AP системы

CP (Consistency + Partition Tolerance)

Система предпочитает ошибку, чем устаревшие данные.

Примеры: ZooKeeper, etcd, MongoDB (write concern majority), HBase

Когда выбирать: финансовые операции, координация (locks), inventory management

AP (Availability + Partition Tolerance)

Система всегда отвечает, даже если данные устаревшие.

Примеры: Cassandra, DynamoDB, CouchDB, DNS

Когда выбирать: соцсети, метрики, корзина покупок, CDN

Таблица выбора

Система Тип Примечание
PostgreSQL (single) CA Нет partition (одноузловая)
PostgreSQL + replicas CP Зависит от настройки
Redis Sentinel CP Downtime при failover
Cassandra AP Tunable consistency
MongoDB CP Write concern majority
Elasticsearch AP Split-brain возможен
etcd CP Raft consensus

Tunable Consistency

Некоторые системы позволяют выбирать компромисс per-query.

<?php

declare(strict_types=1);

/**
 * Tunable consistency levels.
 * Strong consistency: R + W > N (read + write replicas > total replicas).
 */
final class TunableConsistency
{
    /**
     * @return array<string, array{read: int, write: int, consistency: string, use_case: string}>
     */
    public static function levels(int $replicas = 3): array
    {
        $quorum = (int) ceil(($replicas + 1) / 2);

        return [
            'ONE_ONE' => [
                'read' => 1,
                'write' => 1,
                'consistency' => 'eventual (R+W < N)',
                'use_case' => 'Metrics, logs, non-critical data',
            ],
            'QUORUM_QUORUM' => [
                'read' => $quorum,
                'write' => $quorum,
                'consistency' => 'strong (R+W > N)',
                'use_case' => 'Most applications, good default',
            ],
            'ALL_ONE' => [
                'read' => $replicas,
                'write' => 1,
                'consistency' => 'strong (N+1 > N)',
                'use_case' => 'Write-heavy workloads',
            ],
            'ONE_ALL' => [
                'read' => 1,
                'write' => $replicas,
                'consistency' => 'strong (1+N > N)',
                'use_case' => 'Read-heavy workloads',
            ],
        ];
    }
}
## Ограничения CAP теоремы
  1. Partition -- не выбор: разделения случаются, вопрос -- что делать при них
  2. Не бинарный выбор: можно быть "немного" C и "немного" A
  3. Partition -- редкость: большую часть времени система может быть и C, и A
  4. Consistency в CAP != ACID: CAP-consistency -- линеаризуемость, ACID -- целостность данных
  5. Не учитывает latency: CAP говорит о correctness, не о скорости

Для более полной картины: используйте PACELC теорему, которая учитывает latency vs consistency tradeoff в нормальном режиме работы.

Практическое применение

<?php

declare(strict_types=1);

/**
 * Decision framework for choosing CP vs AP.
 */
final class ConsistencyDecision
{
    /**
     * @return array{model: string, reason: string, systems: string[]}
     */
    public static function recommend(
        bool $financial,
        bool $global,
        int $staleTolerance,
    ): array {
        if ($financial) {
            return [
                'model' => 'CP',
                'reason' => 'Financial operations require strong consistency',
                'systems' => ['PostgreSQL + sync replication', 'CockroachDB'],
            ];
        }

        if ($global && $staleTolerance > 5) {
            return [
                'model' => 'AP with tunable consistency',
                'reason' => 'Global reach + latency needs AP; strong for critical paths',
                'systems' => ['DynamoDB', 'Cassandra LOCAL_QUORUM'],
            ];
        }

        return [
            'model' => 'CP with read replicas',
            'reason' => 'Consistency for writes, tolerate stale reads',
            'systems' => ['PostgreSQL + read replicas', 'MongoDB replica set'],
        ];
    }
}
## Выводы
  • CAP теорема: из C, A, P можно выбрать только два, и P обязателен
  • CP: консистентность важнее доступности (финансы, координация)
  • AP: доступность важнее консистентности (соцсети, метрики)
  • Tunable consistency позволяет выбирать компромисс per-query
  • CAP -- полезная модель, но упрощает реальность
  • Для полной картины используйте PACELC теорему