Архитектура 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 — хранение фотографий
    • CloudFront — CDN
  • 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.

www.insight-it.ru/masshtabiruemost/arkhitektura-instagram

Вверх