CoreOS: tcpdump загадочным образом решает проблему с сетью (используется слишком много сокетов)

14

У меня есть для тебя загадка сегодня. На Azure мы запускаем небольшой трехузловой кластер Elasticsearch на основе CoreOS (2023.5.0 / Linux 4.19.25-coreos). Elasticsearch запускается внутри док-контейнера в режиме хост-сети. После почти годовой работы без обслуживания мы видим, что машины находятся в очень интересном состоянии.

Обновить

Эта проблема была решена путем исправления драйвера в ядре Linux . Смотрите ответ ниже.

симптомы

По сути, связь между уязвимой машиной и двумя другими узлами прекращается. Все они находятся в одной виртуальной сети и одной подсети и обычно могут общаться друг с другом. Уязвимый узел все еще может быть доступен из других подсетей (я могу подключиться к нему по ssh) и из другой одноранговой виртуальной сети. Машина также имеет (очень нечеткое) подключение к Интернету, но большинство запросов просто прерываются.

Мы наблюдали, что на затронутом узле число «используемых сокетов», о которых сообщается, /proc/net/sockstatочень велико (~ 4.5k вместо ~ 300 на исправном узле). Мониторинг показывает, что это число быстро увеличивается с того момента, как узел становится недоступным.

Самое интересное, что мы не можем определить источник этих используемых сокетов:

# cat /proc/net/sockstat
sockets: used 4566
TCP: inuse 2 orphan 0 tw 2 alloc 98 mem 4
UDP: inuse 1 mem 0
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0

# cat /proc/net/sockstat6
TCP6: inuse 98
UDP6: inuse 1
UDPLITE6: inuse 0
RAW6: inuse 1
FRAG6: inuse 0 memory 0

В остальном машина выглядит нормально. Подозрительные процессы не выполняются, загрузка процессора минимальна, а доступной памяти недостаточно.

Pinging в «недоступный» VM в одних и тех же результатах подсетей в нескольких EAGAINответов , recvmsgа затем пересекая , чтобы получить ENOBUFSобратно от sendmsg. вывод пинга здесь

Я собрал некоторые дополнительные данные (до того, как были внесены какие-либо изменения в систему) и разместил их в этом списке: https://gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c

Анализ

Мы попытались отключить все, что только можем придумать на сервере, с упругим поиском, который был первым подозреваемым. Но закрытие контейнера с эластичным поиском не освобождает использованные розетки. То же самое для всех процессов, связанных с CoreOS (update-engine, locksmithd, ...) или даже для всей среды выполнения Docker или специфических для Azure вещей. Ничто не помогло.

Но теперь это становится еще более странным: мы попытались запустить tcpdumpмашину, чтобы увидеть, что происходит. И вот: проблема решилась сама собой, связь была восстановлена. Наша теория состояла в том, что tcpdump выполняет своего рода системный вызов, который разрешает его. Мы запустили tcpdump с gdb и установили точки останова на всех системных вызовах. Пройдя через множество точек останова, мы наконец обнаружили, что установка смешанного режима на сокете захвата (в частности, на эту строку в libpcap ) - это то, что сбрасывает счетчик используемых сокетов и возвращает нас в нормальное состояние.

Дополнительные выводы

  • Мы убедились, что работа tcpdumpс -p/--no-promiscuous-modeфлагом не очищает счетчик используемых сокетов и возвращает машину в рабочее состояние.
  • Запуск ifconfig eth0 txqueuelen 1001сбрасывает счетчик используемых сокетов, но связь не восстанавливается.
  • Установка режима Promisc вручную ip link set eth0 promisc onтакже не восстанавливает связь.
    • net.ipv4.xfrm4_gc_thresh установлен на 32768, и его небольшое увеличение не решает проблему.

используемые розетки

Мы связались с Azure, который так же озадачен этим, как и мы. Я понимаю, что это, скорее всего, не проблема, а просто симптом. Но это единственная ощутимая вещь, которую я нашел до сих пор. Я надеюсь, что, поняв симптом, я смогу приблизиться к основной причине. Сетевые интерфейсы в Azure запускаются с этим сетевым драйвером .

Может CoreOS / Kernel виноват?

С точки зрения временной шкалы, проблемы начались 2019-11-11, когда CoreOS автоматически обновился до последней версии. Согласно примечаниям к выпуску , это обновление содержало обновление ядра с 4.15.23 до 4.19.25 . Я все еще изучаю журналы изменений, чтобы понять, не может ли что-нибудь быть там. До сих пор я обнаружил только то, что драйвер гипервосети получил довольно много обновлений в последние месяцы , не все из которых, кажется, являются частью 4.19.25. Набор патчей, который CoreOS применил к 4.19.25, не так впечатляет , но патч, представляющий поддельный модуль nf_conntrack_ipv4, является новым.

Обновление: возможный связанный входящий патч ядра?

Помогите!

