LINUX.ORG.RU

Master-master синхронизация БД. Закат солнца вручную. Нужны идеи.

 , , , ,


0

2

Ломаю голову на счёт «ручной» master-master синхронизации, скажем, того же, MySQL.

Понятно, что есть родная master-master синхронизация на bin-log. Но у неё есть ряд существенных недостатков. Например, она тяжело поднимается после падения одного из серверов. Часто вылезают рассинхронизации и т.п. И плюс оно гвоздями прибито к MySQL. А, да, главное — как я понял, оно позволяет вести только полностью синхронные сервера. Нельзя выборочно часть таблиц синхронизировать, а часть — нет.

Поэтому давно вынашиваю такие планы.

Программа-минимум. Заводим в таблице поле, модифицируемое по изменению записи. И на каждой машине храним время последней синхронизации с другой. Если нужно, делаем запрос, дёргая все ячейки, что обновлялись с последней синхронизации на другой и ставим их на машине первой по REPLACE. Да, естественно, все autoincrement идут с шагом, равным числу синхронизируемых машин, а смещение — номер машины. Также, как в нативной мастер-мастер репликации на бинлогах.

Плюсы — очень простая реализация.

Минус пока вижу один, но очень существенный — проблема конфликтов изменений. Для основных данных обычных web-сервисов (форумы, блоги, страницы сайта) это не проблема. Вероятность того, что за период синхронизации поменяют данные и там, и там — крайне мала. Проблема лезет в часто меняющихся «автоматических» данных. Например, чисто просмотров объекта (топика форума).

Боюсь, что просто так задачу не решить. Видимо, под учёт числа просмотров нужно придумывать отдельный механизм.

Программа-максимум — пока совсем теоретизация. Делать не mysql-dump, а дамп сразу объектов (JSON/XML — не важно). И втягивать на другом сервере изменившееся сразу в объектном виде. Дополнительный плюс — появляется возможность кроссплатформенной синхронизации. Например, MySQL на одной машине и хоть MongoDB на другой. Не то, чтобы пока было актуально и не факт, что понадобится, но интересно. И механизм вообще получается универсальный, не прибитый гвоздями к бэкенду. Но минус в виде конфликта не исчезает. Зато можно указать особое поведение при синхронизации отдельных свойств объекта.

Но я пока, всё же, больше думаю о первом варианте, на простых дампах. Усложнить можно будет всегда и уже в работающей системе.

Есть мысли на этот счёт?

Даже можно конкретизировать — пока реально первый затык именно в учёте числа просмотров. Делать его в виде отдельного центрального сервера? И фиг с ним, если он упадёт, не сказать, что это критичные данные?

★★★★★

Ответ на: комментарий от post-factum

Надо будет посмотреть. Хотя в cookbook'е упоминается навскидку только master-slave, но, возможно, это только навскидку.

Но это в любом случае не решает проблемы конфликта того же числа просмотров. Интересны варианты для решения этой проблемы.



В принципе, вижу, скажем, такой вариант. Крутим число просмотров в локальной базе (возможно, вообще в key-value, типа redis — только не помню, научился ли он извлекать все записи по ключу-тэгу?) в двух экземплярах — ориентировочное число общих просмотров на всех машинах + число просмотров на этой машине с последней синхронизации. Ну и время от времени проводим синхронизацию с центральным сервером, кидая на него инкремент и получая с него общее число, для локального кеша. Немного громоздко и централизованно, но работоспособно при падении центрального сервера.

KRoN73 ★★★★★
() автор топика

пока реально первый затык именно в учёте числа просмотров

Задачи со множественными апдейтами одной и той же записи «в лоб» не решаются. Подели задачу. Представь, что у тебя две задачи - многомастерная репликация и статистика (это деление ты уже сделал сам).

Что же собственно до статистики - сведи её в отдельную таблицу, в которой для каждого мастера будет СВОЯ запись со статистикой, а итоговое количество просмотров вычисляется как сумма всех статистик этой страницы.

no-dashi ★★★★★
()
Ответ на: комментарий от no-dashi

в отдельную таблицу, в которой для каждого мастера будет СВОЯ запись со статистикой

Логично.

KRoN73 ★★★★★
() автор топика

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

no-dashi ★★★★★
()

Проблема лезет в часто меняющихся «автоматических» данных. Например, чисто просмотров объекта (топика форума).

Проблема в том что у тебя архитектура БД и приложения заточена под максимальное впихивание всего в один сервер, а не под распределенную работу в составе кластера. Я когда еще первый раз увидел эти счетчики в базе много лет назад, в разных треш-php-форумах-cms, так сразу схватил фейспалм - авторы явно не думали о том что это все придется потом распараллеливать.

Соответственно и решать эту проблему тебе и придется в этом ключе - делать архитектуру БД/приложения заточенную под распределенную обработку(репликацию). То есть под то что бы «ситуации как со счетчиком» в принципе не возникали.

Что кстате приведет к тому что на одном сервере оно станет работать медленней. :D

Делать не mysql-dump, а дамп сразу объектов (JSON/XML — не важно). И втягивать на другом сервере изменившееся сразу в объектном виде.

Разница между этими вариантами на самом деле еще и в том что в случае mysql может получится более-менее универсальный синхронизатор, а специфичные для тебя вещи можно вынести в отдельные плагины. В случае «дампа объектов» речь пойдет о полностью кастомном, «для себя», варианте.

kernel ★★☆
()

Нельзя выборочно часть таблиц синхронизировать, а часть — нет.

Можно. Вынеси в другую базу данных. Если вынести нельзя, то и синхронизацию отпилить по идее тоже должно быть невозможно.

А вообще, ты правда уверен что тебе так нужен master-master в MySQL?) Какой от него профит?

ei-grad ★★★★★
()
Ответ на: комментарий от ei-grad

Можно. Вынеси в другую базу данных

Логически избыточно

Если вынести нельзя, то и синхронизацию отпилить по идее тоже должно быть невозможно

mysqldump можно потаблично делать (это для самого простого случая)

А вообще, ты правда уверен что тебе так нужен master-master в MySQL?) Какой от него профит?

Главный профит в резервировании, когда при отваливании одной машины простой заменой DNS можно перенести работу на другую. Ну и по мелочи — можно что-то тяжёлое (по обработке) провести на одной (ненагруженной) машине, а результат потом засинкается на другую, боевую.

KRoN73 ★★★★★
() автор топика

Galera (в т.ч. есть арбитр для разруливания конфликтов), pt-table-sync (если просто master-master разъехались и нужно разрулить конфликты

ihanick
()

Делал такие штуки - одна это вообще был асинхронное «синхронное» состояние сети из тысяч систем, вторую на постгресе - асинхронный MMR на три сервера. В постгресе я заводил репликационные таблицы в которых писался лог акций.

Тебе бы предложил сделать так же - например добавился новый пост на форум - добавилась акция insert <data>. Обновился счетчик просмотров - добавилась акция increment <post> +1. Потом при синхронизации ты разматываешь эти логи применяя акции на другом сервере - механизм единообразный.

Делать не mysql-dump, а дамп сразу объектов (JSON/XML — не важно).

Не объектов - «транзакций». С объектами непонятно как он изменился, все что ты можешь сделать это мерж данных или перетирание - это не самый лучший случай, больше информации ты получишь, если ты можешь записать акции и потом 'проиграть' то их на другом сервере, рассчитывая на бесконфликтность или запрограммировав разрешение конфликтов транзакций - например удаление имеет приоритет перед модификацией, последняя модификация имеет приоритет над предыдущей, в самых фиговых случаях - мерж и т.д.

Хорошо бы если есть возможность на уровне приложения перевести все не на данные а на акции - чтобы они применялись и локально и удаленно - тогда ты например не меняешь некое поле в таблице а производишь некую акцию - которая применяется и там и там, а как она уже реализована на уровне хранилища даных отдельный вопрос.

r ★★★★★
()
Ответ на: комментарий от KRoN73

Логически избыточно

О, дааа!! :-D А крутить костыли с реализацией собственной распределенной eventual consistant системы не избыточно?)))

Главный профит в резервировании, когда при отваливании одной машины простой заменой DNS можно перенести работу на другую.

А master-master то на какой хрен тут нужен?) Для реализации такой техники вполне достаточно master-slave с переключением master'а (можно даже автоматически по heartbeat). Btw, замена DNS тут тоже не совсем правильный путь, или ты имел ввиду замену hostname'а сервера БД в конфигах приложения или смену адреса в /etc/hosts?..

Ну и по мелочи — можно что-то тяжёлое (по обработке) провести на одной (ненагруженной) машине, а результат потом засинкается на другую, боевую.

А в чем разница? На самом деле ты своей техникой только увеличиваешь суммарную нагрузку на обе базы :-).

ei-grad ★★★★★
()
Ответ на: комментарий от KRoN73

mysqldump можно потаблично делать (это для самого простого случая)

Ты не понял что я имел ввиду. Давай перефразирую.

Вынести нельзя если данные у тебя связаны. Иначе вынести можно. Если данные связаны - то невозможно синхронизировать одну часть, оставляя другую часть не синхронизированной.

ei-grad ★★★★★
()
Ответ на: комментарий от ei-grad

А крутить костыли с реализацией собственной распределенной eventual consistant системы не избыточно?)))

Нет. Я же сказал _логически_ избыточно, а не, скажем, _скриптово_. Одна коллекция сущностей — одна БД. А сервисная фигня тут вторична.

Для реализации такой техники вполне достаточно master-slave с переключением master'а

