Шаблон дросселирования

Ограничить ресурсы, которые может использовать экземпляр приложения, отдельный клиент или всю службу. Это позволяет системе функционировать и соответствовать целевым показателям уровня обслуживания (SLOs) при внезапной или длительной нагрузке.

Контекст и проблема

Нагрузка на облачное приложение зависит от активных пользователей и их действий. В рабочее время входит больше пользователей, а в конце каждого месяца система выполняет ресурсоёмкую аналитику. Внезапные всплески также происходят. Если объем обработки превышает доступную емкость, система замедляется или завершается сбоем. Если для системы согласован целевой уровень обслуживания (SLO), этот сбой означает его нарушение.

Несколько стратегий обрабатывают различные нагрузки в зависимости от бизнес-целей приложения. Одна из стратегий — автомасштабирование, которое приводит выделенные ресурсы в соответствие с текущим спросом и помогает контролировать затраты. Но подготовка новых ресурсов занимает время и добавляет затраты. Спрос, превышающий рост емкости или бюджет, создает дефицит ресурсов.

Решение

Альтернативой автоматическому масштабированию является ограничение использования ресурсов и регулирование запросов при превышении этого ограничения. Рабочая нагрузка отслеживает использование собственных ресурсов и регулирует запросы от одного или нескольких пользователей при превышении порогового значения. Система продолжает функционировать и соответствовать своим SLO.

Троттлинг — это цикл управления, а не единичное решение о допуске. Системе требуются сигналы с малой задержкой на трёх уровнях: загрузка инфраструктуры, состояние приложения и счётчики для каждого принципала. Он постоянно измеряет насыщенность, применяет ограничения на хорошо определенных границах и адаптирует эти ограничения при изменении шаблонов трафика. Перегрузка — это нормальный режим работы, который зрелая система обнаруживает и после которого восстанавливается. Регулирование обеспечивает возможности самостоятельного сохранения в рабочей нагрузке.

Система может применять несколько стратегий ограничения скорости или связанных с ним стратегий:

  • Ограничения скорости для каждого субъекта: Отклонять запросы от пользователя, который уже превысил настроенную скорость в определенном окне. Эта стратегия требует, чтобы система соотносила каждый запрос с субъектом и учитывала использование ресурсов по этому субъекту. Сведения о мультитенантных рабочих нагрузках см. в разделе "Измерение потребления каждого клиента".

  • Грациозная деградация функций: Отключите или ухудшите нетентичные функции, чтобы необходимые функции имели достаточно ресурсов. Эта стратегия жертвует полнотой ответа ради доступности. Например, приложение для потоковой передачи видео может перейти на более низкое разрешение.

  • Выравнивание нагрузки: Сглаживайте объём активности с помощью очереди. В многоарендной среде выравнивание снижает производительность у каждого арендатора. Если у арендаторов разные соглашения об уровне обслуживания (SLA), немедленно обрабатывайте задачи для приоритетных арендаторов, а задачи с более низким приоритетом откладывайте до тех пор, пока не уменьшится очередь невыполненных задач. Реализуйте этот подход с помощью шаблона очереди приоритета или предоставления отдельных конечных точек для каждого уровня приоритета.

  • Отсрочка на основе приоритета: Отложить операции от имени приложений или клиентов с более низким приоритетом. Приостановьте или ограничьте операции и верните исключение, сообщающее клиенту, что следует повторить попытку позже.

  • Ограничения исходящей скорости: Ограничьте собственные исходящие вызовы, когда внешняя зависимость завершается ошибкой или возвращает ошибки. Уменьшите число запросов в обработке, чтобы не засорять журналы и избежать затрат на повторные попытки при обращении к неисправной зависимости. Восстановите обычный поток запросов после восстановления зависимостей. Например, NServiceBus реализует эту функцию.

На следующей диаграмме показано использование ресурсов (сочетание памяти, ЦП, пропускной способности и других факторов) для приложения, использующего три функции, помеченные как A, B и C. Функция — это определенная область функциональных возможностей, например компонент, выполняющий определенный набор задач, фрагмент кода, выполняющий сложные вычисления, или элемент, предоставляющий службу, например кэш в памяти.

Граф, показывающий использование ресурсов в течение времени для приложений, которые выполняются от имени трех пользователей.

