ftops.space
84 subscribers
510 photos
98 videos
33 files
220 links
ftops.space
Сервера на linux, FreeBSD, сети на микротик и сиськах.
Download Telegram
Дефолтные настройки ImageGC в Kubernetes рассчитаны на гиперскейлеры и ноды с сотнями гигабайт памяти. На небольших VPS с диском 20-40 ГБ стандартный параметр imageGCHighThresholdPercent=85 выставляет смертельную ловушку: сборка мусора начинается только тогда, когда на диске остается 3-5 ГБ. В условиях интенсивного деплоя или роста ephemeral-storage локальная файловая система забивается быстрее, чем kubelet успевает запустить цикл очистки containerd. При достижении порога нода мгновенно получает taint DiskPressure. Kubelet начинает хаотично эвиктить поды, ломая консенсус K3s и переводя файловую систему бюджетного VPS в read-only из-за I/O-ограничений провайдера. Проблема усугубляется тем, что сборщик не трогает образы, созданные меньше чем imageMinimumGCAge назад (по умолчанию 2 минуты), а старые логи контейнеров не входят в зону ответственности ImageGC. Для стабильной работы мелких узлов дисковую гигиену нужно переводить в жесткий режим через конфигурацию K3s (/etc/rancher/k3s/config....
Дефолтные настройки ImageGC в Kubernetes рассчитаны на гиперскейлеры и ноды с сотнями гигабайт памяти. На небольших VPS с диском 20-40 ГБ стандартный параметр imageGCHighThresholdPercent=85 выставляет смертельную ловушку: сборка мусора начинается только тогда, когда на диске остается 3-5 ГБ. В условиях интенсивного деплоя или роста ephemeral-storage локальная файловая система забивается быстрее, чем kubelet успевает запустить цикл очистки containerd. При достижении порога нода мгновенно получает taint DiskPressure. Kubelet начинает хаотично эвиктить поды, ломая консенсус K3s и переводя файловую систему бюджетного VPS в read-only из-за I/O-ограничений провайдера. Проблема усугубляется тем, что сборщик не трогает образы, созданные меньше чем imageMinimumGCAge назад (по умолчанию 2 минуты), а старые логи контейнеров не входят в зону ответственности ImageGC. Для стабильной работы мелких узлов дисковую гигиену нужно переводить в жесткий режим через конфигурацию K3s (/etc/rancher/k3s/config.yaml): kubelet-arg: - image-gc-high-threshold=60 - image-gc-low-threshold=45 - image-minimum-gc-age=1m - eviction-hard=nodefs.available<10%,nodefs.inodesFree<5% Дополнительно зафиксируйте SystemMaxUse=1G в journald.conf и ограничьте размер логов контейнеров через max-size в containerd. На малых объемах управление памятью строится не от пиковых нагрузок, а от физической скорости выедания диска. Разбор оптимизации Bare-Metal и K3s стека читайте на https://ftops.space.
На сетевых интерфейсах 10G+ при высокоинтенсивном трафике классическая проблема фильтрации заключается не только в скорости прохождения пакета по цепочке, но и в поведении подсистемы при динамическом изменении правил. Когда автоматизированные системы защиты, IPS или сетевые контроллеры пытаются оперативно заблокировать атаки или обновить адреса, legacy-стек iptables блокирует весь пайплайн. Каждое изменение в iptables требует полного копирования монолитного массива правил из пространства пользователя в ядро через iptables mutex. На мультигигабитных каналах это приводит к сбросу кешей процессора, cache line bouncing между NUMA-узлами и микроскопическим задержкам, вызывающим потерю пакетов в сетевых очередях NIC. Архитектура nftables решает эту проблему за счет переноса логики в специализированную виртуальную машину ядра (nftvm) и применения нативных структур данных: - Атомарные транзакции: обновления передаются через netlink-сообщения коммитом конкретных элементов, без перезагрузки вс...
На сетевых интерфейсах 10G+ при высокоинтенсивном трафике классическая проблема фильтрации заключается не только в скорости прохождения пакета по цепочке, но и в поведении подсистемы при динамическом изменении правил. Когда автоматизированные системы защиты, IPS или сетевые контроллеры пытаются оперативно заблокировать атаки или обновить адреса, legacy-стек iptables блокирует весь пайплайн. Каждое изменение в iptables требует полного копирования монолитного массива правил из пространства пользователя в ядро через iptables mutex. На мультигигабитных каналах это приводит к сбросу кешей процессора, cache line bouncing между NUMA-узлами и микроскопическим задержкам, вызывающим потерю пакетов в сетевых очередях NIC. Архитектура nftables решает эту проблему за счет переноса логики в специализированную виртуальную машину ядра (nftvm) и применения нативных структур данных: - Атомарные транзакции: обновления передаются через netlink-сообщения коммитом конкретных элементов, без перезагрузки всей таблицы и без заморозки проходящего трафика. - Поиск за O(1): вместо последовательного прогона пакета по сотням правил iptables используются встроенные сеты и мапы на базе хэш-таблиц и rbtree. - Оптимизация памяти: динамические списки IP-адресов подгружаются прямо в структуры ядра без вызова пересборки графа правил. Для высоконагруженных bare-metal маршрутизаторов и пограничных узлов K3s полный отказ от iptables в пользу нативного nftables избавляет сетевой стек от просадок производительности при постоянной смене правил фильтрации. Практические разборы оптимизации сетевого стека ядра и архитектуры устойчивых сервисов выложены на https://ftops.space.
Настройка сетевого стека ядра под высокий RPS в bare-metal окружении часто превращается в карго-культ. Инженеры прописывают net.core.somaxconn = 65535 в sysctl.conf, но забывают, что ядро Linux берет минимальное значение между somaxconn и аргументом backlog в системном вызове listen(). Если Nginx, Envoy или Go-сервис скомпилирован с дефолтным backlog 512, ядро срежет очередь listen-сокета до 512. При микроспайке входящих TCP-соединений очередь переполняется, и ядро начинает молча выбрасывать SYN-пакеты, создавая искусственные таймауты у клиентов. Второй источник частых аварий — некорректная работа с TIMEWAIT сокетами при высокой плотности исходящих соединений. Параметр net.ipv4.tcptwreuse позволяет ядру повторно использовать сокеты в состоянии TIMEWAIT, но только если на обеих сторонах включены RFC 1323 timestamps через net.ipv4.tcptimestamps = 1. Если ради выигрыша CPU отключить tcptimestamps, tcptwreuse просто перестает работать, приводя к исчерпанию локальных портов (ephemer...
Настройка сетевого стека ядра под высокий RPS в bare-metal окружении часто превращается в карго-культ. Инженеры прописывают net.core.somaxconn = 65535 в sysctl.conf, но забывают, что ядро Linux берет минимальное значение между somaxconn и аргументом backlog в системном вызове listen(). Если Nginx, Envoy или Go-сервис скомпилирован с дефолтным backlog 512, ядро срежет очередь listen-сокета до 512. При микроспайке входящих TCP-соединений очередь переполняется, и ядро начинает молча выбрасывать SYN-пакеты, создавая искусственные таймауты у клиентов. Второй источник частых аварий — некорректная работа с TIME_WAIT сокетами при высокой плотности исходящих соединений. Параметр net.ipv4.tcp_tw_reuse позволяет ядру повторно использовать сокеты в состоянии TIME_WAIT, но только если на обеих сторонах включены RFC 1323 timestamps через net.ipv4.tcp_timestamps = 1. Если ради выигрыша CPU отключить tcp_timestamps, tcp_tw_reuse просто перестает работать, приводя к исчерпанию локальных портов (ephemeral port exhaustion). При этом параметр tcp_tw_recycle из ядра давно удален за порчу трафика за NAT, но до сих пор встречается в устаревших инструкциях. Даже идеальный сетевой стек бесполезен, если сервис упирается в файловые дескрипторы. Каждый сетевой сокет в Linux — это файловый дескриптор. Общий лимит sysctl fs.file-max определяет емкость всей системы, но для конкретного процесса определяющим является ulimit. В дистрибутивах с systemd параметры из limits.conf игнорируются для демонов. Без явно прописанного LimitNOFILE=1048576 в unit-файле K3s, Nginx или ingress-контроллера сервис остановит прием новых соединений с ошибкой EMFILE (Too many open files) задолго до исчерпания RAM. Правильный тюнинг ядра требует сквозного аудита: от настроек самого приложения (backlog) и лимитов systemd (LimitNOFILE) до sysctl (somaxconn, tcp_max_syn_backlog, tcp_tw_reuse) и параметров ring-буферов сетевой карты. Настройка одного параметра в отрыве от цепочки всегда приводит к падению под нагрузкой. Практические регламенты отладки bare-metal инфраструктуры и сетевого стека ядра разбираем на https://ftops.space.
Периодические задержки ответов микросервисов ровно в 5 секунд — классический симптом race condition в подсистеме netfilter Linux. В Kubernetes при отправке параллельных DNS-запросов по протоколу UDP несколько подов на одной ноде одновременно обращаются к ClusterIP сервиса CoreDNS. Таблица conntrack пытается выполнить DNAT для двух идентичных потоков до завершения инициализации записи, из-за чего ядро молча отбрасывает один из пакетов. Повторная отправка пакета клиентом происходит только по истечении пятисекундного таймаута glibc. Инженерное решение этой проблемы заключается в разворачивании NodeLocal DNSCache. Компонент запускается как DaemonSet на каждой ноде кластера и поднимает виртуальный IP-адрес (обычно 169.254.20.10) на интерфейсе loopback. Это меняет механику обработки трафика на физическом узле: - Запросы приложений перенаправляются на локальный сокет, исключая прохождение через цепочки DNAT iptables. - Для локального DNS-трафика включается правило NOTRACK в таблице raw, полно...
Периодические задержки ответов микросервисов ровно в 5 секунд — классический симптом race condition в подсистеме netfilter Linux. В Kubernetes при отправке параллельных DNS-запросов по протоколу UDP несколько подов на одной ноде одновременно обращаются к ClusterIP сервиса CoreDNS. Таблица conntrack пытается выполнить DNAT для двух идентичных потоков до завершения инициализации записи, из-за чего ядро молча отбрасывает один из пакетов. Повторная отправка пакета клиентом происходит только по истечении пятисекундного таймаута glibc. Инженерное решение этой проблемы заключается в разворачивании NodeLocal DNSCache. Компонент запускается как DaemonSet на каждой ноде кластера и поднимает виртуальный IP-адрес (обычно 169.254.20.10) на интерфейсе loopback. Это меняет механику обработки трафика на физическом узле: - Запросы приложений перенаправляются на локальный сокет, исключая прохождение через цепочки DNAT iptables. - Для локального DNS-трафика включается правило NOTRACK в таблице raw, полностью разгружая таблицу conntrack. - Связь локального кэша с центральным CoreDNS переводится на надежные постоянные TCP-соединения. При внедрении схемы на голом железе и в K3s критично соблюдать регламент настройки. Ошибки чаще всего возникают при изменении флага cluster-dns в kubelet без обновления dnsPolicy у существующих подов, а также при конфликтах с сетевыми плагинами. Если в системе используется nftables или WireGuard mesh, локальные адреса 169.254.20.10 должны быть явно исключены из маршрутизации туннеля и правил фильтрации. Низкий latency сетевого стека Kubernetes на высоком RPS достигается предсказуемостью маршрута пакета, а не бесконечным увеличением ресурсов CoreDNS. Разборы конфигураций сетевого ядра и архитектурные решения для Bare-Metal кластеров собраны на https://ftops.space.
Утренний статус и чекап инфраструктуры

Утренний health check — это не зеленая галочка в дашборде. Сначала проверяю доступность нод, затем связность WireGuard mesh и только после этого доверяю прикладным метрикам. Нода, которая отвечает на ping, но потеряла маршрут до соседей, уже неисправна.

Минимальный порядок:
- Состояние всех нод кластера и системных сервисов;
- Handshake WireGuard и возраст последнего обмена;
- Маршруты между сегментами, DNS и доступность контрольных endpoint;
- Алерты без подтвержденного recovery;
- Расхождение времени, заполнение дисков и ошибки ядра.

Главное правило — zero silent failures. Мониторинг должен показывать не только "up", но и что именно перестало работать, через какой путь и как давно. Если health check не проверяет реальный рабочий маршрут, он проверяет иллюзию доступности.

Чекап не заменяет наблюдение: после первичной проверки смотрю динамику ошибок и последние изменения конфигурации. Подробные практики отказоустойчивой инфраструктуры — https://ftops.space

#ftops #devops #linux #freebsd #sre #инфраструктура
ftops.space pinned a video
Сравнивать bare-metal K3s с облаком по цене виртуального ядра бессмысленно. Считайте полный юнит: электроэнергия, аренда стойки, диски, запасные узлы, время инженера и стоимость недоступности. У гиперскейлера к этому добавляются egress, cross-zone и managed-control-plane сборы. Для latency измеряйте не средний ping, а p95/p99 от клиента до pod: физический NIC, CNI, kube-proxy, overlay, балансировщик и соседние зоны. На собственных серверах проще удержать маршрут коротким, но сложнее обеспечить N+1, замену диска и независимое питание. Практическая модель для K3s: - выделить критичные сервисы на отдельные ноды; - держать capacity headroom 30–40%; - считать стоимость часа простоя отдельно от железа; - проверять latency после каждого изменения CNI и topology spread. Подробные разборы bare-metal, K3s и сетевой инженерии: https://ftops.space
🧭 Навигатор по материалам канала

Используйте теги для быстрого поиска нужной фактуры:

#постмортем — Разборы реальных аварий
Анатомия сбоев по единому стандарту: Симптом ➔ Ложная гипотеза ➔ Что показал tcpdump/dmesg ➔ Архитектурное исправление.
— Как Happy Eyeballs (RFC 6555) и чистый Go-резолвер уронили кластерный инференс AI.
— BGP-петля транзитного оператора на 450 мс, которую мониторинг принял за OOM Killer.
— Паника Kubelet ImageGC при пороге 80% на VPS с диском 20 ГБ.
— Залипание WireGuard-пиров после смены NAT и лечение через FDB.

#архитектура — Схемы сетей, оверлеи и отказоустойчивость
Чертежи межсерверного взаимодействия, маршрутизация и обход сетевых аномалий.
— Двуххабовая топология AmneziaWG (Forest ➔ Failover Hub Pumpkin) с обходом блокировок UDP.
— Policy routing, fwmark и чистый европейский egress через туннели awg-goog.
— DNAT-трансляция устаревших подсетей внутри Cloudflare Zero Trust туннелей.
— Разделение control-plane и worker-нод в условиях жесткого DPI.

#экономика — Трезвая математика TCO (Bare-Metal vs Cloud)
Реальные расчеты расходов, скрытые налоги облачных провайдеров и границы применимости.
— 17 нод на K3s за €48/мес против аналогичного сетапа в AWS EKS за $540.
— «Налог на лень»: сколько на самом деле стоят AWS NAT Gateway и межзональный трафик.
— Инженерный налог: почему дешевое железо требует строгих сторожевых таймеров (watchdogs).

#паттерны — Конфиги, проверенные в продакшене
Готовые сниппеты, systemd-юниты, скрипты гигиены и правила фильтрации.
— Юнит аварийного блокирования неотфильтрованного IPv6 для Go-бинарников.
— Blackhole для QUIC (UDP/443) в Xray и Hysteria2 для спасения длинных gRPC-сессий.
— Автоматический watchdog туннелей с pre-armed rollback таймерами.
— Сжатие ротированных логов (gzip -9) и чистка containerd без простоя подов.
──────
ftops.space pinned «🧭 Навигатор по материалам канала …»
Ошибочная вера в скорость современных NVMe-накопителей заставляет системных инженеров включать привычный swap-файл на диске для страховки от OOM. На распределенных нодах K3s это приводит к деградации: при всплеске нагрузки kswapd начинает сбрасывать неактивные анонимные страницы на диск. Даже при микронных задержках NVMe очередь блокировок в block layer ядра моментально возрастает. Поток direct reclaim замораживает системные вызовы, контейнерный рантайм пропускает heartbeat, а Kubernetes помечает рабочий узел как NotReady. Отказ от дискового свопа в пользу Zram кардинально меняет механики ядра Linux. Zram создает виртуальное сжатое блочное устройство непосредственно в RAM, используя алгоритмы LZ4 или ZSTD. При сбросе страниц ядро выполняет сжатие памяти в CPU за единицы микросекунд, избегая обращения к дисковой шине и физическим накопителям. В результате пропадает I/O wait, а подсистема управления памятью продолжает работать с детерминированной задержкой. Конфигурация Zram требует пере...
Ошибочная вера в скорость современных NVMe-накопителей заставляет системных инженеров включать привычный swap-файл на диске для страховки от OOM. На распределенных нодах K3s это приводит к деградации: при всплеске нагрузки kswapd начинает сбрасывать неактивные анонимные страницы на диск. Даже при микронных задержках NVMe очередь блокировок в block layer ядра моментально возрастает. Поток direct reclaim замораживает системные вызовы, контейнерный рантайм пропускает heartbeat, а Kubernetes помечает рабочий узел как NotReady. Отказ от дискового свопа в пользу Zram кардинально меняет механики ядра Linux. Zram создает виртуальное сжатое блочное устройство непосредственно в RAM, используя алгоритмы LZ4 или ZSTD. При сбросе страниц ядро выполняет сжатие памяти в CPU за единицы микросекунд, избегая обращения к дисковой шине и физическим накопителям. В результате пропадает I/O wait, а подсистема управления памятью продолжает работать с детерминированной задержкой. Конфигурация Zram требует пересмотра классического тюнинга ядра: - vm.swappiness установите в значение 180 или 200. Это заставляет ядро агрессивно вытеснять анонимную память в сжатый Zram, освобождая несжатую RAM под кеши файловой системы. - vm.watermarkboostfactor сбросьте в 0 для предотвращения ухода ядра в глубокую рекультивацию страниц при кратковременных спайках. - Алгоритм сжатия выбирайте LZ4 для минимальной нагрузки на vCPU или ZSTD для максимальной плотности упакованной памяти. Полный отказ от физических дисков в цепочке своппинга переводит управление дефицитом памяти из области медленного storage I/O в область быстрых процессоров. Тюнинг bare-metal инфраструктуры и сетевого стека ядра разбираем на https://ftops.space.
TCP BBR vs Cubic: почему алгоритм перегрузки решает больше, чем железо

Cubic управляет окном перегрузки по потерям пакетов. В датацентре это терпимо: потери редки, round-trip time предсказуем. На WAN-линках с буферизацией на транзитных узлах (bufferbloat) Cubic раздувает окно до потерь, потом резко режет его вдвое. Итог: пилообразный throughput и латентность, которая прыгает в 3-5 раз от базовой.

BBR строит модель канала иначе. Он оценивает максимальную пропускную способность (BtlBw) и минимальный RTT, и удерживает окно ровно там, где канал заполнен без очереди. Потери для него — шум, а не сигнал. На линках с 1% случайных потерь BBR даёт в 2-25 раз больший throughput, чем Cubic, в зависимости от RTT и глубины буфера на пути.

Включается в одну строку:

sysctl -w net.ipv4.tcpcongestioncontrol=bbr
sysctl -w net.core.defaultqdisc=fq

fq (fair queue) обязателен: без него BBR не может корректно зондировать канал. Дополнительно для высоконагруженного шлюза:

net.core.rmem
ma...
TCP BBR vs Cubic: почему алгоритм перегрузки решает больше, чем железо

Cubic управляет окном перегрузки по потерям пакетов. В датацентре это терпимо: потери редки, round-trip time предсказуем. На WAN-линках с буферизацией на транзитных узлах (bufferbloat) Cubic раздувает окно до потерь, потом резко режет его вдвое. Итог: пилообразный throughput и латентность, которая прыгает в 3-5 раз от базовой.

BBR строит модель канала иначе. Он оценивает максимальную пропускную способность (BtlBw) и минимальный RTT, и удерживает окно ровно там, где канал заполнен без очереди. Потери для него — шум, а не сигнал. На линках с 1% случайных потерь BBR даёт в 2-25 раз больший throughput, чем Cubic, в зависимости от RTT и глубины буфера на пути.

Включается в одну строку:

sysctl -w net.ipv4.tcp_congestion_control=bbr
sysctl -w net.core.default_qdisc=fq

fq (fair queue) обязателен: без него BBR не может корректно зондировать канал. Дополнительно для высоконагруженного шлюза:

net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
net.ipv4.tcp_fastopen = 3

Отдельная история — ethtool и прерывания. ethtool -G ethX rx 4096 увеличивает ring buffer, снижая потери при burst-трафике. Но ethtool -s ethX speed 1000 duplex full autoneg off на живом порту может мгновенно сбросить линк — интерфейс уходит в re-negotiation. На production это означает потерю сессий. Всегда проверяй, что autoneg на обоих концах ведёт себя одинаково, прежде чем трогать скорость вручную.

eBPF и XDP добавляют ещё один уровень: с XDP_DROP на входе NIC ты фильтруешь мусор до аллокации skb. На 10G линке это разница между 14 Mpps wire rate и провалом в kernel stack, который упирается в ~3-4 Mpps на ядро без DPDK.

https://ftops.space
Воскресенье. Самое честное время недели.

Можно строить планы на бумаге, а потом смотреть как реальность их аккуратно переписывает.

На эту неделю у меня:

- Миграция одного из сервисов iris-loyalty на свежую ноду в K3s кластере. Там накопился технический долг, который уже начинает мешать.
- Longhorn snapshots — надо нормально настроить ротацию, сейчас руками слежу что само по себе плохая практика.
- AmneziaWG mesh — документация. Да, я тот человек который сначала строит, потом пишет про это. Живая инфра важнее wiki.
- femida-tech.ru — там ждут несколько задач по AI-пайплайну. Два с половиной года проекту, и каждую неделю что-то новое.

Пятница покажет сколько из этого реально закрылось.

ftops.space — там пишу про инфру когда нахожу время между инцидентами.
Pedit COW (CVE-2026-46331) наглядно разделяет два понятия: изоляция процесса и безопасность ядра. chroot скрывает дерево файлов, cgroups v2 режут CPU и память, seccomp сокращает набор syscall — но все контейнеры по-прежнему используют один kernel image. Опасная цепочка на узлах K3s выглядит так: - unprivileged user namespace включён; - внутри namespace появляется CAPNETADMIN; - доступен netlink и traffic control; - ошибка в actpedit превращается в запись в page cache. Минимальный регламент для bare-metal: - обновить kernel до версии с исправлением CVE-2026-46331; - проверить user.maxusernamespaces и отключить unshare там, где он не нужен; - запускать workload с seccomp-профилем без socket, bpf, perfevent и необязательных netlink-операций; - назначить cgroup v2 memory.max и pids.max, чтобы авария не стала DoS; - считать host kernel критической общей зависимостью при каждом threat model review. Подробные разборы изоляции, K3s и сетевого стека: https://ftops.space
ПОСТМОРТЕМ: Как RFC 6555 (Happy Eyeballs) в чистом Go деградировал P99 латенси AI-инференса на 300 мс

Окружение: Bare-metal K3s кластер ftops.space, Go-микросервис (Go 1.22, pure net/http) в роли локального API-маршрутизатора к VLLM-эндпоинтам. IPv4 /24 внутренний mesh, IPv6 на нодах включен локально, но глобальный egress закрыт на файрволе через DROP (без REJECT).

---

1. Что сломалось
При нагрузке 450 RPS на локальный vLLM-инференс P99 латенси вырос с 12 мс до 312 мс. При этом CPU и GPU инференс-узлов загружены всего на 18%. Каждые ~10-15 запросов получали необъяснимую задержку ровно в 300 мс перед началом потоковой генерации токенов (Server-Sent Events).

2. Ложная гипотеза
Инженеры грешили на работу cgroup memory limit и задержки в GC Go. В системном /etc/gai.conf была явно прописана директива precedence ::ffff:0:0/96 100, чтобы приоритезировать IPv4-трафик над IPv6 в getaddrinfo(). Однако изменения в /etc/gai.conf абсолютно никак не влияли на метрики.

3. Что показал tcpdump и dmesg
Снятие дампа на veth-интерфейсе пода (tcpdump -i any port 53 or port 8080 -nn -ttt) вскрыло следующую картину:
1. net.Dialer из Go генерирует параллельные DNS-запросы типа A (IPv4) и AAAA (IPv6) через встроенный Go-резолвер (net/dnsclient_unix.go), полностью игнорируя libc и /etc/gai.conf (так как Go собран с CGO_ENABLED=0).
2. Резолвер получает ответы для обоих типов записей. RFC 6555 (Happy Eyeballs v2 / RFC 8305) стартует соединение по IPv6.
3. Пакет SYN на IPv6 уходит в тупиковый маршрут и тихо дропается на Edge-фаерволе без ICMPv6 Destination Unreachable.
4. Таймер FallbackDelay в net.Dialer составляет строго 300 мс по умолчанию. Запрет на переключение длится ровно 300 мс, прежде чем Go попробует установиться по IPv4.

4. Архитектурный фикс
Внедрено двухуровневое решение для исключения синтетических задержек:

1. Явное отключение IPv6 в DialContext Go-клиента:
```go
transport := &http.Transport{
DialContext: (&net.Dialer{
Timeout: 30 time.Second,
KeepAlive: 30 time.Second,
// Выключаем дублирующие AAAA запросы и Fallback
Resolver: &net.Resolver{
PreferGo: true,
},
}).DialContext,
}
// Использование custom net.Dialer с forced IP family
Удалить swapfile недостаточно, чтобы исключить дисковый своп. У zram есть собственный механизм writeback: при настроенном backingdev и запуске выгрузки страницы отправляются на блочное устройство. Поэтому единственная строка /dev/zram0 в списке свопа ещё не подтверждает, что страницы остаются в RAM. Механизм описан в [документации ядра](https://cdn.kernel.org/doc/html/latest/admin-guide/blockdev/zram.html). Проверка состоит из трёх пунктов: swapon --show — какие области свопа активны; /sys/block/zram0/backingdev — назначено ли хранилище для выгрузки; /sys/block/zram0/bdstat — были ли обращения к нему. Если требование — своп исключительно в памяти, отдельный NVMe swapfile и backing device у zram должны отсутствовать. Высокий приоритет zram этого требования не обеспечивает. Следующий контроль — реальная цена сжатия. В /sys/block/zram0/mmstat сравнивают origdatasize с memusedtotal: последний учитывает расход памяти вместе с накладными расходами. disksize задаёт логическую ёмкость,...