Эффективная обработка длительных HTTP-соединений в веб-архитектуре nginx/gunicorn/django

Я работаю над веб-службой, реализованной поверх nginx + gunicorn + django . Клиентами являются приложения для смартфонов. Приложению необходимо сделать несколько длительных вызовов внешних API (Facebook, Amazon S3... ), поэтому сервер просто ставит задание в очередь на сервер заданий (, используя Celery через Редис).

По возможности, как только сервер поставит задание в очередь, он сразу же вернется, и соединение HTTP будет закрыто. Это прекрасно работает и позволяет серверу выдерживать очень высокую нагрузку.

client                   server                 job server
 .                        |                        |
 .                        |                        |
  |------HTTP request----->|                        |
  |                        |--------queue job------>|
  |<--------close----------|                        |
 .                        |                        |
 .                        |                        |

Но в некоторых случаях клиенту необходимо получить результат сразу после завершения работы. К сожалению, после закрытия HTTP-соединения сервер не может связаться с клиентом. Одним из решений было бы полагаться на то, что клиентское приложение будет опрашивать сервер каждые несколько секунд, пока задание не будет завершено. Я хотел бы избежать этого решения, если это возможно, в основном потому, что это будет препятствовать реактивности службы,а также потому, что это загрузило бы сервер множеством ненужных запросов опроса.

Короче говоря, я хотел бы поддерживать HTTP-соединение в рабочем состоянии, ничего не делая (, за исключением, возможно, отправки пробела время от времени, чтобы поддерживать TCP-соединение, просто , как это делает Amazon S3 )., пока задание не будет выполнено и сервер не вернет результат.

client                   server                 job server
 .                        |                        |
 .                        |                        |
  |------HTTP request----->|                        |
  |                        |--------queue job------>|
  |<------keep-alive-------|                        |
  |         [...]          |                        |
  |<------keep-alive-------|                        |
  |                        |<--------result---------|
  |<----result + close-----|                        |
 .                        |                        |
 .                        |                        |

Как я могу эффективно реализовать длительные HTTP-соединения, предполагая, что сервер находится под очень высокой нагрузкой (, это еще не так, но цель - выдерживать максимально возможную нагрузку с сотнями или тысячами запросов. в секунду )?

Перенос фактических заданий на другие серверы должен обеспечить низкую загрузку ЦП на сервере, но как избежать накопления процессов и использования всей оперативной памяти сервера или отбрасывания входящих запросов из-за слишком большого количества открытых соединений?

Вероятно, это в основном вопрос правильной настройки nginx и gunicorn. Я немного читал об асинхронных воркерах, основанных на гринлетах в gunicorn :. в документации говорится, что асинхронные рабочие процессы используются «приложениями, выполняющими длительные блокирующие вызовы (т. е. внешними веб-сервисами)", звучит идеально. Там также говорится: "В общем, приложение должно иметь возможность использовать эти рабочие классы без каких-либо изменений ". Звучит великолепно. Есть отзывы по этому поводу?

Спасибо за ваши советы.

17
задан MiniQuark 9 August 2012 в 12:14
поделиться