Аналитика туннельного трафика¶
Полное описание системы сбора, хранения и отображения статистики посещений туннельных сайтов (slug.dix.su).
Для пользователей¶
Доступность по тарифам¶
| Тариф | Аналитика | Квота трафика |
|---|---|---|
| SIMPLE | Нет | Только расход / лимит |
| VIP | Нет | Только расход / лимит |
| PRO | Да — полная детализация | + отображение |
| PERS | Да — полная детализация | + отображение |
| GLAVA | Да | Без ограничений |
Данные появляются с момента перехода на PRO/PERS — ретроспективы за предыдущие дни нет.
Что отображается¶
Суточная сводка (вкладка «Аналитика», выбор даты):
| Метрика | Описание |
|---|---|
| Трафик (байты) | Входящий и исходящий объём за день |
| Запросы | Общее число HTTP-запросов (включая ботов и статику) |
| Уникальные посетители | Оценочное число уникальных людей (дедупликация по IP+UA) |
| Топ страниц | Самые посещаемые пути вашего туннельного сайта |
| Источники трафика | UTM-параметры + домены-рефереры |
| География | Страны и города посетителей |
Месячная сводка (вкладка «Использование»): суммарные байты и запросы за текущий месяц без разбивки по дням — доступна всем тарифам.
Уникальные посетители¶
Уникальность определяется по хэшу SHA-256(суточная_соль | IP | User-Agent). Соль ротируется раз в сутки и нигде не сохраняется — это гарантирует, что по данным в БД нельзя восстановить конкретный IP даже при наличии доступа к базе.
Это приблизительная метрика: несколько человек за общим NAT (корпоративная сеть, мобильный оператор) будут посчитаны как один посетитель. Такой же подход использует Plausible Analytics.
Фильтрация ботов¶
| Категория запроса | Трафик (байты/запросы) | Посещения страниц | Уникальные | Гео |
|---|---|---|---|---|
| Реальные пользователи | ✅ | ✅ | ✅ | ✅ |
| Боты (Googlebot, Yandex, Facebook и др.) | ✅ | ❌ | ❌ | ❌ |
| Статические ресурсы (css/js/img/fonts) | ✅ | ❌ | ❌ | ❌ |
Трафик от ботов включается в байты и запросы — они создают реальную нагрузку и влияют на месячную квоту.
UTM-метки и источники¶
Поддерживаемые параметры: utm_source, utm_medium, utm_campaign, utm_content, utm_term, ref.
Дополнительно автоматически фиксируется домен из заголовка Referer под именем referrer_domain — даёт органические переходы без UTM (из поиска, соцсетей, других сайтов).
Внутренние переходы (рефер с того же хоста туннеля) не считаются.
Хранение и экспорт¶
- Данные хранятся 90 дней, затем удаляются автоматически (ежедневно в 00:10 UTC).
- Экспорт в Excel: произвольный диапазон дат до 365 дней назад. Содержит все 4 метрики (трафик, пути, параметры, гео).
Что НЕ собирается¶
- Содержимое запросов и ответов (тела HTTP)
- Заголовки авторизации, куки, токены
- В режиме E2E — абсолютно ничего (трафик зашифрован до устройства, сервер видит только зашифрованные байты)
Для технических специалистов¶
Архитектура: горячий путь через ETS¶
Прямые INSERT в PostgreSQL на каждый запрос были бы узким местом при тысячах запросов в секунду. Вместо этого:
HTTP-запрос на slug.dix.su
↓
proxy_controller.ex
↓
MetricsCollector.record_request/6 ← атомарный ETS-инкремент, наносекунды
↓ (каждые 60 сек)
flush_to_db/0
↓
PostgreSQL UPSERT × 4 таблиц
MetricsCollector — это GenServer с четырьмя ETS-таблицами в RAM:
| ETS-таблица | Назначение |
|---|---|
:tunnel_metrics |
Счётчики трафика/путей/гео/UTM за текущий флаш-интервал |
:tunnel_unique_fingerprints |
Дедупликация посетителей — хранит хэши за сегодня и вчера |
:tunnel_visitor_salt |
Суточные соли (хранятся только за сегодня и вчера) |
:public_role_cache |
Кэш ролей пользователей (TTL 10 мин) — чтобы не идти в БД за ролью на каждый запрос |
Флаш — best effort: если PostgreSQL недоступен, накопленное за 60 сек теряется. Прокси при этом не деградирует.
Схема PostgreSQL¶
Четыре таблицы, все с составным primary key и ON CONFLICT DO UPDATE:
-- Суммарный трафик за день
tunnel_traffic_daily (
slug TEXT, date DATE,
bytes_in BIGINT, bytes_out BIGINT,
request_count BIGINT, unique_visitors BIGINT,
PRIMARY KEY (slug, date)
)
-- Топ путей за день
tunnel_path_visits_daily (
slug TEXT, date DATE, path TEXT,
visit_count BIGINT,
PRIMARY KEY (slug, date, path)
)
-- UTM-параметры и referrer_domain
tunnel_param_visits_daily (
slug TEXT, date DATE, param_name TEXT, param_value TEXT,
visit_count BIGINT,
PRIMARY KEY (slug, date, param_name, param_value)
)
-- Гео-посещения
tunnel_geo_visits_daily (
slug TEXT, date DATE, country TEXT, city TEXT,
visit_count BIGINT,
PRIMARY KEY (slug, date, country, city)
)
Миграции: V29__Tunnel_analytics.sql, V30__Tunnel_unique_visitors.sql, V31__Tunnel_geo_visits.sql.
Геолокация¶
Страна и город определяются из IP-адреса через оффлайн MaxMind GeoLite2 базу (DixuProxy.GeoIp). Никаких внешних API-запросов в горячем пути нет. Если страна не определена (localhost, VPN без записи, не загружена база) — строка геолокации не создаётся.
Уникальные посетители: реализация¶
# MetricsCollector.ex — дедупликация
defp track_unique_visitor(slug, date, ip, user_agent) do
salt = daily_salt(date)
fingerprint = :crypto.hash(:sha256, [salt, "|", ip, "|", user_agent])
if :ets.insert_new(@uniq_table, {{slug, date, fingerprint}, true}) do
bump({:unique, slug, date}, 1)
end
end
Соль ротируется: при первом обращении за дату генерируется strong_rand_bytes(16), сохраняется в @salt_table. Финпринты и соли старше вчера удаляются каждые 30 флаш-циклов (~30 мин).
API-эндпоинты¶
Все эндпоинты — авторизованные (сессия), доступны только владельцу туннеля.
| Метод | Путь | Минимальный тариф | Описание |
|---|---|---|---|
| GET | /api/analytics/my?date=YYYY-MM-DD&page=N&size=N |
PRO | Суточная аналитика с пагинацией топ-путей |
| GET | /api/analytics/monthly |
Все | Суммарный трафик за текущий месяц |
| GET | /api/billing/traffic |
Все | Расход квоты (байты) с лимитом и датой сброса |
| GET | /api/analytics/my/export?from=YYYY-MM-DD&to=YYYY-MM-DD |
PRO | Скачать Excel (до 365 дней) |
Ответ /api/analytics/my (PRO+):
{
"bytesIn": 1234567,
"bytesOut": 9876543,
"requestCount": 4200,
"uniqueVisitors": 37,
"topPaths": {
"rows": [{"path": "/", "visitCount": 120}, ...],
"total": 42
},
"topParams": [
{"paramName": "utm_source", "paramValue": "telegram", "visitCount": 55},
{"paramName": "referrer_domain", "paramValue": "google.com", "visitCount": 18}
],
"topGeo": [
{"country": "Russia", "city": "Moscow", "visitCount": 30},
...
]
}
Администраторский доступ¶
Через AdminListsController:
| Путь | Описание |
|---|---|
GET /admin/analytics/list?date=&page=&size= |
Постраничный список туннелей с метриками за день |
GET /admin/analytics/top-paths?slug=&date= |
Топ путей конкретного туннеля |
GET /admin/analytics/geo?slug=&date= |
Гео-статистика конкретного туннеля |
Доступно только сессиям с ролью GLAVA (сессионная Spring Security).
Очистка устаревших данных¶
AnalyticsCleanupScheduler — Spring @Scheduled(cron = "0 10 0 * * *"):
DELETE FROM tunnel_traffic_daily WHERE date < CURRENT_DATE - INTERVAL '90 days';
DELETE FROM tunnel_path_visits_daily WHERE date < CURRENT_DATE - INTERVAL '90 days';
DELETE FROM tunnel_param_visits_daily WHERE date < CURRENT_DATE - INTERVAL '90 days';
DELETE FROM tunnel_geo_visits_daily WHERE date < CURRENT_DATE - INTERVAL '90 days';
E2E-туннели и аналитика¶
Для E2E-туннелей (e2e-<token>.dix.su) MetricsCollector.record_request не вызывается — прокси работает как слепой TCP-ретранслятор. Зато e2e_traffic_counter.ex фиксирует только байты (in/out) в отдельной таблице — для биллинга. Никаких путей, гео и UTM для E2E нет.
Лимиты трафика и предупреждения¶
MetricsCollector.check_public_limit/1 вызывается перед каждым запросом на туннель:
- Суммирует ETS-счётчики за текущий месяц + кэшированные данные из БД (TTL 5 мин)
- При ≥ 80% квоты отправляет email-предупреждение (не чаще 1 раза в день)
- При ≥ 100% блокирует туннель до 1-го числа следующего месяца
Масштабирование (будущее)¶
При росте нагрузки план из SCALING.md:
- Read replica для
AnalyticsController— аналитические SELECT не идут на master - Партиционирование
tunnel_path_visits_daily/tunnel_geo_visits_dailyпоdate— дешёвый DROP PARTITION вместо DELETE - Event streaming (Kafka/Kinesis) — замена прямых UPSERT в dixu_proxy, буфер на случай пиков
Смотрите также¶
- Биллинг и тарифы — месячные квоты трафика по тарифам
- Безопасность — rate-limiting, DDoS-защита
- Масштабирование — план роста аналитической инфраструктуры