docs: add routing.md — balancing modes and routing rules
This commit is contained in:
parent
0fa9278eef
commit
6e9c5f20d4
@ -69,6 +69,7 @@ curl -X POST http://localhost:8080/api/auth/login \
|
|||||||
| [docs/architecture.md](docs/architecture.md) | Архитектура, диаграмма потоков данных, стек, структура проекта |
|
| [docs/architecture.md](docs/architecture.md) | Архитектура, диаграмма потоков данных, стек, структура проекта |
|
||||||
| [docs/api.md](docs/api.md) | Полная справка REST API + WebSocket: auth, route, nodes, trunks, users, monitoring, примеры |
|
| [docs/api.md](docs/api.md) | Полная справка REST API + WebSocket: auth, route, nodes, trunks, users, monitoring, примеры |
|
||||||
| [docs/scoring.md](docs/scoring.md) | Scoring engine: lethal-условия, weighted score, пример расчёта, кэширование |
|
| [docs/scoring.md](docs/scoring.md) | Scoring engine: lethal-условия, weighted score, пример расчёта, кэширование |
|
||||||
|
| [docs/routing.md](docs/routing.md) | Маршрутизация: режимы балансировки (best / weighted_random), routing rules (node / pool / auto) |
|
||||||
| [docs/agent.md](docs/agent.md) | pulse-lets-go-agent: collectors, конфигурация, деплой, troubleshooting |
|
| [docs/agent.md](docs/agent.md) | pulse-lets-go-agent: collectors, конфигурация, деплой, troubleshooting |
|
||||||
| [docs/deployment.md](docs/deployment.md) | Production деплой (8 шагов), systemd unit, security, rollback |
|
| [docs/deployment.md](docs/deployment.md) | Production деплой (8 шагов), systemd unit, security, rollback |
|
||||||
| [docs/freeswitch.md](docs/freeswitch.md) | Интеграция с FreeSWITCH: route.lua, dialplan, ESL, предварительные проверки |
|
| [docs/freeswitch.md](docs/freeswitch.md) | Интеграция с FreeSWITCH: route.lua, dialplan, ESL, предварительные проверки |
|
||||||
|
|||||||
@ -16,6 +16,7 @@ Roles: `admin` (full access), `viewer` (read-only nodes/metrics).
|
|||||||
| Method | Path | Auth | Description |
|
| Method | Path | Auth | Description |
|
||||||
|--------|------|------|-------------|
|
|--------|------|------|-------------|
|
||||||
| `GET` | `/api/route` | – | Route a call. Query: `caller_id`, `dest`, `ingress_trunk` |
|
| `GET` | `/api/route` | – | Route a call. Query: `caller_id`, `dest`, `ingress_trunk` |
|
||||||
|
| `PUT` | `/api/route/mode` | admin | Set balancing mode: `{"mode":"best\|weighted_random"}` — см. [Routing](routing.md#balancing-modes) |
|
||||||
| `GET` | `/api/health` | – | Stats: total nodes, healthy, requests, uptime |
|
| `GET` | `/api/health` | – | Stats: total nodes, healthy, requests, uptime |
|
||||||
| `GET` | `/api/health/live` | – | Liveness probe (always 200) |
|
| `GET` | `/api/health/live` | – | Liveness probe (always 200) |
|
||||||
| `GET` | `/api/health/ready` | – | Readiness probe (NATS + metrics) |
|
| `GET` | `/api/health/ready` | – | Readiness probe (NATS + metrics) |
|
||||||
@ -23,9 +24,11 @@ Roles: `admin` (full access), `viewer` (read-only nodes/metrics).
|
|||||||
### Route Response (success)
|
### Route Response (success)
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{ "node_id": "pbx-03", "score": 88, "sip_gateway": "sip:pbx03.lan:5060" }
|
{ "node_id": "pbx-03", "score": 88, "sip_gateway": "sip:pbx03.lan:5060", "matched_rule": "none" }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`matched_rule` — имя сработавшего routing rule, либо `"none"` если применился глобальный scoring.
|
||||||
|
|
||||||
### Route Response (fallback — all nodes unhealthy)
|
### Route Response (fallback — all nodes unhealthy)
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|||||||
104
docs/routing.md
Normal file
104
docs/routing.md
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
# Routing
|
||||||
|
|
||||||
|
Маршрутизация звонков состоит из двух уровней:
|
||||||
|
|
||||||
|
1. **Routing Rules** — priority-based правила с regex-матчингом (first-match-wins)
|
||||||
|
2. **Balancing Mode** — стратегия выбора ноды внутри правила или глобально
|
||||||
|
|
||||||
|
## Routing Rules
|
||||||
|
|
||||||
|
Правила хранятся в `data/routes.json` и проверяются в порядке `Priority` (меньше = раньше). Первое совпавшее правило определяет маршрутизацию. Если правило не сработало (нода мертва / пул пуст) — переход к следующему. Если ни одно правило не совпало — глобальный `PickNode()`.
|
||||||
|
|
||||||
|
### Match Conditions (AND-логика)
|
||||||
|
|
||||||
|
Все непустые поля должны совпасть одновременно. Пустые поля — не проверяются.
|
||||||
|
|
||||||
|
| Поле | Тип | Описание |
|
||||||
|
|------|-----|----------|
|
||||||
|
| `match_caller_id` | regex | Caller ID звонящего |
|
||||||
|
| `match_destination` | regex | Номер назначения |
|
||||||
|
| `match_ingress_trunk` | regex | ID входящего транка |
|
||||||
|
| `match_days` | string | Дни недели: `"1-5"` (пн-пт), `"1,3,5"` (пн,ср,пт), `"6"` (сб). Воскресенье = 0 или 7 |
|
||||||
|
| `match_time_start` | `"HH:MM"` | Начало временного диапазона |
|
||||||
|
| `match_time_end` | `"HH:MM"` | Конец временного диапазона |
|
||||||
|
|
||||||
|
### Action Types
|
||||||
|
|
||||||
|
| Тип | Поле | Описание |
|
||||||
|
|-----|------|----------|
|
||||||
|
| `node` | `action_node_id` | Маршрутизация на конкретную ноду. Если нода dead/stale/lethal — fallthrough к следующему правилу |
|
||||||
|
| `pool` | `action_pool_ids` | Выбор лучшей ноды из заданного списка (по текущему режиму балансировки). Пустой/нездоровый пул — fallthrough |
|
||||||
|
| `auto` | — | Fallthrough к глобальному `PickNode()` с учётом режима балансировки |
|
||||||
|
|
||||||
|
### Пример правила
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "rule-001",
|
||||||
|
"name": "VIP caller to dedicated pool",
|
||||||
|
"enabled": true,
|
||||||
|
"priority": 10,
|
||||||
|
"match_caller_id": "^7495",
|
||||||
|
"match_destination": "",
|
||||||
|
"match_ingress_trunk": "",
|
||||||
|
"match_days": "1-5",
|
||||||
|
"match_time_start": "09:00",
|
||||||
|
"match_time_end": "18:00",
|
||||||
|
"action_type": "pool",
|
||||||
|
"action_pool_ids": ["pbx-01", "pbx-02"],
|
||||||
|
"description": "VIP номера 7495 в бизнес-часы на выделенные ноды"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Balancing Modes
|
||||||
|
|
||||||
|
Режим балансировки определяет, **как** выбирается нода из множества healthy-нод (после отсева lethal). Применяется как в глобальном `PickNode()`, так и внутри `pool`-правил.
|
||||||
|
|
||||||
|
### best
|
||||||
|
|
||||||
|
Выбирает ноду с **максимальным score** из кэша. O(1) — `bestScore` предрассчитывается при каждой метрике.
|
||||||
|
|
||||||
|
- Всегда одна и та же нода при одинаковых метриках — максимально нагружает лучшую ноду
|
||||||
|
- Хорошо для тестирования и сценариев где нужна предсказуемость
|
||||||
|
|
||||||
|
### weighted_random (по умолчанию)
|
||||||
|
|
||||||
|
Выбирает ноду **пропорционально score**: чем выше score, тем выше вероятность быть выбранной. O(n) — сканирует все ноды.
|
||||||
|
|
||||||
|
Алгоритм:
|
||||||
|
1. Отсеивает disabled, stale, lethal (score < 0)
|
||||||
|
2. Суммирует score всех кандидатов (`totalScore`)
|
||||||
|
3. `pick = rand(0, totalScore)`, идёт по кандидатам, вычитая score
|
||||||
|
4. Если `totalScore <= 0` — равновероятный выбор
|
||||||
|
|
||||||
|
- Распределяет нагрузку пропорционально готовности
|
||||||
|
- Предсказуемость ниже, но утилизация выше — менее загруженные ноды получают пропорционально меньше звонков
|
||||||
|
|
||||||
|
### Переключение режима
|
||||||
|
|
||||||
|
**Через API:**
|
||||||
|
```
|
||||||
|
PUT /api/route/mode
|
||||||
|
Authorization: Bearer <admin-jwt>
|
||||||
|
{"mode": "best"}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Через конфиг:**
|
||||||
|
```json
|
||||||
|
{ "balance_mode": "weighted_random" }
|
||||||
|
```
|
||||||
|
|
||||||
|
Допустимые значения: `"best"`, `"weighted_random"`. API-эндпоинт сразу применяет режим и сохраняет в `config.json`.
|
||||||
|
|
||||||
|
## Ответ /api/route
|
||||||
|
|
||||||
|
В ответе маршрутизации появилось поле `matched_rule` — имя сработавшего правила (или `"none"` если правило не применилось):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"node_id": "pbx-03",
|
||||||
|
"score": 88,
|
||||||
|
"sip_gateway": "sip:pbx03.lan:5060",
|
||||||
|
"matched_rule": "VIP to dedicated"
|
||||||
|
}
|
||||||
|
```
|
||||||
@ -50,6 +50,8 @@ score = 83.2×0.40 + 57.5×0.30 + 35.0×0.20 + 99.5×0.10 = 70.1
|
|||||||
`best_node_id`, `best_score`, and `fallback_active` are recalculated on every metric update.
|
`best_node_id`, `best_score`, and `fallback_active` are recalculated on every metric update.
|
||||||
`/api/route` reads them under RLock — O(1) constant time.
|
`/api/route` reads them under RLock — O(1) constant time.
|
||||||
|
|
||||||
|
Выбор ноды из кэша зависит от [режима балансировки](routing.md#balancing-modes).
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user