Hoy tengo un misterio para ti. Ejecutamos un pequeño clúster Elasticsearch de tres nodos basado en CoreOS (2023.5.0 / Linux 4.19.25-coreos) en Azure. Elasticsearch se ejecuta dentro de un contenedor acoplable en modo de red host. Después de ejecutar casi sin mantenimiento durante más de un año, hemos visto cómo las máquinas entran en un estado muy interesante.
Actualizar
Este problema se resolvió mediante una solución a un controlador en el kernel de Linux . Ver la respuesta a continuación.
Síntomas
Básicamente, la red entre la máquina afectada y los otros dos nodos muere. Todos están en la misma red virtual y la misma subred y pueden comunicarse habitualmente con otros. Todavía se puede llegar al nodo afectado desde otras subredes (puedo ingresar en él) y desde una red virtual diferente. La máquina también tiene una conexión (muy irregular) a Internet, pero la mayoría de las solicitudes solo tienen tiempo de espera.
Hemos observado que en un nodo afectado, el número de "sockets utilizados" reportados /proc/net/sockstat
es muy alto (~ 4.5k en lugar de ~ 300 en un nodo sano). El monitoreo muestra que este número aumenta rápidamente desde el momento en que el nodo deja de estar disponible.
Lo divertido es que parece que no podemos identificar la fuente de estos enchufes usados:
# 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
Aparte de eso, la máquina parece estar bien. No hay procesos sospechosos en ejecución, el uso de la CPU es mínimo y hay mucha memoria disponible.
Hacer ping a una máquina virtual "inalcanzable" en la misma subred da como resultado algunas EAGAIN
respuestas recvmsg
y luego se cruza para ENOBUFS
regresar sendmsg
. strace salida de ping aquí
Recopilé algunos resultados adicionales (antes de que se hicieran modificaciones al sistema) y los publiqué en este resumen: https://gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c
Análisis
Intentamos apagar todo lo que se nos ocurre en el servidor, siendo Elasticsearch el primer sospechoso. Pero cerrar el contenedor de búsqueda elástica no libera los enchufes usados. Lo mismo para todos los procesos relacionados con CoreOS (motor de actualización, cerrajero, ...) o incluso todo el tiempo de ejecución de Docker o cosas específicas de Azure. Nada parecía ayudar.
Pero ahora se vuelve aún más extraño: intentamos correr tcpdump
en la máquina para ver qué está pasando. Y he aquí: el problema se resolvió solo, se restableció la conectividad. Nuestra teoría era que tcpdump realiza algún tipo de syscall que lo resuelve. Ejecutamos tcpdump con gdb y establecimos puntos de interrupción en todas las llamadas al sistema. Después de pasar por un montón de puntos de interrupción, finalmente descubrimos que el acto de establecer el modo promisorio en el socket de captura (específicamente esta línea en libpcap ) es lo que restablece el contador de sockets usados y nos devuelve a un estado normal.
Hallazgos adicionales
- Hemos verificado que la ejecución
tcpdump
con el-p/--no-promiscuous-mode
indicador no borra los contadores de sockets usados y devuelve la máquina a un estado utilizable. - La ejecución
ifconfig eth0 txqueuelen 1001
restablece el contador de sockets utilizados, pero la conectividad no se restaura. - Establecer el modo de promisc manualmente con
ip link set eth0 promisc on
tampoco restaura la conectividad.net.ipv4.xfrm4_gc_thresh
está configurado en 32768 y aumentarlo ligeramente no resuelve el problema.
Hemos estado en contacto con Azure, que estamos tan desconcertados como nosotros. Entiendo que probablemente este no sea el problema, sino solo un síntoma. Pero es lo único tangible que encontré hasta ahora. Mi esperanza es que al comprender el síntoma pueda acercarme a la causa raíz. Las interfaces de red en Azure se ejecutan con este controlador de red .
Tal vez CoreOS / Kernel es el culpable?
Desde el punto de vista de la línea de tiempo, los problemas comenzaron el 2019-03-11, que es el día en que CoreOS se actualizó automáticamente a la última versión. De acuerdo con las notas de la versión , esta actualización contenía una actualización del kernel de 4.15.23 a 4.19.25 . Todavía estoy revisando los registros de cambios para ver si algo podría ser un problema allí. Hasta ahora solo he descubierto que el controlador de red Hyperv ha recibido bastantes actualizaciones en los últimos meses , y no todas parecen ser parte de 4.19.25. El conjunto de parches que CoreOS aplicó a 4.19.25 no es tan impresionante , pero el parche que introduce un módulo falso nf_conntrack_ipv4 es nuevo.
Actualización: ¿ Posible parche de kernel entrante relacionado?
¡Ayuda!
Hasta ahora, las preguntas que tenemos son las siguientes:
¿Qué podría causar que esta métrica de "enchufes usados" se dispare? He leído las fuentes del kernel para esta métrica y parece ser solo un contador sin referencia a qué tipo de sockets son realmente o qué los creó.
¿Por qué el número es plano en aproximadamente 4.5k? ¿Qué límite estaría causando esto?
¿Cambió algo significativo entre el kernel 4.14.96 y 4.19.25?
¿Por qué la
setsockopt()
llamada en libpcap restablece el estado?
Error relacionado de CoreOS: https://github.com/coreos/bugs/issues/2572
fuente
Respuestas:
Antes que nada, ¡gracias por una pregunta muy bien escrita!
Como el nivel de detalle que describió es muy alto y ya está en el nivel de gdb, supongo que mi respuesta no será de mucha utilidad para usted. De todos modos, aquí hay un intento:
ss -ae
ylsof -n
?dmesg
Devuelve algo interesante cuando esto sucede?ip link set [interface] promisc on
), ¿esto también soluciona el problema?Espero que esto ayude.
fuente
ss
,lsof
ynetstat
desde "sockets utilizados" en/proc/net/sockstat
. Solo el recuento total (que parece leerse de ese archivo) es el mismo.iptables
se ejecuta pero no tiene reglas especiales (vea lo esencial), no he intentado configurar el modo promisorio yo mismo o ejecutar tcpdump continuamente. Lo haré la próxima vez.ss -aepi
mi colección de resultados: gist.github.com/privatwolke/… - Lamentablemente, dmesg no devuelve exactamente nada cuando esto sucede. De hecho, la última entrada antes del incidente tiene 5 días.dmesg / journalctl -k
Salida agregada .ip link set eth0 promisc on
solo no restaura la máquina a un estado utilizable.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.
Hasta donde puedo decir, está relacionado con IPsec, que tampoco parece estar ejecutando aquí.Esto fue causado por un error en el controlador hv_netsvc en el kernel de Linux. Podríamos resolver esto con un desarrollador de Microsoft y logramos aplicar la solución en sentido ascendente.
Citaré el mensaje de confirmación aquí, ya que resume el problema bastante bien:
Para referencia futura, la confirmación que corrige esto es https://github.com/torvalds/linux/commit/6d9cfab853ca60b2f77b5e4c40443216988cba1f .
fuente