← Назад к вопросам
В каком случае теряется согласованность БД в режиме кластера
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 продолжает работать консистентно
Итоговый ответ
Потеря консистентности в кластере происходит:
- Network Partition — узлы разделяются, получается split brain
- Replication Lag — реплики отстают, читаешь stale data
- Primary Failure — первичный падает с неподтвёрнутыми writами
- Concurrent Writes — конфликты при одновременных изменениях
- Wrong Consistency Level — выбрал AP вместо CP
Для защиты используй:
- Quorum-based reads/writes
- Strong consistency mode
- Synchronous replication
- Consensus algorithms (Raft)
- Transactions с правильным isolation level