График линий отображает использование ресурсов на оси Y в зависимости от времени на оси x. Три цветные линии обозначают функцию A, функцию B и функцию C, при этом линия функции A расположена ниже всех, линия функции B — посередине, а линия функции C — выше всех. Сплошная горизонтальная линия в верхней части диаграммы помечает максимальную емкость, а пунктирная горизонтальная линия под ней обозначает обратимое ограничение использования ресурсов. Две вертикальные пунктирные линии помечают время T1 и T2. До T1 все три кривые функций колеблются, и кривая функции C растёт и пересекает мягкий предел. В момент T1 линия функции B падает до нуля и остается на нуле до T2, так как функция B приостановлена, чтобы высвободить ресурсы для функции A и функции C. Линия функции C снова опускается ниже мягкого лимита между T1 и T2, в то время как функция A продолжает работать в обычном режиме. В момент T2 функция B возобновляет работу, и все три линии продолжают колебаться ниже мягкого ограничения.

Это диаграмма с накоплением областей. В приведенной ниже строке компонента A показаны ресурсы, которые используются компонентом A, область между строками компонента A и компонентом B показывает ресурсы, используемые компонентом B, а область между строками компонента B и Feature C показывает ресурсы, используемые компонентом C. Строка компонента C находится в верхней части стека, поэтому она также показывает общее использование системного ресурса с течением времени.

На диаграмме показана плавная деградация функциональности. Непосредственно перед моментом T1 общее использование ресурсов приближается к пороговому значению и может исчерпать доступную ёмкость. Компонент B менее важен, чем компонент A или Feature C, поэтому система отключает компонент B и освобождает свои ресурсы. В период между T1 и T2 функция A и функция C продолжают работать в обычном режиме. К моменту T2 общее потребление ресурсов снижается достаточно, чтобы снова включить функцию B.

Вы можете объединить автоматическое масштабирование, плавную деградацию и ограничение нагрузки, чтобы обеспечить отзывчивость приложений и соблюдение соглашений об уровне обслуживания (SLA). Когда вы ожидаете, что спрос будет оставаться высоким, регулирование сохраняет стабильность во время масштабирования системы. После завершения масштабирования система восстанавливает полную функциональность.

На следующем графике показано общее использование ресурсов во времени и то, как ограничение производительности сочетается с автомасштабированием и другими компенсирующими механизмами.

Граф, показывающий эффекты объединения регулирования с автомасштабированием.

Линейный график показывает использование ресурсов всеми приложениями по оси Y в зависимости от времени по оси X. Две горизонтальные опорные линии обозначают мягкий предел использования ресурсов и максимальную ёмкость перед автомасштабированием. Более высокая горизонтальная линия, которая начинается в момент T2, обозначает максимальную мощность после автомасштабирования. Линия использования растет и изменяется с течением времени. Он пересекает мягкий предел в момент T1, то есть в точке, где начинается автомасштабирование. В период между T1 и T2 работа системы ограничивается, пока происходит автомасштабирование, а уровень использования ресурсов остается ниже максимальной производительности до автомасштабирования. В момент T2 автомасштабирование завершается, ограничение пропускной способности ослабляется, а линия загрузки резко поднимается и продолжает колебаться ниже нового, более высокого максимального уровня мощности.

В момент T1 система достигает мягкого предела и начинает горизонтально масштабироваться. Если новые ресурсы не поступают вовремя, нагрузка может исчерпать имеющиеся ресурсы, и система может выйти из строя. Регулирование отклоняет избыточные запросы во время горизонтального масштабирования, чтобы обеспечить использование ресурсов ниже жесткого ограничения, а затем отменяет эти ограничения после того, как новая емкость будет подключена к сети.

Tip

Элементы управления Edge и шаблон ограничения скорости предназначены для решения разных задач. Средства защиты на периметре, такие как Azure DDoS Protection и правила ограничения частоты запросов брандмауэра веб-приложений (WAF), применяются на границе сети и отсекают объёмный или вредоносный трафик, прежде чем он достигнет приложения. Шаблон ограничения пропускной способности работает внутри приложения и регулирует разрешённый трафик в соответствии с заданными приложением ограничениями. Используйте оба слоя вместе. Защита от DDoS-атак не мешает легитимному пользователю перегрузить ваш сервис, а ограничение запросов на уровне приложения не способно смягчить объёмную атаку.

Проблемы и рекомендации

