Использование программного компонента#

Квотирование поддерживается только для сервисов, вызываемых по протоколу HTTP (HTTP/1 или HTTP/2). Расчет лимитов может происходить как локально (средствами Envoy), так и глобально (средствами компонента RL Service). Конфигурирование лимитов осуществляется через формирование артефактов GlobalRateLimit или LocalRateLimit соответственно. Для возможности загрузки артефактов GlobalRateLimit и LocalRateLimit необходимо создать роль K8s и привязать к ней ТУЗ Jenkins в namespace.

Роль:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: pipeline-rate-limiter-service-role
rules:
  - verbs:
      - create
      - update
      - patch
      - delete
      - get
      - list
    apiGroups:
      - ratelimit.service
    resources:
      - localratelimits
      - globalratelimits

Глобальный вариант позволяет задать лимиты на Ingress/Egress Gateway в прикладном namespace. Конфигурирование Ingress Gateway позволяет ограничить нагрузку на прикладные сервисы в прикладном namespace. Конфигурирование Egress Gateway позволяет ограничить исходящую нагрузку на внешние сервисы. Локальный вариант позволяет задать лимиты на Ingress/Egress Gateway или Istio Sidecar. Конфигурирование Istio Sidecar позволяет ограничить входящий поток запросов на Pod прикладного сервиса.

Глобальный вариант расчета лимитов#

Формирование и применение артефакта GlobalRateLimit#

Конфигурирование лимитов осуществляется через артефакт GlobalRateLimit. Для применения лимитов необходимо создать артефакт GlobalRateLimit в namespace, где запущены прикладные сервисы, которые указаны в секции endpoints.

Пример конфигурации: GlobalRateLimit.

В примере для endpoint указаны несколько способов задания лимитов:

  1. test-server1 — для обратной совместимости с версией RLS 2.0, нет возможности использовать произвольный заголовок для идентификации потребителя, нет возможности указать раздельно лимит для безымянных потребителей (отсутствует указанный заголовок в запросе) и неуказанных в конфигурации.

  2. test-server2 — применение лимитов с идентификацией потребителя в заголовке, можно указать произвольный заголовок (валидный для протокола HTTP) и раздельно указать лимиты для безымянных потребителей (отсутствует указанный заголовок в запросе) и неуказанных в конфигурации, для этого введено новое поле anon_value.

  3. test-server3 — применение лимитов в разрезе ResourceName, новая функциональность, появившаяся в релизе 2.1, для идентификации потребителя (тенанта) из URL запроса.

  4. test-server4 — применение лимитов с идентификацией потребителя в заголовке, отличие от второго варианта — лимиты конфигурируются для каждого указанного префикса URL в рамках одного endpoint независимо (с релиза 2.4 префиксы /foo и /foo/bar являются независимыми с точки зрения Rate Limiter — запросы /foo/test1?param1=value1 и /foo/bar/test2 будут задействовать свои лимиты независимо друг от друга).

  5. test-server5 — применение лимитов с идентификацией потребителя в заголовке, отличие от четвертого варианта — для одного из префиксов лимиты конфигурируются для указанных HTTP-методов в рамках одного префикса URL независимо.

  6. test-server6 — применение лимитов с идентификацией защищаемого сервиса по номеру порта, в отличие от остальных вариантов данные лимиты применяются ко всем запросам, прошедшим через порт 8443 Ingress (Egress) Gateway (DNS-адрес не имеет значения).

  7. multi-data-center-server — лимиты, которые могут быть разделены с другими ЦОД при наличии в другом ЦОД endpoint с таким же shortname и endpoint_set_selector.

При формировании артефакта необходимо указать:

  • workloadSelector — набор labels для определения нужных Pod Ingress (Egress) Gateway;

  • visibility — отвечает за область видимости данного CRD, возможные значения: cluster, namespace;

  • endpoints — список ваших ресурсов;

  • body_sizes_entries — ограничения в разрезе размера тела запроса (опционально);

  • rlserver — адрес RLS-сервера (для децентрализованной установки следует указать headless server rls например: «rate-limiter-headless-service», для централизованной установки здесь следует указать headless server с namespace rls, рекомендованный формат — <headless_service_name>.<namespace>.svc.cluster.local);

  • rlserverport — порт RLS-сервера, по умолчанию — 8081;

  • rlnamespace — namespace, в котором развернут централизованный оператор, данное поле необходимо указать для возможности развертывания нескольких экземпляров централизованного SRLS в рамках одного кластера Kubernetes или Red Hat OpenShift (опционально), если данное поле не задано, оператор проверит наличие прав на артефакт EnvoyFilter в прикладном namespace;

  • rlservercert — опциональный блок, позволяет задавать сертификаты для доступа к RLS-серверу при прямом подключении.

rlservercert состоит из следующих полей:

  • cert – путь к клиентскому (extendedKeyUsage = clientAuth) сертификату в файловой системе Ingress (Egress) Gateway;

  • key – путь к приватному ключу сертификата в файловой системе Ingress (Egress) Gateway;

  • trust_ca — путь к доверительному сертификату в файловой системе Ingress (Egress) Gateway.

Важно!

Потребитель сам должен обеспечить наличие данных сертификатов на Ingress (Egress) Gateway, подмонтировав их в необходимую директорию.

Для каждого endpoint:

  • обязательно наличие его короткого имени shortname, используется в работе, для каждого endpoint значение shortname должно быть уникальным;

  • endpoint — целевой адрес в формате:

    • host:port, здесь host — DNS-адрес, на который поступает входящий трафик (определяется в артефакте Route или Ingress, используется в артефактах Gateway, VirtualService для манипуляции трафиком с помощью Service Mesh), port — порт, который слушает Ingress (Egress) Gateway (задается в артефакте Gateway), например, 8080 для HTTP-трафика или 8443 для HTTPS-трафика;

    • *:port, здесь * — условное обозначение любого host, port — порт, который слушает Ingress (Egress) Gateway (задается в артефакте Gateway), например, 8080 для HTTP-трафика или 8443 для HTTPS-трафика;

  • overall_limit — максимальное ограничение квоты для endpoint; 0 — блокировка всех запросов, отрицательное значение — нет ограничения; если значение больше 0, дополнительно создается отдельный счетчик всех запросов на endpoint; в случае превышения запрос будет отклонен, даже если потребитель еще не исчерпал свою квоту; если используется режим работы Rate Limit Prefix, overall_limit считается общий для всех префиксов URL запроса, указанных в конфигурации;

  • by_header — список настроек для функциональности идентификации потребителя по HTTP-заголовку (подробное описание приведено в разделах «Rate Limit Header», «Rate Limit Prefix», «Rate Limit Method» и «Rate Limit Size» настоящего руководства);

  • by_path — список настроек для функциональности идентификации потребителя по resourceName (подробное описание приведено в разделе «Rate Limit Path» настоящего руководства);

  • может быть задан лишь один из типов лимитов «by_header» или «by_path»;

  • overall_schedule – опциональный блок, позволяет изменять overall_limit по расписанию;

  • endpoint_set_selector – опциональный блок, позволяет указать параметры для разделения квот endpoint с другими ЦОД.

Лимиты могут быть заданы в следующих единицах измерения:

  • second;

  • minute;

  • hour;

  • day.

