Как масштабировать Ruby-приложения

http://www.nateberkopec.com/2015/07/29/scaling-ruby-apps-to-1000-rpm.html
  • Перевод
Основная цель нашей работы состоит в том, чтобы сделать IaaS простым и понятным даже для тех, кто не сталкивался с ИТ-сферой. Поэтому мы проводим постоянную оптимизацию всех систем и рассказываем о том, что нам удалось сделать, в нашем блоге на Хабре.

Пара примеров:


Сегодня мы решили взглянуть на западный опыт и кратко проанализировать тему масштабирования приложений. Нас привлекло руководство Нейта Беркопека (Nate Berkopec), эксперта по Ruby.


/ фото Juhan Sonin CC

Нейт начинает с того, что говорит о сложности темы в целом. Здесь есть определенная разница между теми методами, которые подходят для масштабирования с 10 до 1000 запросов в минуту, и теми, которые используют компании вроде Twitter для перехода к обработке 600 запросов в секунду.

Особая тяга к масштабированию обычно компенсируется тем, что на определенном этапе у вас возникают проблемы с вводом/выводом в базе данных. Управление количеством процессов, загрузкой ЦП и оперативной памяти усложняют масштабирование для тех, кто разрабатывает приложения на Rails.

Здесь Нейт говорит об использовании Memcached и Redis вместе с RabbitMQ и Kafka. В основном он применял подобные решения на платформе Heroku, которая в целом годится для решения подобной задачи с масштабированием до 1000 запросов в минуту.

Он подчеркивает, что простое добавление Dyno-контейнеров на Heroku не даст желаемого эффекта — приложение не будет быстрее. Эти контейнеры могут лишь увеличить надежность. Если говорить об AWS, то переход с одного типа инстанса на другой (с T2 на M4) уже может оказать влияние на производительность приложения.

Некоторые инсайты из примеров Нейта:

  • Масштабирование может повлиять на время ожидания, если у вас есть очередь
  • Для решения задачи нужно разобраться в принципах работы сервера приложений
  • Документации Heroku не объясняет все нюансы маршрутизации HTTP запросов
  • Веб-приложению на Ruby необходима защита от медленного клиента и отклика
  • Нельзя масштабировать только на основании времени отклика — здесь может играть роль время ожидания в очереди. То же относится и к хостам worker’ов.
  • Веб-приложение может работать не с одной, а с десятками очередей, которые образуются в балансировщике нагрузки, маршрутизаторах Heroku, многопроцессном сервере и в «главном процессе»
  • Закон Литтла позволяет определить число необходимых экземпляров приложения как произведение среднего числа запросов в секунду на среднее время отклика (в секундах). Если начать масштабирование при 25%-й производительности, то это будет что-то в духе фальстарта. Производительность здесь — это отношение числа экземпляров приложения к среднему время отклика.

Маршрутизация запросов


Кратко о том, как устроен этот процесс:

1. В первую очередь запрос встречает балансировщик нагрузки — он распределяет запросы между маршрутизаторами Heroku.

2. Маршрутизатор передает запрос на обработку в случайный контейнер Dyno, который имеет отношение к вашему приложению.

3. Пока маршрутизатор определяется с тем, какой выбрать контейнер, запрос находится в его очереди ожидания. Этот процесс похож на работу nginx и отправку health-check запросов.

Далее с запросом работает выбранный вами сервер:

1. Для Webrick — открывает соединение с маршрутизатором для загрузки запроса, далее запускает ответ маршрутизатору и переходит к следующему запросу. Этот процесс полностью загружает хост и дает ему работать с запросами от других маршрутизаторов.

2. Thin работает немного иначе. Он событийно управляем. Он использует EventMachine, который похож на работу Node.js. Thin принимает запрос по частям, но только после полной загрузки запроса он передает его в приложение. Он хорошо подходит для обработки медленных запросов, но не является многозадачным.

3. Unicorn — это однопоточный, но уже многозадачный веб-сервер. Он построен на worker'ах и прослушивании одного сокета Unix. Здесь ситуация аналогичная — запрос должен быть полностью загружен, поэтому Unicorn не очень подходит для медленных клиентов, как и Webrick. Пока идет загрузка другие соединения не могут быть установлены. Эту проблему решает буферизация запросов, которой и занимается Passenger.

4. Phusion Passenger 5 — он позволяет установить что-то вроде nginx прямо перед worker’ами. В него встроен обратный прокси-сервер, который защитит рабочие процессы от медленных клиентов и загрузок. По мере загрузки запроса его передают HelperAgent'у, который распределяет запросы между worker’ами. Он вполне подходит для масштабирования. Альтернатива — Puma в кластерном режиме или Unicorn в связке с nginx.

