2013-08-23 6 views
1

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

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

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

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

Моя инфраструктура Java с RabbitMQ над MongoDB над Linux.

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

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

  2. Введем Nginx (например ngx_http_limit_req_module), HAProxy (link) или другое программное обеспечение прокси к соединению (как обратные прокси?), У них заботиться о дросселирования через какой-то конфигурации магии. Про является то, что мне не нужно вносить изменения в код. Кон-то, что это больше технологий, и один из них я раньше не использовал, поэтому вероятность неправильной настройки чего-то довольно высока. Также было бы нелегко делать динамическое дросселирование в зависимости от нагрузки на внешний сервер или приоритизировать прямые запросы по пакетным запросам или получать статистику о том, как работает дросселирование. Кроме того, большинство документов и примеров, вероятно, будут влиять на входящие запросы, а не исходящие.

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

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

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

P.S.Несколько смежный вопрос: каков правильный подход для регистрации всех внешних вызовов системы, чтобы собиралась статистика относительно того, как часто я их вызываю, и какова вероятность успеха?

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

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

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

+0

'Изменения данных так опции кэширования, exhausted.', какие изменения мы имеем дело? это уникально для разных пользователей? или как время основано? –

+0

Внешние системы отслеживают информацию об определенных объектах. Эта информация меняется со временем. Я кэширую уже на уровне каждого объекта, обращаясь к внешним системам, только если информация об определенном объекте не была обновлена ​​за последние X минут. В любом случае, хотя разумное кэширование может или не поможет, я бы не хотел, чтобы это было в центре внимания этого вопроса. –

ответ