Балансировка на основании содержимого запроса JSON#

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

profile: chain_stub
system:
  conn_count: 4096
  optional:
    log_level: debug
  wrk_count: 1
version: 2.0.3
service:
  service_static:
    - id: 1
      name: simple_1
      listen:
         - port: 30000
      url: /test
      optional:
        response_body: "OK"
        response_code: 200
      response_headers:
        - name: IDENT
          value: $server_addr:$server_port
    - id: 2
      name: simple_2
      listen:
         - port: 30001
      url: /test
      optional:
        response_body: "OK"
        response_code: 200
      response_headers:
        - name: IDENT
          value: $server_addr:$server_port

Здесь происходит определение двух http-сервисов на портах 30000 и 30001, каждый из которых принимает запросы по контекстному пути /sample и возвращают в ответе 200 «OK». Кроме этого, добавляя в ответе заголовок IDENT, содержащий адрес и порт, на который приходят запросы, можно идентифицировать, от какого backend будет приходить ответ.

Создайте, сконфигурируйте и запустите профиль:

[sowacfg@741037ad695c chains_examples]$ sowa-config --add-profile chain_stub
Profile "chain_stub" was successfully created
[sowacfg@741037ad695c chains_examples]$ sowa-config --config stubs.yml
Profile "chain_stub" was successfully configured.
[sowacfg@741037ad695c chains_examples]$ sowa-config --run chain_stub
Profile "chain_stub" was successfully started.

Допустим есть следующая задача:

Клиент отправляет на шлюз запросы методом POST с телом запроса в виде JSON объекта, в котором определено свойство region. В зависимости от того, какое значение в этом свойстве содержится, необходимо выбирать одну из двух групп балансировки, каждая из которых содержит по одному сервису с нашими заглушками.

Создайте профиль chains со следующей конфигурацией:

profile: chains
system:
  conn_count: 4096
  wrk_count: 1
  optional:
    log_level: debug
    maps:
     - src_var: $clj_region
       dst_var: $sel_upstream
       volatile: True
       default: group_1
       mapping:
        - src_val: Samara
          dst_val: group_2
        - src_val: Moscow
          dst_val: group_1
version: 2.0.3
service:
  service_http_proxy:
    - id: 1
      allowed_queries:
        - method: post
      url: /balancer$
      listen:
        - port: 20200
      modifiers:
        set_output_headers:
          - headers:
             -  REGION $clj_region
      chains:
        request_chains:
          - actions:
             - action: JsonPathExtractToVars
               params:
                 expressions:
                  - path: $.region
                    var: clj_region
            message: $clj_request_body
      upstream_bind_variable: $sel_upstream
      upstream_groups:
        - id: 2
          servers:
            - server: 127.0.0.1:30000
          bind_condition: group_2
          rewrite_uri:
            - from: /balancer
              to:  /test
        - id: 1
          servers:
            - server: 127.0.0.1:30001
          bind_condition: group_1
          rewrite_uri:
           - from: /balancer
             to: /test
          default: True

Рассмотрим подробнее каждый из элементов.

В сервисе нужно определить цепочку действий request_chains, которая показывается, что происходит обработка тела запроса и извлечение из JSON объекта свойства region, после чего помещаем его в переменную clj_region.

Конструкция upstream_bind_variable говорит о том, что в данном сервисе для выбора группы backend необходимо ориентироваться на значение переменной $sel_upstream, которая вычисляется с использованием отображения, определенного следующим образом:

maps:
   # переменная чье мы значение вычисляем  
 - src_var: $clj_region
   # переменная содержащая результирующее значение
   dst_var: $sel_upstream
   # указываем что значение не кэшируется, а вычисляется каждый раз при запросе
   volatile: True
   # если ни одно значение не подходит будем выбирать group_1
   default: group_1
   mapping:
      # если значение = Samara, то выбираем group_2
    - src_val: Samara
      dst_val: group_2
      # если значение = Moscow, то выбираем group_1
    - src_val: Moscow
      dst_val: group_1

Далее, в каждой из групп backend определяем ее привязку к условию через определение bind_condition.

И, наконец в секции modifiers определяем добавление заголовка с вычисленным значением clj_region, чтобы визуально видеть, какое значение было выбрано. Также ограничиваем возможные методы запроса через директиву allowed_queries.

Сконфигурируем и запустим профиль, после чего отправим запрос curl: d32

Как видим, запрос ушел на тот backend, на который и ожидали.

Если отправим запрос без данного свойства, то он пойдет на ту группу backend, которая определена по умолчанию: d33