Привет!
На 2020 год у нас большие планы. Мы намерены активно развивать Badoo и Bumble, поэтому серьёзно расширяем техническую команду. И сегодня мы объявляем о масштабном найме PHP-разработчиков в наш лондонский офис.
В 2017 году мы попробовали новый формат поиска — hiring event: привозим в Москву крутых разработчиков, за один день проводим собеседования и сразу же делаем оффер подходящим кандидатам. Все расходы на поездку в столицу, разумеется, берём на себя.
Формат хорошо себя зарекомендовал, и у нас снова открыто много позиций, поэтому мы объявляем новый PHP Hiring Event.
Правила те же: покажи высокий результат в тесте до 1 марта, успешно пройди интервью 21 или 22 марта в Москве — и в тот же день получи оффер в лондонский офис Badoo.
Под катом я расскажу:
- подробнее про тест;
- какими проектами мы занимаемся: оптимизация фотографий, видеостриминг, machine learning для писем, переход на новые версии PHP и многое другое.
Если ты PHP-шник и хочешь переехать в Лондон, добро пожаловать под кат!
Как пройти тест
Тест состоит из пяти задач. На решение отводится ровно 90 минут: отложить или поставить процесс на паузу не получится. Прежде чем начинать, убедись, что у тебя достаточно времени.
В трёх задачах нужно написать код/SQL-запросы, а в оставшихся двух мы ожидаем увидеть развёрнутые ответы на вопросы. Тест опубликован на HackerRank. Рекомендуем попрактиковаться на тестовых задачах платформы, чтобы освоиться с интерфейсом.
Решения принимаем до 2020-03-01 23:59:59 UTC. По результатам тестирования мы отберём примерно 60 кандидатов, которых пригласим в Москву на собеседование.
Все расходы на поездку в Москву компания берёт на себя, равно как и расходы, связанные с переездом в Лондон. Мы помогаем получить рабочие визы членам семьи нашего нового коллеги, оплачиваем перелёт, аренду жилья на время поиска, выплачиваем денежный бонус на переезд и помогаем в совершенствовании английского. Познакомиться с командой вы сможете уже на этапе собеседования: интервью на hiring event проводят сами разработчики.
Чем занимается команда серверной разработки
Мы отвечаем за бэкенд dating-сервисов Badoo и Bumble. Помимо свайпа влево-вправо для поиска партнёра, в приложениях есть видеостриминг, чат с аудиосообщениями, поиск людей рядом, поиск похожих пользователей, интеграция с платёжными сервисами и многое другое. За относительно простым интерфейсом скрывается много логики на PHP и Go (и его становится всё больше).
В нашей команде больше 40 человек. Работу можно условно разделить на две большие части:
- новая функциональность в приложениях,
- технические проекты — улучшение инструментов, оптимизация, работа с техническим долгом.
Я расскажу о самых интересных проектах, которые мы реализовали за последние два года.
Крутые фишки в продукте
Рынок приложений для знакомств динамичный и конкурентный, поэтому наша главная цель — это развитие продукта: он должен оставаться интересным и безопасным для пользователей.
Научились скрывать слишком «личные» фотографии
Некоторые пользователи отправляют в чат фотографии эротического характера, даже если собеседник о таких подарках не просил.
Задача, которую нам предстояло решить, — научить приложение отличать «приватные» фотографии (18+) от обычных и показывать их в чате заблюренными, давая возможность получателю самому решить, хочет ли он увидеть их целиком.
Вместе с командой R&D мы создали сервис на Go с нейросетью, которая умеет распознавать «приватные» фотки. Если вероятность того, что фотография эротическая, выше установленного порога, в сообщение ставится специальный флаг и клиент соответствующим образом обрабатывает эту ситуацию: показывает размытую заглушку с вопросом, хочет ли получатель посмотреть, что внутри.
Все задачи мы прогоняем через A/B-тесты, а также тщательно покрываем статистикой ключевые точки новой функциональности. Так, мы выяснили, что за день «приватных» фотографий отправляется около 200 000. А ещё — что часто эти фотографии все-таки смотрят и не жалуются на отправителя.
Добавили аудио- и видеосообщения в чате
За последние два года мы подтянулись по фичам к передовым мессенджерам и дали юзерам возможность обмениваться мультимедийными сообщениями. Внедрение этой опции со стороны сервера было достаточно простым благодаря гибкой архитектуре мобильного API и собственной CDN.
Проектируя мультимедиа-сообщения в чате, мы перенесли загрузку файлов из основного клиент-серверного API в отдельные HTTP-сервисы, расположенные внутри CDN. Мы используем единый репозиторий, поэтому с точки зрения поддержки кода такое решение никаких проблем не доставило. Зато дало возможность использовать оптимизированные под характер нагрузки инструменты:
- мобильный API (бинарный протокол) заточен под обмен короткими командами и в пике пропускает через себя более 100 000 запросов в секунду;
- CDN заточена под работу с мультимедиа и способна отдавать 200 000 фотографий в секунду (об оптимизациях CDN мы подробно рассказывали на конференции Uptime day).
С точки зрения CDN тип загружаемого файла не имеет большого значения, да и конвертация видео у нас уже была. Нам оставалось только правильно обработать новые типы (аудио и видео) в протоколе мобильного API.
Научились строить ML-модели без R&D
В 2018 году мы создали собственный фреймворк автоматизации обучения моделей на наших данных. Теперь любой разработчик бэкенда может самостоятельно построить модель, заточенную под его прикладную задачу, не привлекая коллег из R&D.
Этот фреймворк умеет собирать сотни метрик, как универсальных (пол, возраст, активность в приложении), так и специфических, значимых для каждой конкретной модели. Алгоритмы построения ML-моделей гибко конфигурируются, а для аналитики «из коробки» доступны графики полученных результатов. На выходе фреймворк предоставляет работающую модель, которая отвечает достаточно быстро (в пределах 10—100 мс) для того, чтобы её можно было вызывать из PHP прямо в запросах пользователей без ущерба для UX.
В прошлом году мы интегрировали фреймворк в различные части нашего приложения: антиспам-системы, выставление оценки приложению и некоторые другие. Mail ML — одно из самых успешных применений: модель предсказывает вероятность клика по ссылке в email для конкретного пользователя. Модель учится на данных других пользователей, похожих на получателя email «важными» признаками, причём «важность» рассчитывается фреймворком автоматически.
Оценив результаты, мы перестали отправлять письма, вероятность клика по ссылкам в которых наименьшая. Благодаря этому мы:
- повысили лояльность пользователей, что выразилось в улучшении метрик активности в сервисе: люди не любят «безнадёжные» письма;
- повысили inbox rate в ключевых почтовиках: почтовые сервисы любят отправителей с высоким CTR.
Запустили видеостриминг
Мы всегда ищем новые возможности для развития. Когда видеостриминг начал набирать обороты, мы решили интегрировать его в наше приложение. Предсказать успешность проекта было непросто, так что для снижения затрат мы не стали окунаться с головой в разработку своего решения, а нашли компанию, предоставляющую платформу и SDK с нужным нам функционалом.
От нас требовалось построить логику фичи, взаимодействие клиента и сервера, реализовать опции отправки и оплаты подарков, обеспечить быструю модерацию контента (как самого видеопотока, так и комментариев) и покрыть всё метриками. Мы собрали кросс-функциональную команду из разных департаментов и отделов: клиентская разработка, серверная разработка, биллинг, платформа, бэк-офис, BI-аналитика, дизайн и продакт-менеджмент. Все разместились в одном офисном пространстве — и закипела работа.
Мы определили функциональность первой версии (MVP) — и уже через месяц запускали фичу в одной стране за другой. В течение нескольких недель мы выкатывали её в разных странах, и сегодня видеостриминг доступен везде.
Транслировали сообщения пользователей на Арбате
Это была очень необычная промоакция: весь октябрь пользователи Badoo отправляли сообщения на огромный видеобилборд, расположенный на Новом Арбате в Москве. За месяц нам отправили 23 000 сообщений, из которых 12 000 успешно прошли модерацию и попали на экран.
Билборд — это такой умный телевизор с браузером и нашим JavaScript-клиентом внутри. На экране показывались пятиминутные рекламные ролики, в каждом из которых три минуты были отданы нам.
Конечно, всем пользователям хотелось своими глазами увидеть отправленное сообщение на экране. Чтобы это стало возможным, нам нужно было ответить на вопрос, когда каждое из сообщений там появляется.
Сообщить время показа пользователю мы должны были после модерации. Технически в этот момент сообщение попадало в наше внутреннее расписание с чётким временем начала показа и длительностью, которая вычислялась динамически: от 30 секунд до пяти минут (в зависимости от количества отправителей).
Сложность заключалась в том, что провайдер со своей стороны не предоставлял возможности контролировать и отслеживать время показа рекламного ролика, соответственно, нужно было хитро синхронизировать наше расписание с расписанием провайдера, постоянно мониторить и подстраиваться в случае необходимости. Нам помогло то, что мы заметили (логирование — наше всё!), что за несколько десятков секунд до показа очередного ролика умный телевизор перезагружает страницу. Ориентироваться на это время было нельзя, но по нему можно было заметить сдвиги расписания, которые иногда достигали 15–30 секунд. Мы настроили мониторинг сдвигов на своей стороне и в моменты срабатывания начали запрашивать время ближайшего показа у провайдера.
В процессе наладки этой системы наш инженер, работавший из кафе напротив билборда, съел внушительное количество круассанов и выпил много чашек кофе, но благодаря ему трансляция сообщений пользователей шла гладко и обошлось без серьёзных инцидентов.
Технические проекты
Несмотря на большой объём продуктовой работы, мы много времени уделяем техническим проектам. Большая их часть касается производительности наших приложений, а также разработки и улучшения внутренних инструментов.
Open-source-проект Liveprof
У нас давно была возможность включать XHProf на продакшене для конкретного запроса, но этого не всегда достаточно. Запросы бывают разные, а для системной работы над производительностью хочется видеть общую картину по всем запросам. Поэтому родилась такая идея: запускать XHProf автоматически на небольшой части запросов, а результаты агрегировать. Так появился проект Liveprof, который мы выложили в открытый доступ.
В процессе обработки запроса есть логика, которая на основе вероятностей и метода API решает, надо ли запускать XHProf. Результаты профилирования пишутся на диск, а потом доставляются на отдельный сервер, где в сыром виде кладутся в MySQL.
Раз в сутки запускается скрипт, который агрегирует результаты по каждому бренду, платформе и методу API. Таким образом, мы можем посмотреть результаты профилирования по конкретным запросам от Badoo iOS (как в виде дерева, так и в виде flame graph), можем посмотреть, какой процент кластера занимает вызов отдельно взятой функции (например, сколько стоит собрать URL для фотографии), а недавно добавили вывод этой информации прямо в PhpStorm.
Переход на PHP 7.4
Новые версии PHP радуют улучшением производительности. За последние два перехода (с 7.0 на 7.2 и c 7.2 на 7.4) отвечал наш департамент.
Переход начинается задолго до официального релиза. Сначала мы вручную запускаем тесты с новой версией и… сталкиваемся с огромным количеством проблем. Часть из них легко решается, на решение других требуется некоторое время.
Когда большая часть проблем решена, мы переключаемся на новую версию в девел-окружении, некоторое время следим за error logs и собираем фидбэк от разработчиков и QA-инженеров. К моменту официального релиза стабильной версии мы готовы тестировать на продакшене: сначала запускаем на одной машине и постепенно раскладываем на остальные.
Но после того как новая версия разложена на все серверы, переход не заканчивается: мы продолжаем проверять синтаксис обеими версиями PHP (новой и предыдущей). Таким образом мы убеждаемся, что разработчики не начали использовать новый синтаксис и мы в любой момент можем переключиться на старую версию, если в новой всплывут неожиданные проблемы. Например, перед новогодними праздниками мы обнаружили небольшую проблему с утечкой памяти в PHP 7.4, решили не рисковать и перед каникулами вернулись на предыдущую версию. После праздников, разобравшись с проблемой, мы снова раскатили версию 7.4 и до сих пор используем её.
Агрегация реквестов на Go
Обновлением PHP наша борьба за производительность не заканчивается. У нас мощный фреймворк, который на старте делает много работы: от инициализации до различных необходимых каждому запросу проверок.
Мы решили провести простой эксперимент. Выделили часть команд, для которых ответ сервера не критичен (например, отправка статистики от клиента или выбор варианта «Нет» в свайп-игре), и написали сервис на Go, который принимает такие запросы, копит их, а потом пачкой присылает на сервер (для каждого пользователя). Таким образом мы можем очень легко экономить на инициализации приложения без переписывания основного кода.
Эксперимент получился удачным: по нашим оценкам, мы можем сэкономить несколько процентов CPU (что в нашем случае — больше десяти серверов) без переписывания основного кода, но ценой усложнения эксплуатации и логики работы. Для полноты картины мы решили подождать результатов экспериментов с PHP 7.4 preload и RoadRunner, чтобы выбрать оптимальное решение по соотношению выигрыша и сложности внедрения.
Оптимизация фотографий
От некоторых технических проектов напрямую зависит активность пользователей. Например, чем быстрее мы показываем фотографии, тем активнее люди свайпают, тем больше случается мэтчей, тем больше образуется новых пар и так далее.
В октябре 2018 года один из наших брендов, Bumble, решил выйти на рынок Индии. Так как мы ничего не знали про скорость местного интернета, мы решили провести ряд экспериментов с качеством и размером фотографий.
Все технические эксперименты мы запускаем под A/B тестами. Это позволяет увидеть не только разницу в поведении и активности разных групп, но и статистику по работе приложения на клиенте с разбивкой по вариантам. Нас интересовало время на скачивание картинки и время на декодирование и отображение.
Инфраструктурно, помимо серверов-хранилищ, мы выделяем кластер фотокешей — это серверы, на которых хранятся наиболее часто используемые картинки. Так как в мире существует огромное количество смартфонов с разными экранами, мы храним фотографии в нескольких базовых размерах и конвертируем их на лету в запрошенные клиентом размер и формат.
Задача, которую мы хотели решить: выбрать оптимальные формат (JPEG, WebP, PJPEG), размер и качество изображений. В теории лучшим должен быть формат WebP, но он самый дорогой в плане конвертации на лету: вместо сэкономленного трафика нужно покупать больше фотокеш-серверов. Вместе с этим мы решили проверить, как CDN в регионе помогут улучшить UX.
Для запуска проекта в Индии туда были направлены несколько наших инженеров. Так что у нас были не только сухие цифры, но и люди, которые на месте могли тестировать приложение на разных операторах, сравнивать его работу с работой других приложений и так далее.
Результаты экспериментов позволили нам подобрать оптимальные варианты качества и размера фотографий. Например, мы увидели, что большую роль в активности пользователей играет логика предзагрузки фотографий на клиенте. И несмотря на то, что фотографии в WebP скачиваются быстрее, положительный эффект был заметен только в мобильных браузерах. Та же история и с CDN: мы протестировали три внешних CDN-сервиса и, несмотря на ускорение доставки контента, не увидели никаких положительных изменений в активности. В результате мы включили WebP для мобильных браузеров и сэкономили на мощностях, оставив всех остальных клиентов на формате JPEG.
Собственный видеостриминг
Как я упоминал выше, первая версия видеостриминга была запущена с использованием внешнего сервиса. Эксперимент был признан удачным — и мы начали готовить софт и инфраструктуру для запуска в наших дата-центрах.
С помощью готовых транскодер- (для пережатия видеопотока от пользователя) и Edge-серверов (для раздачи потока пользователю) нам предстояло собрать систему, аналогичную внешнему коробочному решению. И, конечно, многое пришлось дорабатывать «напильником» на ходу.
Например, изначально каждый Edge-сервер соединялся с каждым транскодер-сервером, что осложняло масштабирование и увеличивало внутренний трафик. Мы написали балансировку клиентов таким образом, чтобы клиенты одного стрима ходили в наименьшее количество Edge-серверов, учитывая популярность каждого конкретного стрима.
Другой пример, когда нам пришлось проявить смекалку, — логика смены качества стрима в WebRTC: из-за того, что мы используем два варианта качества, стандартному алгоритму сносило голову и он работал только в сторону уменьшения битрейта. Пришлось залезть глубже и править алгоритм, используемый внутри библиотеки WebRTC.
Кроме того, сигналинг WebRTC по умолчанию передавал клиенту слишком много информации о хостах в сети. Решением стал прокси-сервер на Go, который отдаёт клиенту только то, что ему нужно знать, и вдобавок собирает много полезной информации о подключённых клиентах.
От начала исследований до полного внедрения реализация проекта заняла более полугода, но в результате нам удалось существенно сократить расходы, отказавшись от внешнего сервиса.
Оптимизация производительности
Это не разовый проект для нашей команды — это важное направление, которому мы тоже уделяем много внимания. Наш основной кластер, обслуживающий запросы от приложений, состоит из сотен серверов, и поэтому нам выгодно инвестировать время в работу по оптимизации приложения: каждый выигранный процент стоит нам нескольких физических серверов.
Мы постоянно мониторим суммарную нагрузку на нашем кластере и нагрузку по каждому конкретному вызову API. При превышении определённого порога мы приступаем к поиску и оптимизации узких мест. Чем больше превышение, тем больше людей включаются в работу. Такой подход вполне оправдан: в последние два года темп роста кластера в два раза ниже темпа роста аудитории наших сервисов.
Мы активно делимся знаниями, полученными в ходе работы по оптимизации, на конференциях и митапах. Более детально о наших проектах и исследованиях можно узнать из статей и докладов Паши Мурзакова:
- «Производительность PHP: планируем, профилируем, оптимизируем»
- «Боремся с shared-nothing моделью: PHP 7.4 preload, RoadRunner и другие»
- «Как 200 строк на Go помогли нам освободить 15 серверов»
Контроль над старым и неиспользуемым кодом
У нас достаточно интенсивная разработка, и темпы запуска продуктовых задач и экспериментов по мере роста компании тоже растут. В таких условиях кодовая база становится более сложной и менее контролируемой. Ситуацию усугубляют несколько платформ и пользователи со старыми версиями приложений и операционных систем.
Мы стараемся держать «в чистоте» нашу кодовую базу, чтобы поддерживать высокий темп работы:
- автоматически создаём задачи на удаление кода после завершения продуктового эксперимента;
- автоматизировали слежение за старыми версиями приложений и операционных систем и использующимися в них ветками кода;
- внедрили инструменты автоматического поиска неиспользуемого кода.
Подробнее о наших результатах можно будет узнать на Badoo PHP Meetup, который пройдёт в эту субботу, 15 февраля.
Конечно, это не все проекты, о которых хочется рассказать. За последние два года мы боролись со спамерами и грубиянами, пилили свой плагин для PhpStorm, тестировали различные KV-хранилища (и выбрали Aerospike), много экспериментировали, делились знаниями в статьях, на конференциях и не только.
Но если вы решили, что мы только работаем, то это не так. У каждой команды есть свой бюджет на тимбилдинги. Наши коллеги побывали в Амстердаме, Эдинбурге, Праге и других городах. А в прошлом году мы устроили общий слёт департамента в Хорватии:
А ещё мы умеем фотошопить
О переезде в Лондон и офисе в Сохо мы уже рассказывали, поэтому не будем останавливаться на деталях в этой статье — просто покажем пару фоток.
Hiring event — самый простой и быстрый способ присоединиться к нашей команде. Мы принимаем ответы на тест до 1 марта включительно. Потом мы возьмём неделю на разбор результатов и обзвон тех, кто справился с заданиями.
Если хочешь попасть к нам на работу в Лондон, но не хочешь проходить тест, есть и другой вариант: просто откликайся на вакансии на нашем сайте, эта возможность всегда доступна.
Если остались вопросы, смело задавай их в комментариях или присылай мне в личные сообщения.
Удачи!
Автор: AHDREN