Учитывайте следующие моменты при принятии решения о том, как реализовать этот шаблон.

  • Принимайте решения об ограничении заранее. Ограничение пропускной способности — это архитектурное решение, которое влияет на всю систему. Доработать это позже будет дорого.

  • Согласуйте пределы троттлинга с компонентом, который первым достигает насыщения.

    Частота запросов — наиболее привычный параметр, который ограничивают, однако реальным узким местом часто оказываются число одновременно обрабатываемых запросов, глубина очереди, загрузка ЦП или памяти, а также собственные ограничения нижестоящей зависимости. Ограничение на количество запросов в секунду не защищает систему, у которой узкое место — уровень параллелизма в точке разветвления.

    На каждой границе применения ограничения пропускной способности, например на уровне шлюза, службы, раздела или нижестоящей зависимости, определите, какой ресурс исчерпывается первым, и установите предел по этому параметру. О защите с ограничением параллелизма в точках разветвления см. в паттерне «Переборка», который дополняет ограничение скорости.

  • Выбирайте алгоритм ограничения намеренно. Сопоставляйте его с допустимым значением компонента, который вы защищаете.

    Алгоритм Поведение и оптимальное соответствие
    Контейнер токенов Поддерживает всплески нагрузки до заданного размера и поддерживает постоянную скорость пополнения. Используется для шлюзов, которые должны поглощать короткие пики.
    Утечка контейнера Испускает с постоянной скоростью. Используйте для внутренних серверов, которые нуждаются в стабильной скорости входящего трафика.
    Фиксированное окно Легко реализовать, но допускает последовательные всплески на границах окна.
    "Скользящее" окно Сглаживает проблему границ окна фиксированных окон за счет большего количества состояний.
  • Решите, кого затрагивает ограничение. Ограничение на крупном уровне, например на уровне регионального шлюза, может затронуть множество несвязанных пользователей, даже если нагрузку создают лишь некоторые из них.

  • Определите, где находится счетчик, когда один предел охватывает несколько узлов. Локальные счётчики работают быстро, но дают заниженный подсчёт, когда один и тот же вызывающий компонент обращается к нескольким репликам. Централизованный счетчик в общем хранилище, например Redis, видит каждый запрос, но добавляет задержку к каждому решению. Чтобы приблизительно реализовать глобальное ограничение скорости, распределите лимит по репликам и периодически сверяйте его.

  • Быстро принимать решения по регулированию. Система должна обнаруживать рост нагрузки, реагировать и возвращаться в нормальное состояние после облегчения загрузки. Этот процесс требует непрерывного мониторинга производительности.

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

    По мере того как использование приближается к жесткому ограничению, начинайте отклонять растущую долю запросов. Ранний отказ дает вызывающей стороне сигнал снизить нагрузку и предотвращает коллапс задержек, который часто вызывают резкие ограничения. Используйте задержку на уровне p99 относительно вашего SLO в качестве основного критерия срабатывания. Средняя загрузка может казаться нормальной, в то время как p99 уже превысил допустимый порог.

    Там, где можно различать ценность запросов, сначала отбрасывайте менее ценные или легче поддающиеся повтору задачи. Дополнительные сведения см. в шаблоне очереди приоритета.

  • Возвращайте код состояния, указывающий клиенту, что временный отказ вызван ограничением скорости:

    • HTTP 429 (слишком много запросов): Вызывающий объект превышает настроенную частоту запросов по определенному окну.
    • HTTP 503 (служба недоступна): Служба не может обрабатывать запрос прямо сейчас, часто из-за неожиданного всплеска нагрузки.

    Retry-After Включите заголовок HTTP, чтобы клиент смог выбрать стратегию повторных попыток. Верните достаточно контекста, чтобы вызывающая сторона могла осознанно повторить попытку вместо того, чтобы гадать. Например, укажите, какой именно лимит превышен вызывающей стороной, уточните затронутую область действия или предложите такую частоту запросов, при которой запрос будет выполнен успешно. Отказы без объяснения причин не помогают звонящим понять, как им скорректировать свои действия.

  • Передавайте сигналы перегрузки от ваших зависимостей дальше, вместо того чтобы поглощать их. Служба, которая ограничивает интенсивность запросов от своих клиентов, также должна учитывать ответы об ограничении скорости, получаемые от собственных нижестоящих зависимостей. Если ваш сервис скрывает ответ 429 или 503 от нижестоящего сервиса, молча выполняя повторные попытки или возвращая общий ответ HTTP 500 (внутренняя ошибка сервера), вызывающие стороны не могут снизить нагрузку, число повторных попыток растет, и перегрузка распространяется обратно вверх по цепочке. Антипаттерн Retry Storm описывает этот режим сбоя. Передавайте обратное давление вышестоящим вызывающим компонентам, чтобы вся цепочка вызовов согласованно снижала нагрузку.

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

  • Предусмотрите ситуации, когда ограничение запросов не позволяет выиграть достаточно времени до срабатывания автомасштабирования. Если спрос растет быстрее, чем вводятся в эксплуатацию новые мощности, то даже система, работающая с ограничением, может выйти из строя. Если такой результат неприемлем, держите больший резерв мощности и настройте более агрессивное автомасштабирование.

  • Не используйте кэширование в качестве замены ограничению частоты запросов. Кэш снижает среднюю нагрузку на источник, но не ограничивает пиковую нагрузку. Каждый промах кэша доходит до исходного сервера, и когда срок действия популярного ключа истекает при высокой нагрузке, множество запросов могут одновременно попытаться заново заполнить его. Используйте кэширование, чтобы снизить обычную нагрузку, а ограничение интенсивности — чтобы ограничить последствия в худшем случае. Дополнительные сведения см. в разделе «Шаблон Cache-Aside».

  • Нормализуйте затраты на ресурсы для различных операций, так как обычно они не несут равных затрат на выполнение. Например, ограничения регулирования могут быть выше для операций чтения и ниже для операций записи. Игнорирование затрат на каждую операцию может привести к исчерпанию ресурсов и создать возможность для атаки.

  • Сделать конфигурацию ограничения скорости изменяемой во время выполнения. При поступлении аномальной нагрузки необходимо настроить ограничения без развертывания. Развертывания являются медленными и рискованными во время инцидента. Шаблон External Configuration Store pattern выносит конфигурацию во внешнее хранилище, чтобы её можно было изменять во время выполнения.

  • Рассмотрите адаптивные ограничения вместо статических ограничений. Некоторые SDK для троттлинга реагируют на сигналы о задержке или глубине очереди, чтобы лимит соответствовал фактическому состоянию компонента. Всегда используйте адаптивный лимитер вместе с заданным максимальным значением.

  • Пересматривайте ограничения по мере изменения нагрузки. Адаптивные ограничители не могут отслеживать все виды дрейфа, такие как изменения SLO, изменения пропускной способности зависимостей или сдвиги в стоимости одной операции. Запланируйте периодическую проверку оператором на основе этих входных данных.

