Уже несколько месяцев, как фронты Почты Mail.Ru стали 64битными. Лучше поздно, чем никогда, решили мы, и сегодня я расскажу, зачем мы это сделали, через что мы ради этого прошли и как нам это удалось.
И так работает
Долгое время наша Почта работала на 32 битах на первом Apache и Perl 5.8 под управлением CentOS 5. Идея перевести фронтенд на более современное ПО и 64-битную архитектуру бродила в наших умах давно: еще полтора года назад всего два человека — один админ и один разработчик — за какую-то неделю без сна подняли тестовый сервер, на котором крутилось наше светлое будущее. Однако в те времена у нас были более срочные задачи, и про сервер благополучно забыли. Периодически к этой идее возвращались, но все происходило в режиме «А что если так? — Ой, что-то сломалось!», — и снова все откатывалось и откладывалось в долгий ящик.
Time has come
Наконец пришло время перемен. В какой-то момент мы осознали, что дальше так продолжаться не может: полная поддержка CentOS 5 прекращается в 2014 году, Perl 5.10 на некоторых задачах показывает 30% прирост скорости, не говоря уже о том, что 32-битная архитектура в XXI веке несколько отстает от желаемого.
Кроме того, после того как мы перевели Почту на HTTPS, на фронтендовых серверах повысился load average, так что более производительный Perl стал актуальным как никогда.
Трудности перехода
Прежде всего, нам пришлось разово переписать те места кода, которые непосредственно взаимодействуют с Apache. Так как на ErrorLog Apache завязана наша система мониторинга, пришлось научить новый сервер логировать ошибки так, как нам нужно. В результате появился самописный модуль для логирования ошибок Apache 2, доступный по ссылке.
Кроме того, пришлось разбираться с зависимостями: все используемые нами пакеты исторически собирались под c5x32 архитектуру и в таком виде складывались в репозиторий. В изменившихся реалиях все, включая модули под nginx, пришлось пересобирать для c6x64.
Также был полностью переписан модуль генерации капчи.
Однако больше всего хлопот нам доставили баннеры. Вся наша верстка построена на слотах, содержимое которых, в том числе и баннеры, берется из шаблонизатора, написанного на С и глубоко интегрированного в Apache. Модуль, отвечающий за баннеры, подхватывает заголовки Apache и по ним уже таргетируется. Чтобы заставить все это взлететь под Apache 2, пришлось не только потрудится самим, но и раскачать ребят из соответствующего отдела.
Бинарные протоколы
В Почте Mail.Ru взаимодействие часто происходит через бинарные протоколы. Прежде всего, это общение с нашим хранилищем данных Tarantool. Помимо базы, даже между нашими сервисами, например, сервером на Perl и сервером на C, данные передаются в бинарном виде. Это хорошо, быстро и удобно, пока речь не заходит о смене архитектуры.
Каждый раз, когда необходимо шифровать данные или складывать по модулю, вероятность того, что результаты выполнения операции на x32 и x64 будут разными, становится ненулевой. Осложняется все тем, что эти различия проявляются только на специфических данных, так что искать, отлавливать и фиксить эти случаи — задача нетривиальная.
Например, первая строчка кода, приведенного ниже, отработает на разных архитектурах совершенно по-разному.
my $crypted_userid = $user->{'ID'} ^ 41262125215;
getpage('project_url_api?user_id='.$crypted_userid);
Эта разница поведения приводит к проблемам в совершенно неожиданных местах и даже на разных проектах. Например, новые результаты выполнения кода с айдшником пользователя приводили к тому, что благодаря нашей общей системе авторизации смена пароля одним пользователем влекла за собой разлогинивание совершенно другого пользователя из другого сервиса.
Эта же проблема с шифрованием обнаружилась и в самой Почте. После отправки письма пользователь отправляется по URL, который, среди прочего, содержит зашифрованных получателей (никто ведь не хочет, чтобы его email передавался в адресную строку в открытом виде). Что случилось после того, как мы стали формировать URL на 64-битной архитектуре, догадаться несложно: вместо списка получателей появлялся случайный набор символов.
Конечно, сейчас эти проблемы решены, но их отлавливание заняло существенное время.
Всего по два
Сам переход уложился в два месяца. До того как это произошло, около полугода наша Почта работала как на старых фронтах, так и на новых. Мы тщательно мониторили поведение этих двух систем: на нашем дашборде было два отдельных графика, по которым мы следили, где больше ошибок и что работает быстрее. С ними связана забавная история — однажды посреди ночи всех подняли на уши, потому что на графиках перфоманса у новых фронтов линии проходили выше — выходило, что они отрабатывают существенно медленнее. Потом, правда, выяснилось, что это мы настолько наоптимизировались, что шкала для новых фронтов автоматически изменилась на порядок, и на самом деле они отрабатывают в 10 раз быстрее. Тем не менее, перепугаться мы успели.
Кроме того, в условиях двух систем нельзя просто так взять и обработать реквест Apache. Приходится делать следующее:
sub GetApacheRequest {
$ENV{MOD_PERL} =~ m{mod_perl/2}? Apache2::RequestUtil->request(): Apache->request();
}
Сборка пакетов для Почты также стала пестрить условиями вида
%if 0%{?centos} == 6
…
%if 0%{?centos} == 5
…
И таких мест масса.
Помимо мониторинга и внесения изменений в две ветки сразу, нам, конечно же, приходилось тестировать новые итерации в два раза дольше, но наши тестеры справились.
Награда за труды
Итак, что же мы получили в результате этой кропотливой и иногда нервной работы?
- Полная поддержка CentOS 6 — новые патчи, актуальное состояние системы
- Быстрые регулярки в Perl 5.10. Скрипты, выполняющие анализ и парсинг, летают еще быстрее
- Apache 2 подхватывает новый конфиг и скрипты без рестарта. Выкладка кода и конфигов не приводит к 500-й ошибке (теоретически это умел и первый Apache, однако заставить его делать это нормально без отключения фронта от нагрузки — задача из области фантастики)
- Тотальный рефакторинг. Переход на новое ПО — прекрасный повод избавиться от лишних зависимостей, ненужных сущностей и неиспользуемых модулей
- Использование Puppet. Гулять так гулять, решили мы, и заодно перешли на Puppet. Теперь раскладка новых фич и деплой хотфиксов стали существенно проще.
Следовало ожидать, что переход с 32 на 64 бита пагубно скажется на потреблении памяти Apache, который и без того пытается отъесть все, что дадут. Количество памяти, выделяемой под один процесс, разумеется, выросло, от этого никуда не деться. Однако все стало работать быстрее, поэтому с задачами справляется меньшее число процессов, так что в целом затраты по памяти не выросли. Кругом профит.
Perl 5.10, кстати, дает нам дополнительное преимущество: простоту перехода на 5.16 по сравнению с мучительным переходом с 5.8.8. Так что ждите новый Perl в нашей Почте.
Если у вас появились вопросы, предлагаю обсудить их в комментариях.
Илья Зарецкий,
руководитель группы backend разработки Почты
Автор: Croston