202 lines
9.0 KiB
Plaintext
202 lines
9.0 KiB
Plaintext
Инструкция 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.
|