Ограничение скорости (Rate Limiting) в API Management
September 16, 2022
С развитием интернета все больше компаний начали внедрять облачные технологии и микросервисы. Однако из-за технических особенностей облачных технологий и микросервисов нам приходится одновременно управлять сотнями различных сервисов. Поэтому мы должны не только обеспечивать бесперебойную работу всей системы, но и заботиться о безопасности и стабильности каждого API-сервиса.
Ограничение скорости (rate limiting) является одним из наиболее важных решений для обеспечения стабильности API-сервисов. Однако приложение станет чрезмерно перегруженным, если каждый сервис будет требовать собственного ограничения скорости. Как точка входа и выхода всего трафика в цифровом мире, API-шлюз помогает достичь единого управления API для всех сервисов. Он защищает стабильную работу системных сервисов. В этой статье мы покажем, как можно реализовать ограничение скорости через API-шлюз Apache APISIX, а также опишем стратегии и методы ограничения скорости.
Что такое ограничение скорости
Ограничение скорости — это стратегия управления интернет-трафиком и максимизации пропускной способности. Использование ограничения скорости позволяет системе обрабатывать только те запросы, которые соответствуют определенным ограничениям; любые дополнительные запросы, превышающие эти ограничения, будут поставлены в очередь, понижены в приоритете или даже отклонены. Ограничение скорости также защищает систему от непредвиденных ситуаций, таких как всплески трафика или злонамеренные атаки, и позволяет системе предоставлять стабильные и надежные услуги.
Например, когда популярный твит вызывает всплеск трафика, Twitter вынужден применять ограничение скорости, чтобы предотвратить сбои серверов из-за перегрузки.
Зачем это нужно
Сначала рассмотрим несколько простых примеров из реальной жизни, где используется ограничение скорости. Например, туристические достопримечательности могут продавать только определенное количество билетов на праздники. Также в популярных ресторанах нам часто приходится бронировать столики заранее или ждать в очереди.
В API-шлюзе ограничение скорости также имеет множество преимуществ. Оно накладывает определенные ограничения на API-сервисы, обеспечивая их бесперебойную работу и предотвращая потери, вызванные сбоями серверов из-за всплесков трафика. Вот пять различных практических ограничений:
- Ограничение скорости запросов.
- Ограничение количества запросов за единицу времени.
- Задержка запросов.
- Отклонение запросов клиентов.
- Ограничение скорости ответов.
Когда это нужно
Вместе с идентификацией и аутентификацией ограничение скорости может максимально раскрыть свои преимущества и повысить доступность системы следующими способами:
- Избежание злонамеренных атак.
- Обеспечение стабильной работы системы и предотвращение сбоев серверов из-за всплесков трафика.
- Предотвращение сбоев серверов из-за всплесков запросов, вызванных ошибками в вышестоящих или нижестоящих сервисах.
- Избежание слишком частых дорогостоящих вызовов API.
- Снижение ненужного расхода ресурсов за счет ограничения частоты вызовов API.
Теория, лежащая в основе ограничения скорости
В предыдущих разделах мы рассмотрели преимущества ограничения скорости. Теперь давайте разберемся с теорией, лежащей в его основе! Реализация ограничения скорости на низком уровне достигается с помощью определенных алгоритмов. Наиболее часто используемые из них включают:
- Алгоритм счетчика
- Фиксированное окно
- Скользящее окно
- Алгоритм "протекающего ведра" (Leaky Bucket)
- Алгоритм "токенового ведра" (Token Bucket)
Алгоритм счетчика
Алгоритм счетчика относительно прост для понимания и имеет два типа:
Первый тип — это алгоритм фиксированного окна, который поддерживает счетчик в фиксированной единице времени и сбрасывает счетчик до нуля, если обнаруживает, что единица времени прошла.
Второй тип — это алгоритм скользящего окна, который является улучшением первого; он включает следующие шаги:
- Разделение единиц времени на несколько интервалов (каждый называется блоком).
- Каждый блок имеет счетчик; любой входящий запрос увеличивает счетчик на 1.
- Через фиксированный промежуток времени это временное окно сдвигается вперед на один блок.
- Оно вычисляет общее количество запросов в этом временном окне, суммируя все счетчики блоков в окне; если общее количество запросов превышает ограничение, все запросы в этом окне будут отклонены.
Алгоритм "протекающего ведра"
Представьте, что есть протекающее ведро; все запросы сначала попадают в очередь, а затем ведро отправляет их с постоянной скоростью.

