Files
han-app/codebase/Signoz/docs/BACKEND_OTLP.md
T

368 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Подключение 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.
Канонический перечень метрик, SLO, dashboards и alert policy находится в
`modules/module-09-observability.md`.
До прохождения end-to-end и outage/recovery acceptance не используйте
отсутствие ошибок в SigNoz как доказательство здоровья HAN Chat.