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

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

Обновление

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

Симптомы

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

Мы наблюдали, что на затронутом узле количество «используемых сокетов» сообщается в / proc / net / sockstat очень высокий (~ 4,5 КБ вместо ~ 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

Кроме того, машина выглядит нормально. Нет никаких запущенных подозрительных процессов, загрузка ЦП минимальна, а доступной памяти достаточно.

Пинг «недоступной» виртуальной машины в той же подсети приводит к нескольким ответам EAGAIN на recvmsg , а затем переход к получению ENOBUFS обратно от ] sendmsg . вывод команды strace ping здесь

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

Анализ

Мы попытались отключить все, что мы могли придумать на сервере, первыми подозреваемыми были elasticsearch. Но закрытие контейнера elasticsearch не освобождает используемые сокеты. То же самое для всех процессов, связанных с 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 на также не восстанавливает соединение.
    • net.ipv4.xfrm4_gc_thresh имеет значение 32768, и его небольшое увеличение не решает проблему.

sockets used

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

Может быть, виноват CoreOS / Kernel?

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

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

Справка !

На данный момент у нас есть следующие вопросы:

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

  • Почему число ровно на уровне около 4.5k? Какой предел может вызвать это?

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

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

Ошибка CoreOS: https://github.com/coreos/bugs/issues/2572

14
задан 21 August 2019 в 15:21
2 ответа

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

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

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

Этот патч перемещает проверку на последний незаконченный пакет для покрытия и EAGAIN и случаев успеха, таким образом, очередь будет надежно разбужена при необходимости.

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

0
ответ дан 2 December 2019 в 21:13

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

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

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

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

4
ответ дан 2 December 2019 в 21:13

Теги

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