endpoint_set_selector состоит из следующих полей:

  • labels – опциональное поле, набор пар ключ-значение для идентификации endpoint (в дополнение к shortname), ключ и значения должны иметь тип «строка»;

  • export_to – набор namespace, с которыми квоты данного endpoint могут быть разделены, namespace могут относиться к текущему или другим ЦОД, значения должны иметь тип «строка»;

  • protection_coefficient – опциональное поле, коэффициент защиты endpoint, подробнее см. раздел «Режим NЦОД», значение должно иметь тип «целое число», значение по умолчанию 100.

Несколько адресов в артефакте Gateway#

В артефакте Gateway (артефакт Service Mesh) для одного порта Ingress (Egress) Gateway может быть назначено более одного адреса (например, адрес сервиса в текущем кластере и адрес этого же сервиса через гео-балансировщик). Пример такого артефакта Gateway:

  selector:
    istio: igw-mynamespace
  servers:
    - hosts: ["myservice1.mynamespace.mycluster", "myservice2.mynamespace.mycluster"]
      port:
        name: https-8443
        number: 8443
        protocol: HTTPS

Зачастую в паре с таким артефактом Gateway идет артефакт VirtualService с таким же набором адресов, которые в итоге маршрутизируются на один защищаемый сервис. Пример такого артефакта VirtualService:

exportTo: ["."]
gateways: ["mynamespace/mygateway"]
hosts: ["myservice1.mynamespace.mycluster", "myservice2.mynamespace.mycluster"]
http:
- match:
    - uri:
        prefix: /
  route:
    - destination:
        host: myservice.mynamespace.svc.cluster.local
        port:
          number: 8080

При такой конфигурации сервис с адресом myservice.mynamespace.svc.cluster.local:8080 может быть вызван по адресам myservice1.mynamespace.mycluster:8443 и myservice2.mynamespace.mycluster:8443 при правильной настройке маршрутизации до Ingress (Egress) Gateway.

В таком случае выбор корректного адреса для указания в артефакте GlobalRateLimit в поле .spec.endpoints.[].endpoint может быть затруднительным. Возможные варианты:

  1. Указать endpoint в артефакте GlobalRateLimit в виде *:port (например, *:8443). Этот вариант применим при отсутствии необходимости установки различных лимитов на различные адреса, которые используют один порт Ingress (Egress) Gateway. Если артефакты EnvoyFilter создаются самостоятельно (см. подраздел «Выбор варианта установки EnvoyFilter для SRLS» раздела «Установка» документа «Руководство по установке»), то артефакт EnvoyFilter необходимо формировать с учетом пункта «Rate Limit Port» подраздела «Создание артефактов EnvoyFilter вручную» раздела «Подключение и конфигурирование» документа «Руководство прикладного разработчика». При использовании данного варианта необходимо учитывать, что порты не должны пересекаться между собой и между другими endpoint, в которых может быть указан такой же порт.

  2. Указать в артефакте GlobalRateLimit (и артефакте EnvoyFilter, если он создается самостоятельно) первый адрес в лексикографическом порядке. Условия применимости данного варианта совпадают с условиями, описанными для предыдущего пункта.

  3. Разделить один артефакт VirtualService таким образом, чтобы не было артефактов VirtualService, маршрутизирующих несколько адресов на один и тот же адрес назначения. Для примера выше необходимо создать два отдельных артефакта VirtualService:

     exportTo: ["."]
     gateways: ["mynamespace/mygateway"]
     hosts: ["myservice1.mynamespace.mycluster"]
     http:
       - match:
           - uri:
               prefix: /
         route:
           - destination:
               host: myservice.mynamespace.svc.cluster.local
               port:
                 number: 8080
    
    exportTo: ["."]
    gateways: ["mynamespace/mygateway"]
    hosts: ["myservice2.mynamespace.mycluster"]
    http:
      - match:
          - uri:
              prefix: /
        route:
          - destination:
              host: myservice.mynamespace.svc.cluster.local
              port:
                number: 8080
    

    Артефакт Gateway менять не требуется. В артефакте GlobalRateLimit (и артефакте EnvoyFilter, если он создается самостоятельно) указывается тот адрес, на который необходимо применять лимиты.

Ограничения в виде ссылок#

В релизе 4.2 начался переход на другой формат артефакта GlobalRateLimit. Формат предполагает формирование некоторого набора составных частей для идентификации ресурса, поставщика, потребителя, квоты и т.д. Затем из этих отдельных частей происходит формирование непосредственно лимитов (указание конкретного ресурса, поставщика, потребителя, квоты и т.д.).

Ограничения в разрезе размера тела запроса#

Для определения ограничений в разрезе размера тела запроса в артефакт GlobalRateLimit добавлен блок body_sizes_entries. Он позволяет задать набор ограничений в разрезе тела запроса и представляет собой список элементов, каждый из которых имеет:

  • body_sizes_key – уникальный идентификатор набора ограничений, строка;

  • body_sizes – непосредственно набор ограничений, список элементов, см. раздел «Rate Limit Size».

Указание несуществующей ссылки (такой body_sizes_key, который отсутствует в body_sizes_entries) запрещено. При указании в body_sizes_entries вхождений без ссылок на них в логах RL Operator и статусе артефакта GlobalRateLimit выводятся сообщения с предупреждениями о неиспользуемых параметрах.

Режимы работы#

Rate Limit Header#

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

Пример: some service1.

Параметры блока by_header:

  • header — до трех (включительно) произвольных HTTP-заголовков (валидных для протокола HTTP), разделенных запятыми (без пробелов);

  • unit — опциональное поле, по умолчанию second, единица измерения лимитов, используется при расчете overall_limit, для запросов с конкатенацией значений заголовков поля header, не указанной в блоке invokers, и для неидентифицированных потребителей;

  • anon_value — опциональное поле, позволяет задать квоту для неидентифицированных (анонимных) потребителей, то есть в запросе отсутствуют все выбранные HTTP-заголовки; если поле не задано, используется значение поля value;

  • value — опциональное поле, по умолчанию 1, позволяет задать квоту для запросов с конкатенацией значений заголовков поля header, не указанной в блоке invokers, и для неидентифицированных потребителей;

  • soft — опциональный блок, если задан, создается метрика, показывающая приближение к лимиту. soft.value — значение квоты, после которой с шагом кратным soft.step будет инкрементирована метрика мониторинга превышения уровня soft квоты для конкретного потребителя вплоть до превышения основного лимита;

  • invokers — опциональный блок, позволяет задать квоту для определенных потребителей независимо.

overall_schedule и schedule состоят из следующих полей:

  • start – блок, позволяет задать время и дату начала изменения параметров, указанных в блоке;

  • stop – блок, позволяет задать время и дату окончания изменения параметров, указанных в блоке;

  • unit — поле, по умолчанию second, единица измерения лимитов;

  • value — поле, по умолчанию 1, позволяет задать квоту;

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

start и stop состоят из следующих полей:

  • second – блок, секунды, возможные значения – (0-59);

  • minute – блок, минуты, возможные значения – (0-59);

  • hour – блок, часы, возможные значения – (0-23);

  • day – блок, дни, возможные значения – (1-31);

  • month – блок, месяц, возможные значения – (1-12, где 1-январь);

  • weekday – блок, дни недели, возможные значения – (0-6, где 0-воскресенье).

Значение „*“ для полей start и stop является допустимым и позволяет задать любую минуту, час, день, месяц, день недели.

Например:

overall_schedule в примере выше означает, что overall_limit 50 запросов в секунду будет изменен в период с 10 секунды до 30 секунды каждой минуты каждого часа каждого дня каждого месяца в течении всей недели на overall_limit 25 запросов в минуту.

Second

Minute

Hour

Day

Month

Weekday

Примечание

start

„1“

„*“

„*“

„*“

