Мое Java-приложение вытягивает некоторые данные из внешних систем (JSON через HTTP), как в реальном времени, когда пользователи моего приложения запрашивают его, так и в пакетном режиме (ночные обновления для случаев, когда пользователь не запрашивал его). Данные изменяются, поэтому варианты кэширования, вероятно, исчерпаны.Как правильно дросселировать веб-запросы на внешние системы?
Внешние системы имеют дросселирование на месте, точные параметры, о которых я не знаю, и которые, вероятно, будут меняться в зависимости от нагрузки системы (например, пиковое время 10 запросов в секунду от одного IP-адреса, внепиковое время 100 запросов в секунду от открытого IP-адреса). Если запросы слишком часты, они тайм-аут или возвращают HTTP 503.
Прямо сейчас я пытаюсь выполнить запрос 5 раз с задержкой в 2000мс между каждой, отказываясь, если ошибка принимается каждый раз. Это не оптимально, поскольку иногда в периоды пиков почти все запросы терпят неудачу; Я мог бы избежать этих просьб и, возможно, получить хотя бы некоторых, чтобы добиться успеха.
Мои цели состоят в том, чтобы иметь несколько простую, надежную конструкцию и достаточную гибкость, чтобы я мог вытащить некоторые показатели из дросселя, чтобы понять, насколько хорошо реагируют внешние системы (и, следовательно, регулирует частоту их вызова) и автоматически настраивать интервал, с которым я их вызываю (индивидуально для каждой системы), чтобы он был оптимальным как в непиковые, так и в пиковые часы.
Моя инфраструктура Java с RabbitMQ над MongoDB над Linux.
Я имею в виду три основных варианта:
Поскольку я уже RabbitMQ используется для пакетной обработки, я мог бы просто ввести в очередь, в которой веб-процессы будут посылать запросы, которые они имеют для внешних систем , тогда рабочие процессы будут считывать из этой очереди, дросселировать себя по мере необходимости и возвращать результаты. Это позволило бы запускать несколько параллельных рабочих процессов на большее количество серверов, если это необходимо. Моя основная забота заключается в том, что это не очень простое решение, и как управлять максимальной пропускной способностью пикового времени и, следовательно, веб-процессы ждут долгое время. Также это превращает мой RabbitMQ в критическую единую точку отказа; если он умирает, вся система останавливается (в отличие от ночных пакетных процессов, которые просто не работают, что менее критично). Я полагаю, что rpc является правильной моделью использования RabbitMQ, но не уверен. Изменить - я опубликовал связанный с ним вопрос How to properly implement RabbitMQ RPC from Java servlet web container? о том, как это реализовать.
Введем Nginx (например ngx_http_limit_req_module), HAProxy (link) или другое программное обеспечение прокси к соединению (как обратные прокси?), У них заботиться о дросселирования через какой-то конфигурации магии. Про является то, что мне не нужно вносить изменения в код. Кон-то, что это больше технологий, и один из них я раньше не использовал, поэтому вероятность неправильной настройки чего-то довольно высока. Также было бы нелегко делать динамическое дросселирование в зависимости от нагрузки на внешний сервер или приоритизировать прямые запросы по пакетным запросам или получать статистику о том, как работает дросселирование. Кроме того, большинство документов и примеров, вероятно, будут влиять на входящие запросы, а не исходящие.
Выполнение решения на основе чистой Java (например, протекающая реализация ковша). Было бы просто в том смысле, что это «просто код», но дьявол находится в деталях; отладка всех тупиков, голода и условий гонки не всегда весело.
Что мне здесь не хватает?
Какое это лучшее решение в этом случае?
P.S.Несколько смежный вопрос: каков правильный подход для регистрации всех внешних вызовов системы, чтобы собиралась статистика относительно того, как часто я их вызываю, и какова вероятность успеха?
Например, после каждого вызова я бы вызывал что-то вроде .logExternalSystemInvocation (externalSystemName, wasSuccessful, elapsedTimeMills), а затем извлекал из него некоторые агрегированные данные, когда это необходимо.
Есть ли стандартная библиотека/инструмент для использования, или мне нужно катиться самостоятельно?
Если я использую вариант 1. с RabbitMQ, есть ли способ организовать поток, чтобы я получил это из коробки с консоли RabbitMQ? Я бы не хотел отправлять все неудавшиеся сообщения в очередь на яд, он будет слишком быстро заполняться, и в большинстве случаев нет необходимости повторно обрабатывать эти неудавшиеся запросы, поскольку пользователь уже грустно перешел.
'Изменения данных так опции кэширования, exhausted.', какие изменения мы имеем дело? это уникально для разных пользователей? или как время основано? –
Внешние системы отслеживают информацию об определенных объектах. Эта информация меняется со временем. Я кэширую уже на уровне каждого объекта, обращаясь к внешним системам, только если информация об определенном объекте не была обновлена за последние X минут. В любом случае, хотя разумное кэширование может или не поможет, я бы не хотел, чтобы это было в центре внимания этого вопроса. –