feat: фоновый пинг апстримов в backoff-откате (probe_interval) — мгновенное возвращение в пул
Build LLM Proxy / Build and push (release) Successful in 42s
Build LLM Proxy / Build and push (release) Successful in 42s
This commit is contained in:
@@ -85,6 +85,8 @@ providers:
|
||||
allow_fallbacks: false
|
||||
backoff: P1M # опционально; потолок экспоненциального backoff
|
||||
# на весь провайдер (ISO-8601: P1M, PT15M, P1D…)
|
||||
probe_interval: PT1S # опционально; фоновый пинг апстримов в откате
|
||||
# (как часто проверять, жив ли провайдер)
|
||||
|
||||
- id: local-llama
|
||||
url: "http://10.0.0.5:8080/v1"
|
||||
@@ -103,6 +105,8 @@ upstreams:
|
||||
ignore: [deepseek]
|
||||
backoff: PT15M # опционально; собственный backoff этой модели
|
||||
# (приоритет над backoff провайдера)
|
||||
probe_interval: PT0S # опционально; пинг отключён у этой модели
|
||||
# (приоритет над probe_interval провайдера)
|
||||
|
||||
- id: local-qwen
|
||||
provider: local-llama
|
||||
@@ -385,6 +389,68 @@ upstreams:
|
||||
При старте выводится, что настроено:
|
||||
`[llm-proxy] first_byte_timeout: upstreams=routerai-gpt4o=PT0S providers=routerai=PT30S default=PT30S`.
|
||||
|
||||
### Фоновый пинг апстримов в откате (`probe_interval`)
|
||||
|
||||
Когда апстрим «уходит в аут» надолго (backoff растёт до потолка), без пинга
|
||||
он вернётся в ротацию только по истечении интервала отката — это может быть
|
||||
минуты простоя, хотя модель уже могла ожить. `probe_interval` включает
|
||||
фоновый «пингер»: пока апстрим в backoff-откате, HealthProber каждые
|
||||
`probe_interval` шлёт ему минимальный запрос (`2+2=?`, `max_tokens=4`,
|
||||
`stream=true`) и слушает первый байт ответа. Как только апстрим ответил —
|
||||
его снимают с отката немедленно (`backoff.recordSuccess`), и он возвращается
|
||||
в общий пул, не дожидаясь истечения backoff-интервала.
|
||||
|
||||
| Поле | Тип / дефолт | Значение |
|
||||
|---|---|---|
|
||||
| `providers[].probe_interval` | ISO-8601-длительность / отсутствует | Интервал пинга для всех моделей провайдера |
|
||||
| `upstreams[].probe_interval` | ISO-8601-длительность / отсутствует | Интервал для конкретной модели (приоритет над провайдерским) |
|
||||
|
||||
**Дефолт** (если не задан нигде): `PT1S`.
|
||||
|
||||
**Приоритет — модели.** Если `upstreams[].probe_interval` задан, он
|
||||
перекрывает провайдерский; если нет — берётся провайдерский; если нет и там —
|
||||
дефолт `PT1S`.
|
||||
|
||||
**Отключение:** `PT0S` на провайдере или апстриме отключает пинг для этого
|
||||
апстрима — тогда он возвращается в пул только по истечении backoff-интервала.
|
||||
|
||||
Особенности:
|
||||
|
||||
- пингуются **только** апстримы, которые сейчас в backoff-откате; живой
|
||||
апстрим пинг не получает (проверка состояния — каждые `probe_interval`);
|
||||
- пинг **не занимает слот конкурентности** (идёт в обход `max_concurrency`),
|
||||
чтобы не отжимать слот у живых запросов;
|
||||
- ошибка пинга **не** считается в backoff (иначе каждая попытка удваивала
|
||||
бы интервал отката); учитывается только успех;
|
||||
- признак «ответил» — HTTP 2xx и первый байт тела за `first_byte_timeout`
|
||||
(тот же watchdog, что и у обычных запросов);
|
||||
- на пинг применяются патчи провайдера и апстрима (как к обычному запросу),
|
||||
чтобы он валидировал реальный путь;
|
||||
- при восстановлении — лог:
|
||||
`[llm-proxy] probe upstream=<id> ответил — снят с backoff, вернулся в пул`,
|
||||
метрика `llm_proxy_probe_pings_total{result="ok"}`;
|
||||
- при молчании — лог `[llm-proxy] probe upstream=<id> молчит — остаюсь в backoff`,
|
||||
метрика `llm_proxy_probe_pings_total{result="fail"}`.
|
||||
|
||||
Значение — ISO-8601-длительность, формат как у `backoff` (`PT1S`, `PT500MS`,
|
||||
`PT5S`, …).
|
||||
|
||||
```yaml
|
||||
providers:
|
||||
- id: routerai
|
||||
url: "https://routerai.ru/api/v1"
|
||||
probe_interval: PT1S # пингуем все модели провайдера раз в секунду
|
||||
|
||||
upstreams:
|
||||
- id: routerai-gpt4o
|
||||
provider: routerai
|
||||
model: gpt-4o
|
||||
probe_interval: PT0S # у модели пинг отключён (ждать истечения backoff)
|
||||
```
|
||||
|
||||
При старте выводится, что настроено:
|
||||
`[llm-proxy] probe_interval: upstreams=routerai-gpt4o=PT0S providers=routerai=PT1S default=PT1S`.
|
||||
|
||||
### Prometheus-метрики (`/metrics`)
|
||||
|
||||
Прокси отдаёт pull-метрики в Prometheus text-формате по `GET /metrics`
|
||||
@@ -395,6 +461,7 @@ upstreams:
|
||||
| Метрика | Тип | Смысл |
|
||||
|---|---|---|
|
||||
| `llm_proxy_requests_total{model, upstream, provider, result}` | counter | chat-запросы по исходу. `result`: `ok` — успех, `4xx` — ошибка запроса, `429`/`402`/`5xx` — исход с апстрима (каждая фейловер-попытка учитывается отдельно), `net_err` — сетевая ошибка/таймаут, `timeout` — апстрим не прислал первый байт стрима за `first_byte_timeout`, `cancelled` — клиент отвалился посреди стрима |
|
||||
| `llm_proxy_probe_pings_total{upstream, provider, result}` | counter | фоновые пинги апстримов в backoff-откате (HealthProber). `result`: `ok` — апстрим ответил (снят с отката), `fail` — молчит (остался в откате) |
|
||||
| `llm_proxy_upstream_inflight{upstream, provider}` | gauge | занятые слоты апстрима прямо сейчас (конкурентность) |
|
||||
| `llm_proxy_upstream_fail_streak{upstream, provider}` | gauge | счётчик сбоев подряд (backoff): сколько раз подряд упал |
|
||||
| `llm_proxy_upstream_cooling_seconds{upstream, provider}` | gauge | сколько секунд апстрим ещё в backoff-откате (0 = жив) |
|
||||
@@ -494,6 +561,7 @@ data class ProviderConf(
|
||||
val reasoning_empty_ok: Boolean = false,
|
||||
val backoff: Duration? = null, // потолок backoff на провайдера (ISO-8601)
|
||||
val first_byte_timeout: Duration? = null, // окно первого байта стрима (ISO-8601)
|
||||
val probe_interval: Duration? = null, // интервал фонового пинга (ISO-8601)
|
||||
)
|
||||
|
||||
data class UpstreamConf(
|
||||
@@ -505,6 +573,7 @@ data class UpstreamConf(
|
||||
val think_tags: String? = null, // переопределение think-режима модели
|
||||
val backoff: Duration? = null, // потолок backoff на модель (приоритет над провайдерским)
|
||||
val first_byte_timeout: Duration? = null, // окно первого байта стрима (приоритет над провайдерским)
|
||||
val probe_interval: Duration? = null, // интервал фонового пинга (приоритет над провайдерским)
|
||||
)
|
||||
|
||||
@Serializable
|
||||
|
||||
Reference in New Issue
Block a user