Как правильно регулировать веб-запросы к внешним системам?

Мое веб-приложение Java извлекает некоторые данные из внешних систем (JSON через HTTP) как в режиме реального времени, когда пользователи моего приложения запрашивают его, так и в пакетном режиме (ночные обновления для случаев, когда ни один пользователь не запрашивал их). Данные изменяются, поэтому параметры кэширования, вероятно, исчерпаны.

Внешние системы имеют некоторое регулирование, точные параметры которого я не знаю, и которые, вероятно, изменяются в зависимости от нагрузки системы (например, пиковое время 10 запросов в секунду с одного IP-адреса, непиковое время 100 запросов в секунду с открытого IP-адреса). Если запросы слишком частые, они истекают или возвращают HTTP 503.

Прямо сейчас я пытаюсь выполнить запрос 5 раз с задержкой 2000 мс между каждым, отказываясь от получения ошибки каждый раз. Это не оптимально, так как иногда в часы пиковой нагрузки почти все запросы не выполняются; Я мог бы избежать этих запросов и, возможно, получить хотя бы некоторые, чтобы добиться успеха вместо этого.

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

Моя инфраструктура - Java с RabbitMQ поверх MongoDB над Linux.

Я думаю о трех основных вариантах:

  1. Поскольку у меня уже есть RabbitMQ, используемый для пакетной обработки, я мог бы просто ввести очередь, в которую веб-процессы будут отправлять запросы, которые они имеют для внешних систем, затем рабочие процессы будут считывать из этой очереди, регулировать себя по мере необходимости и возвращать результаты. Это позволит при необходимости запускать несколько параллельных рабочих процессов на большем количестве серверов. Моя главная проблема заключается в том, что это не очень простое решение, и как управлять низкой пропускной способностью в пиковые часы и, следовательно, веб-процессами, которые долго ждут. Также это превращает мой RabbitMQ в критическую точку сбоя; если он умирает, вся система останавливается (в отличие от ночных пакетных процессов, которые просто больше не работают, что менее критично). Я полагаю, что rpc - правильный шаблон использования RabbitMQ, но не уверен. Изменить - я разместил связанный вопрос Как правильно реализовать RPC RabbitMQ из веб-контейнера сервлета Java? о том, как реализовать это.

  2. Представьте nginx (например, http://nginx.org/en/docs/http/ngx_http_limit_req_module.html), HAProxy ( link) или другое прокси-программное обеспечение для микса (в качестве обратных прокси?), Попросите их позаботиться о регулировании с помощью некоторой магии конфигурации. Плюс в том, что мне не нужно вносить изменения в код. Дело в том, что используется больше технологий, а я раньше не использовал, так что шансы неверной настройки чего-либо достаточно высоки. Также, вероятно, будет нелегко выполнять динамическое регулирование в зависимости от нагрузки на внешний сервер, или расставлять приоритеты живых запросов над пакетными запросами, или получать статистику того, как происходит регулирование. Кроме того, большинство документации и примеров, вероятно, будут касаться регулирования входящих запросов, а не исходящих.

  3. Сделайте чисто Java-решение (например, реализацию с утечкой памяти). Было бы просто в том смысле, что это "просто код", но дьявол кроется в деталях; отладка всех тупиков, голода и условий гонки - это не всегда весело.

Что мне здесь не хватает?

Какое решение является лучшим в этом случае?

PS В некоторой степени связанный с этим вопрос - как правильно регистрировать все вызовы внешней системы, чтобы собирать статистику относительно того, как часто я их вызываю, и какова вероятность успеха?

Например, после каждого вызова я вызывал что-то вроде.logExternalSystemInvocation(externalSystemName, wasSuccessful, elapsedTimeMills), а затем извлекал из него некоторые агрегированные данные при необходимости.

Есть ли стандартная библиотека / инструмент для использования, или я должен свернуть свой собственный?

Если я использую вариант 1. с RabbitMQ, есть ли способ организовать поток так, чтобы я получил это из коробки с консоли RabbitMQ? Я бы не хотел отправлять все сообщения с ошибками в очередь отравления, хотя они заполнялись бы слишком быстро, и в большинстве случаев нет необходимости повторно обрабатывать эти неудавшиеся запросы, поскольку пользователь уже, к сожалению, перешел.

1 ответ

Возможно, эта система с открытым исходным кодом может вам немного помочь: http://code.google.com/p/valogato/

Другие вопросы по тегам