Очевидно, что Spring рассчитывает ваши запросы и выдает AsyncRequestTimeoutException
, который возвращает 503 вашему клиенту.
Теперь вопрос в том, почему это происходит?Есть две возможности.
Это допустимые тайм-ауты.Вы упомянули, что вы видите исключения только тогда, когда увеличивается нагрузка на ваш сервер.Поэтому, возможно, ваш сервер просто не может справиться с этой нагрузкой, и его производительность снизилась до такой степени, что некоторые запросы не могут быть выполнены до того, как Spring их истечет.
Тайм-ауты вызваны вашимсерверу не удалось отправить ответ на асинхронный запрос из-за ошибки программирования, оставив запрос открытым до тех пор, пока Spring его не истечет.Это легко сделать, если ваш сервер плохо обрабатывает исключения.Если ваш сервер работает синхронно, это нормально, быть немного неаккуратным с обработкой исключений, потому что необработанные исключения будут распространяться до серверной среды, которая отправит ответ клиенту.Но если вам не удается обработать исключение в каком-то асинхронном коде, это исключение будет обнаружено в другом месте (возможно, в некотором коде управления пулом потоков), и у этого кода нет возможности узнать, что существует асинхронный запрос, ожидающий результата операцииЭто вызвало исключение.
Трудно понять, что может происходить, не зная больше о вашем приложении.Но есть некоторые вещи, которые вы можете исследовать.
Сначала попробуйте поискать исчерпание ресурсов.
- Работает ли сборщик мусора постоянно?
- Все ли процессорыпривязано к 100%?
- Сильно ли меняется ОС?
- Если сервер баз данных находится на отдельном компьютере, на этом компьютере наблюдаются признаки исчерпания ресурсов?
- Сколькосоединения открыты для базы данных?Если есть пул соединений, он исчерпан?
- Сколько потоков запущено?Если на сервере есть пулы потоков, не превышены ли они?
Если что-то ограничено, то, возможно, именно узкое место приводит к истечению времени ожидания ваших запросов.
Попробуйтеустановите spring.mvc.async.request-timeout
в -1 и посмотрите, что произойдет.Получаете ли вы теперь ответы на каждый запрос, только медленно, или кажется, что некоторые запросы зависают навсегда?Если это последнее, это настоятельно указывает на наличие ошибки на вашем сервере, которая приводит к тому, что он теряет отслеживание запросов и не может отправлять ответы.(Если настройка spring.mvc.async.request-timeout
, похоже, не имеет никакого эффекта, то следующее, что вам следует выяснить, действительно ли работает механизм, который вы используете для настройки конфигурации.)
Стратегия, которую я нашел полезной вв этих случаях необходимо генерировать уникальный идентификатор для каждого запроса и записывать этот идентификатор вместе с некоторой контекстной информацией каждый раз, когда сервер выполняет асинхронный вызов или получает ответ от асинхронного вызова, а также в различных контрольных точках в асинхронных обработчиках.Если запросы пропадают, вы можете использовать информацию журнала для определения идентификаторов запросов и того, что сервер делал в последний раз с этим запросом.
Аналогичная стратегия заключается в сохранении каждого идентификатора запроса в карте, в которой значениеэто объект, который отслеживает, когда запрос был запущен и что ваш сервер последний раз делал с этим запросом.(В этом случае ваш сервер обновляет эту карту на каждой контрольной точке вместо записи в журнал или в дополнение к ней.) Вы можете настроить фильтр для генерации идентификаторов запросов и ведения карты.Если ваш фильтр видит, что сервер отправляет ответ 5xx, вы можете записать последнее действие для этого запроса с карты.
Надеюсь, это поможет!