На сегодняшний день Facebook является пожалуй самым обсуждаемым интернет-проектом во всем мире. Не смотря на довольно низкий уровень проникновения Facebook в России, темпы захвата аудитории этим проектом мягко говоря поражают. Как же им удается управляться с таким огромным социальным графом и удовлетворять потребности в общении невероятно большого количества людей по всему миру?
Платформа
- Linux - операционная система
- PHP с HipHop - код на PHP компилируется в C++
- memcached - агрессивное кэширование объектов
- MySQL - используется как хранилище пар ключ-значение, никаких join'ов
- Thrift - интерфейс взаимодействия между сервисами, написанными на разных языках программирования
- Scribe - универсальная система сбора и агрегации данных с рабочих серверов
Статистика
- Более 500 миллионов активных пользователей (месячная аудитория)
- Более миллиарда социальных связей
- Более 200 миллиардов просмотров страниц в месяц
- Более 4 триллионов действий попадает в новостные ленты каждый день
- Более 150 миллионов обращений к кэшу в секунду; 2 триллиона объектов в кэше
- Более 8 миллиардов минут провели пользователи на Facebook'е ежедневно
- Более 3 миллиардов фотографий загружается каждый месяц, до 1.2 миллиона фотографий в секунду
- 20 миллиардов фотографий в 4 разрешениях = 80 миллиардов фотографий, их бы хватило чтобы покрыть поверхность земли в 10 слоев; это больше, чем на всех других фото-ресурсах в месте взятых
- О более чем 5 миллиардах единиц контента рассказывается друзьям еженедельно
- Более миллиарда сообщений в чате каждый день
- Более ста миллионов поисковых запросов в день
- Более 250 приложений и 80 тысяч сторонних ресурсов на платформе Facebook Connect
- Более 400 тысяч разработчиков сторонних приложений
- Менее 500 разработчиков и системных администраторов в штате
- Более миллиона активных пользователей на одного инженера
- Десятки тысяч серверов, десятки гигабит трафика
Архитектура
Общие принципы
- Балансировщик нагрузки выбирает веб-сервер для обработки запроса
- PHP-код в веб-сервере подготавливает HTML, пользуясь данными из различных источников:
- MySQL
- memcached
- Специализированные сервисы
- Если взглянуть с другой стороны, то получим трехуровневую архитектуру:
- Вер-приложение
- Распределенный индекс
- Постоянное хранилище
- Использование открытых технологий там, где это возможно
- Поиск возможностей оптимизации используемых продуктов
- Философия Unix:
- Старайтесь делать каждый компонент системы простым и производительным
- Комбинируйте компоненты для решения задач
- Концентрируйте внимание на хорошо обозначенных точках взаимодействия
- Все усилия направлены на масштабируемость
- Попытки минимизации количества точек отказа
- Простота, простота, простота!
PHP
Почему PHP?
- Во многом "так исторически сложилось"
- Хорошо подходит для веб-разработки
- Легок в изучении: небольшой набор выражений и языковых конструкций
- Легок в написании: нестрогая типизация и универсальный "массив"
- Легок в чтении: синтаксис похож на C++ и Java
- Прост в дебаггинге: нет необходимости в перекомпиляции
- Большой ассортимент библиотек, актуальных для веб-проектов
- Подходит для процесса разработки с короткими итерациями
- Активное сообщество разработчиков по всему миру
- Динамическая типизация, интерпретируемый язык для скриптов
Как оказалось на самом деле?
- Высокий расход оперативной памяти и вычислительных ресурсов
- Сложно работать, когда объем исходного кода очень велик: слабая типизация и ограниченные возможности для статичного анализа и оптимизации кода
- Не особо оптимизирован для использования в крупных проектах
- Линейный рост издержек при подключении файлов с исходным кодом
- Механизм разработки расширений не очень удобен
Доработки:
- Оптимизация байт-кода
- Улучшения в APC (ленивая загрузка, оптимизация блокировок, "подогрев" кэша)
- Свои расширения (клиент memcache, формат сериализации, логи, статистика, мониторинг, механизм асинхронной обработки событий)
- HipHop - трансформатор исходных кодов:
- Разработчики пишут на PHP, который конвертируется в оптимизированный C++
- Статический анализ, определение типов данных, генерация кода, и.т.д.
- Облегчает разработку расширений
- Существенно сокращает расходы оперативной памяти и вычислительных ресурсов
- У команды из трех программистов ушло полтора года на разработку, переписаны большая часть интерпретатора и многие расширения языка
- Опубликован под opensource лицензией в начале года, нет необходимости проходить этот же путь с нуля
MySQL
Как используется MySQL?
- Используется как хранилище пар ключ-значение
- Большое количество логических узлов распределено между физическими машинами
- Балансировка нагрузке на уровне физических серверов
- Репликация для распределения операций чтения не используется
- Большинство запросов касаются самой свежей информации: оптимизация таблиц для доступа к новым данным, архивация старых записей
- В целом быстро и надежно
Как оказалось на самом деле?
- Логическая миграция данных очень сложна
- Создавать большое количество логических баз данных и перераспределять их между физическими узлами, балансируя таким образом нагрузку, намного удобнее
- Никаких join'ов на рабочих серверах баз данных
- Намного проще наращивать вычислительные мощности на веб-серверах, чем на серверах баз данных
- Схемы, основанные на структуре данных, делают программистов счастливыми и создают большую головную боль администраторам
- Никогда не храните не-статичные данные в централизованное базе данных
Доработки:
- Практически никаких модификаций исходного кода MySQL
- Своя схема партиционирования с глобально-уникальными идентификаторами
- Своя схема архивирования, основанная на частоте доступа к данным относительно каждого пользователя
- Расширенный движок запросов для репликации между датацентрами и поддержания консистенции кеша
- Библиотеки для доступа к данным на основе графа:
- Объекты (вершины графа) с ограниченными типами данных (целое число, строка ограниченно длины, текст)
- Реплицированные связи (ребра графа)
- Аналоги распределенных внешних ключей (foreign keys)
- Большинство данных распределено случайно
Memcache
Как используется memcached?
- Высокопроизводительная распределенная хэш-таблица
- Содержит "горячие" данные из MySQL
- Снижает нагрузку на уровень баз данных
- Основная форма кэширования
- Используется более 25TB памяти на нескольких тысячах серверов
- Среднее время отклика менее 250 микро-секунд
- Кэшируются сериализованные структуры данных PHP
- Отсутствие автоматического механизма проверки консистенции данных между memcached и MySQL - приходится делать это на уровне программного кода
- Множество multi-get запросов для получения данных на другом конце ребер графа
- Ограниченная модель данных, неэффективен для маленьких объектов
Доработки:
- Порт на 64-битную архитектуру
- Более эффективная сериализация
- Многопоточность
- Улучшенный протокол
- Компрессия
- Проксирование запросов
- Доступ к memcache через UDP:
- уменьшает расход памяти благодаря отсутствию тысяч буферов TCP соединений
- управление ходом исполнения приложение (оптимизация для multi-get)
- Статистика о работе потоков по запросу - уменьшает блокировки
- Ряд изменений в ядре Linux для оптимизации работы memcache:
- распределение управления сетевыми прерывания по всем ядрам
- оппортунистический опрос сетевых интерфейсов
- После вышеперечисленных модификаций memcached способен выполнять до 250 тысяч операций в секунду, по сравнению со стандартными 30-40 тысячами без данных изменений
Thrift
Что это?
- Легкий механизм построения приложений с использованием нескольких языков программирования
- Высокая цель: предоставить механизм прозрачного взаимодействия между языками программирования.
- Предоставляет язык описания интерфейсов, статический генератор кода
- Поддерживаемые языки: C++, PHP, Python, Java, Ruby, Erlang, Perl, Haskell и многие другие
- Транспорты: простой интерфейс для ввода-вывода (сокеты, файлы, буферы в памяти)
- Протоколы: стандарты сериализации (бинарный, JSON)
- Серверы: неблокирующие, асинхронные, как однопоточные, так и многопоточные
Почему именно Thrift?
- Альтернативные технологии: SOAP, CORBA, COM, Pillar, Protocol Buffers - но у всех есть свои существенные недостатки, что вынудило Facebook создать свою технологию
- Он быстрый, очень быстрый
- Меньше рабочего времени тратится каждым разработчиком на сетевые интерфейсы и протоколы
- Разделение труда: работа над высокопроизводительными серверами ведется отдельно от работы над приложениями
- Общий инструментарий, знакомый всем разработчикам
Scribe
Что это?
- Масштабированный распределенный механизм ведения логов
- Перемещает данные с серверов в центральный репозиторий
- Широкая сфера применения:
- Логи поисковых запросов
- Публикации в новостных лентах
- Данные по A/B тестированиям
- Более надежен, чем традиционные системы логгирования, но недостаточно надежен для транзакций баз данных
- Простая модель данных
- Построен на основе Thrift
Хранение фотографий
Сначала сделали это просто:
- Загрузка на сервер: приложение принимает изображение, создает миниатюры в нужных разрешениях, сохраняет в NFS
- Загрузка с сервера: изображения отдаются из NFS через HTTP
- NFS построена на коммерческих продуктах
- Это было необходимо, чтобы сначала проверить, что продукт востребован пользователями и они правда будут активно загружать фотографии
- На самом деле оказалось, что:
- Файловые системы непригодны для работы с большим количеством небольших файлов
- Метаданные не помещаются в оперативную память, что приводит к дополнительным обращениям к дисковой подсистеме
- Ограничивающим фактором является ввод-вывод, а не плотность хранения
Потом начали оптимизировать:
- Кэширование более часто используемых миниатюр изображений в памяти на оригинальных серверах для масштабируемости, надежности и производительности
- Распределение их по CDN для уменьшения сетевых задержек
- Возможно сделать еще лучше:
- Хранение изображений в больших бинарных файлах (blob)
- Сервис, отвечающий за фотографии имеет информацию о том, в каком файле и с каким отступом от начала расположена каждая фотография (по ее идентификатору)
- Этот сервис в Facebook называется Haystack и он оказался в 10 раз эффективнее "простого" подхода и в 3 раза эффективнее "оптимизированного"
Другие сервисы
- SMC: консоль управления сервисами - централизованная конфигурация, определение на какой физической машине работает логический сервис
- ODS: инструмент для визуализации изменений любых статистических данных, имеющихся в системе; удобен для мониторинга и оповещений
- Gatekeeper: разделение развертывания и запуска, A/B тестирования, таргетированный запуск, постепенный запуск
- И еще около 50 других сервисов...
Как это работает все вместе?
Новые альбомы друзей
- Получаем профиль по идентификатору пользователя (скорее всего из кэша, но потенциально возможно обращение к базе данных)
- Получаем список друзей (опять же на основе идентификатора пользователя из кэша или из базы данных в случае промаха)
- Параллельно запрашиваем идентификаторы последних 10 альбомов для каждого из друзей (multi-get, каждый промах мимо кэша индивидуально вытаскивается из MySQL)
- Параллельно получаем данные о всех альбомах (на основе идентификаторов альбомов из предыдущего шага)
- Все данные получены, выполняем логику отрисовки конкретной страницы на PHP
- Отправляем HTML в браузер, пользователь счастлив :)
Новостная лента
Поиск
Подводим итоги
LAMP не идеален
- PHP+MySQL+Memcache решает большинство задач, но не может решить совсем все:
- PHP не может хранить состояния
- PHP не самый производительный язык
- Все данные находятся удаленно
- Facebook разрабатывает собственные внутренние сервисы, чтобы:
- Располагать исполняемый код ближе к данным
- Скомпилированное окружение более эффективно
- Некоторая функциональность присутствует только в других языках программирования
- Философия сервисов:
- Создание сервисов только при необходимости (минимизация издержек по развертке, поддержке и ведению отдельной кодовой базы; потенциальная дополнительная точка сбоя)
- Создание общего набора инструментов для создания сервисов (Thrift, Scribe, ODS, средства мониторинга и уведомлений)
- Использование правильных языка программирования, библиотек и инструментов для решения задачи
- Возвращение инноваций общественности - важный аспект разработки в Facebook:
- Опубликованные свои проекты:
- Thrift
- Scribe
- Tornado
- Cassandra
- Varnish
- Hive
- xhprof
- Доработки популярных решений:
- PHP
- MySQL
- memcached
- Информация о взаимодействии Facebook с opensource-сообществом, этих и других проектах расположена на странице, посвященной opensource.
- Опубликованные свои проекты:
- Ключевые моменты культуры разработки в Facebook:
- Двигайся быстро и не бойся ломать некоторые вещи
- Большое влияние маленьких команд
- Будь откровенным и инновационным
Источники информации
Данная статья не является переводом готовой статьи, в качестве источников информации послужили записи выступлений сотрудников Facebook на конференциях:
Очень рекомендую посмотреть материалы в оригинале, так как естественно я осветил в статье далеко не все, да и неточности какие-либо неисключены. Помимо этого возможно многим будет интересно мероприятие "Facebook: how we scaled to 500 000 000 users ", где Robert Johnson выступает 22 октября в Москве. Еще он числится в списке докладчиков Highload++ с аналогичным выступлением. Дополнительную информацию можно почерпнуть в блоге инженеров Facebook.
UPD: Обновил некоторые моменты после посещения вышеупомянутого выступления Роберта.
И по традиции напоминаю, что так как я пишу довольно редко - читать мой блог намного удобнее по RSS. Спасибо за внимание :)