Если запросы превышают емкость ведра, система отклоняет и отказывает в обработке любых переполненных запросов. Алгоритм "протекающего ведра" может ограничивать скорость запросов и обеспечивать их отправку с постоянной скоростью, создавая режим "легко войти, но трудно выйти".
Основные шаги этого алгоритма:
- Все запросы хранятся в ведре фиксированного размера.
- Ведро отправляет запросы с постоянной скоростью, пока оно не опустеет.
- Когда ведро заполнено, система отклоняет любые дополнительные запросы.
Алгоритм "токенового ведра"
Алгоритм "токенового ведра" состоит из двух частей: генерации токенов и их удаления. Токеновое ведро генерирует токены с постоянной скоростью и хранит их в фиксированном хранилище. Когда запрос проходит через токеновое ведро, он забирает один или несколько токенов. Когда количество токенов в ведре достигает максимальной емкости, новые токены будут отклоняться. Также хранилище отклонит входящие запросы, если токены закончатся.

Основные шаги алгоритма "токенового ведра":
- Токеновое ведро генерирует токены с постоянной скоростью и помещает их в хранилище.
- Если ведро заполнено, новые токены будут отклонены. Когда поступает запрос, он забирает один или несколько токенов из хранилища.
- Если токены в ведре закончились, система отклонит любой входящий запрос.
Реализация ограничения скорости через API-шлюз
Если нужно поддерживать только несколько API-сервисов, можно напрямую использовать алгоритмы ограничения скорости в сервисе. Например, если вы используете Go для разработки системы, можно использовать tollbooth или golang.org/x/time/rate для реализации алгоритмов. Если вы используете Lua, можно использовать модули NGINX limit_req, limit_conn и Lua-resty-limit-traffic для реализации алгоритмов.
Если ограничение скорости реализовано на уровне API-сервиса, ограничения будут задаваться самим сервисом, и каждый сервис может иметь разные ограничения. Эти ограничения и различия могут вызвать проблемы на уровне управления, если количество API-сервисов значительно увеличится. В таком случае мы не сможем использовать API-шлюз для единого управления всеми API-сервисами. Также при использовании API-шлюза для решения проблем ограничения скорости можно реализовать несвязанные бизнес-функции, такие как идентификация, аутентификация, логирование, наблюдаемость и т.д.
Apache APISIX — это динамический, высокопроизводительный облачный API-шлюз. APISIX поддерживает более 80 различных плагинов и уже имеет богатую экосистему. Мы можем управлять трафиком API-сервисов с помощью плагинов APISIX, включая limit-req, limit-conn и limit-count. Здесь я приведу пример использования плагинов ограничения скорости в APISIX.
Предположим, у нас есть API-сервис (/user/login), который помогает пользователям входить в систему. Чтобы избежать злонамеренных атак и истощения ресурсов, нам нужно включить функцию ограничения скорости для обеспечения стабильности системы.
Ограничение запросов
Плагин limit-req ограничивает скорость запросов, используя алгоритм "протекающего ведра", и мы связываем его с соответствующими маршрутами или конкретными клиентами.
Мы можем напрямую использовать Admin API APISIX для создания такого маршрута:
X-API-Key — это admin_key в конфигурации APISIX.
curl http://127.0.0.1:9080/apisix/admin/routes/1 \ -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { "methods": ["POST"], "uri": "/user/login", "plugins": { "limit-req": { "rate": 3, "burst": 2, "rejected_code": 503, "key": "remote_addr" } }, "upstream": { "type": "roundrobin", "nodes": { "127.0.0.1:1980": 1 } } }'
Значение этого фрагмента кода: Мы используем IP-адрес клиента в качестве условия для ограничения скорости запросов.
- Если скорость запросов меньше 3 запросов в секунду (
rate), запрос обрабатывается нормально; - Если скорость запросов больше 3 запросов в секунду, но меньше 5 запросов в секунду (
rate+burst), мы понижаем приоритет этих запросов; - Если скорость запросов больше 5 запросов в секунду (
rate+burst), любые запросы, превышающие максимальное ограничение, возвращают HTTP-код 503.
Если вы хотите узнать больше о limit-req, ознакомьтесь с документацией: APISIX limit-req
Ограничение соединений
Плагин limit-conn ограничивает количество параллельных запросов (или соединений). Вот пример кода для включения этого плагина для /user/login:
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { "methods": ["POST"], "uri": "/user/login", "id": 1, "plugins": { "limit-conn": { "conn": 3, "burst": 2, "default_conn_delay": 0.1, "rejected_code": 503, "key": "remote_addr" } }, "upstream": { "type": "roundrobin", "nodes": { "127.0.0.1:1980": 1 } } }'
Значение этого фрагмента кода: Мы используем IP-адрес клиента в качестве условия для ограничения параллельных запросов.
- Если количество параллельных соединений одного клиента меньше 3 (
conn), запрос обрабатывается нормально с кодом 200; - Если количество параллельных соединений больше 3 (
conn), но меньше 5 (conn+burst), мы замедляем обработку переполненных запросов, добавляя задержку в 0.1 секунды; - Если количество параллельных соединений больше 5 (
conn+burst), запрос будет отклонен с возвратом HTTP-кода 503.
Если вы хотите узнать больше о limit-conn, ознакомьтесь с документацией: APISIX limit-conn
Ограничение количества запросов
Плагин limit-count похож на ограничение скорости API GitHub; он ограничивает общее количество запросов за определенный интервал времени и возвращает оставшееся количество запросов в HTTP-заголовке. Вот пример кода для включения этого плагина для /user/login:
curl -i http://127.0.0.1:9080/apisix/admin/routes/1 \ -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { "uri": "/user/login", "plugins": { "limit-count": { "count": 3, "time_window": 60, "rejected_code": 503, "key": "remote_addr", "policy": "local" } }, "upstream": { "type": "roundrobin", "nodes": { "127.0.0.1:9001": 1 } } }'
Значение этого фрагмента кода: Мы используем IP-адрес клиента в качестве условия для ограничения количества запросов; счетчик сохраняется локально в памяти.
Если количество запросов превышает 3 (count) в течение 60 секунд (time_window), запросы, отправленные сверх этого лимита, будут возвращать HTTP-код 503 (rejected_code).
Если вы хотите узнать больше о limit-count, ознакомьтесь с документацией: APISIX limit-count
Преимущества ограничения скорости в Apache APISIX
Когда мы используем NGINX для управления трафиком, если количество API-запросов вызывает всплеск трафика, NGINX может показать свои недостатки, одним из которых является невозможность динамической загрузки конфигураций. С другой стороны, сервисы APISIX (такие как Route и Service) поддерживают горячую перезагрузку конфигураций. Даже при всплеске трафика APISIX может мгновенно изменить ограничения скорости и другие настройки плагинов безопасности. Благодаря механизму наблюдения etcd, APISIX может обновлять уровень данных за миллисекунды без перезагрузки сервисов.
Кроме того, APISIX также поддерживает ограничение скорости на уровне кластера. Например, мы можем использовать limit-count для изменения конфигурации policy на redis или redis-cluster. Таким образом, мы можем ограничивать скорость на уровне кластера, разделяя результаты вычислений между различными узлами APISIX.
Для DevOps использование графической панели управления для управления всеми API-сервисами может значительно повысить производительность. APISIX предоставляет удобную визуальную панель управления, которая делает изменение конфигураций API более удобным.
Заключение
Ограничение скорости — это распространенная потребность в реальных бизнес-сценариях, и это важный способ защиты системы от всплесков трафика и обеспечения ее бесперебойной работы. Ограничение скорости — это лишь одна часть управления API-сервисами; мы также можем использовать множество других технологий для обеспечения важной поддержки безопасности и улучшения пользовательского опыта.