„*“

„*“

Начало каждую 1 секунду

stop

„10“

„*“

„*“

„*“

„*“

„*“

Окончание каждую 10 секунду

start

„1“

„5“

„3“

„*“

„*“

„*“

Начало каждый день в 3:05:01

stop

„10“

„20“

„6“

„*“

„*“

„*“

Окончание каждый день в 6:20:10

start

„1“

„5“

„3“

„5“

„*“

„*“

Начало каждый день в 3:05:01

stop

„10“

„20“

„6“

„7“

„*“

„*“

Окончание каждый день в 6:20:10

start

„1“

„5“

„3“

„5“

„*“

„*“

Начало 5 числа каждого месяца в 3:05:01

stop

„10“

„20“

„6“

„7“

„*“

„*“

Окончание 7 числа каждого месяца в 6:20:10

start

„1“

„5“

„3“

„5“

„11“

„*“

Начало 5 ноября в 3:05:01

stop

„10“

„20“

„6“

„7“

„11“

„*“

Окончание 7 ноября в 6:20:10

start

„1“

„5“

„3“

„*“

„*“

„1“

Начало каждый понедельник в 3:05:01

stop

„10“

„20“

„6“

„*“

„*“

„1“

Окончание каждый понедельник в 6:20:10

  • Данные в schedule блоки start и stop должны удовлетворять следующим требованиям:

  1. start не должен срабатывать несколько раз до наступления события stop;

  2. stop не должен срабатывать несколько раз до наступления события start;

  3. start и stop не может быть задан в несуществующую дату, например, в сентябре нет 31 дня, в феврале нет 29 дня и подобные.

  • В случае установки некорректных параметров в CRD GlobalRateLimit в блоке schedule или overall_schedule, в статусе CRD будет отражено место с указанием, где задан невалидный интервал времени и даты.

schedule в поле invokers: header_value: synapse-test означает, что лимит 8 запросов в секунду с soft.value=3 и soft.step=1 будет изменен каждый понедельник в период с 2 часов 5 минут 1 секунды до 6 часов 10 минут 30 секунд на 16 запросов в секунду с soft.value=5 и soft.step=2.

Для каждого invoker можно задать:

  • header_value — конкатенация значений заголовков, указанных в поле header (обязательное поле, не может быть пустым);

  • name — опциональное поле, позволяет указать метаданные для header_value;

  • unit — опциональное поле, по умолчанию second, единица измерения лимитов для header_value;

  • value — опциональное поле, по умолчанию 1, позволяет задать квоту для запросов с конкатенацией значений заголовков поля header, равной header_value;

  • soft — опциональный блок, если задан, создается метрика, показывающая приближение к лимиту. soft.value — значение квоты, после которой с шагом кратным soft.step будет инкрементирована метрика мониторинга превышения уровня soft квоты для header_value вплоть до превышения основного лимита;

  • schedule – опциональный блок, позволяет изменять лимиты по расписанию.

Rate Limit Prefix#

Данный режим является расширением режима Rate Limit Header. Применяется в случаях, когда средствами Service Mesh входящий трафик на endpoint на Ingress Gateway распределяется по сервисам этого namespace на основе префикса URL запроса.

Для настройки распределения трафика в Service Mesh используется артефакт VirtualService.

Пример артефакта VirtualService.

Для того чтобы для каждого префикса указать собственные значения квоты, в артефакте GlobalRateLimit в разделе by_header необходимо поле header и блок параметров uri_prefixes, в котором необходимо указать префикс в поле uri_prefix и лимиты по аналогии с режимом by-header.
Для работы функциональности overall_limit необходимо указать поле unit, по умолчанию, если поле не задано, overall_limit будет рассчитываться в секундах. Счетчик overall_limit общий для всех префиксов. Остальные поля блока by_header будут проигнорированы.

Пример конфигурации endpoint.

Таким образом, для вызовов http://ingress-my-namespace-02.apps.domain.org/foo и http://ingress-my-namespace-02.apps.domain.org/bar/pruduct?param=1 будут применяться различные значения лимитов.

С релиза 2.4 префиксы /foo и /foo/bar являются независимыми с точки зрения Rate Limiter — для запросов http://ingress-my-namespace-02.apps.domain.org/foo/test1?param1=value1 и http://ingress-my-namespace-02.apps.domain.org/foo/bar/test2 также будут применяться различные значения лимитов.

Поле schedule в примере выше означает, что для префикса /foo/bar для client 3 будет изменен лимит 6 запросов в минуту в период с 10 секунды по 45 секунду каждой минуты каждого часа каждого дня каждого месяца на 10 запросов в секунду.

Если делается вызов с префиксом, для которого не указан лимит в артефакте GlobalRateLimit, то запросы на него будут идти без лимита. При этом в логах RL Service будут сообщения об ошибках no prefix found, valid prefixes: [/bar /foo/bar]", и метрика ошибок ratelimiterservice_should_rate_limit_unknown_prefix_error будет увеличиваться.

В случаях, когда нет необходимости считать лимиты для определенного префикса, можно указать для него в поле value значение -1.

    - endpoint: 'ingress-my-namespace-02.apps.domain.org:8080'
      name: srls dev 02
      shortname: dev
      overall_limit: 100
      by_header:
        header: synapse-consumerid
        unit: minute
        uri_prefixes:
          - uri_prefix: "/healthcheck"
            value: -1
          - uri_prefix: "/bar"
            unit: minute
            value: 20
            anon_value: 2
            invokers:
              - header_value: bar-client
                name: client 2
                unit: minute
                value: 2

В данном примере запросы с префиксом /healthcheck будут ограничены только лимитом на весь endpoint (значением overall_limit). При этом если будут указаны блоки invokers, http_methods или body_sizes_key, то они будут игнорироваться.

В случаях, когда нет необходимости считать лимиты для всех префиксов, не указанных в артефакте GRL, можно для префикса / указать в поле value значение -1.

    - endpoint: 'ingress-my-namespace-02.apps.domain.org:8080'
      name: srls dev 02
      shortname: dev
      overall_limit: 100
      by_header:
        header: synapse-consumerid
        unit: minute
        uri_prefixes:
          - uri_prefix: "/"
            value: -1
          - uri_prefix: "/bar"
            unit: minute
            value: 20
            anon_value: 2
            invokers:
              - header_value: bar-client
                name: client 2
                unit: minute
                value: 2

В данном примере лимит будет считаться только для запросов с префиксом /bar. Запросы со всеми остальными префиксами будут ограничены только лимитом на весь endpoint (значением overall_limit).

Префикс / так же может быть использован для подсчета общего лимита для всех остальных префиксов, если в поле value задано конкретное значение.

    - endpoint: 'ingress-my-namespace-02.apps.domain.org:8080'
      name: srls dev 02
      shortname: dev
      overall_limit: 100
      by_header:
        header: synapse-consumerid
        unit: minute
        uri_prefixes:
          - uri_prefix: "/"
            value: 10
            unit: minute
          - uri_prefix: "/bar"
            unit: minute
            value: 20

В данном примере лимит для вызовов с префиксом /bar будет 20 запросов в минуту. Запросы со всеми остальными префиксами будут ограничены лимитом 10 запросов в минуту.

Rate Limit Method#

Данный режим является расширением режима Rate Limit Prefix. Позволяет задать ограничения в разрезе HTTP-методов для отдельных префиксов URL запроса.

Считается, что для endpoint используется данный режим работы при следующих условиях:

  • для endpoint сконфигурирована секция by_header;

  • для секции by_header сконфигурирован блок uri_prefixes;

  • хотя бы для одного префикса (uri_prefixes) сконфигурирован блок http_methods.

