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

Что такое Strong Consistency?

1.8 Middle🔥 201 комментариев
#Базы данных и SQL

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

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

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

Strong Consistency (Строгая консистентность)

Strong Consistency — это гарантия того, что после успешного завершения операции записи, все последующие операции чтения будут видеть это изменение. Это самый строгий уровень консистентности в распределённых системах.

Определение Strong Consistency

// ACID транзакция в локальной БД = Strong Consistency

// Сценарий:
// Процесс A пишет: x = 5
// Процесс B читает: x (должен получить 5)

@Transactional
public class StrongConsistencyExample {
    
    public void demonstrateStrongConsistency() {
        // В одной транзакции (ACID гарантирует)
        Account account = findAccount(1);
        account.setBalance(5000);  // Запись
        saveAccount(account);
        
        // Любое последующее чтение видит: balance = 5000
        Account readAccount = findAccount(1);
        assert readAccount.getBalance() == 5000;  // ГАРАНТИРОВАНО true
    }
}

Strong Consistency vs Eventual Consistency

// STRONG CONSISTENCY (Строгая)
// ✅ После COMMIT чтение видит новое значение
// ✅ Всегда актуальные данные
// ❌ Медленнее (нужна синхронизация)
// ❌ Менее доступна при разделении сети

Transaction txn = database.beginTransaction();
txn.write("account_1", 5000);
txn.commit();  // COMMIT завершен

// Следующее чтение ГАРАНТИРОВАНО видит 5000
Integer balance = database.read("account_1");  // = 5000

// EVENTUAL CONSISTENCY (Итоговая)
// ✅ Быстрее (асинхронное распространение)
// ✅ Высокая доступность
// ❌ Временные несогласованности
// ❌ Сложнее для разработчика

cache.put("account_1", 5000);  // Запись в кэш
// Через 100ms реплицируется в другие узлы

// Чтение может вернуть старое значение некоторое время
Integer balance = cache.get("account_1");  // Может быть не 5000

SQL: Strong Consistency в ACID базах

// PostgreSQL, MySQL с InnoDB — Strong Consistency по умолчанию

public class AcidStrongConsistency {
    
    public void transferMoney(Connection conn, Long fromId, Long toId, BigDecimal amount) 
        throws SQLException {
        
        try {
            conn.setAutoCommit(false);
            conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
            
            // Уровень SERIALIZABLE — максимальная consistency
            
            // Операция 1: снять деньги
            String debit = "UPDATE accounts SET balance = balance - ? WHERE id = ? " +
                          "AND balance >= ?";
            PreparedStatement debitStmt = conn.prepareStatement(debit);
            debitStmt.setBigDecimal(1, amount);
            debitStmt.setLong(2, fromId);
            debitStmt.setBigDecimal(3, amount);
            int debitRows = debitStmt.executeUpdate();
            
            if (debitRows == 0) {
                throw new SQLException("Недостаточно средств");
            }
            
            // Операция 2: положить деньги
            String credit = "UPDATE accounts SET balance = balance + ? WHERE id = ?";
            PreparedStatement creditStmt = conn.prepareStatement(credit);
            creditStmt.setBigDecimal(1, amount);
            creditStmt.setLong(2, toId);
            creditStmt.executeUpdate();
            
            // COMMIT — гарантирует видимость для всех читателей
            conn.commit();
            
        } catch (SQLException e) {
            conn.rollback();  // Всё откатывается
            throw e;
        }
    }
    
    // После COMMIT любой читатель видит новые балансы
    public BigDecimal getBalance(Connection conn, Long accountId) throws SQLException {
        String query = "SELECT balance FROM accounts WHERE id = ?";
        PreparedStatement stmt = conn.prepareStatement(query);
        stmt.setLong(1, accountId);
        ResultSet rs = stmt.executeQuery();
        
        if (rs.next()) {
            return rs.getBigDecimal("balance");  // ГАРАНТИРОВАНО актуальное
        }
        return null;
    }
}

Уровни изоляции и Strong Consistency

// SERIALIZABLE — максимальная consistency
// Как если бы транзакции выполнялись последовательно
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
// Медленно, но абсолютная consistency

// REPEATABLE_READ — сильная consistency
conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
// Защита от phantom reads

// READ_COMMITTED — средняя consistency
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
// Базовая гарантия

// READ_UNCOMMITTED — слабая consistency
conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
// Опасно: грязное чтение возможно

Strong Consistency в распределённых системах

// Проблема: несколько узлов БД
// Клиент А пишет на узел 1
// Клиент Б читает с узла 2
// Где гарантия Strong Consistency?

