Блокировка ввода-вывода/Ruby on Rails

Я рассматриваю возможность написания веб-приложения с помощью Rails. Каждый запрос, сделанный пользователем, будет зависеть от вызова внешнего API. Этот внешний API может быть случайным образом очень медленным (2-3 секунды), и поэтому очевидно, что это повлияет на индивидуальный запрос.

В течение этого времени, когда код ожидает возврата внешнего API, будут ли блокироваться дальнейшие пользовательские запросы?

Просто для дальнейшего разъяснения, поскольку, похоже, есть некоторая путаница, это модель, которую я ожидаю:

  • Алиса делает запрос к моему веб-приложению. Для этого выполняется вызов API-сервера A. Сервер API A работает медленно и занимает 3 секунды.
  • В течение этого времени ожидания, когда приложение Rails вызывает сервер API A, Боб делает запрос, который должен сделать запрос серверу API.

Является ли интерпретатор Ruby (1.9.3) (или что-то в структуре Rails 3.x) блокировать запрос Боба, требуя от него ждать, пока запрос Алисы не будет выполнен?

Ответ 1

Если вы используете только один однопоточный, неаудированный сервер (или не используете входы-выходы с событием), да. Среди других решений, использующих Thin и EM-Synchrony, будет избегайте этого.

Разработка, основанная на вашем обновлении:

Нет, ни Ruby, ни Rails не будут блокировать ваше приложение. Вы оставили часть, которая будет, хотя: веб-сервер. Вам также нужно несколько процессов, несколько потоков или связанный с ними сервер в сочетании с выполнением запросов веб-службы с помощью библиотеки событий ввода-вывода.

@alexd описывается с использованием нескольких процессов. Я лично поддерживаю сервер, на который вызывается событие, потому что мне не нужно заранее знать/угадывать, сколько одновременных запросов у меня может быть (или использовать что-то, что вызывает процессы на основе нагрузки). Один процесс nginx, выходящий из одного thin процесс может обрабатывать тонны параллельных запросов.

Ответ 2

Ответ на ваш вопрос зависит от сервера, на котором запущено приложение Rails. Что вы сейчас используете? Тонкий? Unicorn? Apache + Passenger?

Я всем сердцем рекомендую Unicorn для вашей ситуации - это позволяет легко запускать несколько серверных процессов параллельно, и вы можете настроить количество параллельных процессов просто путем изменения числа в файле конфигурации. В то время как один рабочий Unicorn обрабатывает запрос с высокой задержкой Алисы, другой рабочий Unicorn может использовать ваши свободные циклы процессора для обработки запроса Боба.

Ответ 3

Скорее всего, да. Очевидно, есть способы обойти это, но ни один из них не является легким.

Лучший вопрос: зачем вам нужно удалять внешний API по каждому запросу? Почему бы не реализовать уровень кэша между вашим Rails-приложением и внешним API и использовать его для большинства запросов?

Таким образом, с некоторой пользовательской логикой для истечения срока действия кэша у вас будет быстрое приложение Rails и все еще сможет использовать внешнюю службу API.