P.S. Немного о работе нашего IaaS-провайдера:

Метки:
1cloud.ru 165,39
IaaS, VPS, VDS, Частное и публичное облако, SSL
Поделиться публикацией
Комментарии 13
  • +12
    Я прошу прощения, но неужели действительно 1000 запросов в минуту надо масштабировать? Это же всего 16,6 запросов в секунду в среднем. Для руби это столь серьёзная нагрузка?
    • 0
      Тут зависит от конкретной инфраструктуры. Например, в данном случае как раз было подмечено пару тонкостей, на которых погорели старые добрые RapGenius.
      • 0
        Продолжая ваши рассуждения по скользкой дорожке «средних» измерений — получится менее 60мс на каждый запрос (в непрерывном режиме). В целом это уже может себе позволить очень небольшое количество хоть немного серьёзных приложений (на руби или нет — не важно). Но проекция на реальный мир выглядит еще более отрезвляюще — при среднесуточном rpm 1000, в пиковые часы в реальности ваш rpm превратится в 5000-6000.

        У меня есть один проект на rails с среднесуточным rpm ~1400, он крутится на 3х апп-серварх (по 4 ядра) + 2 БД. Загружено это всё в среднем на 20%, в пики — до 80%.
        • 0
          php 2500 000 уников в сутки было 2 проекта.
          И 7+ млн уников в сутки одна штука.

          До 40 виртуальных машин под фронт, базы, полнотекстовый поиск, кеш.

          Поэтому тоже не понял акцента в заголовке статьи на rpm. Вот обзор серверов приложений был полезен для расширения кругозора.
        • –1
          Похоже это первая ошибка.
          Примечание: Это технически сложный текст, так что если вы заметите ошибку или неточность перевода — напишите нам, и мы все поправим, чтобы сделать материал лучше.
          • 0
            Нет конечно. Пустой сервер на EventMachine года 2 назад тащил почти столько же, сколько и нода (~3k rps на ноуте). Рельсы, отдающие просто шаблон, ~400rps выдают.
          • +1
            Годная статья, хороший перевод, спасибо! Буду давать новичкам. Единственное – текст неудобно местами читать из-за «псев-до пере-носов» посреди строк.
            • +1
              Да, это какой-то глюк, уже поправили
            • +2
              Что-то я не очень понял… Автор всю дорогу работал только с heroku и описывает большую проблему с балансировкой. Для меня все это выглядит как неуправляемость — большой провайдер «совершенно случайно» осуществляет балансировку нагрузки, в то же время выдавая ее за некую «интеллектуальную», причем никто точно не может сказать как она работает, какой размер очереди и время запроса в очереди. По-моему, бежать надо от таких провайдеров. Тем более что не самые и дешевые тарифы у них.

              Автор очень рекомендует ставить nginx перед gunicorn и рассказывает о медленных клиентах. Это, конечно, азбука, и это первое о чем следует знать при выборе того же gunicorn… Но, как я понял из статьи, Heroku уже ставит nginx перед Dyno-контейнером. В чем смысл ставить еще один внутри? Или это был совет без привязки к Heroku?

              Webrick? На продакшене? Серьезно? Разве есть случаи когда от него там может быть польза? Возможно я чего-то не знаю, но, мне казалось, что это сервер для разработки и отладки. И вряд ли кто-то его по-другому воспринимает.

              Мне статья показалась слишком «многобуковой», очень много воды и повторений одних и тех же мыслей.
              • 0
                Товарищи, рубисты! Скажите 16 запросов в секунду действительно считается большой нагрузкой для руби? Разьве одной слабой VDS не достаточно для такой нагрузки?
                • 0
                  Запросы очень разные бывают… Если приземлять на более-менее реальные кейсы(и не рассматривать ситуации, когда возможно целиком страницы кешировать), то нагрузки выше 3000 rpm, как правило, создают проблемы для rails-приложения на 1 физическом сервере приличной конфигурации.
                • +1
                  1000 запросов в секунду? Открыл первый попавшийся из своих проектов на джанге — там не в пиковый час две тысячи запросов в минуту, при этом сервера вообще не нагружены.

                  Я как-то даже не очень понимаю что там масштабировать-то под тысячу
                  • +1
                    Ну автор же сразу написал что больше 1000 запросов — это слишком сложно и он лучше расскажет про то, что меньше 1000.

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое