MetricsService — учебно-практический проект, реализованный в рамках программы Курса молодого бойца (КМБ) стажировки в HADAL Project. Этот сервис, предназначен для сбора, хранения и предоставления рантайм-метрик. Проект включает в себя два ключевых компонента: Агент для сбора данных и Сервер для их обработки и хранения. Система поддерживает обмен данными по протоколам REST API и gRPC, обеспечивая гибкость, надежность и безопасность.
- Ключевые возможности
- Архитектура приложения: Трёхуровневый подход 🏛️
- API Документация
- Конфигурация
- Сборка, запуск и тесты
- Два типа метрик: Поддержка метрик типа
gauge(значение с плавающей точкой) иcounter(целочисленный счётчик). - Гибкий транспорт: Взаимодействие между агентом и сервером по протоколам REST API и gRPC.
- Множественные хранилища: Сервер может хранить данные в оперативной памяти, в файле на диске или в СУБД PostgreSQL.
- Пакетная обработка: Возможность отправки и обновления метрик пачками (batch updates) для снижения сетевой нагрузки.
- Безопасность:
- Целостность данных: Подпись запросов и ответов с помощью SHA-256 HMAC.
- Контроль доступа: Ограничение доступа к серверу на основе IP-адреса агента (проверка на вхождение в доверенную подсеть).
- Производительность:
- Параллельная отправка: Агент использует паттерн Worker Pool для контроля интенсивности отправки метрик (
rate limit). - Эффективное сжатие: Поддержка сжатия Gzip для тела запросов и ответов.
- Быстрая сериализация: Использование
easyjsonдля ускоренной обработки JSON.
- Параллельная отправка: Агент использует паттерн Worker Pool для контроля интенсивности отправки метрик (
- Надежность:
- Механизм Retry: Автоматические повторные попытки при сбоях сети или временной недоступности БД с нарастающей задержкой (Exponential Backoff).
- Корректное завершение: Graceful Shutdown для безопасной остановки сервера и агента с сохранением накопленных данных.
- Гибкая конфигурация: Настройка всех ключевых параметров через флаги командной строки и переменные окружения.
Сервис построен по классической и очень эффективной трёхуровневой архитектуре. Этот подход помогает разделить логику, сделать код чище, проще в поддержке и, что самое главное, — невероятно удобным для тестирования. 🧪
Это "лицо" нашего приложения. Он отвечает за всё взаимодействие с внешним миром.
- Задача: Принимать запросы (по HTTP или gRPC), разбирать их, проверять и отдавать ответы.
- Как работает: Этот слой получает, например, JSON-запрос, превращает его в понятную для нашего приложения внутреннюю структуру (модель) и передаёт дальше на средний уровень —
Usecase. Получив ответ отUsecase, он делает обратное преобразование: из внутренней структуры в JSON или Protobuf-ответ и отправляет его клиенту. - Конвейер Middleware: Прежде чем запрос дойдёт до основного обработчика (хендлера), он проходит через цепочку промежуточного ПО:
WithLogging📝: Записывает в лог всю важную информацию о каждом запросе: URI, метод, статус ответа, время выполнения и размер.WithGzipCompress📦: Проверяет, поддерживает ли клиент сжатие (gzip), и сжимает ответ.WithHashing🔐: Проверяет подпись (HashSHA256) входящего запроса и подписывает ответ.WithTrustedSubnet🛡️: Проверяет IP-адрес клиента (X-Real-IP) и пропускает только те, что пришли из доверенной подсети.
Это "мозг" приложения. Здесь живёт вся основная бизнес-логика.
- Задача: Оркестрировать выполнение бизнес-задач. Например, "получить метрику", "обновить пачку метрик".
- Как работает:
Usecaseполучает команду от внешнего слоя. Он не знает ничего про JSON или HTTP. Его задача — вызвать нужные методы у внутреннего слоя (Repository), чтобы получить данные, возможно, как-то их обработать и вернуть результат.
Слой отвечает за хранение и извлечение информации.
- Задача: Выполнять конкретные CRUD-операции (Create, Read, Update, Delete) с данными.
- Как работает:
Repositoryреализует интерфейсы, которые определены дляUsecase(например,MetricGetter). Он знает всё о том, как работать с конкретным хранилищем: как написать SQL-запрос к PostgreSQL, как прочитать данные из файла или как сложить их вmapв памяти.
Ключевое преимущество архитектуры — тестируемость. Благодаря такому разделению, особенно тому, что Usecase зависит от интерфейсов, мы можем легко тестировать бизнес-логику, "подменяя" (mocking) реальный репозиторий на его имитацию (мок) без запуска базы данных.
Возвращает HTML-страницу со списком всех актуальных метрик в виде таблицы.
Проверяет доступность соединения с базой данных PostgreSQL.
200 OK: Соединение успешно установлено.500 Internal Server Error: Ошибка соединения с БД.
Обновляет одну метрику, переданную в теле запроса в формате JSON. Возвращает обновленный объект метрики.
- Тело запроса:
{"id":"some_metric","type":"gauge","value":10.5} - Тело ответа:
{"id":"some_metric","type":"gauge","value":10.5}
Выполняет пакетное обновление нескольких метрик, переданных в виде JSON-массива.
- Тело запроса:
[{"id":"m1","type":"gauge","value":1.2},{"id":"m2","type":"counter","delta":10}] - Ответ:
200 OK.
Получает одну метрику, переданную в теле запроса в формате JSON. Возвращает объект метрики с актуальным значением.
- Тело запроса:
{"id":"some_metric","type":"gauge"} - Тело ответа:
{"id":"some_metric","type":"gauge","value":10.5}
POST /update/{mType}/{mName}/{mValue}GET /value/{mType}/{mName}
Сервис также предоставляет gRPC интерфейс для более эффективного взаимодействия. Полное описание методов доступно в .proto файле.
Приоритет параметров: переменная окружения > флаг командной строки > значение по умолчанию.
| Флаг | Переменная окружения | По умолчанию | Описание |
|---|---|---|---|
-a |
ADDRESS |
localhost:8080 |
Сетевой адрес и порт для запуска HTTP-сервера. |
-g |
GRPC_ADDRESS |
localhost:8081 |
Сетевой адрес и порт для запуска gRPC-сервера. |
-i |
STORE_INTERVAL |
300 |
Интервал в секундах для сохранения метрик в файл (0 — синхронная запись). |
-f |
FILE_STORAGE_PATH |
/tmp/metrics-db.json |
Полный путь к файлу для хранения метрик. |
-r |
RESTORE |
true |
Загружать ли метрики из файла при старте сервера. |
-d |
DATABASE_DSN |
"" |
Строка подключения к PostgreSQL (e.g., postgres://user:pass@host/db). |
-k |
KEY |
"" |
Ключ для вычисления и проверки SHA256-хеша. |
-t |
TRUSTED_SUBNET |
"" |
Доверенная подсеть в формате CIDR для проверки IP-адреса агента. |
| Флаг | Переменная окружения | По умолчанию | Описание |
|---|---|---|---|
-a |
ADDRESS |
localhost:8080 |
Адрес и порт HTTP-сервера для отправки метрик. |
-g |
GRPC_ADDRESS |
localhost:8081 |
Адрес и порт gRPC-сервера для отправки метрик. |
-p |
POLL_INTERVAL |
2 |
Частота сбора метрик в секундах. |
-r |
REPORT_INTERVAL |
10 |
Частота отправки метрик на сервер в секундах. |
-l |
RATE_LIMIT |
10 |
Количество воркеров для одновременной отправки метрик. |
-k |
KEY |
"" |
Ключ для вычисления SHA256-хеша. |
make build- собрать бинарные файлы агента и сервера.make server- собрать только сервер.make agent- собрать только агент.make test- запустить все юнит-тесты.make bench- запустить бенчмарки.make lint- запустить статический анализатор кодаgolangci-lint.make clean- удалить собранные бинарные файлы.
-
Сборка:
make build
-
Запуск сервера (пример с PostgreSQL):
export DATABASE_DSN="postgres://postgres:postgres@postgres:5432/mipt?sslmode=disable" ./cmd/server/server -a localhost:9090
-
Запуск агента:
./cmd/agent/agent -a localhost:9090