Задать вопрос

Рост CLOSE-WAIT и утечки TCP-сокетов в Xray (vless + reality) — что делать?

На сервере с Xray v26.6.1 (VLESS + Reality) наблюдается стабильный рост TCP-состояний CLOSE-WAIT и частично TIME-WAIT, что со временем приводит к деградации работы прокси вплоть до частичной неработоспособности.

Архитектура
Сервер 1: РФ (inbound для клиентов / outbound в нидерланды)
Сервер 2: Нидерланды (inbound с рф)

Проблема проявляется только на РФ-сервере. На NL-сервере аномалий по TCP-состояниям нет.

Симптомы и цифры:
1. CLOSE-WAIT растёт до 500–800+ соединений
2. ESTABLISHED 300–1000+
3. TIME-WAIT растет, если поднимается CLOSE-WAIT
4. ORPHANED = 0
5. CPU почти 0%, RAM в норме
6. Лимиты файловых дескрипторов не достигнуты

Чаще наблюдаю такую картину:
CLOSE-WAIT: 698
ESTABLISHED: 1162
TIME-WAIT: 325
ORPHANED: 0

Дополнительные наблюдения:
1. recv-q у некоторых соединений сильно растёт (до сотен/тысяч)
2. lastrcv у части соединений достигает сотен тысяч миллисекунд (5–13 минут)
3. большое количество fd остаётся открытым (1000+ xray)
4. соединения зависают в состоянии CLOSE-WAIT и не освобождаются

Проверенные моменты:
1. лимиты ulimit -n (open files) не упираются (65535+)
2. CPU/Memory не загружены
3. Системные лимиты в целом не выглядят перегруженными
4. проблема воспроизводится стабильно при работе клиентов
5. на втором сервере (NL) с аналогичной конфигурацией проблема отсутствует

Можно ли как-то заставить Xray корректно закрывать соединения / уменьшить CLOSE-WAIT? С этой проблемой я мучаюсь второй день. Я не профессионал в данной области, все изучаю по мере жесткости ограничений, но конкретно здесь я запутался. Буду очень благодарен любым советам
  • Вопрос задан
  • 1175 просмотров
Подписаться 3 Средний 2 комментария
Помогут разобраться в теме Все курсы
  • Нетология
    Специалист по информационной безопасности + нейросети
    12 месяцев
    Далее
  • Академия Эдюсон
    Python-разработчик + ИИ
    9 месяцев
    Далее
  • ProductStar × РБК
    Профессия DevOps-инженер + ИИ
    5 месяцев
    Далее
Решения вопроса 1
@Zerg89
Конфигурация TCP KeepAlive для Xray Outbound/Inbound
Добавьте следующий блок параметров в streamSettings -> sockopt в вашем конфигурационном файле config.json:
{
  "streamSettings": {
    "network": "tcp",
    "sockopt": {
      "tcpKeepAliveInterval": 10,
      "tcpKeepAliveIdle": 30,
      "mark": 255
    }
  }
}

Описание параметров:
tcpKeepAliveInterval: интервал времени (в секундах) между отправками повторных пакетов (Probes) после того, как соединение перешло в режим ожидания. Значение 10 означает, что зонды отправляются каждые 10 секунд.
tcpKeepAliveIdle: время неактивности (в секундах) до того, как система начнет отправлять KeepAlive-пакеты. Значение 30 означает, что проверка начнется через 30 секунд отсутствия трафика.
mark: системный маркер пакетов (опционально, для Linux/маршрутизаторов), полезен для маршрутизации и обхода сетевых экранов.
Если не поможет есть keepalive системный,
sysctl net.ipv4.tcp_keepalive_time
по умолчанию 2 часа в секундах

Исправить можно в файле /etc/sysctl.conf
Хотя пока не понятно где баг, программа не отправляет close или система его не обрабатывает
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Andrei2025
@Andrei2025
Технический писатель, Linux/DevOps и путешествия
Главное: CLOSE-WAIT — это не проблема тайм-аутов ядра

Состояние CLOSE-WAIT означает, что удалённая сторона уже прислала FIN, ядро передало приложению EOF, но локальный процесс ещё не вызвал close() для своего сокета. Поэтому увеличение tcp_keepalive_* само по себе накопление CLOSE-WAIT не исправляет: keepalive предназначен прежде всего для обнаружения пропавших соединений в состоянии ESTABLISHED.

Сначала нужно определить, какие именно соединения не закрываются и действительно ли их удерживает Xray.

Минимальная диагностика

pid=$(pidof xray)

sudo ss -tanp state close-wait
sudo lsof -nP -a -p "$pid" -iTCP
sudo ls -l "/proc/$pid/fd" | wc -l
readlink -f "/proc/$pid/exe"
"/proc/$pid/exe" version
systemctl cat xray


Сравните локальные и удалённые адреса в выводе ss/lsof. Это покажет, зависают ли клиентские соединения к российскому серверу либо соединения российского сервера с NL-сервером или Reality target.

Почему важно проверить реальный бинарник

В Xray действительно была подтверждённая утечка сокетов VLESS+REALITY: исправление существовало в REALITY, но некоторое время не было подтянуто в основную зависимость Xray. В релизе 26.6.1 заявлено исправление ситуации, когда соединение между сервером и target могло закрываться несвоевременно.

Если Xray установлен панелью или работает в контейнере, строка версии в интерфейсе ещё не гарантирует, что запущен именно обновлённый официальный бинарник. Поэтому стоит проверить путь через /proc/PID/exe, версию самого файла и перезапуск процесса после обновления.

Обсуждение исправления:
https://github.com/XTLS/Xray-core/issues/5828

Релиз 26.6.1:
https://github.com/XTLS/Xray-core/releases/tag/v26.6.1

Что делать дальше

Если фактически запущен официальный 26.6.1, я бы:

  1. воспроизвёл проблему на минимальной конфигурации без панели и лишних маршрутов;
  2. временно включил debug-логирование;
  3. собрал вывод ss с PID и адресами до и после роста CLOSE-WAIT;
  4. собрал pprof-профиль goroutine/heap Xray;
  5. сравнил поведение с соседним релизом core.


О TCP KeepAlive

Для действительно пропавших клиентов можно дополнительно настроить sockopt на нужном inbound:

"sockopt": {
  "tcpKeepAliveIdle": 90,
  "tcpKeepAliveInterval": 30,
  "tcpUserTimeout": 60000
}


Но это вспомогательная мера для зависших ESTABLISHED-соединений, а не лечение бесконечного CLOSE-WAIT. Параметр mark: 255 к закрытию сокетов не относится — это метка для policy routing. Добавлять её без соответствующих правил маршрутизации не нужно.

Документация sockopt:
https://xtls.github.io/en/config/transports/sockop...
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы