Наверх ▲

Нестандартное использование репликации Mysql

Дмитрий Самиров Дмитрий Самиров Разработчик серверной части рекламной системы Advaction. Александр Панков Александр Панков Технический директор рекламной системы Advaction.

Александр Панков: Мы расскажем чуть-чуть о нестандартном использовании MySQL-репликации для написания высоконагруженных демонов. Покажем, как все должно работать правильно. Я думаю, что кто-то из вас уже сегодня сможет посмотреть наши открытые исходники, примеры и посмотреть, как можно спасти свою систему от большой нагрузки.

Я, в принципе, никогда не любил классические базы данных, потому что чаще всего при высоких нагрузках от них одни проблемы. Тем не менее, web-интерфейс с использованием стандартного MySQL на PHP пишется очень дешево и быстро. Поэтому полностью отказаться от баз данных невозможно. Приходится поступать так: пишутся web-приложения, которые работают непосредственно с базой данных, а высоконагруженная часть постепенно "перекочевывает" на самописные демоны и пр.

 

 

Классическое решение предложено Memcached. Какой его основной недостаток? Во-первых, обработчик запросов идет всегда в Memcached, смотрит, есть ли там данные. Если нет, то обращается в базу, и все в принципе устраивает. Одна проблема: если данные изменились, в Memcached останется старая версия. Спрашивается: зачем она тогда нужна? Получается, обработчик должен следить за всеми Memcached и постоянно обновлять Memcached, что происходит не всегда. Поэтому на многих сайтах показывается неактуальная информация.

В чём преимущества нашей архитектуры? Высоконагруженная часть быстро обслуживается демоном на С++, в котором всегда гарантированно актуальные данные. 

Как все устроено? Есть база данных, в которой хранятся самые актуальные данные. Демон представляется базе данных как другой MySQL и просто следит за обновлениями базы. Что получаем в результате? Считывая всю базу и быстро ее раздавая, мы получаем всегда свежую и актуальную копию. Репликация происходит быстро. 

 

Как это используется? 

Дмитрий Самиров: Допустим, у вас есть демон и вы хотите, чтобы он следил за репликацией. Вы делаете так, чтобы класс этого демона еще наследовался от mysql::CLogParser. В этом базовом классе содержаться некоторые виртуальные функции. Эти функции вызываются, когда в базе происходят изменения и репликация. 

В класс требуется внести еще несколько строчек кода, чтобы инициализировать MySQL. Соединение происходит как с обычным пользователем. Далее мы должны перечислить таблицы, за которыми будем следить.

Александр Панков: Спасибо Дмитрию за краткое и доходчивое объяснение. Мы создаем отдельный тред, он следит за репликациями и обновляет демон. 

Каковы особенности архитектуры? Мы не умеем парсить SQL-запросы - и не надо. Приходят готовые строчки. Реализация происходит стандартно на базе MySQL-клиента. Из-за того, что она "висит" в блокирующем потоке, приходится создавать отдельный поток. Мультиплексом пока не работает. 

Версия 5.1 очевидно лучше из-за наличия построчной репликации. В «Бегуне» есть похожая варианция, но она использует Boost. Мы написали без Boost. Мы только используем стандартную библиотеку шаблонов.

Нужно обязательно обращать внимание на права доступа. 

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

Только если вытащить сетевой провод из сервера, то демон репликации будет считать, что обновления просто не приходят. Это - особенность MySQL-клиента и его небольшой недостаток. Подобное случается нечастно. Проблема решается быстро: достаточно перезапустить демона и все восстановится.

С исходными файлами можно ознакомиться по адресу: https://github.com/dimarik/mysqlslave.

Что нас ждет в будущем? Надо проводить тестирования на разных версиях MySQL. Я тестировал на версии 5.5, на 5.1 - тоже никаких проблем, насчет 6.0 не знаю. В принципе, никаких сложностей возникать не должно. 

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

Также мелкие улучшения будут связаны с продакшн, демоном и библиотекой. 

Вопросы и ответы

Вопрос из зала: Почему демон не может узнать об "отваленном" сервере?

Александр Панков: Если сервер перезагружается, то он узнает. Сервер закрывает сокет. Если сервер исчезает (такая ситуация возможна – провод выдернули), демон никак об этом не узнает. 

Вопрос из зала: А если использовать MySQL_ping?

Александр Панков: Он не может сделать MySQL_ping. 

Вопрос из зала: Если сервер исчезает, почему его нельзя проверить MySQL_ping либо обычным ping?

Александр Панков: Потому что инструмент, отслеживающий репликацию, написанный в MySQL-клиенте, находится в Read. Она просто ждет события от сокета. Должно произойти что-то. Сокет должен кто-то закрыть. Но его некому закрыть. Такова репликация MySQL. 

Вопрос из зала: А как же Time out? 

Александр Панков: Time out нет. Кстати говоря, в этом вся беда. Увы, так устроен MySQL. 

Вопрос из зала: То есть фоном не проверяется наличие сервера никак?

Александр Панков: Мы, наверное, займемся этим сразу после того, как напишем клиентскую MySQL-библиотеку.

Вопрос из зала: Скажите, Keep-Alive не помогает в такой ситуации?

Александр Панков: Не помогает.

Вопрос из зала: Демон вообще физически, данные где-то хранит? 

Александр Панков: Я еще раз вернусь к слайду, чтобы показать, как работает демон. 

При старте демон вычитает всю базу и хранит данные в памяти, просто получая апдейты. Если таблица большая, то, скорее всего, тоже можно это сделать. Но можно просто "расшардить" 10 демонов. 

Вопрос из зала: То есть демон грузит при старте?

Александр Панков: Как вариант. У нас есть демоны, которые при запросах, если у них нет данных, делают выбор (англ. select). Если есть данные – они отдают из кэша. Некий аналог Memcached. Такой демон возможен - у нас подобная реализация есть. 

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

Александр Панков: Это не страшно, потому что наши демоны хорошо написаны. У нас нет проблем с обработкой миллиона запросов.

Вопрос из зала: Миллион запросов надо же где-то держать, их надо куда-то писать, например, в память.

Александр Панков: Пока проблем не было. Мы обратим обязательно на это внимание. Попробуем сделать какое-нибудь обновление.

Вопрос из зала: А если DDL-запрос спускается, что вы будете делать?

Александр Панков: По поводу сетевой части. У вас есть ведущий и ведомый сервер. Какие у них возникнут проблемы с сетью, такие же проблемы с сетью будут и у демона. Он ведет себя, как обычная база данных. Там располагается копия исходников.

Вопрос из зала: В чем тогда состоит польза?

Александр Панков: Польза? В демоне - всегда свежие данные.

Вопрос из зала: Миллион строк?

Александр Панков: Миллион. И что?

Вопрос из зала: Лаг же все равно будет такой же, как и на обычном ведомом сервере. Сиюсекундно он же этот миллион не запишет.

Александр Панков: Ну, с некоторым минимальным отставанием. А вы хотите сказать, что тут возможно принципиально другое решение?

Вопрос из зала: Мне интересно, чем ваше решение отличается от стандартной репликации?

Александр Панков: Наше решение – это как раз нестандартное использование репликации. В репликации ничего не меняется. В нашем решении меняется следующее: стандартная репликация создает практически копию базы данных – мы же обновляем данные в демоне. Просто для этого написана специальная, достаточно удобная библиотека.

Вопрос из зала: Хорошо. Спасибо.

Вопрос из зала: Я посмотрел на GitHub у вас через три функции реализовано On_insert, On-delete, On_update. Как вы вообще видите границы транзакции?

Александр Панков: На самом деле все хорошо. Смотрите, что происходит. Границы транзакции мы не видим, и нам их не нужно видеть. Ведущий сервер, до тех пор пока ему не скажут "коммит", не будет рассылать ничего. Если же он сделан, то мы получим все обновления.

Вопрос из зала: Если вы не видите границ транзакции, то не знаете и точки, в которых данные согласованны.

Александр Панков: События Begin и Commit, повторюсь, приходят. Необходимости в этом не было. Функции On_begin, On_commit – хороший патч. Можете сделать его сами, "закоммитить" (или попросить нас) на GitHub, получить у Дмитрия доступ. Сложностей с этим нет, потому что это простые события: On_begin, On_commit. Они приходят. Они даже по логам видны.

Вопрос из зала: Спасибо за предложение. Я просто работаю в компании «Бегун», у которой тоже выложена библиотека libslave с этой функциональностью.

Александр Панков:  Но у вас использует Boost. Это ужасно, мне кажется. 

Вопрос из зала: А все-таки, если спускается DDL-запрос (Alter), как-то он обрабатывается?

Александр Панков: C Alter Table все хорошо. Они тоже приходят, а мы их игнорируем. Обычно такое изменение логики требует перезапуска демонов. Иначе демон пришлось бы изменить, скорее всего, наполовину.

Вопрос из зала: А если добавили индекс?

Александр Панков: Добавили индекс? Он проигнорирует и спокойно улетит.

Вопрос из зала: Проигнорирует?

Александр Панков: Индекс? Зачем ему знать о существовании индекса?

Вопрос из зала: Как демон тогда вообще отдает данные? Он же их тоже выбирает из своей базы. Или нет?

Александр Панков: Демон для того и написан, чтобы он внутри сам решал, как ему отдавать данные, осуществлять выбор и какие использовать индексы.

Вопрос из зала: То есть он на индексы не смотрит?

Александр Панков: Ему безразлично. 

Вопрос из зала: К нему запросу приходят через SQL?

Александр Панков: Нет. Приведу пример. Допустим, мы реализуем демон профайлов пользователей на форуме, в «Одноклассниках», очередной социальной сети. Мы отдаем команду: «Покажи мне профиль такого-то человека». Если он не имеет профиль нужного человека, то выбирает информацию из баз, составляет внутреннюю структуру, в которой это данные закэшированы  и отдает через JSON. 

В базу приходят обновления. Появились новые друзья или фотографии. Он просто корректирует внутреннюю структуру данных. Демон в данном случае – это структура данных не хранения, а использования. Оно, скорее всего, будет в памяти.

Реплика из зала: То есть он не сможет создать сложную структуру?

Александр Панков: Как не сможет?

Реплика из зала: Мне нужно получить результат: множество Join.

Александр Панков: Если вы честно пропишете все Join в демоне… Опять же: все надо реализовать внутри демона. Это не прослойка между базой, заменяющая SQL-запросы. Это инструмент, которые позволяет кешировать и автоматически обновлять множество стандартных запросов.

Комментарии

Нет ни одного комментария

Только пользователи могут оставлять комментарии

Возможно, вам будет интересно:

Андрей Смирнов

Андрей Смирнов

Андрей Смирнов – руководитель разработки, разработчик, фанат Go, Python, DevOps и больших нагрузок. Руководил разработкой backend-сервисов в стартапе Qik, после его покупки продолжил работать в компаниях Skype и Microsoft.

Андрей Смирнов (Qik) рассказывает, для каких задач хорош Twisted, и делится секретами работы с этим фреймворком.

Александр Зиза

Александр Зиза

Разработчик программы развития управленческого мышления.
Консультант по психологии трансформационных изменений и развитию оргуправленческого мышления.
Получил образование физика (МГУ), финансового директора (РАНХиГС, MBA), психолога (СПбГУ).

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

Андрей Дзыня

Андрей Дзыня

Эксперт и тренер в области автоматизации тестирования ПО. Со-организатор сообщества автоматизаторов Automated-Testing.info. Ведущий инженер по автоматизации тестирования в компании Lohika Systems.

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