Во-первых, речь идёт о том, чтобы изначально модификации могли вноситься в оба сервера, независимо от их взаимного статуса. Во-вторых, расскажите, как в mysql автоматически переключать Master'а?

А в чем разница?

В том, что не нужно производить тяжёлую работу на основном сервере, загрузив туда только готовый результат.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от ei-grad

Ты не понял что я имел ввиду

Всё я понял. Речь о другом. Ладно, проехали.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

Нет. Я же сказал _логически_ избыточно, а не, скажем, _скриптово_. Одна коллекция сущностей — одна БД. А сервисная фигня тут вторична.

Если с этой стороны подойти, то мой ответ - логически избыточно держать не связанные сущности в одной БД. Но вообще я про другое. Не нужно переводить single-node систему, которой является master-нода MySQL работающая в паре master-slave, в разряд распределенных систем, где добавляется куча избыточных операций и довольно неприятных подводных камней.

Во-первых, речь идёт о том, чтобы изначально модификации могли вноситься в оба сервера, независимо от их взаимного статуса.

Было бы круто :-). Но, к сожалению, это не возможно реализовать эффективно, если оба сервера работают с одними и теми же данными. Масштабирование на запись нормально реализуется только при использовании шардирования в каком-либо виде.

Во-вторых, расскажите, как в mysql автоматически переключать Master'а?

Как угодно. Можно использовать http://code.google.com/p/mysql-master-ha/, но лучше самому реализовать более подходящее к своей ситуации решение. Тут всё описано - http://dev.mysql.com/doc/refman/5.0/en/ha-overview.html.

В том, что не нужно производить тяжёлую работу на основном сервере, загрузив туда только готовый результат.

Это как? И почему ты вообще хочешь какую-то тяжелую работу на основном сервере БД проводить? Почему не провести её где-то ещё, не нагружая master, а потом поместить результат выполнения в master? Зачем для этого нужно два master?)

ei-grad ★★★★★
()
Ответ на: комментарий от r

Тебе бы предложил сделать так же - например добавился новый пост на форум - добавилась акция ....

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

В данном случае форума у нас есть некая куча таблиц в которых ссылки строк друг на друга делаются через id которые генерятся в сиквенсах. То есть например когда делается пост с аттачем, то пост идет в одну таблицу , там ему через сиквенс присваивается id, а аттач в другую, и там аттач получает id и линк на пост через id поста.

Соответственно если у нас на двух разных узлах добавляются новые сообщения то конфликт может быть только на почве пересекающихся id. Проще всего его устранить выдавая на каждом узле id из своего пула. Если редактирование, то тут в большинстве cms уже есть какой то механиз залочивания сообщения от мультиюзерного редактирования(а часто и механизм версионности, как в друпале том же, что упрощает) - его придется адаптировать к параллелизму. Ну либо идти простым вариантом - сохранять ту версию сообщения которое было последним.

Соответственно главный принцип к которому нужно привести базу(приложение) : для синхронизации n-баз достаточно скопировать все уникальные строчки в таблицах каждой базы во все остальные базы.

Такой вариант более кулхацкерский чем твой, но к нему можно гораздо проще адаптировать большую часть среднего веб-кода. Грубо говоря выдача правильных id шников делается через настройку сиквенсов, а тот код который правит какие то параметры переделывается либо «правка через добавление новой строчки» либо в режим «правка любой конкретной строчки происходит только на том узле который отвечает за эту строчку».

kernel ★★☆
()
Ответ на: комментарий от KRoN73

У просмотров обычно вообще на целостность покласть. Пропадет несколько - никто не помрёт. И гарантированная запись там не нужна - хватит отложенной.

Самое простое - лить инкременты сначала в редис, автоматически мерджа дубли, а потом раз в минуту (или с другой периодичностью) чохом все выливать в базу, одним запросом.

Нагрузка на базу снизится очень сильно. Можно вместо редиса MEMORY table, но редис очень удобен.

Vit ★★★★★
()
Ответ на: комментарий от KRoN73

Здесь не нужен мастер-мастер, нужен автовыбор мастера. И желательно для критичных запросов указывать, что они должны разбежаться на несколько серверов, перед тем как сказать что выполнились. Монга такое точно умеет. Про мускули не знаю.

Vit ★★★★★
()
Ответ на: комментарий от Vit

Монга совсем другую архитектуру имеет, она под такое и затачивалась. С MySQL всё сложнее…

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от kernel

В работающем коде проще почти всегда по данным параллелизм вставлять

С постгресом я так и сделал - весь MMR был на тригерах и кроне, сам аппликейшен ничего про это не знал.

r ★★★★★
()
Ответ на: комментарий от ei-grad

Вот и использовал бы монгу, зачем костыли на MySQL городить? :-)

Legacy

KRoN73 ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.