В Badoo я работаю в команде, которая разрабатывает на PHP. Одна из фич, которой мы занимаемся, со временем начала отъедать всё больше и больше железячных ресурсов. В итоге мы едва успевали добавлять серверы под растущую нагрузку. При этом вечера, проведённые с Go дома, подсказывали, что можно сделать на порядки производительнее, не затратив на разработку много времени.

Я расскажу о том, почему наша фича так плохо ложится на PHP и хорошо – на Go, как уговорить всех всё переписать и не показаться сумасшедшим. Ну и, конечно же, как из 19 серверов оставить только 4.



Павел Мурзаков (далее – ПМ): – Меня зовут Паша Мурзаков, я работаю в Badoo. Всем спасибо, что пришли на meet-up. Сегодня будем говорить о том, как 200 строк на Go помогли нам освободить 15 серверов.

Что думают о Badoo и какова роль PHP?


Вообще, когда мы готовим доклады, мы начинаем с того, что Badoo – это большой-большой dating, что у нас много тысяч серверов и вроде highload. Думаю, здесь все об этом знают, и я хочу сменить фокус на то, чтобы рассказать немного о команде и сказать про роль Go в Badoo.



Вообще, в сообществе нас знают так: Badoo – это что-то о PHP. Ребята сидят, шпилят на PHP, потом выкладывают какие-то статьи на «Хабр» о том, как пошпилили. Иногда что-то в open source выкладывают. В общем, всё что-то о PHP…

Когда я готовился к докладу, то зашёл в нашу корпоративную директорию и написал “php” с помощью CTRL+F – получилось 62 результата. Хотел показать, что, если написать “go”, получится 0, но что-то пошло не так:



Надо было писать “golang”, как это обычно бывает.

Вообще, это правда, что PHP в «Баду» очень распространён. Больше всего девелоперов пишет именно на PHP. У нас есть четыре больших отдела, которые пишут только на PHP. Я, например, тимлид в отдел Features – мы тоже пишем только на PHP, решая на самом деле много интересных задач, порой сложных: когда у тебя много клиентов, разные версии, надо поддерживать «Андроид», iOS, мобильный веб, веб, и ещё все эти данные гонять между дата-центрами, и вообще highload…



…каждый запрос, отосланный в MySQL или MemCache, можно случайно завалить, если сделать что-то не так. Поэтому нужно вопросов надо решить. Вопрос о выборе языка перед всеми этими людьми в принципе не стоит:



Это команда PHP в «Баду». Вы спросите: «Какова роль Go в «Баду» и каково его место»?

Go в Badoo


Видите белый пробел (на предыдущем слайде справа)? Это место Go в «Баду» по состоянию на 2012 год. В 2014-м силами этих трёх бойцов (Марко Кевац, Андрей Нигматуллин и Дмитрий Новиков).



написан первый daemon на Go. Они выложили его в продакшн. Об этом рассказывал Тоха Поваров у нас на «кухне», на точь-в-точь таком же митапе два года назад. Тогда был Go 1.3 или 1.4. Ребята написали демона, который хранит уйму объектов в памяти (просто какое-то нереальное количество памяти было занято).

Все помнят истории про Garbage Collector: как пауза там была 30 секунд и всё такое. Доклад очень интересный – всем советую посмотреть.

Потом тот же Тоха Поваров и Саша Холодов написали несколько других сервисов на Go:



В итоге стало как-то так:



Эти 5 человек – из отдела «Си». В принципе, только они и писали что-то на Go. Но у нас в компании принят прагматичный подход – ориентированность на результат. Поэтому не важно, откуда ты: если ты знаешь, как сделать что-то эффективнее, сэкономить, то – welcome!

К тому же это ж си-шники, а не go-шники! Но пишут на Go. Почему бы PHP-шникам не начать, кстати?.. Попробую ответить на этот вопрос.

Содержание доклада


  • Я расскажу о задаче, которую мы решали.
  • Расскажу про реализацию на PHP и что в ней не так.
  • Как был создан прототип на Go и что с этим получилось.