public class DistributedConsistency {
    
    // Решение 1: Single Leader (Master) Replication
    // Все записи идут на ОДИН мастер
    // Реплики только для чтения
    public void writeWithSingleLeader(String data) {
        masterNode.write(data);  // Только сюда
        // Затем асинхронно распространяется на replicas
        // Эта задержка может нарушить strong consistency
    }
    
    public String readWithSingleLeader() {
        // Читаем с мастера = Strong Consistency
        return masterNode.read();
    }
    
    // Решение 2: Quorum-based consistency (Raft, Paxos)
    // Запись требует большинства узлов
    // Чтение требует большинства узлов
    public void writeWithQuorum(String data, List<Node> nodes) {
        int quorum = (nodes.size() / 2) + 1;
        int successCount = 0;
        
        for (Node node : nodes) {
            try {
                node.write(data);
                successCount++;
            } catch (Exception e) {
                // Игнорируем неудачи некоторых узлов
            }
        }
        
        if (successCount >= quorum) {
            // Strong Consistency гарантирована
            return;
        } else {
            throw new IOException("Недостаточно узлов для quorum");
        }
    }
    
    // Решение 3: Consensus (Raft, Paxos)
    // Все узлы синхронизируются перед COMMIT
    public void writeWithConsensus(String data) {
        // 1. Лидер получает запрос
        // 2. Лидер репликирует на большинство
        // 3. После подтверждения большинства -> COMMIT
        // 4. Клиент получает ответ
        
        // Strong Consistency гарантирована
    }
}

CAP теорема и Strong Consistency

// Согласно CAP теореме (Consistency, Availability, Partition tolerance)
// Можно выбрать максимум 2 из 3

// Strong Consistency (C) + Availability (A) = требует отсутствия Partition (P)
// В надежной локальной сети: SQL базы (PostgreSQL, MySQL)

// Strong Consistency (C) + Partition tolerance (P) = жертвуем Availability
// При сбое узла система неактивна
// Пример: Raft, Google Spanner

// Availability (A) + Partition tolerance (P) = жертвуем Consistency
// Eventual Consistency
// Пример: Cassandra, DynamoDB

public class CAPExample {
    
    // PostgreSQL — выбирает CP (Consistency + Partition tolerance)
    public void consistencyOverAvailability() {
        // Если узел недоступен:
        // - Читать может быть не возможно
        // - Писать может быть не возможно
        // НО гарантирована consistency
    }
    
    // Cassandra — выбирает AP (Availability + Partition tolerance)
    public void availabilityOverConsistency() {
        // Если узел недоступен:
        // - Читать можно с других узлов
        // - Писать можно на любой узел
        // НО данные временно несогласованы
    }
}

Практический пример: Spring @Transactional

@Service
public class BankService {
    
    @Transactional  // Strong Consistency гарантирована
    public void transfer(Long fromId, Long toId, BigDecimal amount) {
        Account from = accountRepository.findById(fromId).orElseThrow();
        Account to = accountRepository.findById(toId).orElseThrow();
        
        from.debit(amount);
        to.credit(amount);
        
        accountRepository.save(from);
        accountRepository.save(to);
        // Spring коммитит транзакцию
    }
    
    @Transactional(readOnly = true)
    public BigDecimal getBalance(Long accountId) {
        // Чтение гарантированно актуальное
        // (если БД использует Strong Consistency)
        Account account = accountRepository.findById(accountId).orElseThrow();
        return account.getBalance();
    }
}

Стоимость Strong Consistency

// ❌ Недостатки
// 1. Медленнее: нужна синхронизация между узлами
// 2. Менее доступна: при разделении сети система замирает
// 3. Сложнее масштабировать

// ✅ Преимущества
// 1. Нет конфликтов данных
// 2. Логика приложения проще
// 3. Подходит для критичных операций (деньги, инвентарь)

// Правило:
// - Для финансовых операций: Strong Consistency
// - Для кэшей, рекомендаций: Eventual Consistency
// - Для социальных сетей: Eventual Consistency

Вывод

  1. Strong Consistency — гарантирует, что чтение видит последнее значение записи
  2. ACID базы (PostgreSQL, MySQL) обеспечивают Strong Consistency
  3. Распределённые системы требуют consensus алгоритмов (Raft, Paxos)
  4. CAP теорема показывает трейд-офф между Consistency, Availability, Partition tolerance
  5. @Transactional в Spring гарантирует Strong Consistency на уровне приложения
  6. Цена — производительность и доступность, но абсолютная надежность данных
Что такое Strong Consistency? | PrepBro