Жизнеспособность Kubernetes - Резервируйте потоки / память для определенной конечной точки с Spring Boot
Знаете ли вы (если это возможно), как зарезервировать потоки / память для конкретной конечной точки в микросервисе с пружинной загрузкой?
У меня есть одна микросервисная служба, которая принимает HTTP-запросы через Spring MVC, и эти запросы инициируют http-вызовы в 3-ю систему, которая иногда частично ухудшается и реагирует очень медленно. Я не могу сократить время ожидания, потому что некоторые вызовы очень медленные по своей природе.
У меня есть пружинный привод /health
конечная точка включена, и я использую ее как контейнер livenessProbe
в кучернетском кластере. Иногда, когда 3-я система деградирует, микросервис не реагирует на /health
конечная точка и kubernetes перезапускает мой сервис.
Это потому, что я использую RestTemplate для выполнения HTTP-вызовов, поэтому я постоянно создаю новые потоки, и у JVM возникают проблемы с памятью.
Я думал о некоторых решениях:
Реализуйте конечную точку высокой доступности "/health", резервные потоки или что-то в этом роде.
Используйте асинхронный http-клиент.
Реализуйте автоматический выключатель.
Настройте пользовательские таймауты для 3-й конечной точки, которую я использую.
Создайте другой небольшой сервис (golang) и разверните его в том же модуле. Эта служба собирается обработать датчик живучести.
Перенос / рефакторинг сервисов на небольшие сервисы и, возможно, с другими фреймворками / языками, такими как Vert.x, go и т. Д.
Как вы думаете?
Заранее спасибо.
1 ответ
Конечная точка работоспособности привода очень удобна с пружинной загрузкой - почти слишком удобна в этом контексте, так как она выполняет более глубокие проверки работоспособности, чем вы обязательно хотите в тесте живучести. Для готовности вы хотите сделать более глубокие проверки, но не живость. Идея состоит в том, что, если Pod немного перегружен и не готов, то он будет снят с балансировки нагрузки и получит передышку. Но если он потеряет жизнеспособность, он будет перезапущен. Таким образом, вам нужны только минимальные проверки жизнеспособности ( если Health Checks вызывает другие App Health Checks). Используя оба состояния привода, ваши занятые стручки не смогут получить передышку, когда их убьют первыми. И kubernetes периодически вызывает конечную точку http при выполнении обоих проб, что еще больше усугубляет проблему использования вашего потока (рассмотрите периоды на пробах).
Для вашего случая вы можете определить команду живучести, а не зонд http - https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/. Команда может просто проверить, что Java-процесс запущен (что-то вроде того, что вы предлагаете для проверки на основе go).
Во многих случаях использование исполнительного механизма для жизнеспособности было бы хорошо (представьте себе приложения, которые сталкиваются с другим ограничением перед потоками, что было бы вашим случаем, если бы вы использовали асинхронную / неблокирующую работу с реактивным стеком). В вашем случае это может привести к проблемам - проверка привода на наличие зависимостей, таких как брокеры сообщений, может быть другой, когда вы получаете чрезмерный перезапуск (в этом случае при первом развертывании).
У меня есть прототип, который просто завершает эту проблему: SpringBoot позволяет заполнять 100% доступных потоков запросами общедоступной сети, оставляя конечную точку /health недоступной для балансировщика нагрузки AWS, который отключает службу, считая ее нездоровой. Существует различие между нездоровым и занятым... и здоровье - это больше, чем просто запущенный процесс, прослушивание порта, поверхностная проверка и т. Д. - это должен быть "глубокий пинг", который проверяет, что он и все его зависимости работоспособны, чтобы дать уверенный ответ проверки здоровья.
Мой подход к решению этой проблемы заключается в создании двух новых компонентов с автоматическим подключением: первый для настройки Jetty с фиксированным, настраиваемым максимальным числом потоков (убедитесь, что вашей JVM выделено достаточно памяти для соответствия), а второй для сохранения счетчика. каждого запроса, когда он запускается и завершается, генерируя исключение, которое сопоставляется с ответом HTTP 429 СЛИШКОМ МНОГО ЗАПРОСОВ, если число приближается к потолку, который является maxThreads - reserveThreads. Затем я могу установить для параметра ReserveThreads все, что захочу, и конечная точка /health не будет привязана счетчиком запросов, гарантируя, что он всегда сможет войти.
Я просто искал вокруг, чтобы выяснить, как другие решают эту проблему, и нашел ваш вопрос с той же самой проблемой, пока что не видел ничего более твердого.
Чтобы настроить параметры потока Jetty через файл свойств приложения: http://jdpgrailsdev.github.io/blog/2014/10/07/spring_boot_jetty_thread_pool.html
Похоже, ваш микросервис должен реагировать на проверки здоровья /health
в то время как возвращая результаты этого 3-го сервиса его вызова.
Я бы собрал асинхронный http-сервер с Vert.x-Web и попробовал бы проверить его перед тем, как изменить ваш хороший код. Создайте две конечные точки. /health
проверить и /slow
вызов, который просто Sleeps() в течение примерно 5 минут, прежде чем ответить "привет". Разверните его в minikube или в вашем кластере и посмотрите, сможет ли он реагировать на проверки работоспособности во время сна другого HTTP-запроса.