Twitter стартовал как побочный подпроект, но не смотря на это темпы его роста были впечатляющими: путь от 0 до миллионов просмотров страниц занял всего несколько коротких месяцев. Ранние решения о проектировании системы неплохо справлялись с небольшими нагрузками, но они быстро таяли под напором огромного количества пользователей, желающих разослать весточки всем своим друзьям с ответом на простой вопрос: а чем ты занимаешься?

Поначалу все винили Ruby on Rails во всех проблемах с масштабированием, но Blaine Cook, главный архитектор Twitter, встал на его защиту:

Основной для нас на самом деле является проблема горизонтального масштабирования, с этой точки зрения Ruby on Rails ничем не хуже других языков программирования или framework'ов: переход на "более быстрый" язык программирования дал бы нам 10-20% прирост производительности, в то время архитектурные преобразования, легко реализованные средствами Ruby on Rails, сделали Twitter быстрее на 10000%.

Даже если Ruby on Rails оказался невиновен, как же тогда Twitter научился с его помощью рости до все больших и больших высот?

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

Этот текст является продолжением серии переводов, автор оригинала - Todd Hoff. На этот раз написать что-либо своими силами у меня не сложилось, все мысли ушли на другой пост, который я скоро опубликую, а перевод этот получился несколько менее строгим, чем обычно, но я думаю ничего страшного.

Платформа

Статистика

  • Более 350000 пользователей. Точная цифра, как обычно, держится в секрете.
  • Около 600 запросов в секунду.
  • В среднем система поддерживает 200-300 соединений в секунду. Максимум обычно достигается при значении 800.
  • MySQL обрабатывает примерно 2400 запросов в секунду.
  • 180 экземпляров приложений на Rails, использующих Mongrel как веб-сервер.
  • 1 MySQL сервер (одна большая машина с 8 ядрами) и 1 slave, используемый лишь для статистики и отчетов.
  • 30+ процессов для выполнения произвольных работ.
  • 8 Sun X4100
  • Обработка запроса обычно занимает у Rails 200 миллисекунд.
  • В среднем ответ на запрос к базе данных занимает 50-100 миллисекунд.
  • Более 16 GB выделено под memcached.