Пока что у нас есть следующие вопросы:

  • Что может привести к тому, что метрика «использованные сокеты» взлетит до небес? Я прочитал исходные коды ядра для этой метрики, и это, кажется, просто счетчик без ссылки на то, что это за сокеты на самом деле или что их создало.

  • Почему номер ровный около 4,5к? Какой лимит будет причиной этого?

  • Что-то существенно изменилось между ядром 4.14.96 и 4.19.25?

  • Почему setsockopt()вызов в libpcap сбрасывает состояние?

Связанная ошибка CoreOS: https://github.com/coreos/bugs/issues/2572

Стефан Кляйн
источник
Открытые сокеты - это возникающая проблема, а не корневая проблема ИМХО. У меня было такое поведение в системе Linux с устройствами Macvlan (с их собственными Mac-адресами) на устройстве моста. Установка моста в promisc заставила работать устройства macvlan. Я не знаю кореос или лазурь. Проблема в том, что нижележащий уровень не знает о mac-адресах на верхних уровнях.
AndreasM
Спасибо за ваш комментарий! Я понимаю, что большое количество используемых сокетов не является основной причиной, я просто цепляюсь за одну осязаемую вещь, которую я могу назвать ненормальной на машине.
Стефан Кляйн
Привет Стефан. Любые новости? пожалуйста, сообщите 1) включен ли WOL? 2) разрешает ли sysctl -w net.ipv4.route.flush = 1? 3) что такое кеш arp в нерабочем состоянии? в рабочем состоянии?
Массимо

Ответы:

4

Прежде всего, спасибо за очень хорошо написанный вопрос!

Поскольку уровень детализации, который вы описали, очень высок, и вы уже находитесь на уровне GDB, я предполагаю, что мой ответ не будет для вас особенно полезен. Во всяком случае, вот попытка:

  • Предположительно вы уже пробовали что-то подобное ss -aeи lsof -n?
  • Вернет ли dmesgчто-нибудь интересное, когда это произойдет?
  • Вы используете iptables на сервере?
  • Если вы установили случайный режим другим способом, чем tcpdump (скажем, ip link set [interface] promisc on), это также решит проблему?
  • Вы проверили на наличие каких-либо подозрительных процессов, файлов или других странных действий? Подумать только, что, может быть, какой-то незваный неприятный процесс скрывается в тени, прячась за собой, и замолкает всякий раз, когда установлен беспорядочный режим?
  • Если вы оставите tcpdump в фоновом режиме, эта проблема вернется?

Надеюсь, это поможет.

Янне Пиккарайнен
источник
1
Спасибо за ваш ответ! Я действительно собрал выходные данные некоторых команд, на которые вы ссылаетесь. Теперь они также связаны в вопросе ( gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c ). Странно то, что прибудет гораздо меньше сокеты сообщили из ss, lsofа netstatне от «розеток используются» в /proc/net/sockstat. Только общее количество (которое кажется только что прочитанным из этого файла) одинаково. iptablesработает, но не имеет специальных правил (см. суть), я не пробовал сам устанавливать режим смешанного режима или постоянно запускать tcpdump. Сделаем это в следующий раз.
Стефан Кляйн
Я добавил вывод ss -aepiсвоей коллекции выходных данных: gist.github.com/privatwolke/… - К сожалению, dmesg ничего не возвращает, когда это происходит. На самом деле самой последней записи до инцидента 5 дней.
Стефан Кляйн
Добавлен dmesg / journalctl -kвывод.
Стефан Кляйн
Я проверил, что ip link set eth0 promisc onсамо по себе не восстанавливает машину в работоспособное состояние.
Стефан Кляйн
Здравствуйте, Вы смотрели на этот другой вопрос на этом сайте? serverfault.com/questions/614453/… Похоже, это означает, что вы, возможно, исчерпали кэш xfrm4 dest. Вы можете увеличить его с помощью этого параметра ядра: xfrm4_gc_thresh - INTEGER The threshold at which we will start garbage collecting for IPv4 destination cache entries. At twice this value the system will refuse new allocations. насколько я могу судить, он связан с IPsec, который, похоже, здесь тоже не работает.
Педро Перес
0

Это было вызвано ошибкой в ​​драйвере hv_netsvc в ядре Linux. Мы могли бы решить эту проблему с разработчиком Microsoft и смогли применить исправление в апстриме.

Я процитирую здесь сообщение о коммите, так как оно довольно хорошо подводит итог проблемы:

Когда кольцевой буфер почти заполнен из-за сообщений о завершении приема, пакет TX может достигнуть «нижнего водяного знака» и вызвать остановку очереди. Если завершение передачи происходит раньше, чем остановка очереди, пробуждение может быть пропущено.

Этот патч перемещает проверку последнего ожидающего пакета, чтобы охватить как EAGAIN, так и успешные случаи, поэтому очередь будет надежно пробуждена при необходимости.

Для дальнейшего использования, фиксация, исправляющая это, - https://github.com/torvalds/linux/commit/6d9cfab853ca60b2f77b5e4c40443216988cba1f .

Стефан Кляйн
источник