Для указания отдельных значений квот для различных методов в артефакте GlobalRateLimit в блоке соответствующего префикса необходимо добавить блок параметров http_methods. Блок является списком объектов, каждый из которых имеет поле непосредственно метода http_method и другие поля лимитов по аналогии с режимом Rate Limit Prefix (value, unit, anon_value, soft, schedule, invokers).

Пример конфигурации endpoint:

    - endpoint: 'ingress-my-namespace-02.apps.domain.org:8080'
      name: methodsservice
      shortname: srvmethod
      by_header:
        header: synapse-consumerid
        uri_prefixes:
          - uri_prefix: "/foo"
            unit: minute
            value: 7
            http_methods:
              - http_method: GET
                unit: minute
                value: 4
              - http_method: POST
                unit: minute
                value: 10
                invokers:
                  - header_value: foo-POST-client
                    name: client 1
                    unit: minute
                    value: 5
          - uri_prefix: "/bar"
            unit: minute
            value: 20
            invokers:
              - header_value: bar-client
                name: client 2
                unit: minute
                value: 2

При отправке запросов на адрес http://ingress-my-namespace-02.apps.domain.org/foo/test методами GET и POST будут применяться различные значения лимитов.

При отправке запроса методом, для которого не указан лимит в артефакте GlobalRateLimit (например, PUT для /foo или любой запрос для /bar), будут применяться значения лимитов из самого префикса с учетом invokers из префикса.

Для снятия ограничений для отдельного метода можно указать для него в поле value значение -1. В таком случае блок invokers (при его наличии) для соответствующего метода будет проигнорирован.

    - endpoint: 'ingress-my-namespace-02.apps.domain.org:8080'
      name: methodsservice
      shortname: srvmethod
      by_header:
        header: synapse-consumerid
        uri_prefixes:
          - uri_prefix: "/foo"
            unit: minute
            value: 7
            http_methods:
              - http_method: GET
                unit: minute
                value: 4
              - http_method: POST
                value: -1

В данном примере POST-запросы с префиксом /foo будут ограничены только лимитом на весь endpoint (значением overall_limit при его наличии). При этом если будут указаны блоки invokers или body_sizes_key, то они будут игнорироваться.

Rate Limit Size#

Данный режим является расширением режимов Rate Limit Header, Rate Limit Prefix, Rate Limit Method. Позволяет задать ограничения в разрезе размера тела запроса.

Указание ограничений в разрезе размера тела запроса реализовано в виде ссылок (см. раздел «Ограничения в разрезе размера тела запроса» данного документа). Каждый элемент ограничений имеет поля:

  • body_size — непосредственно размер тела запроса;

  • value, unit, anon_value, soft, invokers — набор полей, аналогичный режиму Rate Limit Header и другим его расширениям.

Допустимые единицы измерения размера тела запроса представлены в таблице:

Единица измерения

Множитель

Обозначение

Пример

Байт

1

(пустая строка)
B

1
2B

Килобайт

10³

K
KB

3K
4KB

Кибибайт

2¹⁰

Ki
KiB

5Ki
6KiB

Мегабайт

10⁶

M
MB

7M
8MB

Мебибайт

2²⁰

Mi
MiB

9Mi
10MiB

Гигабайт

10⁹

G
GB

11G
12GB

Гибибайт

2³⁰

Gi
GiB

13Gi
14GiB

Указание нескольких блоков с одинаковыми размерами в рамках одного набора ограничений запрещено. При проверке данного требования учитываются указанные единицы измерения (например, 2048 и 2Ki выражают одинаковый размер — 2048 байт).

Размер тела запроса задает верхнюю границу (включительно) диапазона, определяющего размеры тела запроса, для которых будут применены лимиты соответствующего блока. Нижняя граница диапазона для рассматриваемого блока определяется:

  • как размер тела запроса, который является ближайшим из меньших по отношению к рассматриваемому (не включительно);

  • как 0 (включительно), если рассматриваемый блок имеет наименьший размер.

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

Пример формирования диапазонов в зависимости от конфигурации артефакта GlobalRateLimit в разрезе размера тела запроса представлен в таблице:

Заданные размеры

Диапазоны (заданный размер: диапазон применения)

50
1000

50: [0; 50]
1000: (50; +∞)

0
1
2

0: [0; 0]
1: (0; 1]
2: (1; +∞)

5

5: [0; +∞)

размер тела запроса не учитывается, применяются лимиты с родительского уровня

Порядок указания размеров в артефакте GlobalRateLimit не имеет значения, разбиение на диапазоны выполняется в порядке возрастания.

Другими словами, в режиме работы Rate Limit Size алгоритм выбора лимита, который должен быть применен для поступившего запроса, состоит в следующем:

  • если запрос не имеет тела, то размер тела принимается равным 0;

  • если для соответствующего запроса по совокупности параметров (префикс и/или метод) не сконфигурированы ограничения в разрезе размера тела сообщения, то применяется лимит с родительского уровня;

  • размер тела запроса округляется в большую сторону к ближайшему сконфигурированному размеру (если размер тела запроса превышает максимальный сконфигурированный размер, то округление выполняется в меньшую сторону).

Пример набора ограничений в разрезе тела запроса.

Как видно из примера, секция body_sizes_entries позволяет задать произвольное количество наборов ограничений в разрезе размера тела запроса. Каждый набор ограничений при этом может содержать произвольное количество непосредственно ограничений (body_sizes). Каждое ограничение при этом может содержать произвольное количество потребителей (invokers). Каждый из сконфигурированных наборов ограничений может быть использован (и переиспользован) в произвольном количестве endpoint и в различных его местах (например, в разных префиксах одного endpoint).

Для снятия ограничений для сообщений определенного размера для них в поле value установлено значение -1. В таком случае блок invokers (при его наличии) для сообщений соответствующего размера будет проигнорирован.

spec:
  endpoints:
    - endpoint: my-service.my-domain:8080
      shortname: service
      overall_limit: 50
      by_header:
        header: synapse-consumerid
        body_sizes_key: size1
  body_sizes_entries:
    - body_sizes_key: "size1"
      body_sizes:
        - body_size: "10"
          value: -1
        - body_size: "2K"
          value: 14
          anon_value: 15
          invokers:
            - header_value: "invoker13"
              value: 13

В данном примере запросы с размером тела до 10 байт будут ограничены только лимитом на весь endpoint (значением overall_limit) вне зависимости от наличия и значения заголовка synapse-consumerid в запросе.

Пререквизиты для ограничений по размеру тела запроса#

Передача информации о размере тела запроса в RL Service для применения необходимых ограничений может быть выполнена разными способами.

По умолчанию при включенной автоматизации RL Operator создает EnvoyFilter с использованием механизма, описанного в разделе «EnvoyFilter с computed-дескрипторами» настоящего руководства, и параметра request.size. Для возможности изменения данного поведения в блок by_header добавлена опциональная секция size_source, которая имеет поле: header — опциональное поле, тип string, позволяет задать имя заголовка запроса, содержащего размер тела запроса.

Возможные комбинации данных параметров представлены в таблице.

Параметры в артефакте GlobalRateLimit

Способ определения размера запроса

1

Секция size_source отсутствует;
или header не задано;
или в header указана пустая строка

Определение с помощью внутреннего механизма Envoy с использованием параметра request.size

2

Секция size_source задана;
в header указана непустая строка

Определение с помощью заголовка запроса

