Instagram - всего лишь iOS, а теперь и Android, приложение для обмена фотографиями с друзьями. Последнее время находится на слуху благодаря новости о покупке проекта Facebook'ом за кругленькую сумму. Недавно один из основателей проекта, Mike Krieger, выступил на конференции с докладом о техническом аспекте проекта, который я и хотел бы вкратце пересказать.
Статистика
Начало:
- 1 сервер слабее Macbook Pro
- 25к регистраций в первый день
- 2 разработчика
Сегодня:
- 40+ миллионов пользователей
- 100+ виртуальных серверов в EC2, в том числе:
- Проект куплен Facebook за 1 млрд. долл
- 1 миллион регистраций за 12 часов после запуска Android-версии
- 5 разработчиков
Технологии
- UbuntuLinux 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.
13 апреля 2012 | | Высокие нагрузки