Перейти к содержанию

Выпуск наблюдаемого сервиса

«Пульс» теперь содержит ручные spans, коррелированные события, общие метрики, Collector, три backend, provisioned dashboard и rules. Завершим серию подготовкой выпуска и передачи. Исходники написаны локально, приложения, контейнеры, SQL и зависимости не запускались. Поэтому финальное состояние — конкретный проект для будущей лаборатории, а не утверждение о проверенной производственной наблюдаемости или уже доставленных оповещениях.

Главная цель передачи — сохранить смысл сигналов и границы ответственности. Команда должна знать, какой процесс создаёт данные, какие поля допустимы, какой путь их хранит, сколько они живут и кто реагирует на отказ. Без этих сведений даже правильный SDK быстро превращается в набор разноимённых метрик и панелей, из которых невозможно сделать уверенный вывод при инциденте.

Согласованные версии

Прямые зависимости API и SDK закреплены в package.json: OpenTelemetry API 1.9.0, stable packages 2.0.0, экспериментальные SDK и OTLP exporters 0.200.0, PostgreSQL client 8.13.3. Runtime выбран Node.js 22.14.0. В этой семье LoggerProvider ещё имеет addLogRecordProcessor, а resources создаются через resourceFromAttributes. Определения прочитаны в источниках выбранных версий, поэтому новые примеры документации не копируются без проверки API.

Полный файл package.json состояния 12:

{
  "name": "pulse-lesson-12",
  "private": true,
  "type": "module",
  "engines": {
    "node": ">=22.14.0"
  },
  "dependencies": {
    "pg": "8.13.3",
    "@opentelemetry/api": "1.9.0",
    "@opentelemetry/core": "2.0.0",
    "@opentelemetry/resources": "2.0.0",
    "@opentelemetry/sdk-node": "0.200.0",
    "@opentelemetry/sdk-trace-base": "2.0.0",
    "@opentelemetry/sdk-metrics": "2.0.0",
    "@opentelemetry/api-logs": "0.200.0",
    "@opentelemetry/sdk-logs": "0.200.0",
    "@opentelemetry/exporter-trace-otlp-http": "0.200.0",
    "@opentelemetry/exporter-metrics-otlp-http": "0.200.0",
    "@opentelemetry/exporter-logs-otlp-http": "0.200.0"
  }
}

Lockfile не создан: установка прямо не выполнялась. Следовательно, package.json фиксирует прямые pins, но не весь транзитивный граф. Для воспроизводимой среды читатель отдельно разрешает зависимости, сохраняет lockfile и фиксирует runtime. Исторические pins не представлены как текущая рекомендация безопасности для публичного сервиса; перед настоящим выпуском нужен отдельный согласованный upgrade и проверка поведения exporters, processors и бинарных образов.

В Compose указаны Collector contrib 0.123.0, Tempo 2.7.2, Loki 3.4.2, Prometheus 3.2.1, Grafana 11.6.0 и PostgreSQL 17.4. Протоколы соединены через OTLP HTTP и scrape. Подтверждение существования версий не равнозначно выполненной интеграции на конкретной машине. Строгий выпуск дополнительно фиксирует digest образов, доступную архитектуру и фактическую конфигурацию после собственной проверки среды.

Прикладной процесс и shutdown

API прекращает принимать соединения, завершает текущие запросы, закрывает пул и отправляет буферы SDK. Worker прекращает брать новые задания и завершает текущую работу перед flush. Инфраструктура должна дать этому процессу ограниченный срок graceful shutdown. Если процесс принудительно убит, telemetry может потеряться, а SQL-задание сохраниться. Поэтому принятие отчёта определяется базой, а не наличием последнего лога.

Для job особенно важен условный UPDATE с lease token. Наблюдаемость сообщает outcome done лишь когда строка действительно изменена; нулевой rowCount даёт lease_lost. Иначе красивые logs скрывали бы потерю права фиксации. Прикладные инварианты и телеметрия развиваются вместе: сигнал должен отражать результат системы, а не только факт возврата локальной функции.

Пул PostgreSQL, statement timeout и lease выбираются по прикладным ограничениям. Текущий worker имеет учебное вычисление с паузой, а не настоящий движок отчёта. Его длительность не доказывает capacity промышленного сервиса. Для нового вычислителя определяют срок работы, восстановление и ресурсные пределы, затем расширяют spans и метрики в рамках безопасного словаря. Нельзя обещать производительность по искусственной операции.

Доступ и срок хранения

Лабораторные порты опубликованы только на loopback. Для реальной сети нужны TLS, аутентификация OTLP, ограничения входящего объёма и прав backend. Grafana должна иметь роли пользователей и контролируемые источники. Оператору поддержки необязательно нужен admin. Telemetry не содержит PII по модели приложения, но раскрывает структуру системы, версии и операционные события, поэтому доступ к ней всё равно является правом.

Авторизация «Пульса» использует один локальный bearer-токен и не моделирует полноценные пользовательские аккаунты. В выпуске её заменяют системой продукта; при cookie-входе защищают изменяющие запросы CSRF и проверкой Origin. Trace context не участвует в авторизации. Внешние traceparent и tracestate принимаются только по согласованной доверенной границе, чтобы посетитель не управлял стоимостью sampling произвольно.

