Проект разделен на два репозитория

This commit is contained in:
mi
2026-08-14 15:42:45 +03:00
parent e06a77ee1d
commit bbef7a30c9
521 changed files with 2597 additions and 2302 deletions
+368
View File
@@ -0,0 +1,368 @@
# Подключение HAN Chat к SigNoz
## Схема
Приложения на ВМ1 и ВМ2 отправляют OTLP только своему локальному `otel-collector`:
```text
VM1 containers -> VM1 otel-collector:4317 -> 192.168.0.5:4317 -> SigNoz
VM2 containers -> VM2 otel-collector:4317 -> 192.168.0.5:4317 -> SigNoz
```
Локальный Collector выполняет редактирование чувствительных атрибутов,
добавляет `service.namespace=han-chat`, окружение и версию, сохраняет очередь
на диск и пересылает данные в SigNoz.
Collectors имеют отдельные bounded persistent queue volumes. ВМ2 не использует
Docker hostname collector ВМ1. Недоступность SigNoz/Collector fail-open для
business/Safety readiness; переполнение очереди создаёт alert и controlled drop.
## Настройка backend
В non-secret env manifest каждой VM:
cd /opt/han-chat/backend
```dotenv
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
OTEL_REMOTE_ENDPOINT=192.168.0.5:4317
OTEL_REMOTE_AUTH_HEADER=
OTEL_REMOTE_TLS_INSECURE=true
```
`OTEL_REMOTE_TLS_INSECURE=true` допустим только потому, что трафик идёт по
изолированной приватной сети. Self-hosted SigNoz по умолчанию не требует
authorization header. Не подставляйте фиктивный токен.
Применение:
```bash
cd /opt/han-chat/backend
# Перед сменой sampling остановите producers и дайте persistent queue уйти.
docker compose stop api-backend sms-service sms-worker
until ! docker compose logs --since=2m otel-collector |
grep -Eq 'queue is full|sending_queue.*[1-9][0-9]*'; do sleep 15; done
# Сначала validate той же версией Collector, которая закреплена в Compose.
docker run --rm \
-e APP_ENV=validate -e RELEASE_VERSION=validate \
-e OTEL_REMOTE_ENDPOINT=192.168.0.5:4317 \
-e OTEL_REMOTE_AUTH_HEADER= -e OTEL_REMOTE_TLS_INSECURE=true \
--tmpfs /var/lib/otelcol/queue:rw,noexec,nosuid,size=16m,mode=0777 \
-v "$PWD/observability/otel-collector.yaml:/etc/otelcol/config.yaml:ro" \
otel/opentelemetry-collector-contrib:0.117.0 \
validate --config=/etc/otelcol/config.yaml
docker compose config >/dev/null
docker compose up -d --force-recreate otel-collector
docker compose up -d --build api-backend sms-service sms-worker
docker compose up -d --wait api-backend sms-service sms-worker
# Nginx хранит IP Docker upstream после загрузки config. После пересоздания
# API/SMS перечитайте Docker DNS без остановки edge.
docker compose exec -T nginx nginx -t -c /tmp/nginx.conf
docker compose kill -s HUP nginx
docker compose ps otel-collector
docker compose logs --tail=200 otel-collector
curl -fsS https://chat.han0107.ru/api/v1/public/app-config >/dev/null
```
Не удаляйте `observability/.otel-queue`: это bounded persistent queue, которая
обеспечивает recovery после недоступности SigNoz.
Проверка сети с backend-хоста:
```bash
timeout 3 bash -c 'exec 3<>/dev/tcp/192.168.0.5/4317' \
&& echo 'OTLP gRPC reachable'
curl -fsS --max-time 5 \
-H 'Content-Type: application/json' \
--data '{"resourceSpans":[]}' \
http://192.168.0.5:4318/v1/traces
```
Если используется только gRPC, после диагностики порт 4318 можно закрыть.
## End-to-end тест канала
Одна лишь доступность TCP не доказывает запись в ClickHouse. Отправьте тестовые
трейсы через локальный Collector из его Docker-сети:
```bash
cd /opt/han-chat/backend
chmod +x deployment/scripts/verify-observability.sh
./deployment/scripts/verify-observability.sh
```
Скрипт проверяет внутренние SMS metrics endpoints, отправляет canary traces и
проверяет свежие exporter/queue ошибки. Эквивалентная ручная отправка:
```bash
docker run --rm --network han-chat-observability \
ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:latest \
traces --otlp-endpoint otel-collector:4317 --otlp-insecure \
--service han-chat-otlp-smoke --traces 100 --rate 20
```
Collector сохраняет только 10% traces. Сто тестовых traces дают достаточно
высокую вероятность увидеть результат; запуск с десятью traces может случайно
не оставить ни одного.
Если имя образа/синтаксис изменились, используйте актуальный `telemetrygen`
из релиза OpenTelemetry Collector Contrib. На production-хосте образ нужен
только для smoke-теста и затем может быть удалён.
В SigNoz откройте **Services** или **Traces** и отфильтруйте:
```text
service.name = han-chat-otlp-smoke
service.namespace = han-chat
```
Проверьте, что timestamps свежие. Затем изучите логи Collector:
```bash
docker compose logs --since=10m otel-collector
```
Не должно быть `connection refused`, `tls`, `Unauthenticated`, переполнения
очереди или постоянных retry.
## Outage/recovery acceptance
Проводите тест в согласованное окно. Нужны доступ к security group VM SigNoz,
две SSH-сессии на backend и открытый UI SigNoz. Бизнес-сервисы и локальный
Collector не останавливайте.
### 1. Зафиксировать baseline
На backend:
```bash
cd /opt/han-chat/backend
date -u '+baseline_started=%Y-%m-%dT%H:%M:%SZ'
docker compose ps otel-collector api-backend sms-service sms-worker
./deployment/scripts/verify-observability.sh
```
Получить внутренние метрики очереди через Python, уже имеющийся в
`sms-service`:
```bash
collector_metrics() {
docker compose exec -T sms-service python -c \
'import urllib.request; print(urllib.request.urlopen(
"http://otel-collector:8888/metrics", timeout=3
).read().decode())'
}
collector_metrics |
grep -E 'otelcol_exporter_(queue_size|queue_capacity|send_failed)'
```
Перед тестом `queue_size` для exporter `otlp/remote` должен быть `0` или
стабильно уменьшаться. Сохраните baseline:
```bash
collector_metrics > /tmp/otel-metrics-before.txt
docker compose logs --since=10m otel-collector \
> /tmp/otel-collector-before.log
```
### 2. Отключить только remote OTLP
В security group VM SigNoz временно отключите входящее правило:
```text
source: приватный IP backend
destination: 192.168.0.5
protocol/port: TCP 4317
```
Не меняйте TCP 22, маршруты приватной сети и правила самого backend. Запишите
UTC-время изменения. На backend проверьте, что блокировка действительно
применилась:
```bash
date -u '+outage_started=%Y-%m-%dT%H:%M:%SZ'
if timeout 5 bash -c 'exec 3<>/dev/tcp/192.168.0.5/4317'; then
echo 'ОШИБКА: 4317 всё ещё доступен'
else
echo 'OK: remote OTLP недоступен'
fi
```
### 3. Проверить fail-open бизнес-запросов
Укажите реальный публичный URL HAN Chat. Используйте read-only endpoint, чтобы
не создавать бизнес-данные:
```bash
export HAN_BASE_URL='https://<HAN_CHAT_HOST>'
rm -f /tmp/otel-outage-http.tsv
for i in $(seq 1 24); do
request_id="$(cat /proc/sys/kernel/random/uuid)"
if ! code="$(curl -sS -o /dev/null -w '%{http_code}' \
-H "X-Request-ID: $request_id" \
"$HAN_BASE_URL/api/v1/public/content")"; then
code=000
fi
printf '%s\t%s\t%s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$code" "$request_id" |
tee -a /tmp/otel-outage-http.tsv
sleep 5
done
awk -F '\t' '$2 !~ /^2/ {print "FAIL", $0; failed=1} END {exit failed}' \
/tmp/otel-outage-http.tsv
```
Все 24 запроса должны вернуть `2xx`. Это подтверждает, что недоступность
remote exporter не останавливает API. `429`, `5xx` или `000` требуют разбора;
не считайте такой запуск успешным.
Чтобы очередь гарантированно получила достаточное число traces, пока порт
заблокирован, отправьте canary через локальный Collector:
```bash
docker run --rm --network han-chat-observability \
ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:latest \
traces --otlp-endpoint otel-collector:4317 --otlp-insecure \
--service han-chat-outage-canary --traces 100 --rate 20
```
### 4. Контролировать bounded queue
Во второй SSH-сессии сначала повторно объявите функцию `collector_metrics` из
шага 1, затем каждые 10 секунд выполняйте:
collector_metrics() {
docker compose exec -T sms-service python -c \
'import urllib.request; print(urllib.request.urlopen("http://otel-collector:8888/metrics", timeout=3).read().decode())'
}
collector_metrics > /tmp/otel-metrics-before.txt
docker compose logs --since=10m otel-collector \
> /tmp/otel-collector-before.log
```Проверка
collector_metrics | grep otelcol_exporter_queue
```bash
collector_metrics |
grep -E 'otelcol_exporter_(queue_size|queue_capacity|send_failed)'
docker compose logs --since=30s otel-collector |
grep -Ei 'retry|queue is full|dropp|refused|permanent error' || true
```
Ожидаемо: `queue_size` растёт, Collector пишет о временных retry, а приложения
остаются healthy. Немедленно восстановите правило TCP 4317, если:
- `queue_size / queue_capacity >= 0.8`;
- появился `queue is full`, permanent error или dropped telemetry;
- любой бизнес-запрос перестал возвращать `2xx`;
- тест длится более 5 минут.
Зафиксируйте максимальный `queue_size`. Не ждите заполнения очереди специально.
``` Посмотреть компактно метрики (общий объем, логи, метрики, трэйсы)
collector_metrics |
awk '/^otelcol_exporter_queue_(size|capacity)\{/ &&
/exporter="otlp\/remote"/ {print}'
### 5. Восстановить связь и дождаться drain
Верните исходное правило TCP 4317 в security group и проверьте сеть:
```bash
date -u '+recovery_started=%Y-%m-%dT%H:%M:%SZ'
timeout 5 bash -c 'exec 3<>/dev/tcp/192.168.0.5/4317' \
&& echo 'OK: remote OTLP доступен'
```
Наблюдайте очередь до нуля:
```bash
while true; do
date -u '+%Y-%m-%dT%H:%M:%SZ'
output="$(collector_metrics)"
printf '%s\n' "$output" |
grep -E 'otelcol_exporter_(queue_size|queue_capacity|send_failed)'
size="$(printf '%s\n' "$output" |
awk '/otelcol_exporter_queue_size.*exporter="otlp\/remote"/ {print $NF; exit}')"
[[ "${size:-unknown}" == "0" ]] && break
sleep 10
done
date -u '+drain_finished=%Y-%m-%dT%H:%M:%SZ'
```
Если версия Collector использует другие labels, найдите фактическую строку
командой `collector_metrics | grep otelcol_exporter_queue` и скорректируйте
только выражение `awk`.
После drain:
```bash
docker compose logs --since=10m otel-collector |
grep -Ei 'queue is full|dropp|refused|permanent error' || true
```
В SigNoz установите период от `outage_started` до `drain_finished` и найдите:
```text
service.name = han-chat-outage-canary
service.namespace = han-chat
deployment.environment = production-like
```
Из-за tail sampling сохраняется около 10% обычных успешных traces, поэтому
ожидайте не все 100, а хотя бы один свежий canary trace. Проверьте также свежий
trace `api-backend` с правильными `service.version` и environment.
### 6. Записать результат
В runbook/протоколе теста зафиксируйте:
- UTC `outage_started`, `recovery_started`, `drain_finished`;
- длительность outage и recovery;
- количество/коды synthetic HTTP responses;
- baseline, peak и конечный queue size, queue capacity;
- были ли `queue is full`, dropped/refused/permanent errors;
- ссылку на canary trace в SigNoz;
- итог `PASS` только при `2xx`, bounded queue, успешном drain и наличии trace.
Не удаляйте queue-файлы и не имитируйте outage остановкой локального Collector:
это проверяет другой failure mode.
## Реализованный MVP и ограничения
После развёртывания актуальной версии backend в SigNoz поступают:
- traces и OTLP runtime metrics `api-backend`, `sms-service`, `sms-worker`;
- FastAPI, HTTPX, SQLAlchemy, Redis и botocore dependency spans по месту
использования;
- ручной span `sms.process` без SMS/user identifiers;
- Prometheus metrics `sms-service`, `sms-worker`, Keycloak и Collector;
- API-метрики `han_http_*`, bootstrap и rate-limit decisions;
- errors и traces медленнее 2 секунд полностью, остальные успешные — 10%
через tail sampling.
Structlog получает настоящий `trace_id`/`span_id`, но JSON stdout пока
остаётся только локальным аварийным журналом Docker и не экспортируется в
SigNoz. Audit events продолжают храниться отдельно в PostgreSQL.
Следующая фаза:
1. инструментировать `message-safety`, Bitrix-сервисы и остальные workers;
2. провести redaction-аудит и выбрать OTLP logs либо ограниченный filelog;
3. добавить Redis/nginx exporters и безопасный nginx route class;
4. экспортировать проверенный Dashboard V2 JSON;
5. уточнить sampling, retention и alert thresholds после baseline/load test.
Канонический контракт telemetry, SLO и сквозных dashboards — `architectory/arch-07-observability.md`.
Сервисные метрики, dashboards и alerts — `modules/module-09-observability-vm1.md` и
`modules/module-09-observability-vm2.md`. Указатель: `modules/module-09-observability.md`.
До прохождения end-to-end и outage/recovery acceptance не используйте
отсутствие ошибок в SigNoz как доказательство здоровья HAN Chat.
@@ -0,0 +1,89 @@
# SigNoz MVP: dashboards и alerts
Документ фиксирует versioned-спецификацию первых панелей. Создавайте их через
SigNoz Query Builder и экспортируйте полученный Dashboard V2 JSON обратно в
репозиторий после проверки реальных имён attributes на production-like данных.
Обязательные фильтры каждой панели:
```text
service.namespace = han-chat
deployment.environment = production-like
```
Добавьте переменные `deployment.environment`, `service.name` и
`service.version`. Идентификаторы пользователей, запросов, SMS и сессий
переменными dashboard не являются.
Для Prometheus-scraped SMS/Keycloak metrics имя источника находится в bounded
datapoint label `service_name`; для OTLP signals используется resource
attribute `service.name`.
## Dashboard: HAN API RED
1. **Request rate** — rate/sum `han_http_requests_total`, group by
`http.route`, `http.request.method`.
2. **Error rate** — доля `han_http_requests_total` с
`http.response.status_class=5xx`.
3. **Latency p50/p95/p99**`han_http_request_duration_seconds`, group by
route template.
4. **Rate-limit decisions** — rate `han_rate_limit_decisions_total`, group by
`scope`, `outcome`.
5. **Bootstrap outcomes** — rate `han_auth_bootstrap_total`, group by
`outcome`.
6. **Slow/error traces** — link в Traces с `service.name=api-backend`.
## Dashboard: HAN SMS
1. **Send outcomes** — rate `sms_send_total`, group by `provider`,
`send_status`.
2. **Provider p95 latency**`sms_provider_request_duration_seconds`.
3. **Uncertain outcomes** — rate `sms_uncertain_total`.
4. **Callback result/lag**`sms_callback_total`,
`sms_callback_lag_seconds`.
5. **Oldest pending**`sms_pending_oldest_age_seconds`.
6. **Journal rows/settings**`sms_journal_rows`, `sms_settings_valid`.
7. **Worker traces**`service.name=sms-worker`, span `sms.process`.
## Dashboard: Collector health
Используйте autocomplete Metrics Explorer для фактических `otelcol_*` имён
версии Collector `0.117.0`:
1. accepted и refused spans/metric points/log records;
2. exporter sent/failed;
3. sending queue capacity/size;
4. tail-sampling sampled/dropped/late spans;
5. process RSS/CPU;
6. Prometheus scrape failures для `sms-service`, `sms-worker`, `keycloak`;
7. отсутствие данных по каждому обязательному `service.name`.
## Первые alerts
Alerts создаются после 24 часов baseline. Все правила получают owner, severity
и ссылку на `SIGNOZ_RUNBOOK.md`.
- **API 5xx:** доля 5xx > 5% в течение 5 минут.
- **API latency:** p95 выше 750 ms 10 минут; до разделения route-классов это
warning, не page.
- **SMS uncertain:** рост `sms_uncertain_total` дольше 5 минут.
- **SMS pending stale:** `sms_pending_oldest_age_seconds > 300` 5 минут.
- **SMS settings invalid:** `sms_settings_valid < 1` 5 минут.
- **Collector refused/dropped:** значение > 0 дольше 5 минут.
- **Collector queue:** заполнение > 80% 10 минут.
- **No telemetry:** обязательный production-like сервис отсутствует 10 минут
при ожидаемом трафике.
Не создавайте SLO по sampled traces. Availability/error budget рассчитываются
по metrics. Multi-window burn alerts добавляются после двух недель baseline.
## Acceptance
Dashboard считается введённым в эксплуатацию, когда:
1. панели показывают свежие данные после synthetic request;
2. фильтр release отделяет текущий rollout от предыдущего;
3. route содержит template, а не UUID/raw URI;
4. ни одна metric series не содержит user/session/request/trace identifiers;
5. alert проверен контролируемым synthetic failure;
6. экспортированный Dashboard V2 JSON сохранён рядом с этим документом.
+107
View File
@@ -0,0 +1,107 @@
# Сеть и доступ
## Сбор диагностики
До изменения Netplan выполните и сохраните вывод:
```bash
ip -br link
ip -br -4 address
ip -4 route
ip -4 rule
sudo netplan get
sudo netplan status --all 2>&1 || true
sudo ls -la /etc/netplan
sudo sh -c 'for f in /etc/netplan/*.yaml; do echo "--- $f"; cat "$f"; done'
systemctl is-active systemd-networkd NetworkManager
networkctl list 2>&1 || true
networkctl status 2>&1 || true
grep -RniE 'network:|network-config|disable_network_config' \
/etc/cloud/cloud.cfg /etc/cloud/cloud.cfg.d 2>/dev/null || true
```
Диагностика этой VM показала:
- публичный интерфейс `eth0`, `135.106.166.7/24`, default gateway
`135.106.166.1`;
- приватный интерфейс `eth1`, MAC `fa:16:3e:b6:c6:70`, изначально
`DOWN/unmanaged`;
- приватный адрес VM — `192.168.0.5/24`.
Для `eth1` не нужен gateway: узлы `192.168.0.0/24` доступны connected route.
Default route должен остаться только на `eth0`.
## Настройка приватного интерфейса
Используйте подготовленный скрипт:
```bash
cd /opt/signoz
sudo ./scripts/05-configure-private-network.sh
```
Он создаёт отдельный `/etc/netplan/60-signoz-private.yaml`, проверяет MAC,
выполняет `netplan generate` и запускает `netplan try --timeout 120`. Файл
`50-cloud-init.yaml` не изменяется: cloud-init продолжает управлять публичным
`eth0`, а отдельный файл сохраняет конфигурацию `eth1`.
Пока `netplan try` ожидает подтверждения:
```bash
ip -br -4 address show eth1
ip route get 192.168.0.1
ping -c 3 192.168.0.1
```
С другой VM приватной сети проверьте:
```bash
ping -c 3 192.168.0.5
ssh -i ~/.ssh/hansel-private root@192.168.0.5
```
Если новая SSH-сессия работает, вернитесь в первую и подтвердите Netplan
клавишей Enter. Если нет — не подтверждайте: через 120 секунд произойдёт откат.
Отсутствие ответа на ping само по себе может означать запрет ICMP; SSH является
основной проверкой.
## Группа безопасности
Минимальные входящие правила для VM SigNoz:
- TCP 22 от административного узла/подсети приватной сети;
- TCP 4317 от security groups/private IP ВМ1 и ВМ2;
- TCP 4318 от ВМ1/ВМ2 только если планируется OTLP/HTTP;
- никаких входящих правил для 8080, 5432, 8123, 9000, 9181.
Для текущего backend используется OTLP/gRPC, поэтому после проверки 4318 можно
закрыть. Исходящий доступ к приватной сети оставьте. Для обновления временно
разрешайте HTTPS/DNS наружу или используйте внутренний registry/proxy.
## Доступ к UI
UI слушает только `127.0.0.1:8080` на VM SigNoz.
Через доступный jump host:
```powershell
ssh -i C:\Users\MI\.ssh\hansel `
-J root@<JUMP_PUBLIC_IP> `
-L 8080:127.0.0.1:8080 `
root@192.168.0.5 -N
```
Если ключи jump host и SigNoz различаются, удобнее добавить оба узла в
`~/.ssh/config`. После запуска туннеля откройте
`http://127.0.0.1:8080`.
## Проверки перед удалением внешнего IP
1. Новая SSH-сессия к `192.168.0.5` через jump host открывается.
2. Туннель показывает UI SigNoz.
3. `scripts/30-verify-signoz.sh` проходит без ошибок.
4. С ВМ1 и ВМ2 доступны `192.168.0.5:4317` и при необходимости `:4318`.
5. В SigNoz появился свежий trace сервиса HAN Chat.
6. Все контейнеры имеют статус `running`, healthcheck — `healthy`.
7. Создан snapshot диска ВМ.
8. В облачной группе безопасности нет публичного доступа к служебным портам.
+144
View File
@@ -0,0 +1,144 @@
# Работа с SigNoz для HAN Chat
## Базовые фильтры
Во всех разделах начинайте с:
```text
service.namespace = han-chat
deployment.environment = production-like
```
Для сравнения релизов используйте `service.version`. Не смешивайте production
и smoke/local данные в одном запросе без фильтра окружения.
MVP service names:
```text
api-backend
sms-service
sms-worker
```
Для worker ищите ручные spans `sms.claim`, `sms.process`, `sms.provider`,
`sms.save_result`. Health routes исключены до tail sampling.
## Ежедневная проверка
1. **Services** — появились ли ожидаемые сервисы, нет ли резкого роста error
rate или p95 latency.
2. **Traces** — последние ошибки и медленные запросы, путь от HTTP endpoint до
БД/Redis/внешнего API.
3. **Logs** — события рядом с trace по `trace_id`, ошибки и повторы workers.
4. **Metrics** — насыщение ресурсов, очереди, SMS и фоновые задачи.
5. **Alerts** — firing/acknowledged alerts и причины, а не только факт firing.
Пока приложения не инструментированы, эти представления будут неполными; см.
ограничение в `BACKEND_OTLP.md`.
## Разбор инцидента
Начните с узкого временного диапазона вокруг события:
1. найдите пользовательский `request_id` из ответа API или журнала;
2. в Logs ищите точное значение `request_id`;
3. откройте связанный trace по `trace_id`;
4. найдите первый ошибочный или самый долгий span, а не последний симптом;
5. сравните с предыдущей версией по `service.version`;
6. проверьте зависимости: PostgreSQL, Redis, Keycloak, S3, SMS provider,
Bitrix;
7. сохраните ссылку на запрос SigNoz и зафиксируйте UTC-интервал инцидента.
Не добавляйте в SigNoz телефон, email, токены, cookie, содержимое сообщений,
полные SQL statements и query string. Collector удаляет известные
чувствительные атрибуты, но новые поля должны проходить отдельную проверку.
## Рекомендуемые представления после инструментации
**API**
- request rate, error rate, p50/p95/p99 duration;
- разрез по нормализованному `http.route`, не по сырому URL;
- 401/403 отдельно от 5xx;
- latency PostgreSQL, Redis, Keycloak и S3;
- количество активных WebSocket/SSE соединений и reconnect.
**SMS**
- `sms_send_total` по результату/provider;
- provider latency;
- uncertain deliveries и callback lag;
- возраст pending-заявок и размер journal;
- валидность runtime settings.
**Workers**
- длительность и результат job;
- глубина очереди, oldest item age;
- retries/dead-letter/recovery;
- lag cleanup/delivery/safety/notification jobs.
**Инфраструктура**
- CPU, RAM, filesystem usage VM SigNoz;
- ClickHouse inserts/query latency, parts и disk usage;
- dropped/refused spans, exporter failures и queue size Collector;
- restarts и health контейнеров.
## Первые алерты
Точный состав панелей и acceptance-критерии зафиксированы в
`MVP_DASHBOARDS_ALERTS.md`.
Создавайте алерты только после получения базовой линии, чтобы избежать шума:
- API 5xx rate выше согласованного порога 5–10 минут;
- p95 latency выше SLO 10 минут;
- нет телеметрии от production-сервиса 5–10 минут при ожидаемом трафике;
- Collector exporter failures/dropped telemetry больше нуля;
- очередь workers или oldest item age растёт;
- SMS uncertain/callback lag превышает бизнес-порог;
- диск VM SigNoz заполнен более чем на 75% и 85%;
- любой критичный контейнер перезапускается или unhealthy.
Для каждого alert укажите severity, owner, runbook URL и минимальное время
устойчивого нарушения. Не оповещайте по единичной ошибке.
## Sampling и интерпретация
Collector сейчас применяет probabilistic sampling 10% только к traces.
Метрики и логи не sampled этим processor. Следствия:
- единичный запрос может не попасть в Traces;
- абсолютное число traces нельзя считать числом запросов;
- ошибки тоже могут быть отброшены, потому что tail/error-aware sampling пока
не настроен;
- SLO и alerting следует строить на метриках, а не на подсчёте sampled traces.
Для production рекомендуется перейти к tail sampling: сохранять 100% ошибок и
медленных traces, а успешные быстрые запросы — выборочно.
## Обслуживание SigNoz
Проверка:
```bash
cd /opt/signoz
sudo ./scripts/30-verify-signoz.sh
sudo docker compose -f pours/deployment/compose.yaml logs --since=30m
df -h
docker system df
```
Перед обновлением:
1. временно разрешить исходящий интернет;
2. сделать snapshot диска;
3. проверить свободное место;
4. выполнить `scripts/20-deploy-signoz.sh`;
5. повторить smoke-тест и проверить сохранность старых данных;
6. отключить внешний доступ.
Не выполняйте `docker compose down -v`, `docker volume prune` или
`docker system prune --volumes`: эти команды могут удалить телеметрию и
метаданные SigNoz.