Rate limiting с Congestion Control

В микросервисной архитектуре встречаются «лавинообразные» падения. Это, например, когда один сервис не вывозит нагрузку и начинает долго обрабатывать запрос, а его клиенты, вместо того, чтобы перестать нагружать сервис, начинают его ретраить, тем самым создавая еще большую нагрузку. 

Проблему можно решать несколькими путями. Со стороны клиентов — реализуя классический Circuit Breaker, о котором не так давно был пост.

Со стороны самого запрашиваемого ресурса — это может быть Rate Limiting, или чуть более умный Rate Limiting, про него сегодня и поговорим.

Rate Limiting, как следует из названия — это ограничение количества обрабатываемых операций (единичных запросов, батчей или даже размеров данных за единицу времени). В микросервисах часто предполагается, что если сервису приходит за какое-то временное окно больше N запросов (далее для простоты RPS), то сервис просто «бесплатно» откидывает остальные запросы.

Основная сложность с тем, чтобы выбрать этот самый ограничивающий N.

* Можно провести нагрузочное тестирование и понять количество RPS, больше которых сервис уже не переваривает.

* Еще можно накинуть какой-то процент к пиковым нагрузкам и выбрать это за N.

* Можно даже просто как-то посчитать.

Усложняется все тем, что быстро меняющееся число, которое зависит от характеристик железа, от количества инстансов, на которые распределяется нагрузка, от бизнесс-логики, работающей в конкретный момент времени. Если у вас несколько микросервисов, поддерживать руками актуальный потолок количества запросов весьма затруднительно.

Один из вариантов, это своего рода эвристический механизм Congestion control.

Механизм отслеживает «загруженность» каждого конкретного инстанса каждого конкретного микросервиса. (это может быть CPU, у нас это загруженность «основного процессора задач» нашего веб-фреймворка). Если инстанс самодиагностирует, что он не справляется с нагрузкой (превышен порог задач в очереди), начинает срабатывать лимит RPS. Лимит уменьшается до тех пор, пока инстанс не начнет чувствовать себя лучше. Если инстанс справляется с нагрузкой, лимит постепенно увеличивается. Если долгое время не было перегруза, лимит RPS снимается.

Стоит также обратить внимание, что механизм плохо подходит, если:

— есть требования точного ограничения RPS. Эвристика сильно зависит от того, сколько и в каком режиме используется CPU в текущем контейнере.

— CPU не является ограничивающим ресурсом.

— Не требуется стабильное время отклика. Например, сервис обрабатывает события батчами, батчи могут приходить неравномерно. При этом пиково CPU может быть перегружен, но в среднем ресурсов хватает на обработку потока событий.

— Нагрузка на CPU в процессе обработки запроса продолжается десятки секунд. Механизм предполагает, что ручки отрабатывают быстро, и изменение лимита RPS очень быстро повлияет на загруженность CPU (секунды или доли секунды). Если endpoint отрабатывает длительное время, то обратная связь будет происходить медленно, и сходимость RPS к максимальному RPS не гарантируется.