Секцию size_source необходимо указывать для endpoint в артефакте GlobalRateLimit только при включенной автоматизации создания артефактов EnvoyFilter и при необходимости изменить поведение RL Operator при создании EnvoyFilter.

EnvoyFilter с computed-дескрипторами#

В Envoy 1.25 (Istio 1.17, SSM 3.9) появилась поддержка механизма расширений для дескрипторов, который может быть использован для получения размера тела запроса. Механизм позволяет указать способ получения размера тела запроса путем выбора значения параметра. Возможное значение параметра одно: request.size — получение размера тела запроса на основе заголовка content-length (если заголовка нет, то в качестве размера тела запроса будет использован 0).

Данное решение:

  • не требует создания дополнительного EnvoyFilter для вычисления размера тела запроса;

  • опирается на заголовок content-length.

EnvoyFilter с lua-скриптом#

Для добавления в запрос заголовка с размером тела сообщения до вызова RL Service необходимо загрузить артефакт EnvoyFilter в прикладной namespace.

EnvoyFilter для вычисления размера тела запроса.

Данный фильтр добавляет к запросу заголовок с размером тела запроса. Если запрос не имеет тела, то значение заголовка указывается как 0. Фильтр вносит дополнительные задержки в обработку запроса, поэтому рекомендуется создавать фильтры только для тех endpoint, для которых планируется использование ограничений в разрезе размера тела запроса.

Ниже приведены параметры для конфигурирования данного артефакта EnvoyFilter:

Название параметра

Описание

Пример

namespace

Идентификатор пространства имен

my-namespace

labels

Список label для определения необходимого Ingress (Egress) Gateway

app: ingress-my-namespace

Endpoint

Точка подключения входящего трафика

my-server-my-namespace.domain.ru:8080

Shortname

Уникальное короткое название точки подключения, значение должно совпадать со значением из GRL

myserver

SizeHeader

Название заголовка для определения размера тела сообщения (должен совпадать с заголовком в созданном EnvoyFilter для endpoint)

X-Received-Bytes

Данный фильтр добавляет заголовок к запросу. При необходимости данный служебный заголовок может быть удален путем модификации артефакта VirtualService вызываемого прикладного сервиса. Пример секции .spec артефакта VirtualService с удалением заголовка X-Received-Bytes из запроса:

spec:
  exportTo:
    - .
  gateways:
    - my-service
  hosts:
    - my-server-my-namespace.domain.ru
  http:
    - match:
        - uri:
            prefix: /
      route:
        - destination:
            host: my-server
            port:
              number: 8080
      headers:
        request:
          remove:
            - "X-Received-Bytes"

Примечание.

При использовании представленного выше артефакта EnvoyFilter для запросов без заголовка content-length максимальный размер тела запроса имеет ограничение в 1048576 байт (на запросы с заголовком content-length ограничение не распространяется). Для увеличения максимального размера тела запроса может быть использован следующий артефакт EnvoyFilter:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ${namespace}-listener-buffer
  namespace: ${namespace}
spec:
  workloadSelector:
    labels:
      ${labels}
  configPatches:
    - applyTo: LISTENER
      match:
        listener:
          portNumber: ${port}
      patch:
        operation: MERGE
        value:
          per_connection_buffer_limit_bytes: ${buffer}

Здесь:

  • namespace — идентификатор пространства имен;

  • labels — список label для определения необходимого Ingress (Egress) Gateway;

  • port — порт для входящих соединений Ingress (Egress) Gateway;

  • buffer — максимальный размер тела запросов (в байтах).

Данное решение:

  • требует создания дополнительного EnvoyFilter для вычисления размера тела запроса;

  • работает при отсутствии заголовка content-length в запросе (с ограничением);

  • может привести к задержкам в обработке запросов, обусловленным вычислением фактического размера запроса;

  • модифицирует запрос, добавляя в него дополнительный заголовок.

Использование заголовка Content-Length#

Размер тела запроса передается в заголовке content-length, но в соответствии со стандартом RFC 2616 данный заголовок не указывается (и игнорируется, если указан) при наличии заголовка transfer-encoding (он используется в случаях, когда тело запроса сжато или разбито на части и передается в нескольких запросах). Если во всех взаимодействиях, которые должны иметь ограничения в разрезе размера тела запроса, гарантированно передается заголовок content-length или в рамках рассматриваемых взаимодействий для запросов без данного заголовка допускается не применять ограничения вовсе, то ограничения в разрезе размера тела запроса могут быть реализованы на основе данного заголовка. Для этого при создании EnvoyFilter вручную в качестве параметра SizeHeader необходимо указать content-length.

Данное решения:

  • не требует создания дополнительного EnvoyFilter для вычисления размера тела запроса;

  • использует штатный заголовок, дополнительные затраты на вычисление размера тела запроса отсутствуют;

  • приводит к игнорированию запросов без заголовка content-length.

Применение ограничений в разрезе размера тела запроса к разным режимам#
Rate Limit Header Size#

Endpoint соответствует режиму Rate Limit Header Size в том случае, если он соответствует режиму Rate Limit Header, и его секция by_header содержит ссылку на ограничения в разрезе размера тела запроса (поле body_sizes_key).

Пример артефакта GlobalRateLimit с endpoint, соответствующего режиму Rate Limit Header Size представлен далее.

Пример GRL для Rate Limit Header Size.

Соответствия между комбинациями параметров запроса и лимитов, которые будут применены к ним, представлены в следующей таблице.

Тело запроса

Заголовок synapse-consumerid

Лимит

Нет или до 10 килобайт (вкл.)

Нет

12

Нет или до 10 килобайт (вкл.)

invoker13

13

Нет или до 10 килобайт (вкл.)

Есть, не invoker13

11

Свыше 10 килобайт

Нет

15

Свыше 10 килобайт

Есть

14

Rate Limit Prefix Size#

Endpoint соответствует режиму Rate Limit Prefix Size в том случае, если он соответствует режиму Rate Limit Prefix, и хотя бы один его префикс uri_prefix содержит ссылку на ограничения в разрезе размера тела запроса (поле body_sizes_key).

Пример артефакта GlobalRateLimit с endpoint, соответствующего режиму Rate Limit Prefix Size представлен далее.

Пример GRL для Rate Limit Prefix Size.

Соответствия между комбинациями параметров запроса и лимитов, которые будут применены к ним, представлены в следующей таблице.

Префикс

Тело запроса

Заголовок synapse-consumerid

Лимит

/foo

Нет или до 10 килобайт (вкл.)

Нет

12

/foo

Нет или до 10 килобайт (вкл.)

invoker13

13

/foo

Нет или до 10 килобайт (вкл.)

Есть, не invoker13

11

/foo

Свыше 10 килобайт

Нет

15

/foo

Свыше 10 килобайт

Есть

14

/bar

Не имеет значения

Нет

32

/bar

Не имеет значения

invoker33

31

/bar

Не имеет значения

Есть

31

Не /foo, не /bar

Не имеет значения

Не имеет значения

Лимиты не применяются

Rate Limit Method Size#

Endpoint соответствует режиму Rate Limit Method Size в том случае, если он соответствует режиму Rate Limit Method, и хотя бы один его метод http_method хотя бы одного префикса содержит ссылку на ограничения в разрезе размера тела запроса (поле body_sizes_key).

Пример артефакта GlobalRateLimit с endpoint, соответствующего режиму Rate Limit Method Size представлен далее.

Пример GRL для Rate Limit Method Size.

Соответствия между комбинациями параметров запроса и лимитов, которые будут применены к ним, представлены в следующей таблице.

