Facebook Logo На сегодняшний день 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 других сервисов...

Как это работает все вместе?

Новые альбомы друзей

Facebook Screenshot

  1. Получаем профиль по идентификатору пользователя (скорее всего из кэша, но потенциально возможно обращение к базе данных)
  2. Получаем список друзей (опять же на основе идентификатора пользователя из кэша или из базы данных в случае промаха)
  3. Параллельно запрашиваем идентификаторы последних 10 альбомов для каждого из друзей (multi-get, каждый промах мимо кэша индивидуально вытаскивается из MySQL)
  4. Параллельно получаем данные о всех альбомах (на основе идентификаторов альбомов из предыдущего шага)
  5. Все данные получены, выполняем логику отрисовки конкретной страницы на PHP
  6. Отправляем HTML в браузер, пользователь счастлив :)

Новостная лента

News Feed Screenshot

News Feed Scheme

Поиск

Search Screenshot

Search Scheme

Подводим итоги

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. Спасибо за внимание :)