Архитектура 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:
- nginx — второй уровень балансировки входящихHTTP-запросов
- gunicorn — WSGI-сервер
- HAProxy — балансировка нагрузки внутри системы
- PostgreSQL — основное хранилище данных
- postgis — поддержка гео-запросов
- pgfouine — отчеты на основе логов
- pgbouncer — создание пула соединений
- Redis — дополнительное хранилище данных
- Memcached — кэширование
- Gearman — очередь задач
- Solr — гео-поиск
- munin, statsd, pingdom — мониторинг
- Fabric — управление кластером
- xfs — файловая система
Философия
- Простота
- Минимизация операционных издержек
- Использование подходящих инструментов
История
- Забыли сделать 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