Подтвердить что ты не робот

Запросить очередь перед службой REST

Какое лучшее технологическое решение (инфраструктура/подход) должно иметь очередь запросов перед службой REST. так что я могу увеличить количество экземпляров службы REST для более высокой доступности и путем размещения очереди запросов перед формированием границы службы/транзакции для клиента службы.

  • Мне нужна хорошая и легкая технология/выбор рамки для очереди запросов (java).
  • Подход к реализации конкурирующего потребителя с ним.
4b9b3361

Ответ 1

Здесь есть несколько проблем, в зависимости от ваших целей.

Во-первых, это только повышает доступность ресурсов на задней панели. Подумайте, есть ли у вас 5 серверов, обрабатывающих запросы очереди на задней панели. Если один из этих серверов опускается, то запрос в очереди должен возвращаться в очередь и быть переадресован на один из оставшихся 4 серверов.

Однако, в то время как эти серверы back end обрабатываются, серверы переднего плана поддерживают текущие инициирующие запросы. Если один из этих интерфейсных серверов выходит из строя, то эти соединения полностью теряются, и исходный клиент должен повторно отправить запрос.

Возможно, предпосылка заключается в том, что более простые системы переднего конца имеют более низкий риск отказа, и это, безусловно, справедливо для отказа программного обеспечения. Но сетевые карты, источники питания, жесткие диски и т.д. Являются довольно агностическими для таких ложных надежд человека и наказывают всех одинаково. Итак, подумайте об этом, говоря об общей доступности.

Что касается дизайна, задним концом является простой процесс, ожидающий очереди сообщений JMS и обрабатывающий каждое сообщение по мере их поступления. Существует множество примеров этого, и любой JMS-сервер будет соответствовать на высоком уровне. Все, что вам нужно, это убедиться, что обработка сообщений транзактивна, так что, если обработка сообщений не удалась, сообщение остается в очереди и может быть повторно добавлено к другому обработчику сообщений.

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

Передняя часть - это то, где все становится немного сложнее, поскольку серверы переднего плана являются мостом из синхронного мира запроса REST в асинхронный мир процессоров задней части. Запрос REST следует типично шаблону RPC для потребления полезной нагрузки запроса из сокета, открытия соединения, обработки результатов и передачи результатов обратно в исходный сокет.

Чтобы отобразить эту руку, вы должны взглянуть на асинхронный сервлет, обрабатывающий введенный сервлет 3.0, и доступен в Tomcat 7, последнем Jetty (не уверен, какая версия), Glassfish 3.x и т.д.

В этом случае то, что вы сделаете, - это когда приходит запрос, вы конвертируете номинально синхронный вызов Сервл в асинхронный вызов с помощью HttpServletRequest.startAsync(HttpServletRequest request, HttpServletResponse response).

Это возвращает AsynchronousContext, и после его запуска сервер освобождает поток обработки. Затем вы делаете несколько вещей.

  • Извлеките параметры из запроса.
  • Создайте уникальный идентификатор для запроса.
  • Создайте новую полезную нагрузку запроса конечного пользователя из ваших параметров.
  • Свяжите идентификатор с AsyncContext и сохраните контекст (например, вставьте его в общую карту приложения).
  • Отправьте запрос завершения в очередь JMS.

В этот момент начальная обработка выполняется, и вы просто возвращаетесь из doGet (или службы или что-то еще). Поскольку вы не вызывали AsyncContext.complete(), сервер не будет закрывать соединение с сервером. Поскольку у вас есть хранилище AsyncContext на карте по идентификатору, оно удобно для безопасного хранения в настоящее время.

Теперь, когда вы отправили запрос в очередь JMS, он содержал: идентификатор запрашиваемого вами запроса (который вы сгенерировали), любые параметры для запроса и идентификацию фактического сервера, делающего запрос. Этот последний бит важен, так как результаты обработки должны возвращаться к его началу. Источник идентифицируется идентификатором запроса и идентификатором сервера.

Когда ваш сервер для входа в систему запустился, он также запустил поток, который должен выполнить прослушивание очереди ответов JMS. Когда он устанавливает свое JMS-соединение, он может настроить фильтр, например "Дайте мне только сообщения для ServerID ABC123". Или вы можете создать уникальную очередь для каждого внешнего сервера, а серверный сервер использует идентификатор сервера, чтобы определить очередь для возврата ответа.

Когда процессоры на задней панели потребляют сообщение, они берут идентификатор запроса и параметры, выполняют работу, а затем берут результат и помещают их в очередь ответа JMS. Когда он вернет результат, он добавит исходный идентификатор сервера и исходный идентификатор запроса в качестве свойств сообщения.

Итак, если вы получили запрос первоначально для Front End Server ABC123, процессор задней части будет возвращать результаты на этот сервер. Затем этот поток прослушивателя будет уведомлен, когда он получит сообщение. Задача потоков слушателей состоит в том, чтобы принять это сообщение и включить его во внутреннюю очередь на интерфейсном сервере.

Эта внутренняя очередь опирается на пул потоков, задачей которого является отправка данных запроса обратно в исходное соединение. Он делает это, извлекая исходный идентификатор запроса из сообщения, просматривая AsyncContext из этой внутренней карты, рассмотренной ранее, а затем отправляя результаты до HttpServletResponse, связанного с AsyncContext. В конце он вызывает AsyncContext.complete() (или аналогичный метод), чтобы сообщить серверу, что вы сделали, и разрешить ему освободить соединение.

Для ведения домашнего хозяйства на сервере переднего плана должен быть другой поток, который должен определить, когда запросы слишком долго ожидали на карте. Часть исходного сообщения должна была быть временем начала запроса. Этот поток может просыпаться каждую секунду, сканировать карту для запросов и для любых, которые были там слишком долго (скажем, 30 секунд), он может отправить запрос на другую внутреннюю очередь, потребляемую набором обработчиков, предназначенных для информирования что запрос был отложен.

Вам нужны эти внутренние очереди, чтобы основная логика обработки не задерживалась, ожидая, когда клиент будет потреблять данные. Это может быть медленное соединение или что-то еще, поэтому вы не хотите блокировать все остальные ожидающие запросы, чтобы обрабатывать их один за другим.

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

Вы не можете повторно использовать эти запросы, там нет такой вещи, как балансировщик нагрузки, возвращающийся к клиенту. Если клиент разрешает вам делать обратные вызовы через опубликованные конечные точки, то, конечно, вы можете просто использовать другой обработчик JMS-сообщений. Но это не объект REST, REST на этом уровне обсуждения больше клиент/сервер/RPC.

Что касается поддержки асинхронных сервлетов на более высоком уровне, чем сырой сервлет (например, Джерси для JAX-RS или что-то в этом роде), я не могу сказать. Я не знаю, какие рамки поддерживают его на этом уровне. Похоже, что это особенность Jersey 2.0, которого еще нет. Там могут быть и другие, вам придется осмотреться. Кроме того, не фиксируйте сервлет 3.0. Servlet 3.0 - это просто стандартизация методов, используемых в отдельных контейнерах в течение некоторого времени (особенно Jetty), поэтому вы можете захотеть взглянуть на конкретные параметры контейнера за пределами только Servlet 3.0.

Но понятия одинаковы. Большой вынос - это прослушиватель очереди ответов с фильтрованным JMS-соединением, внутренней карточкой запроса в AsyncContext и внутренними очередями и пулами потоков для выполнения фактической работы в приложении.

Ответ 2

Если вы расслабляете свое требование о том, что оно должно быть на Java, вы можете рассмотреть HAProxy. Он очень легкий, очень стандартный, и делает много хороших вещей (запрос пула /keepalives/queueing ).

Подумайте дважды, прежде чем выполнять очередь запросов. Если ваш трафик не будет чрезвычайно громоздким, он ничего не сделает, но повредит вашу производительность системы под нагрузкой.

Предположим, что ваша система может обрабатывать 100 запросов в секунду. Ваш HTTP-сервер имеет ограниченный рабочий поток. Единственный способ, которым может помочь пул запросов, - это получение более 100 запросов в секунду. После заполнения пула рабочих потоков запросы начнут накапливаться в пуле балансировки нагрузки. Поскольку они прибывают быстрее, чем вы можете справиться с ними, очередь становится больше... и больше... и больше. В конце концов, этот пул тоже заполняется, или вы исчерпали ОЗУ, и балансировщик нагрузки (и, следовательно, вся система) сильно сработает.

Если ваш веб-сервер слишком занят, начните отклонять запросы и получите дополнительную емкость в Интернете.

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

Ответ 3

Дизайн, который мы используем, представляет собой интерфейс REST, который получает весь запрос и отправляет их в очередь сообщений (т.е. Rabbitmq)

Затем рабочие прослушивают сообщения и выполняют их по определенным правилам. Если все пойдет вниз, у вас все равно будет запрос в MQ, и если у вас будет большое количество запросов, вы можете просто добавить рабочих...

Проверьте этот лейтмотив, это как-то показывает силу этой концепции!

http://www.springsource.org/SpringOne2GX2012