Когда следует использовать этот шаблон

Используйте этот шаблон:

  • Чтобы сохранить систему в своих SLO.

  • Чтобы предотвратить монополизацию ресурсов приложения одним клиентом.

  • чтобы справляться со всплесками активности;

  • Чтобы ограничить максимальный уровень ресурсов, необходимый системе.

  • Сократить низкоценные вычисления в периоды высокой углеродоёмкости электросети.

Проектирование рабочей нагрузки

Оцените, как использовать шаблон ограничения пропускной способности при проектировании рабочей нагрузки для достижения целей и соблюдения принципов, изложенных в основных принципах платформы Azure Well-Architected Framework. В следующей таблице приведены рекомендации по использованию этого шаблона для целей каждого компонента.

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

- RE:07 Самосохранение
Решения по проектированию безопасности помогают обеспечить конфиденциальность, целостность и доступность данных и систем рабочей нагрузки. Вы можете разработать ограничения, чтобы предотвратить исчерпание ресурсов, которые могут привести к автоматическому злоупотреблению системой.

- Сетевые элементы управления SE:06
- SE:08 Укрепление ресурсов
Оптимизация затрат фокусируется на поддержании и улучшении окупаемости ваших инвестиций в рабочие процессы. Примененные ограничения могут информировать моделирование затрат и напрямую связываться с бизнес-моделью приложения. Они также помещают четкие верхние границы на использование, которые можно учитывать в размерах ресурсов.

- Модель затрат CO:02
- CO:12 Затраты на масштабирование
Эффективность производительности помогает рабочей нагрузке эффективно соответствовать требованиям путем оптимизации масштабирования, данных и кода. Если система испытывает высокий спрос, этот шаблон помогает уменьшить перегрузку, которая может привести к появлению узких мест производительности. Вы также можете использовать его для проактивного предотвращения сценариев проблемы «шумного соседа».

- Планирование емкости PE:02
- Pe:05 Масштабирование и секционирование

Если этот шаблон вводит компромиссы внутри столпа, рассмотрите их против целей других столпов.

Example

На следующей схеме показано ограничение пропускной способности в мультитенантной системе.

Схема, иллюстрирующая ограничение пропускной способности в мультитенантном приложении.

Три пользователя с подписями слева представляют арендаторов многоарендного приложения Surveys: Adatum, Fabrikam и Contoso. Каждый пользователь отправляет запросы через личный домен для конкретного клиента, который приложение использует для идентификации клиента. Adatum отправляет 5 запросов в секунду через surveys.adatum.com, Fabrikam отправляет 10 запросов в секунду через surveys.fabrikam.com, а Contoso отправляет 150 запросов в секунду через surveys.contoso.com. Справа веб-роль приложения опросов измеряет частоту запросов в секунду для каждого клиента. Потоки запросов Adatum и Fabrikam передаются в приложение. Поток запросов Contoso заблокирован из-за ошибки: ответ с ограничением скорости, так как частота запросов превышает лимит для клиента.

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

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

Следующий шаг