Префикс

Метод

Тело запроса

Заголовок synapse-consumerid

Лимит

/foo

GET

Нет или до 10 килобайт (вкл.)

Нет

12

/foo

GET

Нет или до 10 килобайт (вкл.)

invoker13

13

/foo

GET

Нет или до 10 килобайт (вкл.)

Есть, не invoker13

11

/foo

GET

Свыше 10 килобайт

Нет

15

/foo

GET

Свыше 10 килобайт

Есть

14

/foo

POST

Не имеет значения

Нет

28

/foo

POST

Не имеет значения

Есть

27

/foo

Не GET, не POST

Нет или до 10 килобайт (вкл.)

Нет

12

/foo

Не GET, не POST

Нет или до 10 килобайт (вкл.)

invoker13

13

/foo

Не GET, не POST

Нет или до 10 килобайт (вкл.)

Есть, не invoker13

11

/foo

Не GET, не POST

Свыше 10 килобайт

Нет

15

/foo

Не GET, не POST

Свыше 10 килобайт

Есть

14

Не /foo

Не имеет значения

Не имеет значения

Не имеет значения

Лимиты не применяются

Rate Limit CN#

Данный режим является расширением режима Rate Limit Header и других его расширений. Применяется в случаях, когда требуется идентифицировать потребителя по конкретным атрибутам поля Subject сертификата.

Для перевода endpoint, работающего в режиме Rate Limit Header (или его расширении), в режим Rate Limit CN необходимо добавить в артефакт GlobalRateLimit раздел modify_header.

Блок modify_header влияет на весь endpoint, указывается внутри by_header и содержит в себе два параметра:

  • type — тип преобразования заголовка (для режима Rate Limit CN необходимо указывать значение cert — преобразования в терминах сертификата);

  • rule — опциональное правило преобразования заголовка (для типа cert через запятую указываются необходимые атрибуты сертификата из поля Subject).

Значение поля header сокращается до одного заголовка в случае, если было указано два или три.

При конфигурировании лимитов можно использовать как все поле Subject целиком (параметр rule не указан), так и конкретный атрибут (или набор атрибутов) из него. Правило преобразования rule поддерживает следующие атрибуты поля Subject сертификата:

  • CN: CommonName

  • OU: OrganizationalUnit

  • O: Organization

  • L: Locality

  • S или ST: StateOrProvinceName

  • C: CountryName

Пример поля Subject: CN=tribe-sy-dev-srls-dev-04, OU=R&D, O=sbertech, L=Moscow 10, S=Moscow, C=RU.

Примеры указания правила преобразования заголовка: rule: cn, rule: CN, o, rule: Ou,O

Пример конфигурации endpoint c modify_header:

- endpoint: 'ingress-my-namespace-02.apps.domain.org:8443'
  name: srls dev 02
  shortname: dev
  by_header:
    modify_header:
      type: cert
      rule: cn
    anon_value: 1
    header: synapse-consumerid
    invokers:
      - header_value: tribe-sy-dev-srls-dev-04
        name: client 1
        unit: minute
        value: 13
    unit: minute
    value: 7

Предположим, что в сертификате задан Subject="CN=tribe-sy-dev-srls-dev-04, OU=R&D, O=sbertech, C=RU". Рассмотрим для этого примера варианты указания блока modify_header и соответствующие ему header_value для задания лимитов:

  • блок modify_header не задан — идентификация потребителя выполняется по заголовку, Subject из сертификата не анализируется:

     by_header:
       header: synapse-consumerid
       invokers:
        - header_value: test-client-1
          name: client 1
          unit: minute
          value: 13
       unit: minute
       value: 7
    
  • в modify_header не задано правило преобразования rule (или задано пустое значение) — преобразование заголовка не выполняется, для задания лимита используется все значение поля Subject:

     by_header:
       modify_header:
         type: cert
       header: synapse-consumerid
       invokers:
        - header_value: CN=tribe-sy-dev-srls-dev-04, OU=R&D, O=sbertech, C=RU
          name: client 1
          unit: minute
          value: 13
       unit: minute
       value: 7
    
  • в modify_header в правиле указан один атрибут, который присутствует в Subject — преобразование заголовка выполнится, для задания лимита используется значение указанного атрибута:

     by_header:
       modify_header:
         type: cert
         rule: cn
       header: synapse-consumerid
       invokers:
        - header_value: tribe-sy-dev-srls-dev-04
          name: client 1
          unit: minute
          value: 13
       unit: minute
       value: 7
    
  • в modify_header в правиле указано несколько атрибутов, которые присутствуют в Subject — преобразование заголовка выполнится, для задания лимита используется конкатенация значений указанных атрибутов:

     by_header:
       modify_header:
         type: cert
         rule: cn,o
       header: synapse-consumerid
       invokers:
        - header_value: tribe-sy-dev-srls-dev-04sbertech
          name: client 1
          unit: minute
          value: 13
       unit: minute
       value: 7
    
  • в modify_header в правиле указано несколько атрибутов, но не все они присутствуют в Subject — преобразование заголовка выполнится, для задания лимита используется конкатенация значений атрибутов, имеющихся в Subject:

     by_header:
       modify_header:
         type: cert
         rule: cn,l,st,o
       header: synapse-consumerid
       invokers:
        - header_value: tribe-sy-dev-srls-dev-04sbertech
          name: client 1
          unit: minute
          value: 13
       unit: minute
       value: 7
    
  • в modify_header в правиле указано несколько атрибутов, но они не присутствуют в Subject — преобразование заголовка выполнится с ошибкой и вернет исходное значение. Для задания лимита в таком случае, можно использовать все значение поля Subject. Но при этом метрика ошибок модификации ratelimiterservice_should_rate_limit_modify_header_error будет постоянно увеличиваться, и в логах rate-limiter-service c уровнем debug будет выводиться ошибка типа: Error modify header: the specified cert artifact was not found in the header: CN=tribe-sy-dev-srls-dev-04, OU=R&D, O=sbertech, C=RU:

     by_header:
       modify_header:
         type: cert
         rule: l,st
       header: synapse-consumerid
       invokers:
        - header_value: CN=tribe-sy-dev-srls-dev-04, OU=R&D, O=sbertech, C=RU
          name: client 1
          unit: minute
          value: 13
       unit: minute
       value: 7
    
  • EnvoyFilter не добавлен, пользователь при запросе добавляет заголовок, например synapse-consumerid: Kafka, но в артефакте GlobalRateLimit задан блок modify_header — преобразование заголовка выполнится с ошибкой и вернет исходное значение. Для задания лимита в таком случае, можно использовать значение «Kafka». Но при этом метрика ошибок модификации ratelimiterservice_should_rate_limit_modify_header_error будет постоянно увеличиваться, и в логах rate-limiter-service c уровнем debug будет выводиться ошибка типа: Error modify header: the specified cert artifact was not found in the header: CN=tribe-sy-dev-srls-dev-04, OU=R&D, O=sbertech, C=RU:

     by_header:
       modify_header:
         type: cert
         rule: cn
       header: synapse-consumerid
       invokers:
        - header_value: Kafka
          name: client 1
          unit: minute
          value: 13
       unit: minute
       value: 7
    

Rate Limit Path#

Данный режим позволяет идентифицировать потребителя (тенанта) по ResourceName из URL запроса.

Формат ResourceName состоит из трех частей: account-id, project-id, resource-id. В конфигурации Rate Limit можно задать значимую часть идентификатора потребителя с помощью маски для расчета лимита.

