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