Архитектура

  • Проект столкнулся с массой проблем, связанных с масштабируемостью. Маленькая птичка частенько давала сбои.
  • Изначально не было реализовано никаких форм мониторинга, графиков или статистики, это очень затрудняло обнаружение м решение возникающих проблем. Впоследствии были внедрены Munin и Nagios. Разработчики столкнулись с некоторыми трудностями при использовании этих продуктов в Solaris. Помимо этого был использован сервис Google Analytics, но от него обычно мало толку, особенно когда страницы даже не загружаются.
  • Активное использование кэширования средствами memcached:

    • Например, если подсчет количества чего-либо выполняется медленно, намного эффективнее один раз запомнить результат в memcached, чем каждый раз считать его заново.
    • Получение информации о статусе своих друзей - непростая задача. Вместо использования запросов информация о статусе друзей обновляется в кэше. База данных совсем не используется. Такой подход позволяет получить предсказуемое время отклика (ограниченное сверху примерно 20 миллисекундами).
    • Объекты ActiveRecord настолько велики, что кэширование их нецелесообразно. Критичные атрибуты хранятся в хэше, а остальная их часть подвергается "ленивой загрузке" в момент запроса на доступ.
    • 90% запросов являются запросами к API. Таким образом кэширование страниц или их фрагментов становится бессмысленным, зато никто не мешает им кэшировать сами API запросы.
  • Внутренняя организация работы с сообщениями:

    • Сообщения очень активно используются: производители генерируют сообщения, они образуются в очереди, а затем распространяются по потребителем.
    • Основная функция Twitter заключается в реализации своеобразного моста между различными форматами электронных сообщений (SMS, электронная почта, сервисы мгновенного обмена сообщениями и так далее).
    • Чтобы инвалидировать в кэше информацию можно просто отправить внутреннее сообщение, зачем выполнять все действия синхронно?
    • Изначально этот механизм основывался на DRb (distributed Ruby) - библиотека, позволяющая отправлять и принимать сообщения сообщения между удаленными Ruby-объектами по TCP/IP. Но она была несколько странноватой, да и являлось потенциально слабым местом с точки зрения стабильности.
    • Со временем сервис перевели на Rinda, представляющую собой набор общих для всей системы очередей. Но и у нее были недостатки: все очереди были постоянными, а данные терялись при сбоях.
    • Следующей попыткой был Erlang. Но однажды возникла проблема: каким образом сломавшийся сервер может продолжать работать, но при этом в очереди откуда-то возникли целых 20000 ожидающих пользователей? Разработчики не знали. На лицо явный недостаток документации...
    • В конце концов решение было разработано своими силами: Twitter выпустил Starling, распределенный легковесный сервер очередей, написанный на Ruby и поддерживающий протокол memcache. Сейчас серверная часть Twitter управляется именно им.
    • Распределенные очереди позволяют переживать сбои путем записи их на диск в критических ситуациях. Другие крупные интернет-проекты также часто пользуются таким подходом.
  • Работа с SMS осуществляется с помощью сторонних сервисов и предоставляемых ими шлюзов. Достаточно дорогое удовольствие.
  • Развертывание:
    • Просто запускаются дополнительные сервера с mongrel, более элегантного решения пока нет.
    • Все внутренние ошибки выдаются пользователям, если обслуживающий их mongrel сервер на данный момент заменяется.
    • Все сервера останавливаются одновременно. Отключение их по одному по определенным причинам не используется.
  • Неправильное использование сервиса:
    • Много времени сервис был не доступен, так как люди проходились специальными программами по сайту с целью добавить всех кто попадался под руку в друзья. 9000 друзей за 24 часа. Это просто-напросто останавливало работу сайта.
    • Были разработаны средства для своевременного обнаружения таких ситуаций.
    • Будте беспощадными, таких пользователей нужно просто удалять.
  • Сегментирование:
    • Пока оно только в планах, сейчас оно не используется.
    • В будущем оно будет основываться на времени, а не на пользователях, так как запросы обычно очень локальны по времени.
    • Сегментирование будет не так просто реализовать благодаря автоматическому запоминанию результатов выполнения функций для последующего повторного их использования. Никто не даст гарантии, что операции "только для чтения" на самом деле будут таковыми являться. Запись в slave, работающий в режиме read-only, - не самая лучшая идея.
  • API Twitter генерирует в 10 раз больше трафика, чем сам сайт.
    • Их API - самая важная вещь из всех, что они разработали.
    • Простота сервиса позволила разработчикам строить свои приложения поверх инфраструктуры Twitter, привнося все новые и новые идеи. Например, Twitterrific - красивый способ использовать Twitter в небольшой команде.
  • Мониторинг используется для остановки слишком больших процессов.

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

  • Общайтесь со своим сообществом. Не прячьтесь и не пытайтесь решить абсолютно все проблемы самостоятельно. Много отличных людей будут готовы помочь, достаточно лишь попросить.
  • Рассматривайте вашу стратегию масштабирования как бизнес-план. Соберите советы помощников для того чтобы облегчить для себя принятие решений.
  • Стройте свой проект сами. Twitter потратил много времени, пытаясь приспособить готовые решения других людей, которые казалось бы должны работать, но это оказалось не совсем так. Лучше построить какие-то вещи самостоятельно, чтобы иметь высокую степень контроля над ситуацией и иметь возможность привносить новые возможности как только они понадобились.
  • Ставьте перед своими пользователями разумные ограничения. На обычных пользователей это не повлияет, но когда кому-нибудь взбредет в голову попытаться сломать систему (а такой человек рано или поздно найдется) - они сыграют свою роль и спасут работоспособность системы.
  • Не делайте базу данных центральным узким местом системы, врядли Ваше приложение на самом деле требует гигантских операций по объединению данных из нескольких таблиц. Используйте кэширование, или проявите свою смекалку для поиска альтернативных способов достижения того же результата.
  • Предусмотрите возможность сегментирования с самого начала, тогда перед Вами всегда будут открыты пути для дальнейшего масштабирования.
  • Очень важно вовремя осознать, что сайт начинает работать медленно. Сразу стоит задуматься о системе отчетов для отслеживания потенциальных проблем.
  • Оптимизируйте базу данных:
    • Индексируйте все таблицы, Rails не будет делать это за Вас.
    • Используйте "explain" для анализа выполнения запросов. Результаты могут не совпадать с Вашими ожиданиями.
    • Денормализуйте данные. Один только этот совет порой может спасти ситуацию. Для примера, в Twitter хранят все ID друзей каждого пользователя вместе, это позволило избежать многих ресурсоемких запросов.
    • Избегайте комплексного объединения данных из нескольких таблиц.
    • Избегайте сканирования больших наборов данных.
  • Кэшируйте все, что только можно.
  • Тестируйте все максимально тщательно:
    • Когда Вы развертываете приложение, Вы должно быть уверены, что оно будет работать корректно.
    • Они используют полный набор средств для тестирования. Таким образом, когда произошла неполадка в кэшировании, они узнали о ней еще до того как она на самом деле произошла.
  • Длительно функционирующие процессы стоит оформить в виде daemon'ов.
  • Используйте уведомления об исключительных ситуациях в совокупности с ведением логов, это необходимо для своевременного реагирования на них.
  • Не делайте глупостей!
    • Масштаб проект несколько меняет понятие "глупость".
    • Пытаться загрузить 3000 друзей в память одновременно может заставить сервер временно перестать функционировать, хотя когда друзей было всего 4 - этот механизм прекрасно работал.
  • Большая часть производительности зависит не от использованного языка программирования, а от продуманной структуры приложения.
  • Превратите свой сайт в открытый сервис с помощью создания API. Их API является ключом к успеху Twitter. Он позволяет пользователям создавать постоянно расширяющуюся экосистему вокруг Twitter, соревноваться с которой не так-то просто. Вы никогда не сможете сделать столько же работы, сколько смогут Ваши пользователи для Вас, Вам просто не хватит креативных идей. Так что не стесняйтесь, откройте свое приложение и сделайте интеграцию Вашего приложения с другими максимально простой и удобной!