← Назад к вопросам

В каком случае теряется согласованность БД в режиме кластера

2.7 Senior🔥 101 комментариев
#Docker, Kubernetes и DevOps#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Потеря согласованности БД в режиме кластера

Определение

Согласованность (Consistency) в кластере — это то, что все узлы содержат одинаковые данные и вернут одинаковый результат при запросе.

Потеря согласованности происходит когда:

  • Разные узлы имеют разные версии данных
  • Один узел принял изменение, другой нет
  • Запросы к разным узлам возвращают разные результаты

Основные сценарии потери согласованности

1. Network Partition (Разрыв сети)

Это самый частый случай — когда сеть разделяется и узлы не могут общаться.

До разрыва:
Node A: data = 100
Node B: data = 100
Node C: data = 100

Разрыв сети! Node A отделяется:

Partition 1:          Partition 2:
Node A: data=100      Node B: data=100
                      Node C: data=100

Приложение пишет в Node A:
Node A: data=150 (успешно)

Приложение пишет в Node B:
Node B: data=200 (успешно)

Разрыв заканчивается:
Node A: data=150      ← Конфликт! Какое значение выбрать?
Node B: data=200
Node C: data=200

2. Replication Lag (Задержка репликации)

Первичный узел (Primary) обновляется, но реплики отстают.

// PostgreSQL Replication пример
Primary: UPDATE users SET balance = 500 WHERE id = 1;
// Успешно

Replica: SELECT balance FROM users WHERE id = 1;
// Может вернуть старое значение 100, если репликация отстаёт!

Визуализация:

Time  Primary   Replica1  Replica2
---   -------   --------  --------
1     100       100       100
2     500       100       100       ← PRIMARY обновился, реплики отстают
3     500       100       500       ← Replica2 синхронизировалась
4     500       500       500       ← Все синхронизированы

3. Split Brain (разделённый мозг)

Оба узла думают, что они первичные.

Before split brain:
Primary: Node A (elected by consensus)

Network partition:
┌─────────────┬─────────────┐
│ Partition1  │ Partition2  │
│ Node A      │ Node B, C   │
└─────────────┴─────────────┘

Both partitions elect new primary:
Node A: "Я первичный" → writes data = 100
Node B: "Я первичный" → writes data = 200
Node C: follows Node B

Network heals:
Node A: data=100
Node B: data=200
Node C: data=200
↓
Конфликт! Какое значение истинное?

4. Committed Write Loss (потеря подтвёрнутых записей)

Первичный узел падает после того, как вернул OK клиенту, но до реплики.

// MySQL Replication (без SYNC_BINLOG=1)
public void transfer(int from, int to, int amount) {
    primary.beginTransaction();
    primary.execute("UPDATE accounts SET balance=balance-" + amount + " WHERE id=" + from);
    primary.execute("UPDATE accounts SET balance=balance+" + amount + " WHERE id=" + to);
    primary.commit();
    
    client.respondOK(); // ← Клиенту сказали OK
    
    // ЗДЕСЬ первичный падает!
    // Реплика не получила эти изменения!
    
    replica.failover();
    // Данные потеряны, но клиент думает что OK
}

5. Concurrent Writes (конкурирующие записи)

Два клиента одновременно пишут в разные узлы.

Client 1 пишет в Shard A:
UPDATE inventory SET quantity = 5 WHERE product_id = 1;

Client 2 пишет в Shard B (другой шард того же продукта):
UPDATE inventory SET quantity = 3 WHERE product_id = 1;

// Результат: Shard A видит quantity=5, Shard B видит quantity=3
// Несогласованность! Продукт имеет два разных количества

Как теряется консистентность по CAP теореме

Теорема CAP говорит: выбери 2 из 3:

  • C (Consistency) — все узлы всегда синхронизированы
  • A (Availability) — система всегда доступна
  • P (Partition tolerance) — работает при разрыве сети
При network partition ты должен выбрать:

1. Sacrifice Availability (CP):
   ├─ При разрыве откажешь клиентам
   ├─ Но данные всегда консистентны
   └─ Пример: PostgreSQL без replication

2. Sacrifice Consistency (AP):
   ├─ При разрыве продолжишь работать
   ├─ Но данные могут быть несогласованными
   └─ Пример: DynamoDB, Cassandra, MongoDB (в режиме eventual consistency)

Практические примеры в Java/Spring

PostgreSQL (синхронная репликация)

// Консистентна: требует ack от реплик перед commit
primary.execute("SET synchronous_commit = on;");
// Медленнее, но data безопасна

// Может потерять данные: не ждёт реплик
primary.execute("SET synchronous_commit = off;");
// Быстрее, но риск потери при падении primary

Cassandra (eventual consistency)

// LOW consistency — быстро, но несогласованно
BoundStatement bs = session.prepare(
    "INSERT INTO users (id, name) VALUES (?, ?)"
).bind(1, "Alice").setConsistencyLevel(ConsistencyLevel.ONE);

// HIGH consistency — медленно, но синхронно
bs.setConsistencyLevel(ConsistencyLevel.ALL); // Ждёт всех нод

Redis Cluster

// Redis Cluster может потерять данные при failover:
redis.set("key", "value");
// PRIMARY добавил, но реплики не получили
// PRIMARY падает → реплика становится primary
// Данные потеряны!

// Решение: использовать WAIT
redis.set("key", "value");
Long numReplicasAcked = redis.waitReplicas(numReplicas, timeout);
if (numReplicasAcked < numReplicas) {
    // Не все реплики синхронизировались
    throw new InconsistencyException();
}

Как защитить от потери консистентности

1. Используй Quorum Reads/Writes

// Write to majority:
int quorum = (nodes / 2) + 1;  // 3 ноды → пиши на 2
write(key, value, quorum); // Ждём 2 OK

// Read from majority:
read(key, quorum); // Читай с 2 нод (видишь latest)

2. Используй Strong Consistency Mode

// MongoDB: readConcern = "majority"
MongoDB читает только committed данные:
ReadPreference rp = ReadPreference.primary();
ReadConcern rc = ReadConcern.MAJORITY;
client.getDatabase("mydb")
    .withReadConcern(rc)
    .getCollection("users")
    .find();

3. Используй Transactions

// PostgreSQL SERIALIZABLE
try (Connection conn = datasource.getConnection()) {
    conn.setTransactionIsolation(
        Connection.TRANSACTION_SERIALIZABLE
    );
    // Работаешь в SERIALIZABLE режиме
}

4. Используй consensus алгоритмы (Raft, Paxos)

Etcd, Consul, ZooKeeper используют Raft:
- Node может стать leader только если имеет majority
- Write успешен только если leader получит majority ack
- При partition: меньшая partition останавливается
- Большая partition продолжает работать консистентно

Итоговый ответ

Потеря консистентности в кластере происходит:

  1. Network Partition — узлы разделяются, получается split brain
  2. Replication Lag — реплики отстают, читаешь stale data
  3. Primary Failure — первичный падает с неподтвёрнутыми writами
  4. Concurrent Writes — конфликты при одновременных изменениях
  5. Wrong Consistency Level — выбрал AP вместо CP

Для защиты используй:

  • Quorum-based reads/writes
  • Strong consistency mode
  • Synchronous replication
  • Consensus algorithms (Raft)
  • Transactions с правильным isolation level
В каком случае теряется согласованность БД в режиме кластера | PrepBro