Upload
avitotech
View
43
Download
1
Embed Size (px)
Citation preview
Badoo — это
✦ 320 млн пользователей
✦ 400 тыс регистраций каждый день
✦ ~3000 серверов
✦ 70 тыс клиентских запросов на бэкенды в секунду
✦ 4 больших отдела: Features, Billing, Back Office, Platform
✦ В каждом по ~10-25 человек (разделены на команды)
✦ Вопроса о выборе языка не встаёт (есть куча других важных проблем!)
PHP в Badoo
Блок Friends
✦ Основан на друзьях из Facebook
✦ Общие друзья
✦ Особенно интересны не зарегистрированные на Badoo
Реализация #1
✦ Заранее скачиваем с FB друзей текущего пользователя
✦ Заранее скачиваем с FB друзей просматриваемого пользователя
A X Y BZ Y
Реализация #1
✦ Заранее скачиваем с FB друзей текущего пользователя
✦ Заранее скачиваем с FB друзей просматриваемого пользователя
✦ Пересекаем списки в момент показа
A X Y BZ Y
Реализация #1
✦ Заранее скачиваем с FB друзей текущего пользователя
✦ Заранее скачиваем с FB друзей просматриваемого пользователя
✦ Пересекаем списки в момент показа
✦ PROFIT!!!!
A X Y BZ Y
Апдейт FB API v2.0Было
Friends endpoint
* Зарегистрированные (дали доступ Badoo на FB) * Незарегистрированные
Апдейт FB API v2.0Было Стало
Friends endpoint
* Зарегистрированные * Незарегистрированные
Friends endpoint
* Только зарегистрированные
Апдейт FB API v2.0Было Стало
Friends endpoint
* Зарегистрированные * Незарегистрированные
All Mutual Friends endpoint
* Зарегистрированные * Незарегистрированные * Нужно 2 fb_id
Friends endpoint
* Только зарегистрированные
Реализация #1 — крах
✦ Предварительно скачать всех друзей мы не можем
✦ => Надо получать общих друзей в онлайне
Реализация #2
✦ Предварительно скачиваем списки зарегистрированных друзей
✦ В клиентском запросе на профайл делаем HTTP-запрос в Facebook за общими друзьями
Реализация #2
✦ Предварительно скачиваем списки зарегистрированных друзей
✦ В клиентском запросе на профайл делаем HTTP-запрос в Facebook за общими друзьями
Мы не можем ждать 1с на отрисовку профиля!
Реализация #3
✦ Предварительно скачиваем списки зарегистрированных друзей
✦ В клиентском запросе на профайл отдельном асинхронном запросе делаем HTTP-запрос в Facebook за общими друзьями
PHP-FPMMaster process
Child process 1
Child process 2
Child process 3
Child process 4
Child process N
Client 1
Client 2
✦ 100 воркеров PHP-FPM на сервер
✦ 100 серверов
✦ => 100 * 100 = 10 000 воркеров
✦ нагрузка 1 000 rps
Реализация #3
✦ 100 воркеров PHP-FPM на сервер
✦ 100 серверов
✦ => 100 * 100 = 10 000 воркеров
✦ нагрузка 1 000 rps
✦ FB “подтупляет" и начинает отвечать по 10 сек
Реализация #3
✦ 100 воркеров PHP-FPM на сервер
✦ 100 серверов
✦ => 100 * 100 = 10 000 воркеров
✦ нагрузка 1 000 rps
✦ FB “подтупляет" и начинает отвечать по 10 сек
✦ через 10 сек 1 000 * 10 = 10 000 => все воркеры будут заняты
Реализация #3
✦ CPU-bound нагрузка (обычно)
✦ Память
✦ Context Switch’es
✦ Непредсказуемость времени ответа от Facebook (нужно “перезакладываться” в десятки раз)
Воркеры — ограничения
✦ Предварительно скачиваем списки зарегистрированных друзей
✦ В клиентском запросе на профайл отдельном запросе делаем HTTP-запрос в Facebook за общими друзьями
Мы не можем себе позволить долгие запросы!(вообще)
Реализация #3
Реализация #4
✦ В коротком клиентском запросе запускаем скрипт в PHProxyd
✦ Клиент перепроверяет (поллит) результаты
Реализация #4
✦ В коротком клиентском запросе запускаем скрипт в PHProxyd
✦ Клиент перепроверяет (поллит) результаты
✦ В скрипте в PHProxyd делаем HTTP-запрос к FB + небольшая бизнес логика
Реализация #4
✦ В коротком клиентском запросе запускаем скрипт в PHProxyd
✦ Клиент перепроверяет (поллит) результаты
✦ В скрипте в PHProxyd делаем HTTP-запрос к FB + небольшая бизнес логика
Теперь точно PROFIT!!!!!!!
PHProxyd — замена
✦ Создание воркера на новый запрос (phproxyd)
✦ Преподготовить заранее кучу воркеров (php-fpm)
PHProxyd — замена
✦ Создание воркера на новый запрос (phproxyd)
✦ Преподготовить заранее кучу воркеров (php-fpm)
Не работает
PHProxyd — замена
✦ Создание воркера на новый запрос (phproxyd)
✦ Преподготовить заранее кучу воркеров (php-fpm)
✦ Что-то асинхронное (nodejs, React PHP)
PHProxyd — замена
✦ Создание воркера на новый запрос (phproxyd)
✦ Преподготовить заранее кучу воркеров (php-fpm)
✦ Что-то асинхронное (nodejs, React PHP)
Мы любим PHP…
PHProxyd — замена
✦ Создание воркера на новый запрос (phproxyd)
✦ Преподготовить заранее кучу воркеров (php-fpm)
✦ Что-то асинхронное (nodejs, React PHP)
… но НЕТ!
Мы любим PHP…
PHProxyd — замена
✦ Создание воркера на новый запрос (phproxyd)
✦ Преподготовить заранее кучу воркеров (php-fpm)
✦ Что-то асинхронное (nodejs, React PHP)
✦ Go = пишешь “синхронный” код, работает асинхронно
PHProxyd — замена
✦ Создание воркера на новый запрос (phproxyd)
✦ Преподготовить заранее кучу воркеров (php-fpm)
✦ Что-то асинхронное (nodejs, React PHP)
✦ Go = пишешь “синхронный” код, работает асинхронно
+ “сложились звёзды”
✦ Предварительно скачиваем списки зарегистрированных друзей
✦ В коротком клиентском запросе запускаем скрипт в PHProxyd
✦ Клиент перепроверяет (поллит) результаты
✦ В скрипте в PHProxyd делаем HTTP-запрос к FB + небольшая бизнес логика
Реализация #4 (предыдущая)
✦ Предварительно скачиваем списки зарегистрированных друзей
✦ В коротком клиентском запросе запускаем скрипт в PHProxyd
✦ Клиент перепроверяет (поллит) результаты
✦ В скрипте в PHProxyd делаем HTTP-запрос к FB + небольшая бизнес логика (походы в MySQL, memcache итд)
Реализация #4 (предыдущая)
Реализация #5 — отличия
✦ Принимает на вход “образ” http/https запроса
✦ Отвечает “in progress”, начинает исполнять запрос асинхронно
Реализация #5 — отличия
✦ Принимает на вход “образ” http/https запроса
✦ Отвечает “in progress”, начинает исполнять запрос асинхронно
✦ На повторные реквесты отвечает “in progress” либо данными
Реализация #5 — отличия
✦ Принимает на вход “образ” http/https запроса
✦ Отвечает “in progress”, начинает исполнять запрос асинхронно
✦ На повторные реквесты отвечает “in progress” либо данными
✦ Всю остальную бизнес-логику (базы, мемкеши) оставляем снаружи
Реализация #5
✦ Глобальный map с заданиями и результатами
✦ HTTP-сервер, принимает “json” образ запроса, шлёт его в канал
Реализация #5
✦ Глобальный map с заданиями и результатами
✦ HTTP-сервер, принимает “json” образ запроса, шлёт его в канал
✦ N горутин читают из канала, шлют запрос в FB
Реализация #5
✦ Глобальный map с заданиями и результатами
✦ HTTP-сервер, принимает “json” образ запроса, шлёт его в канал
✦ N горутин читают из канала, шлют запрос в FB
✦ После получения результата пишут его в глобальный map
Реализация #5
✦ Глобальный map с заданиями и результатами
✦ HTTP-сервер, принимает “json” образ запроса, шлёт его в канал
✦ N горутин читают из канала, шлют запрос в FB
✦ После получения результата пишут его в глобальный map
✦ Повторный запрос отдаёт результат из этого map
Реализация #5
✦ Глобальный map с заданиями и результатами
✦ HTTP-сервер, принимает “json” образ запроса, шлёт его в канал
✦ N горутин читают из канала, шлют запрос в FB
✦ После получения результата пишут его в глобальный map
✦ Повторный запрос отдаёт результат из этого map
Дублируем продакшен-трафик!!!
Вписываем в инфраструктуру
✦ JSON over HTTP -> “homemade” proto (GPB/JSON over TCP)
✦ Tests
✦ Build / Deploy
Вписываем в инфраструктуру
✦ JSON over HTTP -> “homemade” proto (GPB/JSON over TCP)
✦ Tests
✦ Build / Deploy
✦ Statistics / monitoring
✦ Badoo, Фича Friends
✦ PHP, PHP-FPM, долгие запросы, запросы к внешним сервисам
✦ Go: прототип, pprof, keep-alive
Заключение