Задача


Кто-нибудь из зала когда-нибудь пользовался Badoo? Поднимите, пожалуйста, руки… Отстой, мало! Всем установить «Баду», посмотреть. На первый раз прощаю. Расскажу немного о том, как он работает.

Как я уже сказал, мы – dating. Очень многое у нас крутится вокруг профайлов:



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



Продуктовый смысл, думаю, всем более-менее понятен. Ты смотришь на профайл: видишь, что это не какие-то маньяки-педофилы, а тут вообще твои друзья (на «Баду») и можно этой компании можно доверять…

Из зала: – Вот жена! =)

ПМ: – Вообще, это повышает вовлечённость пользователей: они начинают больше кликать, больше проводить времени, совершать больше действий. И одна из самых важных составляющих – это, что мы можем сподвигнуть пользователя на приглашение других. Мы говорим: «Этот человек ещё не на «Баду», пригласи его».

Я хочу, чтобы вы часть слева «забыли» (friends). Сегодня нас будет интересовать то, что называется in common:



Блок Friends


  • Основан на друзьях из «Фейсбука».
  • Мы там показываем общих друзей (сегодня нас интересуют только общие).
  • Особенно интересные те, кто на «Баду» не зарегистрирован.

Что такое общие друзья, думаю, понятно. На всякий случай быстренько пройдёмся:



Мы – пользователь А, у нас есть друзья Х и Y. Смотрим на пользователя B: у него есть друзья Z и Y. Y – общий друг. Выглядит всё просто, детский сад. Как реализовать:



  1. Скачиваем заранее из «Фейсбука» список друзей A;
  2. Скачиваем из «Фейсбука» список друзей B;
  3. Когда смотрим на них – пересекаем списки и получаем Y;
  4. Всё отлично – расходимся!

Обновление API (v2.0) «Фейсбука»


Так и работало до того момента, когда «Фейсбук» обновил свой API на версию 2.0:



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

Раньше, когда мы просили у «Фейсбука» друзей, он возвращал нам тех, кого я называю зарегистрированными: когда человек кликает «Авторизоваться через Facebook», у него спрашивается, даёт ли он доступ к «Фейсбуку»; если дал – мы начинаем считать зарегистрированным через наше приложение.

Мы также могли получить и тех, кто не зарегистрирован.: ели мы просим друзей у какого-нибудь пользователя, мы получаем даже тех, кто вообще ничего о «Баду» не знает. Было отличное время, но потом всё стало хуже…



Реализация № 1 (крах)


«Фейсбук» начал заботиться о приватности и стал выдавать на запросы друзьями только зарегистрированных пользователей. Чтобы это как-то компенсировать, он добавил новый endpoint, который возвращал только общих друзей между двумя.

Это в принципе то, что нам нужно – общие друзья. Он возвращал как зарегистрированных, так и незарегистрированных. Но проблема в том, что нам для получения этого нужно два Facebook id.
Если взять нашу базу, в которой 300 миллионов [пользователей]: чтобы предварительно получить все пересечения, нам нужно сделать 3002 млн запросов, что не очень реалистично. Потом ещё и поддерживать это в актуальном состоянии. Поэтому надо получать друзей в онлайне.

Реализация № 2


Окей. Что надо получать – мы получаем. Скачиваем зарегистрированных (так же, как и было). Потом, когда клиент делает запрос на профайл, мы делаем запрос в «Фейсбук» за общими друзьями.

Есть диаграммка (детский сад, но уже второй курс):



Клиент делает запрос к нам в PHP. Мы готовим профайл. Делаем запрос в «Фейсбук». С результатом возвращаемся. Никаких проблем нет, но вот так «Фейсбук» отвечал нам в последнюю неделю:



Это время ответа. Можно заметить, что он сильно разнится. Грубо говоря, это 1 секунда. Это полный провал, потому что пользователь будет видеть что-то такое:



