Как устроена
MySQL репликация
Андрей Аксенов, Sphinx
v.1.2
О чем доклад
• Краткий общий обзор
• “А как оно устроено внутри”
– Как бывает в целом
– Как сделано в MySQL
• Если совсем не знаете, оставайтесь
• Если хоть раз настраивали или даже
чинили, возможно, лучше убежать!!!
Чего щаз НЕ будет
• Мастер: [mysqld], log-bin=binlog, server-id=1,
остановить запись, SHOW MASTER STATUS
• Слейв: [mysqld], server-id=2
CHANGE MASTER TO …_HOST/USER/PASS=…,
MASTER_LOG_FILE=‘binlog.000001’,
MASTER_LOG_POS=1234;
START SLAVE;
• Обучалки replication 101 и в интернетах есть
(Хотя, технически, там все есть: исходники!)
Как бывает
“вообще”?
Вкратце про репликацию
• Репликация = скейлинг чтений!
• Бывает
– Sync / Async / Semisync
– Logical / Physical
• Logical = SBR / RBR / mixed
– Push / pull
– Master-slave, master-master
Про масштабирование
• Что дает репликация?
• Дает N копий одной БД
– 1 ведущия копия, мастер
– N ведомых реплик, слейвы
• Дает HA (high availability)
• Дает масштабирование reads
• НЕ дает масштабирования writes!
– Shard, shard, shard
Про синхронизацию
• Sync = local + remote commit
– Данные доступны везде
• Async = local commit
– Данные доступны только локально
• Semi = local commit + remote ack
– Данные доступны только локально,
но уже скопированы везде
Про уровень
• Logical = копируем “записи”
– Строго внутри БД
• Physical = копируем “файлы”
– Можно внутри, можно вне БД
– DRBD, ZFS, …
Про модель
• Кто ответственный за рассылку
изменений с мастера?
• Pull = слейв качает, мастеру пофиг
• Push = мастер сует, слейву пофиг
• Push если и бывает, то рееедко
Про мастеров
• M-S, 1 ведущая + N ведомых
• M-M, N ведущих + они же ведомые
– Упс, конфликты, сверка часов, …
– Упс, не обязано помочь write bandwidth!
– Зато cross-DC disaster recovery, говорят!!!
• M-S + routing = писать “куда угодно”
• Читать и так откуда угодно, всегда
И еще про logical format
• Можно передавать сами запросы
– UPDATE table SET x=123 WHERE id=456
– SBR, statement based replication
• Можно передавать измененные строчки
– {“id”:456, “x”:123} (есс-но в бинарном формате)
– RBR, row based replication
• И так и эдак плохо – но можно смешивать,
mixed
Как сделано
в MySQL?
А какая версия?!
• Всегда master-slave, pull-based, logical
• 4.1 = async, SBR, logpos
• 5.1 = +RBR, +mixed
• 5.6 = +semisync, +mtslave (per-db),
+slavedelay, +GTID
• 5.7 = +mtslave, +master-master
(plugin), +default-RBR (image=full?!)
Что делает мастер
• Как обычно, обрабатывает writes
• Вдобавок, из-за репликации
– Еще надо писать binlogs
– Еще надо уметь рассылать их по сетке
• NB, архитектура бьет спина!
– MySQL binlog != InnoDB WAL !=
MyMegaEngine oplog != …
– Двойная запись и все такое 
Что делает слейв
• Как обычно, обрабатывает reads
– Писать туда ОЙ НЕ НАДО
• Slave I/O thread, качаем binlogs
• Slave SQL thread(s), играем binlogs
• Отслеживаем позиции
– либо master/relay log info
– либо GTID
Путь записи
Самурай без меча...
• INSERT INTO test VALUES (123,’hello’)
• Приложение-писатель
=> таблица на мастере mysqld
=> приложение-читатель
...подобен самураю с мечом
• INSERT INTO test VALUES (123,’hello’)
• Приложение-писатель
=> таблица на мастере mysqld
=> binary log на мастере
=> relay log на слейве
=> таблица на слейве mysqld
=> приложение-читатель
Ок, что там в binary log?
• Зависит от настроек SBR/RBR/mixed
• Представь себя базой данных!!!
• UPDATE users SET x=123 WHERE id=456
– Плюс-минус пофигу
• UPDATE users SET bonus=bonus+100
– Запрос = 32 байта, пользователей = ууу, ааа
– Надо писать текст запроса, и вот мы изобрели
SBR, statement based replication
Ок, что там в binary log?
• UPDATE users SET disabled=1 WHERE
last_login < UNIX_TIMESTAMP(NOW())-
100*86400
– Для краткости надо бы сам запрос, но…
Ок, что там в binary log?
• UPDATE users SET disabled=1 WHERE
last_login < UNIX_TIMESTAMP(NOW())-
100*86400
– Время никогда не синхронно!
– Опа, реплика разошлась с мастером!
– Опа, надо бы строчки, а не запрос
– И вот мы изобрели RBR, row based replication
• А ещё бывает uuid(), found_rows(), rand(),
разные UDF, триггер на апдейт
auto_increment поля, …
Борода под/над одеялом!
• SBR хорошо, меньше данных
• SBR плохо, недетерминизм (rand,
now, итп), перевычисление сложного
• RBR хорошо, детерминизм и можно
реплицировать уааабще всё
• RBR плохо, куча данных в логе, никак
не отличить границы statement
• Есть вариант смешивать
Mixed binlog format
• Mixed = SBR, но иногда RBR
• Олимпиард условий, см.доку
– UUID(), FOUND_ROWS(), USER(), sysvar
reference, LOAD_FILE(), autoincrement +
trigger/stored function, UDF call, …
• В целом, пытается как лучше, а…
• Дефолтом стояло чуток в 5.1 – и все
Как, кстати, посмотреть?
• RBR, mysqlbinlog –v:
# at 218 #080828 15:03:08 server id 1 end_log_pos 258
Write_rows: table id 17 flags: STMT_END_F
BINLOG '
fAS3SBMBAAAALAAAANoAAAAAABEAAAAAAAAABHRlc3QAA
XQAAwMPCgIUAAQ=
fAS3SBcBAAAAKAAAAAIBAAAQABEAAAAAAAEAA//8AQAAAA
VhcHBsZQ== '/*!*/;
### INSERT INTO test.t
### SET
### @1=1
### @2='apple‘
### @3=NULL
Ок, что дальше?
• INSERT INTO test VALUES (123,’hello’)
• Приложение-писатель
=> таблица на мастере mysqld
=> binary log на мастере
=> relay log на слейве
=> таблица на слейве mysqld
=> приложение-читатель
Есть ли жизнь на слейве?
• Спецтред, тащит binary log по сети
• Пишет в relay log, локальную копию
• Другое имя файла, позиции, итд итп
• По 5.5 включительно,
– слейв 1-поточный
– txn_id = {master binlog fname, pos}
Есть ли жизнь на слейве?
• По 5.5 включительно,
– слейв 1-поточный
– txn_id = {master binlog fname, pos}
• 5.6.5, началась борьба!
– слейвы “многопоточные”, per database
– txn_id = GTID, но надо явно включить!
– gtid_mode=ON
Есть ли жизнь на слейве?
• 5.6.5, началась борьба!
– слейвы “многопоточные”, per database
– txn_id = GTID
• 5.7.2, борьба продолжается!
– поистине многопоточные слейвы
– slave_parallel_workers=N
– slave_parallel_type={ogical_clock
– binlog_group_commit_{count | delay}
Есть ли жизнь на слейве?
• 5.7.7, борьба ваще продолжается!
– binlog_format = ROW
– binlog_row_image = FULL
Внезапно, снова binlog
• binlog_row_image =
– Full = полные before + after копии!!!
– Noblob = полные, кроме ненужных blob
– Minimal = changed + ID columns
Итого, про версии MySQL
• Чем свежее, тем бодрее
– 5.7 + gtid + groupcommit + mts = FTW!
– 5.6 + gtid = ну хоть так!
• Но: дефолты, дефолты, дефолты...
– По умолчанию всякое отключено
– Или включено full row (*)
• Не, ну, э, ну, э, ну может теперь ок?!…
• Также: минорные версии важны!
Итого, про репликацию
• В целом бывает – вот такая
• В MySQL устроена – вот так
• В принципе – не так все сложно 
• Однако – надо представлять себе
ключевые слова binlog, relay log,
SBR/RBR, GTID, MTS, group commit, …
• Вот, попробовали попредставлять!
Вопросы?
для стеснительных:
shodan@sphinxsearch.com
Bonus track:
problems & tips
Всякие проблемы
• Начальный слейв (см. --master-data)
• У слейва протух лог, слетела позиция итп
• Слейв лагает и никак не может догнать
• Мастер забивает логами весь диск
• Ручные “перевыборы” мастера
• Слейвы с GTID бывают crash unsafe
• Ошибочные слейв транзакции с GTID
• …
Всякие фокусы
• Мастер A => мастер B => мастер C … => A!
• Catch-all слейв (multi source, 5.7.6+)
• Репликация логическая, возможен креатив!
– Фильтрация через {binlog|replicate}_{do|ignore}
– Подмена storage engine (innodb => myisam ради
fts, => archive для бэкапа, итд итп)
– Подмена схемы на слейве (не грузить же мастер)
– Апгрейд репликацией
– ….
Всякие ключевые слова
• server-id, SHOW MASTER/SLAVE STATUS, SHOW SLAVE
HOSTS, CHANGE MASTER TO …, START/STOP SLAVE, …
• SHOW BINARY LOGS, SHOW BINLOG EVENTS, …
• Tungsten Replicator, Galera, MySQL…
• {binlog|replicate}_{do|ignore}_db, …
• MySQL Replication Listener
• log_slave_updates, slave_checkpoint_{group|period}
• {master|relay_log}_info_repository={file|table}
• gtid_{executed|purged}

Как устроена MySQL-репликация / Андрей Аксенов (Sphinx)

  • 1.
  • 2.
    О чем доклад •Краткий общий обзор • “А как оно устроено внутри” – Как бывает в целом – Как сделано в MySQL • Если совсем не знаете, оставайтесь • Если хоть раз настраивали или даже чинили, возможно, лучше убежать!!!
  • 3.
    Чего щаз НЕбудет • Мастер: [mysqld], log-bin=binlog, server-id=1, остановить запись, SHOW MASTER STATUS • Слейв: [mysqld], server-id=2 CHANGE MASTER TO …_HOST/USER/PASS=…, MASTER_LOG_FILE=‘binlog.000001’, MASTER_LOG_POS=1234; START SLAVE; • Обучалки replication 101 и в интернетах есть (Хотя, технически, там все есть: исходники!)
  • 4.
  • 5.
    Вкратце про репликацию •Репликация = скейлинг чтений! • Бывает – Sync / Async / Semisync – Logical / Physical • Logical = SBR / RBR / mixed – Push / pull – Master-slave, master-master
  • 6.
    Про масштабирование • Чтодает репликация? • Дает N копий одной БД – 1 ведущия копия, мастер – N ведомых реплик, слейвы • Дает HA (high availability) • Дает масштабирование reads • НЕ дает масштабирования writes! – Shard, shard, shard
  • 7.
    Про синхронизацию • Sync= local + remote commit – Данные доступны везде • Async = local commit – Данные доступны только локально • Semi = local commit + remote ack – Данные доступны только локально, но уже скопированы везде
  • 8.
    Про уровень • Logical= копируем “записи” – Строго внутри БД • Physical = копируем “файлы” – Можно внутри, можно вне БД – DRBD, ZFS, …
  • 9.
    Про модель • Ктоответственный за рассылку изменений с мастера? • Pull = слейв качает, мастеру пофиг • Push = мастер сует, слейву пофиг • Push если и бывает, то рееедко
  • 10.
    Про мастеров • M-S,1 ведущая + N ведомых • M-M, N ведущих + они же ведомые – Упс, конфликты, сверка часов, … – Упс, не обязано помочь write bandwidth! – Зато cross-DC disaster recovery, говорят!!! • M-S + routing = писать “куда угодно” • Читать и так откуда угодно, всегда
  • 11.
    И еще проlogical format • Можно передавать сами запросы – UPDATE table SET x=123 WHERE id=456 – SBR, statement based replication • Можно передавать измененные строчки – {“id”:456, “x”:123} (есс-но в бинарном формате) – RBR, row based replication • И так и эдак плохо – но можно смешивать, mixed
  • 12.
  • 13.
    А какая версия?! •Всегда master-slave, pull-based, logical • 4.1 = async, SBR, logpos • 5.1 = +RBR, +mixed • 5.6 = +semisync, +mtslave (per-db), +slavedelay, +GTID • 5.7 = +mtslave, +master-master (plugin), +default-RBR (image=full?!)
  • 14.
    Что делает мастер •Как обычно, обрабатывает writes • Вдобавок, из-за репликации – Еще надо писать binlogs – Еще надо уметь рассылать их по сетке • NB, архитектура бьет спина! – MySQL binlog != InnoDB WAL != MyMegaEngine oplog != … – Двойная запись и все такое 
  • 15.
    Что делает слейв •Как обычно, обрабатывает reads – Писать туда ОЙ НЕ НАДО • Slave I/O thread, качаем binlogs • Slave SQL thread(s), играем binlogs • Отслеживаем позиции – либо master/relay log info – либо GTID
  • 16.
  • 17.
    Самурай без меча... •INSERT INTO test VALUES (123,’hello’) • Приложение-писатель => таблица на мастере mysqld => приложение-читатель
  • 18.
    ...подобен самураю смечом • INSERT INTO test VALUES (123,’hello’) • Приложение-писатель => таблица на мастере mysqld => binary log на мастере => relay log на слейве => таблица на слейве mysqld => приложение-читатель
  • 19.
    Ок, что тамв binary log? • Зависит от настроек SBR/RBR/mixed • Представь себя базой данных!!! • UPDATE users SET x=123 WHERE id=456 – Плюс-минус пофигу • UPDATE users SET bonus=bonus+100 – Запрос = 32 байта, пользователей = ууу, ааа – Надо писать текст запроса, и вот мы изобрели SBR, statement based replication
  • 20.
    Ок, что тамв binary log? • UPDATE users SET disabled=1 WHERE last_login < UNIX_TIMESTAMP(NOW())- 100*86400 – Для краткости надо бы сам запрос, но…
  • 22.
    Ок, что тамв binary log? • UPDATE users SET disabled=1 WHERE last_login < UNIX_TIMESTAMP(NOW())- 100*86400 – Время никогда не синхронно! – Опа, реплика разошлась с мастером! – Опа, надо бы строчки, а не запрос – И вот мы изобрели RBR, row based replication • А ещё бывает uuid(), found_rows(), rand(), разные UDF, триггер на апдейт auto_increment поля, …
  • 23.
    Борода под/над одеялом! •SBR хорошо, меньше данных • SBR плохо, недетерминизм (rand, now, итп), перевычисление сложного • RBR хорошо, детерминизм и можно реплицировать уааабще всё • RBR плохо, куча данных в логе, никак не отличить границы statement • Есть вариант смешивать
  • 24.
    Mixed binlog format •Mixed = SBR, но иногда RBR • Олимпиард условий, см.доку – UUID(), FOUND_ROWS(), USER(), sysvar reference, LOAD_FILE(), autoincrement + trigger/stored function, UDF call, … • В целом, пытается как лучше, а… • Дефолтом стояло чуток в 5.1 – и все
  • 25.
    Как, кстати, посмотреть? •RBR, mysqlbinlog –v: # at 218 #080828 15:03:08 server id 1 end_log_pos 258 Write_rows: table id 17 flags: STMT_END_F BINLOG ' fAS3SBMBAAAALAAAANoAAAAAABEAAAAAAAAABHRlc3QAA XQAAwMPCgIUAAQ= fAS3SBcBAAAAKAAAAAIBAAAQABEAAAAAAAEAA//8AQAAAA VhcHBsZQ== '/*!*/; ### INSERT INTO test.t ### SET ### @1=1 ### @2='apple‘ ### @3=NULL
  • 26.
    Ок, что дальше? •INSERT INTO test VALUES (123,’hello’) • Приложение-писатель => таблица на мастере mysqld => binary log на мастере => relay log на слейве => таблица на слейве mysqld => приложение-читатель
  • 27.
    Есть ли жизньна слейве? • Спецтред, тащит binary log по сети • Пишет в relay log, локальную копию • Другое имя файла, позиции, итд итп • По 5.5 включительно, – слейв 1-поточный – txn_id = {master binlog fname, pos}
  • 29.
    Есть ли жизньна слейве? • По 5.5 включительно, – слейв 1-поточный – txn_id = {master binlog fname, pos} • 5.6.5, началась борьба! – слейвы “многопоточные”, per database – txn_id = GTID, но надо явно включить! – gtid_mode=ON
  • 30.
    Есть ли жизньна слейве? • 5.6.5, началась борьба! – слейвы “многопоточные”, per database – txn_id = GTID • 5.7.2, борьба продолжается! – поистине многопоточные слейвы – slave_parallel_workers=N – slave_parallel_type={ogical_clock – binlog_group_commit_{count | delay}
  • 31.
    Есть ли жизньна слейве? • 5.7.7, борьба ваще продолжается! – binlog_format = ROW – binlog_row_image = FULL
  • 32.
    Внезапно, снова binlog •binlog_row_image = – Full = полные before + after копии!!! – Noblob = полные, кроме ненужных blob – Minimal = changed + ID columns
  • 34.
    Итого, про версииMySQL • Чем свежее, тем бодрее – 5.7 + gtid + groupcommit + mts = FTW! – 5.6 + gtid = ну хоть так! • Но: дефолты, дефолты, дефолты... – По умолчанию всякое отключено – Или включено full row (*) • Не, ну, э, ну, э, ну может теперь ок?!… • Также: минорные версии важны!
  • 35.
    Итого, про репликацию •В целом бывает – вот такая • В MySQL устроена – вот так • В принципе – не так все сложно  • Однако – надо представлять себе ключевые слова binlog, relay log, SBR/RBR, GTID, MTS, group commit, … • Вот, попробовали попредставлять!
  • 36.
  • 37.
  • 38.
    Всякие проблемы • Начальныйслейв (см. --master-data) • У слейва протух лог, слетела позиция итп • Слейв лагает и никак не может догнать • Мастер забивает логами весь диск • Ручные “перевыборы” мастера • Слейвы с GTID бывают crash unsafe • Ошибочные слейв транзакции с GTID • …
  • 39.
    Всякие фокусы • МастерA => мастер B => мастер C … => A! • Catch-all слейв (multi source, 5.7.6+) • Репликация логическая, возможен креатив! – Фильтрация через {binlog|replicate}_{do|ignore} – Подмена storage engine (innodb => myisam ради fts, => archive для бэкапа, итд итп) – Подмена схемы на слейве (не грузить же мастер) – Апгрейд репликацией – ….
  • 40.
    Всякие ключевые слова •server-id, SHOW MASTER/SLAVE STATUS, SHOW SLAVE HOSTS, CHANGE MASTER TO …, START/STOP SLAVE, … • SHOW BINARY LOGS, SHOW BINLOG EVENTS, … • Tungsten Replicator, Galera, MySQL… • {binlog|replicate}_{do|ignore}_db, … • MySQL Replication Listener • log_slave_updates, slave_checkpoint_{group|period} • {master|relay_log}_info_repository={file|table} • gtid_{executed|purged}