Балансировка на основании содержимого запроса 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:

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