Эта реализация нам не подходит – надо что-то менять, потому что наши пользователи в игре «Да-нет» могут проголосовать за 3 профайла за секунду. Скажем так, они очень «скиловые» парни…
Проблема ясна. Решение суперпростое.

Реализация № 3


Мы просто делаем запрос в «Фейсбук» не в этом же запросе на профайл, а в отдельном:



Клиент говорит: дай мне профайл без друзей. Потом говорит: дай мне просто друзей. И в момент, когда профайл полностью получен, мы лезем в «Фейсбук» и отдаём его:



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



PHP


Есть ли в зале кто-то, кто пишет на PHP? Я видел на Mac’ах, что у кого-то «Шторм» открыт, так что давайте честно. А есть те, кто реально любит PHP?



Мы в Badoo очень любим PHP. У нас много инструментов написано под него. Мы знаем, как его готовить, что в нём хорошего и что плохого. Я расскажу, как работает PHP-FPM.

Образно его паттерн работы можно назвать thread pool, но на самом деле у него не треды, а процессы:



Есть Master process, который спаунит n child’ов. Каждый child обрабатывает в единицу времени только одного клиента. Можно видеть, что child’ы 1 и 2 заняты, остальные свободны – если какой-то клиент придёт, он может их обработать. Теперь попробуем это знание положить на нашу последнюю реализацию.

Реализация № 3. PHP-FPM


Представим, что у нас есть 100 таких child’ов на каждый сервер. Имеется 100 серверов, то есть всего на кластер у нас 10 000 child’ов. Представим, что у нас нагрузка 1000 requests/сек.

И в какой-то момент «Фейсбук» начинает тупить – отвечает за 10 секунд. Тогда мы получим, что у нас через 10 секунд все 10 тысяч воркеров будут чем-то заняты.



Внимательный слушатель скажет: что такое 100 воркеров? Валюта? Почему не наспаунить 300 или 7300 воркеров?

Наспаунить-то можно, но вопрос в том, что у нас в основном на кластере CPU-bound нагрузка. Это означает, что нам нужно какие-то более мощные серверы ставить или больше серверов в кластер. Память и Context Switch’es тоже играют роль. А самое главное, всё это умножается тем, что «Фейсбук» отвечает не столько медленно, сколько непредсказуемо медленно.

Тот же график показываю:



Он отвечает секунду за последнюю неделю, но в течение каких-то пары часов начала отвечать за 3 секунды. И вообще, легко может быть такое, что он отвечает за 10 секунд. И поскольку это сеть, мы через половину глобуса ходим в «Фейсбук» за ответом – это может быть вообще что угодно, сколько угодно секунд.

Поэтому вопрос в том, что нам нужно всегда перезакладываться, если мы хотим полностью обеспечить ресурсоёмкость кластера. Получится так, что мы в 10 раз кластер увеличили. При этом основное время используется только 10 % ресурсов. И это всё ради того, чтобы, когда «Фейсбук» тупит 10 минут, мы смогли бы справиться.

Это звучит как-то нерационально. Мы сделали вывод, что так делать не надо:



Badoo существует уже 10 лет. С такой проблемой столкнулись не вчера, не месяц назад и не год назад.

Продолжение будет совсем скоро…


Немного рекламы :)


Спасибо, что остаётесь с нами. Вам нравятся наши статьи? Хотите видеть больше интересных материалов? Поддержите нас, оформив заказ или порекомендовав знакомым, облачные VPS для разработчиков от $4.99, уникальный аналог entry-level серверов, который был придуман нами для Вас: Вся правда о VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps от $19 или как правильно делить сервер? (доступны варианты с RAID1 и RAID10, до 24 ядер и до 40GB DDR4).

Dell R730xd в 2 раза дешевле в дата-центре Equinix Tier IV в Амстердаме? Только у нас 2 х Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 ТВ от $199 в Нидерландах! Dell R420 — 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB — от $99! Читайте о том Как построить инфраструктуру корп. класса c применением серверов Dell R730xd Е5-2650 v4 стоимостью 9000 евро за копейки?