company_banner

Как мы мигрировали миллионные страны за рабочий день

    Badoo — крупнейшая в мире социальная сеть для знакомств с новыми людьми, насчитывающая 190 миллионов пользователей.
    Все данные хранятся в двух дата-центрах — европейском и американском. Некоторое время назад мы исследовали качество интернет-соединения у наших пользователей из Азии и обнаружили, что для 7 миллионов пользователей наш сайт будет загружаться в 2 раза быстрее, если мы переместим их из европейского дата-центра в американский. Перед нами впервые встала задача крупномасштабной миграции данных пользователей между дата-центрами, с которой мы успешно справились: мы научились перемещать 1,5 миллиона пользователей за один рабочий день! Мы смогли перемещать целые страны! В первой части мы подробно расскажем о поставленной перед нами задаче и о том, какого результата мы достигли.

    Архитектура Badoo


    Об архитектуре Badoo было много рассказано на различных конференциях и на самом Хабре, но мы всё же повторим основные моменты, которые важны для понимания нашей задачи. В Badoo для отдачи веб-страничек используется стандартный стек технологий: Linux, nginx, PHP-FPM (разработка Badoo), memcached, MySQL.
    Почти все данные пользователей находятся на паре сотен MySQL-серверов и распределены («расшардены») по ним с использованием «самописного» сервиса под названием authorizer. Он хранит в себе большую таблицу соответствий id пользователя и id сервера, на котором находится пользователь. У нас не используются «остатки от деления» и другие похожие способы распределения пользователей по серверам, поэтому мы можем без особых проблем перемещать пользователей между серверами баз данных: это изначально заложено в архитектуре Badoo.



    Помимо MySQL, у нас есть множество C/C++ сервисов, которые хранят различные данные: сессии, даты последнего захода на сайт, фотографии пользователей для голосования, основные данные всех пользователей для осуществления поиска.

    У нас также есть сервис, который обслуживает раздел «Знакомства». Он отличается от других тем, что существует в одном экземпляре для каждой страны. Просто он потребляет так много оперативной памяти, что все его данные не могут физически поместиться на один сервер, даже если поставить туда 384 Гб. При этом он «живет» только в «своем» дата-центре.

    Плюс ко всему у нас есть ряд «центральных» баз данных MySQL, которые хранят общую информацию обо всех пользователях, и отдельные базы для биллинга, которые тоже хранят информацию сразу по всем пользователям Badoo. Помимо этого, у нас имеются отдельные хранилища для загруженных фотографий и видео, о которых будет отдельная статья. Эти данные тоже должны быть перемещены.

    Постановка задачи


    Задача формулируется очень просто: перенести за один рабочий день данные пользователей из целой страны, и чтобы во время миграции эти пользователи могли пользоваться сайтом. Самая большая страна из тех, что мы «мигрировали» — это Таиланд, в котором у нас зарегистрировано порядка 1,5 млн пользователей. Если поделить это число на 8 рабочих часов (плюс обед), то получим требуемую скорость миграции, которая составляет около 170 тысяч пользователей в час.
    Требование мигрировать страну за один рабочий день продиктовано тем, что в это время может случиться всё что угодно. Например, могут «лечь» или начать тормозить какие-то сервера или сервисы, и тогда надо будет «на живую» править код, чтобы уменьшить создаваемую на них нагрузку. Также возможны ошибки в коде миграции, которые приведут к проблемам у пользователей, и тогда должна быть возможность быстро увидеть это и приостановить (или даже откатить) процесс. Одним словом, при осуществлении такой масштабной операции по переносу пользователей обязательно требуется присутствие «оператора», который будет контролировать происходящее и вносить нужные коррективы во время работы.

    Технически для каждого пользователя нужно сделать выборки из всех таблиц всех инстансов MySQL, на которых могут находиться данные об этом пользователе, а также перенести данные, которые хранятся в C/C++-сервисах. Причём для одного из сервисов нужно перенести сам демон, а не данные между запущенными инстансами демона в обоих дата-центрах.
    Задержка передачи данных между дата-центрами составляет около 100 мс, поэтому операции должны быть оптимизированы таким образом, чтобы данные загружались потоком, а не большим количеством мелких запросов. Во время миграции время недоступности сайта для каждого пользователя должно быть минимальным, поэтому процесс должен осуществляться для каждого пользователя по отдельности, а не большой пачкой. Время, на которое мы ориентировались — это не более 5 минут недоступности сайта для конкретного пользователя (желательно 1-2 минуты).

    План работы


    Исходя из того, что нам нужно было мигрировать 170 000 пользователей в час, и время миграции каждого пользователя должно составлять около 2-3 минут, мы рассчитали количество параллельно исполняемых потоков, которые потребуются для выполнения этих условий. Каждый поток может перенести в среднем 25 пользователей за час, поэтому общее число потоков получилось 6 800 (т.е. 170 000 / 25). На деле мы смогли ограничиться «всего лишь» 2 000 потоков, т.к. бóльшую часть времени пользователь просто «ожидает» наступления различных событий (например, MySQL-репликации между дата-центрами). Таким образом, каждый поток брал в обработку трёх пользователей одновременно и переключался между ними, когда кто-то из них переходил в состояние ожидания чего-либо.

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

    Структура и последовательность наших действий

    Подготовительные шаги
    Помечаем пользователя как «мигрируемого» в данный момент и дожидаемся окончания его обработки фоновыми скриптами, если такие есть. Этот шаг у нас занимал около минуты, в течение которой можно мигрировать другого пользователя в том же потоке.

    Миграция данных биллинга
    Во время миграции страны мы полностью отключали в ней биллинг, поэтому никаких особых действий и блокировок для этого не требовалось — данные просто переносились из одной центральной MySQL-базы в другую. К этой базе устанавливалось MySQL-подключение от каждого потока, поэтому суммарное количество подключений к базе биллинга у нас составляло более 2 000.

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

    Заливка основных данных пользователя
    В этом шаге мы формировали SQL-дамп данных каждого пользователя и применяли его на удаленной стороне. При этом старые данные в этом шаге не удалялись.

    Обновление данных в сервисе authorizer
    Сервис authorizer хранит соответствия между id пользователя и id сервера, и пока мы не обновим данные в этом сервисе, скрипты будут ходить за данными пользователя в старое место.

    Удаление данных пользователя со старого места
    Очищаем с помощью запросов DELETE FROM данные пользователя на исходном MySQL-сервере.

    Шаги по переносу данных из центральных баз
    Одна из центральных баз под красноречивым названием Misc (от англ. miscellaneous ― разное) содержит очень много различных таблиц, и для каждой из них мы делали по одному SELECT и DELETE на пользователя. Мы «выжимали» из бедной базы 40 000 SQL-запросов в секунду и держали открытыми к ней более 2 000 соединений.

    Шаги по переносу данных из сервисов
    Как правило, все данные итак содержатся в базе данных, а сервисы лишь позволяют быстро получать доступ к ним. Поэтому для большинства сервисов мы просто удаляли данные из одного места и заново наполняли их информацией из базы данных, которые уже находились в новом месте. Однако один сервис мы просто переносили целиком, а не по пользователям, потому что данные в нём хранились в единственном экземпляре.

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

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

    Перенос данных MySQL


    Как уже говорилось ранее, мы храним данные пользователей на MySQL-серверах, которых примерно по полторы сотни на каждый дата-центр. На каждом сервере находится несколько баз данных, в каждой из которых находятся тысячи таблиц (в среднем мы стараемся иметь по одной таблице на 1000 пользователей). Данные устроены таким образом, чтобы либо вообще не использовать автоинкрементные поля, или хотя бы не ссылаться на их в других таблицах. Вместо этого в качестве первичного ключа используется комбинация user_id и sequence_id, где user_id — это идентификатор пользователя, а sequence_id — это счетчик, который автоматически увеличивается и является уникальным в пределах одного сервера. Таким образом, записи про каждого пользователя могут быть свободно перемещены на другой сервер без потери ссылочной целостности и необходимости строить соответствия между значениями старых и новых автоинкрементных полей.

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

    • Идем на «сторону-приемник» и проверяем, нет ли там уже данных пользователя. Если есть, значит, заливка данных прошла успешно, но выполнение шага не было завершено корректно.
    • Если данных на удаленной стороне нет, делаем SELECT из всех нужных таблиц с фильтрацией по пользователю и формируем SQL-дамп, содержащий BEGIN в начале и COMMIT в конце.
    • Заливаем дамп через SSH на «прокси» на удаленной стороне и применяем его с помощью консольной утилиты mysql. Может так случиться, что запрос COMMIT пройдет, но ответ мы не сможем получить, например, из-за сетевых проблем. Для этого мы сперва проверяем, не залился ли дамп в предыдущей попытке. Причём в некоторых базах данных отсутствие данных для пользователя является нормальной ситуацией, и чтобы иметь возможность проверить, выполнялся ли перенос данных, мы в таких случаях добавляли INSERT в специальную таблицу, по которой при необходимости делали проверку.
    • Удаляем исходные данные с помощью DELETE FROM с теми же WHERE, которые были в SELECT-запросах. Как правило, условия WHERE содержали в себе user_id, а на части таблиц это поле не являлось частью первичного ключа в силу разнообразных причин. Там, где было возможно, индекс был добавлен. Там, где это оказалось затруднительно или нецелесообразно, при удалении данных сначала делалась выборка по user_id, а потом удаление по первичному ключу, что позволило избежать блокировок на чтение и существенно ускорить процесс.

    Если мы точно знаем, что никогда до этого не приступали к соответствующему шагу, то мы пропускаем проверку наличия данных на удаленной стороне. Это позволяет выиграть нам около секунды для каждого сервера, на который мы переносим данные (что происходит из-за задержки в 100 мс для каждого отправляемого пакета).

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

    Автоикрементные поля (auto_increment)


    В базе данных биллинга активно используются автоинкрементные поля, поэтому для них пришлось писать сложную логику «маппинга» старых id в новые.
    Сложность заключалась в том, что данные из таблиц, где в первичный ключ входит только описанный выше sequence_id, нельзя просто перенести, так как sequence_id уникален только в пределах сервера. Заменить sequence_id на NULL, вызвав тем самым генерацию нового значения автоинкремента, тоже нельзя, поскольку, во-первых, генерация sequence_id производидтся вставкой данных в одну таблицу, а полученное значение используется в другой. А во-вторых, на таблицу, использующую sequence_id, ссылаются другие таблицы. То есть необходимо получить нужное количество значений автоинкрементного поля на сервере, куда переносятся данные, заменить старые sequence_id на новые в данных пользователя и записать готовые INSERT’ы в файл, который впоследствии будет применён консольной утилитой mysql.
    Для этого мы на принимающем сервере открывали транзакцию, делали необходимое количество вставок, вызывали mysql_insert_id(), который в случае вставки нескольких строк в одной транзакции возвращает значение автоинкремента для первой строки, после чего откатывали транзакцию. При этом после отката транзакции автоинкремент будет оставаться увеличенным на число вставленных нами строк, если только не произойдёт перезагрузки сервера базы данных. Получив необходимые нам значения автоинкремента, мы формировали соответствующие запросы на вставку, в том числе в таблицу, отвечающую за генерацию автоинкремента. Но в этих запросах уже явно были указаны значения автоинкремента, чтобы заполнить дыры, образовавшиеся в нем после отката транзакции.

    Max_connections и нагрузка на MySQL

    Каждый поток создавал по одному MySQL-соединению на сервер, с которым ему приходилось иметь дело. Поэтому на всех центральных MySQL-серверах мы держали по 2 000 соединений. При большем количестве соединений MySQL начинал вести себя неадекватно, вплоть до падения (мы используем версии 5.1 и 5.5).

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

    InnoDB, MVCC и DELETE FROM: подводные камни

    Поскольку мы храним все данные в InnoDB и все перенесенные данные сразу удалялись, у нас сильно начали тормозить все скрипты, которые разгребают очереди, находящиеся в таблицах на некоторых серверах. Мы с удивлением наблюдали, как SELECT из пустой таблицы занимал минуты. MySQL purge thread не успевал очищать удаленные записи, и несмотря на то, что таблицы с очередями были пусты, в них было очень много удаленных записей, которые физически еще не были удалены и просто пропускались MySQL при выборке. Количественную характеристику длины очереди на очистку записей можно получить, набрав SHOW ENGINE INNODB STATUS и посмотрев на строчку History list length. Самое большое значение, которое мы наблюдали — несколько миллионов записей. Рекомендуем с большой осторожностью удалять много записей из InnoDB-таблиц с помощью DELETE FROM. Намного лучше этого избегать и использовать, например, TRUNCATE TABLE, если это возможно. Запросы вида TRUNCATE TABLE полностью очищают таблицу, и эти операции являются DDL, поэтому удаленные записи не складываются в undo/redo log (InnoDB не поддерживает транзакции для DDL-операций).
    Если же вам нужно после удаления всех данных с помощью DELETE FROM делать выборку из таблицы, то постарайтесь наложить на первичный ключ условие BETWEEN. Например, если вы используете auto_increment, выберите из таблицы MIN(id) и MAX(id), после чего выбирайте все записи между ними — это существенно быстрее, чем выбирать записи с каким-то лимитом или только с одним из условий вида id > N или id < N. Запросы, которые получают MIN(id) и MAX(id), будут выполняться очень долго, потому что InnoDB будет пропускать удаленные записи. Но зато запросы по диапазонам ключей будут выполнены с такой же скоростью, как и обычно — удаленные записи при таких запросах в выборку попадать не будут.

    Также мы с удивлением наблюдали много «висящих» запросов вида DELETE FROM WHERE user_id = , где у всех запросов одна и та же, и при этом в этой таблице нет индекса по user_id. Как оказалось, MySQL версии 5.1 (и в меньшей степени 5.5) обладает очень плохой масштабируемостью таких запросов, если делается FULL SCAN таблицы при удалении записей и уровне изоляции REPEATABLE READ (по умолчанию). Происходит очень высокая конкуренция блокировок за одни и те же записи, что приводит к лавинообразному росту времени обработки запроса.
    Одно из возможных решений проблемы — поставить уровень изоляции READ COMMITED для транзакции, которая удаляет данные, и тогда InnoDB не будет ставить блокировки на те строки, которые не подходят под условие WHERE. Чтобы проиллюстрировать, насколько это была серьёзная проблема, приведем скриншот, снятый во время миграции. Таблица tmp.tiw_fix на скриншоте содержит всего около 60 записей (!) и не содержит индекса по user_id.



    Распределение пользователей по потокам


    Изначально мы распределяли пользователей по потокам равномерно, без учета того, на каком сервере находится конкретный пользователь. Также в каждом потоке мы оставляем открытые подключения ко всем MySQL-серверам, с которыми нам пришлось встретиться для миграции пользователей, выделенных соответствующему потоку. В итоге мы получили еще две проблемы:
    • Когда какой-то MySQL-сервер начинал тормозить, то миграция пользователей, живущих на этом сервере, замедлялась. Поскольку все остальные потоки продолжали исполнение, они постепенно тоже доходили до пользователя, живущего на проблемном сервере. Постепенно все большее число потоков скапливалось на этом сервере, и он начинал тормозить еще сильнее. Чтобы сервер при этом не упал, мы вносили временные патчи в код прямо во время работы, с помощью различных «костылей» ограничивая нагрузку на этот сервер.
    • Поскольку мы держали открытыми MySQL-соединения в каждом из потоков ко всем нужным MySQL-серверам, мы постепенно приходили к тому, что каждый поток имел большое количество открытых подключений ко всем MySQL-серверам, и мы начинали упираться в max_connections.

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

    Продолжение следует…


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

    Юрий youROCK Насретдинов, PHP-разработчик
    Антон antonstepanenko Степаненко, Team Lead, PHP-разработчик
    Badoo
    351,00
    Big Dating
    Поделиться публикацией

    Комментарии 41

      +1
      Простите, честно не читал предыдущих статей про архитектуру Badoo, но из краткого описания, приведенного здесь, создается четкое впечатление, что большинство данных вообще никак не резервируется. Это такая специальная политика (фича) или упущение со стороны архитекторов (бага)?
        +4
        У нас есть репликация данных в MySQL — мы реплицируем все DML-запросы с одного датацентра на другой, так что у нас всегда есть «горячий бэкап» данных в MySQL. Также мы делаем полный бэкап данных раз в неделю. Про фотографии, можно, подскажет antonstepanenko
        +3
        Суммарно сколько информации (гигабайт, терабайт?) пришлось перекинуть между датацентрами?
        +2
        Сами себе придумали проблему. Почему нельзя было неделю переносить каждую ночь по 1 млн. пользователей? В худшем случае пользователь, зашедший в 05.00 увидел надпись «Сервис обновляется» на 2-3 минуты…
          +5
          Не совсем понимаю вас. Мы переносили по примерно одному миллиону пользователей в день (в это время у этих пользователей была ночь). Каждый из переносимых пользователей в течении 2-3 минут при попытке логина наблюдал надпись «Сервис недоступен».
            +1
            «Как мы мигрировали миллионные страны за рабочий день» что то здесь не так
              0
              Рабочий день — это 8 часов плюс перерыв на обед. В статье исходя из этого была приведена примерная скорость — 170 000 пользователей в час. Где вы видите несоответствие?
                +5
                Ну понятно, я подумал что вы все 7 млн. за один день перенесли
                  +2
                  Все-таки 26 Тб через Атлантику за 8 часов передать весьма проблематично :). Мы бы с радостью, конечно.
                    0
                    Несколько жестких дисков самолетом… ;)
                      +1
                      Конкорды уже не летают. А ведь надо учесть время на доставку винтов в самолёт из одного ДЦ и потом из самолёта в другой ДЦ. Не хватило бы 8 часов если бы не конрод, но см. первое предложение.
          +11
          Долго не могла понять смысл заголовка. Ребята — вы, наверное, прекрасные специалисты в своём деле, но нельзя же так коверкать русский язык. «Мигрировать» — это непереходный глагол, его нельзя использовать с существительным/местоимением в винительном падеже без предлога: невозможно кого-то мигрировать.
          Далее, страны вы никуда не перемещали, перемещали пользователей — а это совсем не одно и то же. Ну и оборот «за рабочий день» подразумевает именно один-единственный рабочий день.
          Правильным построением фразы было бы: «Как мы переносили между серверами по миллиону пользователей в день».
            +8
            Если уж быть настолько принципиальным, тогда и пользователей они не переносили из одного дата-центра в другой, а только данные, касающиеся пользователей из определенной страны. Но суть из заголовка, думаю, ясна для людей из мира ИТ, ведь у них (и у нас) свой сленг…
              –6
              1.А при чем тут сленг, если по-русски так нельзя говорить. Вообще нельзя.
              2.Суть из заголовка ясна только после прочтения статьи. То есть НЕ ясна.
              3. Если быть принципиальным как вы предлагаете, то слово миграция тут неуместно (это уже кроме того, что нарушены нормы языка), так как речь идет о переносе, а миграция — это переход
              4. Нормально и понятно — Как мы переносили с сервера на сервер по миллиону учетных записей пользователей (аккаунтов) в день.
                +1
                Да, любителям русского языка суть статьи не ясна, с этим сложно спорить. Можно ли поподробнее про п.3? Потому что педивикия сообщает: «комп., жарг. переход с одной программной платформы на другую » ru.wiktionary.org/wiki/%D0%BC%D0%B8%D0%B3%D1%80%D0%B0%D1%86%D0%B8%D1%8F
                  0
                  Да, любителям русского языка суть статьи не ясна, с этим сложно спорить.

                  Речь шла о том, что:
                  1)из заголовка не понятно о чем речь. О сути статьи речи нигде не было? Или я что-то упустил? Тогда поправьте меня (с цитатами)
                  2)еще речь шла о том, что в русском языке нельзя мигрировать кого-то или что-то. Можно мигрировать куда-то или мигрировать «С» (откуда) «НА» (куда)
                  3)по пункту 3: ну вроде же подробнее некуда — я написал, что миграция — это переход, если иметь ввиду жаргон ИТ. В приведенной вами ссылке то же самое:
                  комп., жарг. переход с одной программной платформы на другую

                  Хотя миграция — это действительно уход на другую платформу. То есть это слово в заголовке употреблено некорректно.

                    0
                    «2. Суть из заголовка ясна только после прочтения статьи» — вот здесь я грешным делом подумал, что речь идёт о сути статьи, но теперь я вижу, что ошибался. Здесь идёт речь просто у сути. Поправьте меня, если я не прав.

                    Компьютерный жаргон является частью русского языка?

                    Я как бы не спорю, с Вами в части, что Вам «Суть из заголовка ясна… То есть НЕ ясна»
                      –2
                      Есть два и более вариантов заголовка:

                      1.Как мы мигрировали миллионные страны за рабочий день (оригинальный, но некорректный)
                      2. Как мы переносили с сервера на сервер по миллиону учетных записей пользователей (аккаунтов) в день. (алтернативный)

                      1)нельзя мигрировать кого-то (это непереходный глагол).Можно мигрировать куда-то или мигрировать «С» (откуда) «НА» (куда)
                      2)из оригинального заголовка нельзя понять о чем статья
                      3)из альтернативного — можно, даже не читая статьи, так как в нем которотко изложена суть процесса
                      4)оригинальный заголовок «не дружит» с русским языком
                      5)в оригинальном заголовке некорректно употреблен термин миграция, так как это- ПЕРЕХОД, а суть статьи — ПЕРЕНОС (данных)
                      6)жаргон является частью языка, безусловно

            +2
            А расскажите пожалуйста поподробнее про существующую репликацию данных и фото между ДЦ
              +10
              Ребята, я вас люблю!

              PHP+MySQL в таком масштабе, подробнейшие образовательные проекты, статьи — спасибище!
                +3
                А вы не думали мигрировать с MySQL на MariaDB? И если нет, то чем объясняется?
                  +11
                  Думали, и пока думаем. Причины две: (1) стоимость перехода, риски и (2) неопределенность на рынке.
                  1) Badoo — проект с одним из крупнейших в мире кластеров БД — много сотен серверов. Поэтому стоимость любого проекта по миграции будет для нас очень высока.

                  2) Мы используем дистрибутив Percona. За последний год-полтора развернулась плотная борьба трех дистрибутивов MySQL. Три-четыре года назад (когда мы пересели на Percona) был вечно-тормозящий с патчами Oracle (заблудившийся в бранче 6.0, с массовым исходом окешихся и не очень сотрудников), странная Maria и слизанный с Oracle, но не тормозящий со сторонними патчами XtraDB. Теперь же многое поменялось. Сейчас мы видим, что Percona реально отстаёт. И очень хорошо набирает Oracle (я где-то читал, что у них уже работает под 200 человек над MySQL уже). У нас также есть свой патч (его сделал Костя Осипов, это фикс давнишней проблемы со вложенными пользовательскими блокировками), — этот патч, кстати, быстро приняла только Maria. Oracle и Percona тупят. То есть сигналы о том, что Maria хороша — они идут где-то последние полгода. Плюс неожиданная поддержка гигантов (вероятнее всего когда они поняли, что Oracle очень хорошо прёт). Но и Oracle не отстает. Так что скорее всего мы немного подождем, посмотрим, что происходит, как будет реагировать Percona. Для нас если уж делать переход, то года на три, а то и на пять. Очень важный шаг.
                  +1
                  > Поэтому нам приходилось ждать окончания репликации для каждого пользователя, чтобы все работало корректно и данные были согласованы между собой

                  Поделитесь плз критерием, по которому Вы определяли окончание репликации
                    0
                    Последним запросом делали вставку в таблицу User (где хранятся настройки пользователя, email, дата рождения и т.д.). Когда данные пользователя появлялись в этой таблице в удаленном ДЦ, это означало, что репликация всех остальных данных тоже закончилась (наша репликация однопоточная).
                    +1
                    Про user_id, sequence_id.

                    Решение выглядит классно, но насколько я понял, sequence_id инкрементится в пределах пользователя. В таком случае на момент вставки, необходимо знать last_sequence_id(user_id). Насколько такой способ замедляет вставку в таблицы? Много ли делаете вставок?
                      0
                      last_sequence_id отлично генерируется каким-нибудь redis с гораздо большей скоростью, чем можно вставлять в mysql
                        0
                        В таблице, отвечающей за генерацию sequence_id, первичным ключём является (`sequence_id`,`class_id`,`user_id`), причём sequence_id — это автоинкремент. Соответственно, для генерации нового sequence_id нужно просто сделать INSERT INTO… (user_id,class_id) VALUES (123, 256). class_id — это, можно сказать, тип сиквенса.
                        0
                        А сколько у Вас данных на один сервер MySQL? Интересны предельные значения, которые выдерживает MySQL. Спасибо.
                          0
                          хмм, на сайте php-fpm.org написано
                          Andrei Nigmatulin is the original author of PHP-FPM
                          почему тогда вы заявляете что это разработка badoo? :)
                            +3
                            Дада! Хотелось бы объяснений от официальных лиц компании!
                              +3
                              Посмотрите внимательно профили этих людей, о которых там говорится :).

                              Андрей Нигматулин: habrahabr.ru/users/anight/
                              Антон Довгаль: habrahabr.ru/users/tony2001/
                                0
                                1) Андрей подписан на блог Badoo (как и еще сотни человек), и я не выгуглил чтобы было явно написано что он работает на badoo (прежде чем задать вопрос я погуглил, но не долго :).
                                2) согласно вики badoo появилась в 2006-ом, а согласно about php-fpm разработка началась в 2004-ом

                                собственно поэтому вопрос и возник :)
                                  +1
                                  Если это вас убедит, то вот профиль Тони на гитхабе: github.com/tony2001.
                                  Да, оба этих человека работали в Баду с самого основания.
                                    +1
                                    Я просто оставлю это здесь — habrahabr.ru/company/badoo/questions/466/
                                      +1
                                      ну, на это я наткнулся уже после :)
                                  0
                                  Ничего удивительного, если в крупных компаниях навроде нашей могут работать core разработчики языков, которыми мы пользуемся.
                                    +8
                                    История такая:
                                    Набор патчей с подобным функционалом начал делать Владимир Вологжанин еще в Мамбе, хотя идея была Андрея.
                                    В какой-то момент Андрей это всё сам переписал и выложил под GPL.
                                    Поскольку GPL несовместима с PHP License (верней наоборот, но не суть), я уговорил Андрея поменять на что-то более permissive, немного подправил и патч предложил в PHP Core.
                                    Патч приняли и теперь оно живёт своей жизнью.

                                    Все вышеупомянутые люди (включая меня) работают в Баду и сейчас, если вам интересно.
                                      +2
                                      вопросов больше не имею. спасибо за историческую справку :)
                                        +2
                                        Я, ребят, наверное, сейчас немного нас всех подставлю, но это очень хороший кейс, самое интересное было в 2008-2009, когда проект фактически стал отходить к Майклу Шаддлу и умирать. Можете считать меня тщеславным ублюдком, мне всё равно — это просто очень хороший кейс для всех красноглазых заек. В 2009-м году если бы я вас не распинал и не выделил официально время внутри Badoo на порт fpm в ядро пхп (Антон Довгаль официально на работе имел проект номер один — перенос FPM в ядро PHP), — так вот сидели бы мы, вероятно, до сих пор с неподдерживаемым патчем, с собственным либевентом, и странным мейнтейнером микро-хостером, которому просто очень нужен process spawning. Ну и очень-очень большой вклад в проект сделал Jerom Loyet.
                                      0
                                      Вы полностью переносили данные из одной базы в другую? А бывает, наверное, когда требуется сбалансировать или перенести часть только? Боритесь ли вы как то с фрагментацией? Может быть она не столь существенна чтобы на нее обращать внимание?

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

                                      Самое читаемое