Варианты маски:

  • mask = rn/*:*:* получим итоговое значение: account-idproject-idresource-id;

  • mask = rn/*:*:_ получим итоговое значение: account-idproject-id;

  • mask = rn/*:_:_ получим итоговое значение: account-id.

Формат URL запроса:

"http(s)://{HOST}:{PORT}/[{*Код продукта*}]/[{*версия*}]/rn/account-id:project-id:resource-id/{Контекст продукта}"

Пример конфигурации для режима Rate Limit Path.

Параметры блока by_path:

  • mask — опциональное поле, по умолчанию rn/*:*:*, маска для определения значимой части идентификатора потребителя;

  • unit — опциональное поле, по умолчанию second, единица измерения лимитов, используется при расчете overall_limit и потребителей, неуказанных в блоке tenants;

  • quotas — конфигурация квоты для потребителей, неуказанных в блоке tenants;

  • tenants — опциональный блок, позволяет задать квоту для определенных потребителей независимо.

Параметры блока quotas:

  • flat — опциональное поле, по умолчанию 1, позволяет задать квоту для запросов;

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

Для каждого tenant можно задать:

  • name — опциональное поле, позволяет указать метаданные для resourceName;

  • quotas — конфигурация квоты для потребителя, указанного в resourceName;

  • resourceName — идентификатор потребителя, значение необходимо указать в формате account-id:project-id:resource-id без разделителя, например accProjRes, если используется маска, необходимо указать только значимую часть, например accProj;

  • unit — опциональное поле, по умолчанию second, единица измерения лимитов;

  • schedule – опциональный блок, позволяет изменять лимиты по расписанию.

Поле schedule в примере выше означает, что для тенанта: name: server1.path будет изменен лимит 7 запросов в секунду в период с 2 часов 1 января по 12 часов 12 января на 20 запросов в минуту.

Локальный вариант расчета лимитов#

Для работы данной функциональности при установке необходимо задать true в значении стендозависимого параметра operator.localLimitsEnabled

Формирование и применение артефакта LocalRateLimit#

Для конфигурирования лимитов необходимо создать артефакт LocalRateLimit в namespace, где запущены необходимые Ingress Gateway (либо Egress Gateway) или прикладной сервис с Istio Sidecar.

Пример конфигурации: LocalRateLimit.

При формировании артефакта есть возможность указать:

  1. Аннотацию srls.sei/operator-namespace, в которой указывается namespace, где развернут централизованный оператор. Данную аннотацию необходимо указать для возможности развертывания нескольких экземпляров централизованного SRLS в рамках одного кластера Kubernetes или Red Hat OpenShift (опционально). Если при централизованном варианте данная аннотация не задана, оператор проигнорирует артефакт LocalRateLimit.

  2. Поля в блоке spec:

    • applyTo — определяет точку расчета лимитов, возможные значения: ingress, egress, sidecar;

    • limitEntries — список лимитов;

    • limit — явное указание квоты на весь Pod, квота будет применена к каждому listener (порт), для каждого listener подсчет запросов будет вестись независимо;

    • limitRef — указание квоты на весь Pod через ссылку на лимит из списка limitEntries, квота будет применена к каждому listener (порт), для каждого listener подсчет запросов будет вестись независимо;

    • endpoints — список защищаемых адресов с лимитами для них (смотри режим работы Rate Limit Endpoint в данном документе);

    • ports — список защищаемых портов с лимитами для них (смотри режим работы Rate Limit Port в данном документе);

    • visibility — отвечает за область видимости данного CRD, возможные значения: cluster, namespace;

    • workloadSelector — набор labels для определения нужных Pod (Ingress Gateway, Egress Gateway, Istio Sidecar).

В примере указаны несколько способов задания лимитов:

  1. Явное задание, через поле limit, содержит ключи и значения, позволяющие настроить частоту допустимых запросов, представляет из себя абстрактную «корзину токенов» или квот. Каждый поступающий запрос потребляет по одному токену. Элементы поля:

    • interval — содержит значение временного интервала (protobuf duration), при истечении которого «корзина» наполняется новыми токенами (выдаются очередные квоты на обработку запроса);

    • tokens — максимальное число токенов, которое «корзина» может вместить, также является начальным числом токенов;

    • tokensPerFill — число токенов, которое добавляется при истечении временного интервала.

  2. Указание ссылки на лимит через поле limitRef, в котором указывается id квоты из списка limitEntries.

Внимание!

Функция указания ссылки на лимит через поле limitRef — экспериментальная, рекомендуется использовать явное задание лимита.

Важно!

Если указаны оба варианта, приоритет отдается явной квоте, а не лимиту по ссылке.

Лимиты, установленные в примере:

  • на весь Pod — 100 запросов в 60 секунд;

  • на endpoint test-server1-endpoint.apps.stands-test.ru — 10 запросов в 60 секунд;

  • на endpoint test-server2-endpoint.apps.stands-test.ru — 15 запросов в 60 секунд;

  • на порт 8081 — 7 запросов в 60 секунд;

  • на порт 8443 — 5 запросов в 60 секунд.

Задание лимитов для конкретного режима работы подробнее описано в следующем разделе.

Режимы работы#

Для локального варианта лимитирования возможны следующие режимы работы: Rate Limit Pod, Rate Limit Endpoint и Rate Limit Port. В рамках одного артефакта LocalRateLimit есть возможность задать лимиты сразу для всех режимов. Если с режимом Rate Limit Pod заданы режимы Rate Limit Endpoint и Rate Limit Port, то они являются более приоритетными.

Ограничения:

  1. Значение shortname должно быть уникальным для всех ресурсов независимо от режима работы.

  2. Для конкретного значения порта может быть задан лишь один из режимов работы (Rate Limit Endpoint или Rate Limit Port).

Rate Limit Pod#

Данный режим работы используется при задании лимитов на Pod в целом, без идентификации потребителя и ресурса, квота будет применена к каждому listener (порт), для каждого listener подсчет запросов будет вестись независимо. Для конфигурирования необходимо использовать поле limitRef или поле limit в блоке spec. Если лимит не задан или по ссылке не удается найти квоту в списке limitEntries, то ограничения заданы не будут.

Пример: pod rate limit.

Rate Limit Endpoint#

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

Пример: endpoint rate limit.

Для каждого ресурса в списке endpoints можно указать:

  • shortname — обязательное поле c коротким именем для каждого защищаемого ресурса. Значение shortname должно быть уникальным;

  • endpoint — обязательное поле c целевым адресом в формате:

    • host:port, здесь host — DNS-адрес, на который поступает входящий трафик (определяется в артефакте Route или Ingress, используется в артефактах Gateway, VirtualService для манипуляции трафиком с помощью Service Mesh), port — порт, который слушает Ingress (Egress) Gateway (задается в артефакте Gateway), например, 8080 для HTTP-трафика или 8443 для HTTPS-трафика;

    • *:port, здесь * — условное обозначение любого host, port — порт, который слушает Ingress (Egress) Gateway (задается в артефакте Gateway), например, 8080 для HTTP-трафика или 8443 для HTTPS-трафика;

  • limit — явное указание квоты на endpoint;

  • limitRef — указание квоты на endpoint через ссылку на лимит из списка limitEntries.

Если лимит не задан или по ссылке не удается найти квоту в списке limitEntries, то применятся значения по умолчанию из CRD (1 запрос в секунду).

Rate Limit Port#

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

Пример: port rate limit.

Для каждого ресурса в списке ports можно указать:

  • shortname — обязательное поле c коротким именем, для каждого защищаемого ресурса значение shortname должно быть уникальным;

  • port — обязательное поле c целевым значением порта;

  • limit — явное указание квоты на порт;

  • limitRef — указание квоты на порт через ссылку на лимит из списка limitEntries.

Для варианта применения квот на Istio Sidecar, чтобы установить лимит на конкретный порт, необходимо использовать режим Rate Limit Endpoint. Например, задание лимита на все входящие на порт 8080 запросы:

  endpoints:
    - endpoint: 'inbound|http|8080'
      shortname: echo
      limit:
        interval: 60s
        tokens: 10
        tokensPerFill: 10

Если лимит не задан или по ссылке не удается найти квоту в списке limitEntries, то применятся значения по умолчанию из CRD (1 запрос в секунду).

Применение нескольких артефактов GlobalRateLimit (LocalRateLimit) в рамках одного namespace#

В рамках одного namespace можно создать несколько артефактов GlobalRateLimit (LocalRateLimit) для независимого конфигурирования лимитов для сервисов. При этом можно создавать артефакты с разным значением поля workloadSelector, например, для работы как с Ingress Gateway, так и с Egress Gateway.

После создания артефакта происходит «слияние» артефактов с одним и тем же workloadSelector, на этапе «слияния» выполняется валидация конфигурации лимитов.

Для GlobalRateLimit осуществляются проверки:

  • на уникальность значений полей endpoint и shortname;

  • на уникальность значения поля resourceName для одного endpoint;

  • валидация значений полей overall_schedule и schedule.

Для LocalRateLimit осуществляются проверки:

  • на соответствие полей applyTo, limit, limitRef, visibility;

  • на уникальность значений полей shortname, endpoint и port;

  • на уникальность режима задания лимита на конкретный порт (проверяем, что для портов, указанных в режиме Rate Limit Endpoint, в поле endpoint не был задан отдельный лимит в режиме Rate Limit Port).

В случае ошибки валидации необходимо скорректировать значения невалидного артефакта GlobalRateLimit (LocalRateLimit) или удалить артефакт.

Ограничение списка namespace для централизованного SRLS#

Ограничение списка namespace для централизованного SRLS необходимо, чтобы была возможность развернуть несколько централизованных SRLS в рамках одного кластера Kubernetes или Red Hat OpenShift (опционально).

Алгоритм работы с GlobalRateLimit:

  1. Пользователь создает в своем namespace артефакт GlobalRateLimit.

  2. RL Operator считывает поле «rlnamespace» из созданного артефакта GlobalRateLimit, сравнивает значение с идентификатором namespace, в котором RL Operator установлен.

    1. Если значение не совпадает, RL Operator не берет в работу артефакт GlobalRateLimit.

    2. Если значение совпадает, RL Operator формирует конфигурацию для RL Service.

    3. Если поле «rlnamespace» не задано, RL Operator осуществляет проверку на наличие прав доступа к артефакту EnvoyFilter в namespace пользователя:

      • если права есть, формирует конфигурацию для RL Service;

      • если доступа нет, не берет в работу.

Алгоритм работы с LocalRateLimit:

  1. Пользователь создает в своем namespace артефакт LocalRateLimit.

  2. RL Operator считывает значение аннотации srls.sei/operator-namespace из созданного артефакта LocalRateLimit, сравнивает значение с идентификатором namespace, в котором RL Operator установлен.

    1. Если значение не совпадает, RL Operator не берет в работу артефакт LocalRateLimit.

    2. Если значение совпадает, RL Operator формирует необходимые параметры для артефактов EnvoyFilter.

    3. Если аннотация srls.sei/operator-namespace не задана, RL Operator не берет в работу артефакт LocalRateLimit.

Режим NЦОД#

В режиме NЦОД квоты endpoint могут рассчитываться с учетом количества ЦОД по формуле:

квота_ЦОД = min(квота / количество_ЦОД, квота * protection_coefficient / 100)

Здесь:

  • квота_ЦОД – значение квоты после расчета;

  • квота – исходное значение квоты из артефакта GlobalRateLimit;

  • protection_coefficient – коэффициент защиты endpoint, целое число от 1 до 100;

  • количество_ЦОД – количество активных ЦОД, которые подтвердили наличие такого же endpoint.

Если protection_coefficient имеет значение 0, то квоты рассчитываются по формуле:

квота_ЦОД = квота / количество_ЦОД

Здесь:

  • квота_ЦОД – значение квоты после расчета;

  • квота – исходное значение квоты из артефакта GlobalRateLimit;

  • количество_ЦОД – общее количество ЦОД (без учета их статусов, без подтверждений).

Примечание.

При делении квоты выполняется округление к ближайшему целому числу. Например, 1.1 = 1; 1.5 = 2; 1.9 = 2.

Для включения режима NЦОД для endpoint необходимо указать опциональное поле endpoint_set_selector в артефакте GlobalRateLimit. Квоты endpoint с указанным endpoint_set_selector рассчитываются с учетом количества ЦОД (при условии, что SRLS был установлен с поддержкой режима NЦОД). Для успешного расчета квот с учетом количества ЦОД необходимо полное совпадение параметров endpoint в текущем и других ЦОД:

  • shortname;

  • endpoint_set_selector.labels;

  • endpoint_set_selector.export_to.

Параметр endpoint endpoint_set_selector.protection_coefficient в разных ЦОД может отличаться. Также в разных ЦОД могут отличаться как значения квот для endpoint (например, в одном ЦОД для одного потребителя для endpoint может быть задано ограничение в 10 запросов в секунду, а в другом ЦОД – 20 запросов в минуту), так и набор ограничений в целом (например, в одном ЦОД для endpoint могут быть заданы ограничения по CN, а в другом ЦОД – по prefix и header).

Параметр endpoint endpoint_set_selector.export_to должен содержать namespace, в котором данный endpoint (артефакт GlobalRateLimit) представлен.

Не допускается дублирование реплик endpoint в рамках одного ЦОД. Допустим, имеется endpoint:

shortname: myservice
endpoint_set_selector:
  export_to: [test1, test2]

В таком случае предполагается, что test1 и test2 – namespace в разных ЦОД (namespace test1 принадлежит одному ЦОД, а test2 – другому ЦОД). Загружать артефакты GlobalRateLimit с таким endpoint в namespace test1 и test2 одного ЦОД не допускается, процедура деления квот будет запущена только для одного из них.

Примеры расчета квот представлены в таблице.

Квота

Коэффициент защиты

Общее число ЦОД

Число активных ЦОД

Расчет

Результат

20

100

3

3

min(20/3, 20*100/100) = min(7, 20)

7

20

100

3

2

min(20/2, 20*100/100) = min(10, 20)

10

20

100

3

1

min(20/1, 20*100/100) = min(20, 20)

20

20

75

3

3

min(20/3, 20*75/100) = min(7, 15)

7

20

75

3

2

min(20/2, 20*75/100) = min(10, 15)

10

20

75

3

1

min(20/1, 20*75/100) = min(20, 15)

15

20

0

3

3

20/3

7

20

0

3

2

20/3

7

20

0

3

1

20/3

7

Примечание.

Балансировка запросов между ЦОД может выполняться неравномерно. Это может привести к ложным ограничениям запросов компонентом SRLS. Поэтому рекомендуется учитывать погрешность балансировки при установке ограничений.

Например, при необходимости ограничить 100 запросов суммарно на два ЦОД можно установить ограничение в 105-110 запросов. Это позволит избежать ложных ограничений запросов при некорректной балансировке в пределах 2,5-5%.