Files
elmprodvpn/selective-vpn-api/инструкция3-safe.txt
beckline 10a10f44a8 baseline: api+gui traffic mode + candidates picker
Snapshot before app-launcher (cgroup/mark) work; ignore binaries/backups.
2026-02-14 15:52:20 +03:00

202 lines
9.0 KiB
Plaintext
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.
Инструкция 3 (safe-версия)
Цель:
Сделать улучшения резолвера без risky-переписывания, сохранить обратную совместимость с текущим GUI/API,
и убрать главные источники шума: массовые NXDOMAIN, таймауты и нечитабельные метрики.
--------------------------------------------------------------------
0) Что подтверждено по текущему состоянию
--------------------------------------------------------------------
1. Основной рабочий код сейчас в:
- app/resolver.go
- app/routes_update.go
- app/dns_settings.go
- app/domains_handlers.go
2. Логи показывают:
- много NXDOMAIN (ожидаемо при широком base x subs)
- заметную долю timeout
- один агрегированный счетчик dns_errors, из-за чего трудно понять причину деградации.
3. Формат dns upstream у нас: host#port (например 94.140.14.15#53 или 127.0.0.1#6053).
Это важно: нельзя использовать валидацию, которая принимает только host:port.
--------------------------------------------------------------------
1) Архитектурное решение (рекомендуемое)
--------------------------------------------------------------------
Не оставлять только переключатель direct <-> smartdns.
Сделать 3 режима резолвера:
- direct:
обычные домены через default/meta upstream.
- smartdns:
все домены через SmartDNS address.
- hybrid_wildcard (recommended):
только wildcard-домены через SmartDNS, остальные напрямую через default/meta.
Почему так лучше:
- сохраняем скорость и отказоустойчивость direct для обычных доменов;
- wildcard-логику держим строго в SmartDNS, как ты и хотел;
- не ломаем текущий UX: можно оставить старый bool и маппить его на mode.
--------------------------------------------------------------------
2) Что НЕ внедряем из старой инструкция3
--------------------------------------------------------------------
1. Не используем netip.ParseAddrPort для upstream-валидации (ломает host#port).
2. Не используем netip.MustParseAddr в hot path (может паниковать).
3. Не добавляем лишний semaphore поверх worker pool (сложность без явной выгоды).
4. Не делаем агрессивный рефактор API-контрактов без backward-compat.
--------------------------------------------------------------------
3) Пакет безопасных правок (приоритет P1)
--------------------------------------------------------------------
P1.1 - Режимы DNS (backward compatible)
Файлы:
- app/types.go
- app/dns_settings.go
- app/routes_update.go
- app/resolver.go
Изменения:
1) Ввести enum режима:
type DNSResolverMode string
const (
DNSModeDirect DNSResolverMode = "direct"
DNSModeSmartDNS DNSResolverMode = "smartdns"
DNSModeHybrid DNSResolverMode = "hybrid_wildcard"
)
2) Расширить DNSMode/DNSStatusResponse/DNSModeRequest полем Mode,
но оставить ViaSmartDNS для старого GUI:
- если Mode пустой, использовать ViaSmartDNS:
- true -> smartdns
- false -> direct
3) В ResolverOpts передавать Mode и список wildcard-доменов (один раз на job).
4) В resolveHostGo выбирать dnsList так:
- mode == smartdns: []{smartdnsAddr}
- mode == hybrid_wildcard и host совпал с wildcard: []{smartdnsAddr}
- иначе: meta или default по текущей логике.
Примечание:
Wildcard-список уже хранится в smartdns-wildcards.json через /api/v1/smartdns/wildcards.
Нужно только использовать его в резолвере.
P1.2 - Upstream fallback с классификацией ошибок
Файл:
- app/resolver.go
Изменения:
1) В digA:
- идти по upstream последовательно;
- timeout/temporary -> fallback на следующий upstream;
- nxdomain -> остановить попытки для домена (дальше пробовать бессмысленно).
2) Классифицировать ошибки через net.DNSError + fallback по тексту:
- nxdomain
- timeout
- temporary
- other
3) Вместо одного dns_errors вести структуру счетчиков:
dns_attempts, dns_ok, dns_nxdomain, dns_timeout, dns_temporary, dns_other.
P1.3 - Разделенные метрики в summary
Файл:
- app/resolver.go
Изменения:
1) Обновить финальный лог "resolve summary" с раздельными счетчиками DNS-ошибок.
2) Добавить per-upstream агрегаты (минимум attempts/ok/timeout/nxdomain/other).
Формат может быть одной строкой JSON, чтобы GUI/анализатору было проще парсить.
P1.4 - Ограничение domain expansion
Файл:
- app/routes_update.go
Изменения:
1) Добавить конфиг-лимиты через env:
- RESOLVE_SUBS_PER_BASE_LIMIT (например default 25)
- RESOLVE_DOMAINS_HARD_CAP (например default 12000)
2) После построения domainSet:
- сортировать домены;
- при превышении hard cap обрезать хвост детерминированно;
- писать явный warning в trace.
3) Логировать breakdown:
bases_count, subs_count, expanded_count, total_domains.
--------------------------------------------------------------------
4) Пакет улучшений P2 (после P1)
--------------------------------------------------------------------
P2.1 - Negative cache
Файл:
- app/resolver.go
Идея:
- кэшировать nxdomain/servfail на короткий TTL (например 10-20 минут),
чтобы не долбить одинаковые несуществующие имена каждую прогонку.
P2.2 - PTR retry (ограниченный)
Файл:
- app/resolver.go
Идея:
- для digPTR сделать 1-2 retry только на timeout/temporary;
- не ретраить nxdomain.
P2.3 - GUI/API отображение режима
Файлы GUI:
- selective-vpn-gui/api_client.py
- selective-vpn-gui/dashboard_controller.py
- selective-vpn-gui/vpn_dashboard_qt.py
Идея:
- показать mode = direct/smartdns/hybrid_wildcard;
- оставить старый toggle рабочим (маппинг direct/smartdns),
а hybrid можно добавить как отдельный выбор (позже).
--------------------------------------------------------------------
5) Порядок внедрения (рекомендуемый)
--------------------------------------------------------------------
Шаг 1:
Реализовать режимы + fallback + split-метрики (P1.1, P1.2, P1.3).
Шаг 2:
Добавить лимиты expansion (P1.4), проверить изменение unresolved/timeouts.
Шаг 3:
Добавить negative cache и PTR retry (P2.1, P2.2).
--------------------------------------------------------------------
6) Критерии готовности
--------------------------------------------------------------------
1. В trace видно не один dns_errors, а раздельные причины.
2. В режиме direct при падении одного upstream запросы частично продолжают проходить через fallback.
3. В режиме hybrid_wildcard wildcard-домены уходят через SmartDNS, остальные через direct.
4. Количество timeout и общее время прогона снижаются относительно текущего baseline.
--------------------------------------------------------------------
7) Короткий диагноз по сути
--------------------------------------------------------------------
Проблема не в одном SmartDNS bottleneck.
Основной вклад сейчас дает комбинация:
- большой domain expansion,
- много несуществующих имен (NXDOMAIN),
- и отсутствие четкой стратегии fallback/метрик.
Safe-путь:
ввести гибридный routing DNS + раздельную диагностику + контролируемый expansion.