Архитектура Instagram

(Из ленты )

Instagram — всего лишь iOS, а теперь
и Android, приложение для обмена фотографиями с
друзьями. Последнее время находится на слуху благодаря новости о покупке
проекта Facebook‘ом за кругленькую сумму. Недавно один
из основателей проекта, Mike Krieger, выступил на конференции с докладом
о техническом аспекте проекта, который я и хотел бы вкратце пересказать.

Статистика

Начало:

  • 1 сервер слабее Macbook Pro
  • 25к регистраций в первый день
  • 2 разработчика

Сегодня:

  • 40+ миллионов пользователей
  • 100+ виртуальных серверов в EC2, в том числе:
  • Проект куплен Facebook за 1 млрд. долл
  • 1 миллион регистраций за 12 часов после запуска Android-версии
  • 5 разработчиков

Технологии

  • Ubuntu Linux 11.04 — основная
    операционная система
  • Python — основной язык программирования серверной части
  • Django — фреймворк
  • Amazon:
    • EC2 — хостинг
    • ELB — балансировка входящих HTTP-запросов
    • Route53 — DNS
    • S3 — хранение фотографий
    • CloudFrontCDN
  • nginx — второй уровень балансировки входящихHTTP-запросов
  • gunicorn — WSGI-сервер
  • HAProxy — балансировка нагрузки внутри системы
  • PostgreSQL — основное хранилище данных
  • postgis — поддержка гео-запросов
  • pgfouine — отчеты на основе логов
  • pgbouncer — создание пула соединений
  • Redis — дополнительное хранилище данных
  • Memcached — кэширование
  • Gearman — очередь задач
  • Solr — гео-поиск
  • munin, statsd, pingdom — мониторинг
  • Fabric — управление кластером
  • xfs — файловая система

Философия

  1. Простота
  2. Минимизация операционных издержек
  3. Использование подходящих инструментов

История

  • Забыли сделать favicon.ico до запуска — в первый же день логи
    пестрили ошибками 404
  • Для хранения данных использовали просто Django ORM и
    PostgreSQL (из-за postgis)
  • Начали с одного слабого сервера, после успешного запуска решили
    переехать на EC2
  • Довольно быстро пришлось вынести СУБД на отдельный сервер
    (виртуальный, естественно)
  • Количество фотографий продолжало расти и расти, даже самый большой
    инстанс EC2 не справлялся
  • Решили вертикально разделить данные на несколько баз, с использованием
    механизма routers из ORM, параллельно избавившись от внешних ключей
  • Через несколько месяцев суммарный размер базы данных перевалил за 60Гб и
    перестало справляться и это решение
  • Следующим шагом стало горизонтальное разбиение данных (sharding):
  • Создали несколько тысяч логических баз данных.
  • Распределили их по существенно меньшему количеству физических серверов (читай: виртуальных машин).
  • Написали свой механизм определения где искать какую базу данных, с поддержкой миграции (вероятно тоже на основе routers).
  • По последним данным под PostgreSQL используется 12+12 виртуальных
    машин с максимальной оперативной памятью (68.4Гб), а также сетевые диски
    EBS, объединенные в программный RAID посредством mdadm. Это необходимо,
    чтобы весь массив данных помещался в памяти, EBS не в состоянии
    обеспечить достаточную производительность.
  • С некоторыми задачами лучше справляется Redis:
  • Для каждого пользователя в Redis есть список идентификаторов новых
    фотографий от других пользователей, на которых он подписан.
  • При отображении потока новых для пользователя фотографий делается
    выборка части такого списка, после чего посредством multiget достается
    подробная о них информация из memcached.
  • Пробовали возложить на него задачу хранения списков подписчиков, но в
    итоге вернулись к решению на PostgreSQL с небольшим кэшированием.
  • В Redis также хранится информация о сессиях.
  • Несколько фактов о Redis:
    • Так как все находится в памяти — очень быстрые операции записи и работы с множествами.
    • Является не заменой, а дополнением к основному хранилищу данных.
    • Redis хорош для структур данных, которые относительно ограничены.
    • Отлично подходит для кэширования комплексных структур данных, где нужно большее, чем просто получить значение по ключу (например — счетчики, подмножества, проверка вхождения в множества).
    • Механизм репликации (посредством slaveof) позволяет легко
      масштабировать операции чтения.
  • Пользователи синхронно загружают фотографии на медиа-сервер с
    (опциональными) заголовком и месте на карте, все остальное происходит
    асинхронно посредством очередей, например:

    • Сохраняются гео-метки, обновляется Solr (который впоследствии заменил postgis).
    • Идентификатор нового фото добавляется в обсуждавшиеся выше списки для всех подписчиков автора.
  • Поначалу использовали Apache + mod_wsgi для запуска
    Django, впоследствии перешли к gunicorn из-за меньшего потребления
    ресурсов и простоты настройки.
  • С недавних пор начали использовать Amazon ELB вместо DNS
    round-robin
    для первичной балансировки входяших HTTP-запросов, что
    позволило:
  • избежать необходимости дешифровки SSL посредством nginx;
  • ускорить исключение из балансировки проблемных серверов.
  • Благодаря использованию xfs есть возможность «замораживать» и
    «размораживать» дисковые массивы при резервном копировании.

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

  • Многие проблемы с масштабируемостью — результат банальных
    человеческих ошибок.
  • Масштабирование = замена всех деталей в машине на скорости 150 км/ч.
  • Заранее сложно узнать как в основном будут обращаться к данным, без
    реального использования.
  • В первую очередь попытайтесь адаптировать известные Вам технологии и
    инструменты для создания простого и понятного решения, прежде чем
    бросаться на поиски чего-то нетривиального.
  • Дополните свое основное хранилище более гибким компонентом, вроде
    Redis.
  • Постарайтесь не использовать два инструмента для решения одной и той
    же задачи.
  • Оставайтесь гибкими и ловкими = напоминайте себе о том, что на самом
    деле имеет значение.
  • Разрабатывайте решения, к которым не придется постоянно возвращаться
    из-за их сбоев.
  • Активное юнит- и функциональное тестирование стоят потраченного на
    них времени.
  • DRY: не делайте одну и ту же работу несколько раз.
  • Слабая связанность посредством уведомлений или сигналов позволяет
    легко менять структуру проекта.
  • Дисковый ввод-вывод часто оказывается узким местом, особенно на EC2.
  • Спускаться до C нужно только при необходимости, большую часть работы
    лучше делать в Python.
  • Короткий цикл разработки — залог быстрого развития.
  • Частые совместные рассмотрения кода нужны, чтобы все были в курсе
    происходящего.
  • Не изобретайте велосипед.
  • Окружите себя с толковыми консультантами.
  • Культура открытости вокруг разработки.
  • Делитесь с opensource сообществом.
  • Фокусируйтесь на том, что вы делаете лучше всего.
  • Вашим пользователям абсолютно без разницы, написали ли Вы
    собственную СУБД или нет.
  • Не переоптимизируйте и не предполагайте заранее как сайт будет
    расти.
  • Не рассчитывайте, что «кто-то еще присоединится к команде и
    разберется с этим».
  • Для социальных стартапов очень мало, или даже совсем нет, нерешимых
    вопросов, связанных с масштабируемостью.

Источник информации

Упоминавшаяся во вступлении неприлично длинная презентация из 185
слайдов:

На видео, к сожалению, это выступление не записывалось.

Часть информации взята из технического блога Instagram.

Источник: Архитектура Instagram