Настройка динамической генерации ответа о текущем состоянии экземпляра Platform V SOWA#
В ряде случаев, сервисам-клиентам, использующим Platform V SOWA, необходимо получение информации о текущем состоянии экземпляра Platform V SOWA. В случае, если состояние экземпляра управляется вручную, это можно сделать с помощью параметра healthcheck. В том же случае, если необходимо это делать на основании некоторой информации о состоянии самого экземпляра или бэкенд-серверов, располагающихся за экземпляром Platform V SOWA, необходимо использовать параметр healthcheck_dynamic.
Данный параметр позволяет шаблонизировать ответ о текущем состоянии экземпляра или конкретного сервиса на экземпляре за счет определения правил формирования ответов, шаблонов и условий их сопоставлений.
В условиях правил и шаблонах можно использовать следующие конструкции:
Константные строковые значения.
Стандартные переменные NGINX, но при этом необходимо учитывать, что все значения переменных в данном случае вычисляются в контексте запроса к сервису HC, поэтому в основном доступны и имеет смысл использовать ограниченный круг переменных, чьи значения не привязаны к запросам к конкретным сервисам. Например, переменные:
модуля статистики: https://nginx.org/ru/docs/http/ngx_http_stub_status_module.html#variables;
текущего времени -
$msec,$time_iso8601,$time_local;информации об экземпляре или сервисе, например
$server_addr;переменные Platform V SOWA, доступные в случае использования соответствующей функциональности - например, статистика по загрузке CPU и RAM
stat_cpu_usage,stat_memory_usage.
Переменные, значения которых устанавливаются вручную через загрузку файла с параметрами в момент конфигурирования и через вызов соответствующей командной строки, обращение к ним осуществляется через
$ключ_в_файле.Переменных функциональности динамической генерации ответа о текущем состоянии:
profile_upstream_group_state_fmt- объект в формате JSON или XML или текста (зависит от указанного параметреresponse.content_type), содержащий информацию о состоянии всех групп балансировки профиля.Пример:
{ "service_use_bind_ug": { "hasLiveUpstream": true, "upstreamStates": [ { "state": "UP", "upstreamName": "internal1" }, { "state": "UP", "upstreamName": "internal2" } ] } }Состояние группы определяется с учетом значения параметра
upstream_check_type, в список включаются те группы балансировки, которые удовлетворяют регулярному выражению указанному в параметреupstream_filter.service_upstream_group_state_fmt- объект в формате JSON или XML или текста (зависит от указанного параметреresponse.content_type), содержащий информацию о состоянии всех групп балансировки сервиса. Переменная заполняется только при объявлении параметраendpointsна уровне сервиса.profile_upstream_group_state_fmt- объект в формате JSON или XML или текста (зависит от указанного параметреresponse.content_type), содержащий информацию о состоянии всех групп балансировки профиля. Переменная заполняется только при объявлении параметраendpointsна уровне main_proxy.profile_upstream_group_alive- содержит 1, если хотя бы одна группа балансировки профиля находится в активном состоянии, активность состояния определяется также с учетом заданных параметровupstream_check_typeиupstream_filter.service_upstream_group_alive- содержит 1, если хотя бы одна группа балансировки сервиса находится в активном состоянии, активность состояния определяется также с учетом заданных параметровupstream_check_typeиupstream_filter.Аналогично, определены переменные
bind_upstream_group_state_fmt,bind_upstream_group_alive, которые равны либоservice_*либоprofile*переменным в зависимости от того, где определен параметрendpoints- в сервисе с типом main_proxy или в сервисе не с типом main_proxy.upstream_group_state_имя_группы_балансировки- возвращает состояние группы балансировки, определенной по правилам аналогичным для предыдущих переменных.upstream_group_state_orig_имя_группы_балансировки- возвращает состояние группы балансировки, в соответствии со следующими критериями, UP - хотя бы один в сервер в состоянии UP, DRAIN - нет серверов в состоянии UP, но есть в состоянии DRAIN, DOWN - нет серверов в состоянии UP или DRAIN.Важно
Использование заглавных букв в имени группы балансировки приводит к некорректному определению статуса групп балансировки.
upstream_group_state_origотдаст статус UNKNOWN (при этом значение переменной null), аupstream_group_state- DOWN.
Особенности применения#
Ниже описаны некоторые особенности настройки динамической генерации ответов на запросы о текущем состоянии экземпляра или сервиса, объявленного в конфигурации:
При объявлении параметра
endpointsв секции endpoints:В случае наличия сервиса с типом
main_proxyдоступны при обращении на порты сервисаmain_proxy, объявленные в секцииlistenданного сервиса. При этом переменныеservice_upstream_upstream_group_state_fmt,service_upstream_group_aliveне определены.В случае отсутствия сервиса с типом
main_proxyдоступны на портах всех сервисов, кроме тех случаев, когда в соответствующем сервисе определен собственный параметрhealthcheck_dynamic. Объявлениеhealthcheck_dynamicв рамках сервиса отменяет наследование endpoint с уровняsystem.
Параметры
initial_state_param_fileиmanual_state_var_refresh_intervalдоступны для определения только в секции system, то есть их действие распространяется на все эндпоинты healthcheck. Это нужно учитывать при ссылке на параметры, указанные в файле параметров. Если необходимо использовать разные значения в разных endpoint, параметрам нужно давать разные имена.Для изменения параметров, задаваемых вручную в файле
initial_state_param_fileв runtime, необходимо использовать команду--set-healthcheck-paramsутилиты конфигурирования:sowa-config --set-healthcheck-params <имя_профиля> <путь к файлу с параметрами>Для получения текущего значения параметров, установленных в runtime, необходимо использовать команду
--upload-healthcheck-params:sowa-config --upload-healthcheck-params <имя_профиля> <путь к файлу, куда будут сохранены текущие значения параметров>При выполнении операции конфигурирования текущее значение параметров, заданных в runtime, будет перезаписано значениями, указанными в файле, заданном в параметре
initial_state_param_file, поэтому в момент конфигурирования он должен содержать актуальные значения параметров.
Некоторые примеры использования#
Пример 1
Пусть в сервисе определены две группы балансировки, группа 1 и группа 2, и есть два потребителя, для которых доступность сервиса определяется на основании следующих условий:
Для потребителя 1 сервис является доступным, если доступна хотя бы одна группа балансировки.
Для потребителя 2 сервис доступен, если доступны или обе группы балансировки одновременно, или группа 2.
Группа балансировки считается доступной, если хотя бы один сервер группы находится в состоянии UP.
Если условия выполняются, то возвращается ответ со статусом 204 и пустым телом ответа, в ином случае возвращается 503, с ответом
{"status": "Service temporary unavailable"}.
Конфигурация определена следующим образом:
service_http_proxy:
- id: 1
listen:
- 6060
...
upstream_groups:
- id: upstream_group_1
servers:
- server: west.myserver.com:30000
max_fails: 1
- id: upstream_group_2
servers:
- server: east.myserver.com:30000
optional:
healthcheck_dynamic:
endpoints:
- url: /hc-first
response:
upstream_check_type: ANY_UPSTREAM_UP
rules: rules_1.yml
content_type: appication/json
- url: /hc-second
response:
upstream_check_type: ANY_UPSTREAM_UP
content_type: appication/json
rules: rules_2.yml
Файлы с правилами:
rules_1.yml:
rules:
- condition:
- var: service_upstream_group_alive
val: 1
operator: "="
status: 204
- default: true
status: 503
responsePattern: "{\"status\": \"Service temporary unavailable\"}"
rules_2.yml:
rules:
- condition:
- var: service_upstream_group_alive
val: 1
operator: "="
status: 204
- condition:
- var: upstream_group_state_upstream_group_2
val: "UP"
operator: "="
status: 204
- default: true
status: 503
responsePattern: "{\"status\": \"Service temporary unavailable\"}"
Соответственно, потребитель 1 должен обращаться к endpoint /hc-first, потребитель 2 должен обращаться к endpoint 2.
Пример 2
Пусть у сервиса есть две группы потребителей - привилегированные и непривилегированные. Привилегированным потребителям сервис доступен до тех пор, пока текущая загрузка CPU экземпляра не превысит 80%, непривилегированным потребителям сервис доступен до тех пор, пока нагрузка на CPU не превысит 40%. Обеим группам потребителей сервис не доступен, если администратор выставил вручную параметр manual_set_offline в значение 1.
Если условия выполняются, то возвращается ответ со статусом 204 и пустым телом ответа, в случае, если администратором выставлен флаг manual_set_offline возвращается 503, с ответом {"status": "Service temporary unavailable"}, если превышена нагрузка по ЦПУ, возвращается 503, с ответом {"status": "system overloaded"}.
Конфигурация определена следующим образом:
system:
optional:
#включаем сбор статистики по потреблению системных ресурсов
get_load:
enabled: true
healthcheck_dynamic:
initial_state_param_file: profile_params.data
manual_state_var_refresh_interval: 5s
service_http_proxy:
- id: 1
listen:
- 6060
...
optional:
healthcheck_dynamic:
endpoints:
- url: /hc-priveleged
response:
rules: rules_1.yml
content_type: appication/json
- url: /hc-unpriveleged
response:
content_type: appication/json
rules: rules_2.yml
Файлы с правилами:
rules_1.yml:
rules:
- condition:
- var: stat_cpu_usage
val: 80
operator: "<"
- var: manual_set_offline
val: 1
operator: "!="
status: 204
- condition:
- var: stat_cpu_usage
val: 80
operator: ">"
- var: manual_set_offline
val: 1
operator: "!="
status: 503
responsePattern: "{\"status\": \"system overloaded\"}"
- condition:
- var: manual_set_offline
val: 1
operator: "="
responsePattern: "{\"status\": \"Service temporary unavailable\"}"
status: 503
- default: true
status: 503
responsePattern: "{\"status\": \"Service temporary unavailable\"}"
rules_2.yml:
rules:
- condition:
- var: stat_cpu_usage
val: 40
operator: "<"
- var: manual_set_offline
val: 1
operator: "!="
status: 204
- condition:
- var: stat_cpu_usage
val: 40
operator: ">"
- var: manual_set_offline
val: 1
operator: "!="
status: 503
responsePattern: "{\"status\": \"system overloaded\"}"
- condition:
- var: manual_set_offline
val: 1
operator: "="
pattern: "{\"status\": \"Service temporary unavailable\"}"
status: 503
- default: true
status: 503
pattern: "{\"status\": \"Service temporary unavailable\"}"
Файл profile_params.data:
manual_set_offline: 1
Пример 3
Пусть в профиле объявлен сервис service_http_proxy и нужно определить правила определения состояния экземпляра следующим образом:
Если администратор выставил вручную параметр
manual_set_offlineв значение 1, экземпляр считается недоступным, в ответ возвращается{"status": "Service temporary unavailable"}.Если ни одна группа балансировки, определенная в профиле, недоступна, но при этом группа считается доступной, если в ней хотя бы один сервер находится не в состоянии DOWN, возвращается 502 с телом ответа
{"status": "Bad gateway"}.Если ни первое, ни второе условие не выполняется, возвращается 200 c перечислением состояния всех групп балансировки для всех сервисов. Потребитель сам должен принять решение, считать ли данный экземпляр доступным.
Конфигурация определена следующим образом:
system:
optional:
healthcheck_dynamic:
initial_state_param_file: profile_params.data
manual_state_var_refresh_interval: 5s
service_http_proxy:
- id: 1
listen:
- 6060
...
optional:
healthcheck_dynamic:
endpoints:
- url: /hc
upstream_check_type: ANY_UPSTREAM_UP_OR_DRAIN
response:
rules: rules_1.yml
content_type: appication/json
Файл с правилами:
rules_1.yml:
rules:
- condition:
- var: profile_upstream_group_alive
val: 1
operator: "!="
status: 502
responsePattern: "{\"status\": \"Bad gateway\"}"
- condition:
- var: manual_set_offline
val: 1
operator: "="
responsePattern: "{\"status\": \"Service temporary unavailable\"}"
priority: 100
status: 503
- default: true
status: 200
responsePattern: "{\"upstream_group_states\":
$profile_upstream_group_state_fmt}"
Файл profile_params.data:
manual_set_offline: 1
Пример 4
В примере ниже, демонстрируется возможность совместного использования и перекрытия точек входа healthcheck.
Здесь доступна точка входа healthcheck для сервиса main_proxy c контекстным путем /healthcheck, она же наследуется в сервисе service_use_main_ug (так как определена в секции system/optional и сервис не имеет своего слушающего порта).
Сервис service_use_bind_ug имеет свой собственный healthcheck, доступный при обращении на порт 28176 по тому же контекстному пути /healthcheck.
profile: hc_dynamic
service:
service_http_proxy:
- id: service_use_main_ug
allowed_queries:
- method: get
upstream_group_id: extgw_adapter
#url для HC сервиса service_use_main_ug
url: ^\/first$
use_main_upstream_groups: true
- id: service_use_internal_ug
#url для HC сервиса service_use_internal_ug
url: ^\/first$
allowed_queries:
- method: get
upstream_group_id: internal1
upstream_groups:
- id: internal1
servers:
- max_fails: 0
server: myserver:20003
weight: 1
- id: service_use_bind_ug
#url для HC сервиса service_use_internal_ug
listen:
- port: 28176
optional:
healthcheck_dynamic:
endpoints:
- url: /healthcheck
upstream_check_type: ANY_UPSTREAM_UP_OR_DRAIN
upstream_filter: .*
response:
pattern_file: hc_pattern_default.json
rules: hc_response_rules.data
url: ^\/second$
allowed_queries:
- method: get
upstream_bind_variable: $uri
upstream_groups:
- id: internal1
bind_condition: value1
servers:
- max_fails: 0
server: myserver:20004
weight: 1
- id: internal2
bind_condition: value2
default: true
servers:
- max_fails: 0
server: myserver:20005
weight: 1
service_main_proxy:
- id: 1
listen:
- port: 28175
modifiers:
set_header:
- Client-Cert $uri
upstream_groups:
- id: extgw_ecom_adapter
keepalive_conn_count: 100
servers:
- max_fails: 0
server: myserver:20000
weight: 1
url: /
system:
optional:
healthcheck_dynamic:
initial_state_param_file: hc_params.data
manual_state_var_refresh_interval: 1m
endpoints:
- url: /healthcheck
upstream_check_type: ANY_UPSTREAM_UP_OR_DRAIN
upstream_filter: .*
response:
pattern_file: hc_pattern_default.json
rules: hc_response_rules.data
version: 2.0.3