На одном из последних митапов мы подробно разбирали кейс клиента: нестабильную работу репликации MariaDB в одном из проектов. Ситуация была неприятная именно тем, что на мастере всё выглядело идеально — нагрузка переваривалась, ошибок почти не было, метрики стабильные. А вот реплика вела себя хаотично и непредсказуемо.
Ниже — краткая выжимка того, как мы шли по проблеме, какие гипотезы проверяли и к какому итоговому сетапу в итоге пришли.
С какими симптомами столкнулись
В «рандомные» моменты времени на реплике наблюдались:
• отставание или полная остановка репликации;
• периодические зависания и перезапуски;
• нарушения порядка транзакций, приводящие к deadlock;
• в целом низкая и нестабильная производительность.
При этом мастер в эти же моменты чувствовал себя нормально: без перегрузок и без видимых проблем.
Гипотеза №1. Не хватает ресурсов
Первое, что бросилось в глаза — мастер и реплика были развёрнуты на ВМ с сильно отличающимися характеристиками.
Реплике добавили ресурсы до уровня мастера: 16 vCPU / 48 GB RAM. По рекомендациям выставили: innodb_buffer_pool_size = 38G (около 80% от RAM).
Чтение действительно ускорилось, но ключевые проблемы — зависания, отставания, ошибки репликации — никуда не делись.
Гипотеза №2. Слишком маленькие таймауты
В логах регулярно появлялись ошибки: ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction. Это натолкнуло на мысль, что тяжёлые запросы просто не успевают отрабатывать и откатываются по таймауту.
Пробуем:
innodb_lock_wait_timeout = 120
innodb_rollback_on_timeout = 1
То есть увеличиваем время ожидания блокировок и включаем откат всей транзакции, а не только последнего запроса.
Ситуация становится чуть стабильнее, но полностью проблему это не решает.
Гипотеза №3. Параллельная репликация
Включаем и наращиваем количество потоков: slave_parallel_threads = 4, потом = 8. Без эффекта.
Напомним, как вообще устроена репликация в MariaDB:
1. IO thread читает события с мастера и пишет их в relay log.
2. SQL thread (или несколько потоков) читает события из relay log.
3. События применяются на реплике. Начиная с MariaDB 10 — параллельно в несколько потоков, что увеличивает производительность.
Гипотеза №4. Режим параллельной репликации
Пробуем разные режимы:
• optimistic (по умолчанию)
• conservative
Оба варианта проблему не решают. В итоге полностью отключаем параллельное применение: slave_parallel_threads = 0.
Гипотеза №5. Неоптимальные запросы пользователей
В процессе разбора увидели соединения от пользователей, которые висели по несколько часов с открытыми транзакциями.
Вводим жёсткие, но спасительные ограничения:
idle_transaction_timeout = 600 (рвём соединение, если в транзакции 10 минут ничего не происходит);
max_statement_time = 900 (обрываем запросы, которые выполняются дольше 15 минут).
После этого количество «вечных» блокировок резко сократилось.
Гипотеза №6. Перебор с памятью
Под нагрузкой стало понятно, что innodb_buffer_pool_size в 80% RAM — это перебор именно для этой машины и этого профиля нагрузки. В пиках либо начинала зависать сама база, либо OOM-killer убивал другие процессы хоста (вплоть до sshd).
В итоге пришли к формуле: «80% минус примерно 2 ГБ».
И отдельно — swap отключать не стали. По сути, он не для производительности, а для того, чтобы система не умирала при кратковременных всплесках.
Итоговая конфигурация
В финале сетап выглядел так:
innodb_buffer_pool_size = 36G
innodb_rollback_on_timeout = 1
idle_transaction_timeout = 600
max_statement_time = 900
innodb_lock_wait_timeout = 120
slave_parallel_threads = 0
И главный результат: за последний месяц — ни одного разрыва репликации.
Выводы
Главный вывод из этого кейса — универсального рецепта настройки репликации не существует.
Ниже — краткая выжимка того, как мы шли по проблеме, какие гипотезы проверяли и к какому итоговому сетапу в итоге пришли.
С какими симптомами столкнулись
В «рандомные» моменты времени на реплике наблюдались:
• отставание или полная остановка репликации;
• периодические зависания и перезапуски;
• нарушения порядка транзакций, приводящие к deadlock;
• в целом низкая и нестабильная производительность.
При этом мастер в эти же моменты чувствовал себя нормально: без перегрузок и без видимых проблем.
Гипотеза №1. Не хватает ресурсов
Первое, что бросилось в глаза — мастер и реплика были развёрнуты на ВМ с сильно отличающимися характеристиками.
Реплике добавили ресурсы до уровня мастера: 16 vCPU / 48 GB RAM. По рекомендациям выставили: innodb_buffer_pool_size = 38G (около 80% от RAM).
Чтение действительно ускорилось, но ключевые проблемы — зависания, отставания, ошибки репликации — никуда не делись.
Гипотеза №2. Слишком маленькие таймауты
В логах регулярно появлялись ошибки: ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction. Это натолкнуло на мысль, что тяжёлые запросы просто не успевают отрабатывать и откатываются по таймауту.
Пробуем:
innodb_lock_wait_timeout = 120
innodb_rollback_on_timeout = 1
То есть увеличиваем время ожидания блокировок и включаем откат всей транзакции, а не только последнего запроса.
Ситуация становится чуть стабильнее, но полностью проблему это не решает.
Гипотеза №3. Параллельная репликация
Включаем и наращиваем количество потоков: slave_parallel_threads = 4, потом = 8. Без эффекта.
Напомним, как вообще устроена репликация в MariaDB:
1. IO thread читает события с мастера и пишет их в relay log.
2. SQL thread (или несколько потоков) читает события из relay log.
3. События применяются на реплике. Начиная с MariaDB 10 — параллельно в несколько потоков, что увеличивает производительность.
Гипотеза №4. Режим параллельной репликации
Пробуем разные режимы:
• optimistic (по умолчанию)
• conservative
Оба варианта проблему не решают. В итоге полностью отключаем параллельное применение: slave_parallel_threads = 0.
Гипотеза №5. Неоптимальные запросы пользователей
В процессе разбора увидели соединения от пользователей, которые висели по несколько часов с открытыми транзакциями.
Вводим жёсткие, но спасительные ограничения:
idle_transaction_timeout = 600 (рвём соединение, если в транзакции 10 минут ничего не происходит);
max_statement_time = 900 (обрываем запросы, которые выполняются дольше 15 минут).
После этого количество «вечных» блокировок резко сократилось.
Гипотеза №6. Перебор с памятью
Под нагрузкой стало понятно, что innodb_buffer_pool_size в 80% RAM — это перебор именно для этой машины и этого профиля нагрузки. В пиках либо начинала зависать сама база, либо OOM-killer убивал другие процессы хоста (вплоть до sshd).
В итоге пришли к формуле: «80% минус примерно 2 ГБ».
И отдельно — swap отключать не стали. По сути, он не для производительности, а для того, чтобы система не умирала при кратковременных всплесках.
Итоговая конфигурация
В финале сетап выглядел так:
innodb_buffer_pool_size = 36G
innodb_rollback_on_timeout = 1
idle_transaction_timeout = 600
max_statement_time = 900
innodb_lock_wait_timeout = 120
slave_parallel_threads = 0
И главный результат: за последний месяц — ни одного разрыва репликации.
Выводы
Главный вывод из этого кейса — универсального рецепта настройки репликации не существует.