У меня для вас есть загадка. Мы запускаем небольшой трехузловой кластер 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
сбрасывает счетчик используемых сокетов , но подключение не восстановлено. ip link set eth0 promisc на
также не восстанавливает соединение.
net.ipv4.xfrm4_gc_thresh
имеет значение 32768, и его небольшое увеличение не решает проблему. Мы связывались с Azure, которые так же озадачены этим, как и мы. Я понимаю, что скорее всего это не проблема, а всего лишь симптом. Но это единственная материальная вещь, которую я пока нашел. Я надеюсь, что, разобравшись в симптоме, я смогу приблизиться к первопричине. Сетевые интерфейсы в Azure работают с этим сетевым драйвером .
С точки зрения временной шкалы, проблемы начались 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
Это было вызвано ошибкой в hv_netsvc драйвере в ядре Linux. Мы могли разрешить это с разработчиком Microsoft и управляемый для получения фиксации, примененной в восходящем направлении.
я заключу сообщение о фиксации в кавычки здесь, поскольку оно подводит итог проблемы вполне хорошо:
, Когда кольцевой буфер почти полон из-за сообщений завершения RX, пакет TX может достигнуть "низкого водяного знака" и вызвать остановленную очередь. Если завершение TX прибывает ранее, чем остановка очереди, пробуждение может быть пропущено.
Этот патч перемещает проверку на последний незаконченный пакет для покрытия и EAGAIN и случаев успеха, таким образом, очередь будет надежно разбужена при необходимости.
Для дальнейшего использования, фиксация, которая фиксирует это, https://github.com/torvalds/linux/commit/6d9cfab853ca60b2f77b5e4c40443216988cba1f.
Прежде всего, спасибо за очень хорошо написанный вопрос!
Поскольку уровень детализации, который вы описали, очень высок, и вы уже находитесь на уровне GDB , Я полагаю, мой ответ не будет вам очень полезен. В любом случае, вот попытка:
ss -ae
и lsof -n
? dmesg
что-нибудь интересное, когда это происходит? ip link set [interface] promisc на
), это тоже решит проблему? Надеюсь, это поможет.