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

Для чего нужна репликация в БД?

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

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

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

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

Репликация в базах данных

Репликация — это один из самых важных механизмов в современных высоконагруженных системах. За 10+ лет я видел множество проектов, которые благодаря репликации смогли масштабироваться, и наоборот, проекты, которые её игнорировали и потом страдали от недоступности.

Определение

Репликация БД — это процесс копирования и синхронизации данных с одного сервера БД (master/primary) на один или несколько других серверов (slave/replica/secondary). Это обеспечивает отказоустойчивость, масштабируемость и высокую доступность.

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

1. Высокая доступность (High Availability)

Проблема без репликации:
Мастер БД       Приложения
    |-----X-----|  БД упала, всё падает

С репликацией:
Мастер БД        Приложения
    |-----------|  Даже если упадёт...
    |
Реплика БД
    |-----------|  ...есть резервная копия

Если master упадёт, можно переключиться на replica (failover).

2. Масштабируемость по чтению (Read Scaling)

// БЕЗ репликации - bottleneck
DataSource masterOnly = createMasterConnection();

// С репликацией - распределяем нагрузку
DataSource masterDataSource = createMasterConnection();
DataSource slaveDataSource = createSlaveConnection();

// Запись всегда идёт на master
public void updateUser(User user) {
    masterDataSource.execute("UPDATE users SET ...");
}

// Чтение идёт на slave если возможно
public User getUser(Long id) {
    // 99% запросов это чтение!
    // Распределяем на replica
    return slaveDataSource.query("SELECT * FROM users WHERE id = ?", id);
}

В типичной системе 80-99% запросов это чтение. Репликация позволяет распределить эту нагрузку.

3. Отказоустойчивость (Fault Tolerance)

Сценарий 1: Потеря master
Master         Replica 1     Replica 2
  |              |              |
UPDATE ...       |              |  Master упал!
  | ---------->  |              |
  X              ↓              ↓
              (новый master)  (replica)

Сценарий 2: Потеря replica
Master         Replica 1     Replica 2
  |              |              |
UPDATE ...       |              |  Replica упала!
  | ---------->  |              X
  ↓              ↓
          Чтение всё равно работает

4. Аналитика и отчёты

// Тяжёлые отчёты не влияют на боевую базу
DataSource analyticsDb = createAnalyticsReplicaConnection();

// Основное приложение
public User getUser(Long id) {
    return masterDb.query("SELECT * FROM users WHERE id = ?", id);
}

// Аналитика идёт на отдельную replica
public List<UserStats> generateMonthlyReport() {
    return analyticsDb.query(
        "SELECT user_id, COUNT(*) FROM events GROUP BY user_id"
    );  // Не нагружает боевую БД
}

Типы репликации

1. Синхронная репликация (Synchronous)

Клиент          Master          Slave
  |               |              |
  | UPDATE        |              |
  |---> |         |              |
  |     | UPDATE  |              |
  |     |-------->|              |
  |     |         | UPDATE       |
  |     |         |-------->     |
  |     |         |              | ACK
  |     |         |<--------------|
  |     | ACK     |              |
  |     |<--------|              |
  | OK  |         |              |
  |<----|         |              |

Все слейвы подтверждают ДО commit'а на master
Безопасно, но медленно

Java пример:

@Transactional(
    isolation = Isolation.READ_COMMITTED
)
public void criticalUpdate(User user) {
    // С синхронной репликацией гарантирует:
    // Данные были запрошены НА ВСЕ NODES перед commit
    userRepository.save(user);
}

2. Асинхронная репликация (Asynchronous)

Клиент          Master          Slave
  |               |              |
  | UPDATE        |              |
  |---> |         |              |
  |     | UPDATE  |              |
  |     |-------->|              |
  |     | OK      |              |
  | OK  |<--------|              |
  |<----|         | UPDATE (позже)  |
  |     |         |-------->     |
  |     |         |              |