Тела запросов, ответы, query, Authorization, cookie, SQL и параметры не собираются автоматически. Collector deletion actions остаются дополнительной защитой известных полей, но не универсальной очисткой body. Перед вводом новой автоматической инструментации проверяют её фактический payload. Нельзя объявить данные безопасными по одному wrapper, если другие библиотеки теперь отправляют собственные атрибуты в обход выбранного контракта.

Retention лаборатории составляет сутки для трёх backend. В эксплуатации сроки определяют по нуждам расследования, бюджету и правилам компании. Для долгих jobs traces producer и consumer должны иметь совместимое окно хранения. Увеличение retention не исправляет потерю контекста и sampling, а увеличение числа сохранённых traces не заменяет общие metrics. Каждый рычаг решает свой ограниченный вопрос.

Полный файл release.md состояния 12:

# Выпуск «Пульса»

example_execution: not_run. Контейнеры, npm, SQL и приложения не запускались.
Учебные прямые pins: Node 22.14.0, pg 8.13.3, OTel API 1.9.0,
stable SDK/core/resources/metrics 2.0.0, sdk-node/sdk-logs/api-logs/OTLP exporters 0.200.0.
Исторические pins требуют отдельного обновления безопасности перед публичной эксплуатацией.
Collector contrib 0.123.0; Tempo 2.7.2; Loki 3.4.2; Prometheus 3.2.1; Grafana 11.6.0; PostgreSQL 17.4.
Протоколы связаны через OTLP HTTP; это проверка конфигурации по документации, а не выполненный запуск.

Для самостоятельной лаборатории выбрать полное lesson-NN. Скопировать .env.example в .env,
задать PULSE_TOKEN и POSTGRES_PASSWORD, затем самостоятельно установить зависимости и зафиксировать lockfile.
docker compose --env-file .env up -d: PostgreSQL и с нужного этапа слой наблюдения.
Node работает на хосте: node --env-file=.env --import ./telemetry.mjs server.mjs
и отдельно node --env-file=.env --import ./telemetry.mjs worker.mjs с OTEL_SERVICE_NAME=pulse-worker.
Для worker задать service.name через отдельное окружение; API использует pulse-api по умолчанию.
SQL init применяется контейнером только к пустому volume, это не миграция существующей базы.
Grafana password требуется через GRAFANA_PASSWORD; anonymous access выключен.

Перед выпуском: TLS/аутентификация OTLP и backends, RBAC Grafana, bounded resource attributes,
request bodies/query/Authorization/PII не собирать, alerts delivery настроить отдельным Alertmanager.
Сравнить обещания SLA с window/thresholds, определить владельца runbook и данные retention.
Graceful shutdown сначала завершает HTTP/job, затем flush SDK с ограниченным сроком процесса.
Проверять отдельно пропуск telemetry pipeline и отказ пользовательской операции.
Обновление версии фиксировать service.version, сохранять dashboard/rules/config и совместимость схемы jobs.

Оповещения и передача команде

Rules вычисляются в Prometheus, но внешняя доставка не создана. До выпуска выбирают Alertmanager или другой согласованный путь, контакт, группировку и escalation. Получатель должен понимать runbook и иметь права читать панели. Пропуск уведомления — отдельный отказ наблюдения, который нельзя заметить лишь по успешной работе приложения. В учебном ZIP нет утверждения, что сообщения уже отправлялись или alarm срабатывал фактически.

Дашборд и источники задаются файлами с постоянными UID. Их изменения сохраняют вместе с версией приложения и rules. Если правка была сделана только в интерфейсе, она может исчезнуть при новом provisioning. Поэтому перед передачей сверяют источник конфигурации и реальное желаемое состояние. Случайные ручные улучшения без истории усложняют rollback и объяснение того, почему график после выпуска выглядит иначе.

service.version помогает сопоставить инцидент с выпуском. При обновлении меняют значение осознанно и сохраняют историю совместимости schema jobs. Откат API или worker возможен только если прежний код понимает текущие данные. Полный schema.sql предназначен для пустой базы и не является процедурой обновления. Реальные миграции и откат отдельно описывают входное состояние и сохранение незавершённых заданий.

Готовность будущей лаборатории

При самостоятельной проверке нужно подтвердить структуру trace, совпадение trace ID в logs, независимость metrics от sampling и отсутствие запрещённых полей. Затем проверить OTLP до Collector, три exporters, scrape и queries datasource. Только после этого можно говорить, что данные доступны в Grafana. Красивый dashboard JSON и точные номера версий сами по себе не доказывают этот путь.

Серия дала один последовательный проект: от выбора сигналов к диагностике конкретного запроса и очереди. В архиве двенадцать накопительных состояний, а план содержит результаты, зависимости, ссылки и редакционный инвентарь. Приложение подготовлено для отдельного исполнения читателем; фактические timings, screenshots, incident и доставка alerts не заявляются. Теперь вы можете объяснить каждый участок пути и назвать, какое подтверждение понадобится перед реальным выпуском.

Предыдущий урок: Сэмплирование и разбор инцидента

Оглавление серии · Исходники всех состояний.

Документация: SDK 2.0 release, Collector configuration.