Master не ждёт подтверждения от slave
Быстро, но может быть потеря данных при падении master
@Transactional
public void normalUpdate(BlogPost post) {
    // С асинхронной репликацией
    // Commit происходит сразу, slave обновляется позже
    postRepository.save(post);
}

3. Полусинхронная репликация (Semi-Synchronous)

Мастер ждёт подтверждения хотя бы ОД НОМ слейва (не всех)
Баланс между безопасностью и производительностью

Топологии репликации

1. Master-Slave (самая простая)

Master
  |
  +-- Slave 1
  |
  +-- Slave 2
  |
  +-- Slave 3

Все читают с Slave, все пишут в Master

2. Master-Master (Multi-Master)

Master 1 <---> Master 2
  |              |
  v              v
Slave 1        Slave 2

Оба master'а могут принимать write
Дано сложность с разрешением конфликтов

3. Chain (Каскадная)

Master
  |
  Slave 1
  |
  Slave 2 (реплика Slave 1)
  |
  Slave 3 (реплика Slave 2)

Реплика получает изменения через цепь

Проблемы репликации

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

// ПРОБЛЕМА: Пишем в master, тут же читаем из slave

public void createAndFetchUser(String name) {
    // Пишем в master
    User user = new User(name);
    userRepository.save(user);  // INSERT в master
    
    // Читаем из slave (может быть lag!)
    User fetched = slaveRepository.findByName(name);  // SELECT из slave
    if (fetched == null) {  // NULL!
        // Slave ещё не получила данные
        // Реplication lag
    }
}

Решение:

public void createAndFetchUser(String name) {
    User user = new User(name);
    user = userRepository.save(user);
    
    // Используем только что созданный объект
    // Не обращаемся к БД
    System.out.println(user.getName());
}

2. Split Brain (Раздвоение мозга)

Шкаф 1                 Шкаф 2
Master БД           Replica БД
  |                    |
  X <--- СЕТЬ УПАЛА ---|X
  |
  Приложение 1
  (видит только Master)
       
                    |
                    Приложение 2
                    (видит только Replica)

Два приложения создают две разные версии БД!

Решение: Использовать zookeeper/etcd для consensus

MySQL репликация (практический пример)

-- На MASTER:
CREATE USER 'replication'@'slave_ip' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'replication'@'slave_ip';

SHOW MASTER STATUS;  -- Запоминаем File и Position

-- На SLAVE:
CHANGE MASTER TO
  MASTER_HOST = 'master_ip',
  MASTER_USER = 'replication',
  MASTER_PASSWORD = 'password',
  MASTER_LOG_FILE = 'mysql-bin.000001',
  MASTER_LOG_POS = 154;

START SLAVE;
SHOW SLAVE STATUS;  -- Проверяем статус

Java код с маршрутизацией

@Component
public class DatabaseRouter {
    private final DataSource masterDataSource;
    private final DataSource slaveDataSource;
    
    // Пишем только в master
    public void write(String query, Object... params) {
        try (Connection conn = masterDataSource.getConnection()) {
            // execute
        }
    }
    
    // Читаем с slave если возможно
    public <T> T read(Function<DataSource, T> queryFn) {
        try {
            // Пытаемся читать с slave
            return queryFn.apply(slaveDataSource);
        } catch (Exception e) {
            // Failover на master если slave недоступна
            return queryFn.apply(masterDataSource);
        }
    }
}

Когда использовать репликацию

Используй репликацию, если:

  • High traffic приложение
  • Нужна отказоустойчивость
  • Много read операций
  • Нужна резервная копия

Не нужна репликация, если:

  • Маленькое приложение с низкой нагрузкой
  • Данные некритичны
  • Простая архитектура

Вывод

Репликация БД — это не luxury, это NECESSITY в production системах. Она решает три критических проблемы: доступность, масштабируемость и отказоустойчивость. Но она добавляет сложность, особенно в управлении consistency'ю. Используй её мудро.