Me he encontrado con un problema extraño en el que un ps -o args -p <pid>comando muy ocasionalmente no puede encontrar el proceso en cuestión, aunque definitivamente se está ejecutando en el servidor en cuestión. Los procesos en cuestión son scripts de reinicio de larga duración utilizados para iniciar algunas aplicaciones Java.
Las ocurrencias "en estado salvaje" de la cuestión siempre parecen ocurrir temprano en la mañana, por lo que hay cierta evidencia de que se ha relacionado con la carga de disco en el servidor en cuestión, porque están muy fuertemente cargados entonces, pero ejecutando el psen pregunta en un bucle cerrado, eventualmente puedo replicar el problema: una vez cada cientos de ejecuciones obtengo un error.
Al ejecutar el siguiente script bash, he logrado generar resultados extraños tanto para una ejecución fallida como exitosa:
while [ $? == 0 ] ; do strace -o fail.out ps -o args -p <pid> >/dev/null ; done ; strace -o good.out ps -o args -p <pid>
Comparando el resultado de fail.outy good.out, puedo ver que la getdentsllamada del sistema en la ejecución que falla de alguna manera devuelve un número mucho menor que el recuento real de procesos en el sistema (del orden de ~ 500 en comparación con ~ 1100)
grep getdents good.out
getdents(5, /* 1174 entries */, 32768) = 32760
getdents(5, /* 31 entries */, 32768) = 992
getdents(5, /* 0 entries */, 32768) = 0
grep getdents fail.out
getdents(5, /* 673 entries */, 32768) = 16728
getdents(5, /* 0 entries */, 32768) = 0
... y esa lista más corta no incluye el pid real en cuestión, por lo que no se encuentra.
Puede ignorar esta sección, los errores ENOTTY se explican por el comentario de dave_thompson a continuación, y no están relacionados
Además, la ejecución fallida obtiene algunos
ENOTTYerrores que no aparecen en la ejecución exitosa. Cerca del comienzo de la salida veoioctl (1, TIOCGWINSZ, 0x7fffe19db310) = -1 ENOTTY (ioctl inapropiado para dispositivo) ioctl (1, TCGETS, 0x7fffe19db280) = -1 ENOTTY (ioctl inapropiado para dispositivo)
Y al final veo un solo
ioctl (1, TCGETS, 0x7fffe19db0d0) = -1 ENOTTY (ioctl inapropiado para el dispositivo)
El error
ioctlal final ocurre justo antes de laspsdevoluciones, pero ocurre después de quepsya ha impreso un conjunto de resultados vacío, por lo que no estoy seguro de si están relacionados. Sé que son consistentes en todos los resultados de strace fallidos que tengo, pero no aparecen en los exitosos.
No tengo absolutamente ninguna idea de por getdentsqué ocasionalmente no encontraría la lista completa de procesos, y ahora he llegado al punto en el que solo voy a aplicar una curita en todo el asunto cambiando el script de control que verifica el script de envoltura en cuestión para llamar por pssegunda vez si falla la primera, pero me interesaría saber si alguien tiene alguna idea de lo que está sucediendo aquí.
El sistema en cuestión ejecuta Kernel 4.16.13-1.el7.elrepo.x86_64 en CentOS 7 y procps-ng versión 3.3.10-17.el7_5.2.x86_64

>/dev/nullen la invocación 'falla' (en el bucle) pero no la invocación 'buena', de ahí la ENOTTY en fd 1.Respuestas:
Considere leer la información que necesita directamente del
/procsistema de archivos en lugar de a través de una herramienta comops. Encontrará la información que busca ("args") dentro del archivo/proc/$pid/cmdline, solo separada por bytes NUL en lugar de espacios.Puede usar esta
sedlínea para obtener los argumentos del proceso$pid:Este comando es equivalente a:
(El uso de
args=inpsomitirá el encabezado).El
sedcomando primero buscará el último byte NUL final y lo reemplazará con una nueva línea, y luego reemplazará todos los demás bytes NUL (separando argumentos individuales) con espacios, finalmente produciendo el mismo formato que está viendops.Con respecto a los procesos de listado en el sistema, lo
pshace enumerando directorios/proc, pero hay condiciones de carrera inherentes a ese procedimiento, ya que los procesos comienzan y salen mientraspsse ejecuta, por lo que lo que obtienes no es realmente una instantánea sino una aproximación. En particular, es posible quepsmuestre procesos que ya han finalizado para el momento en que muestra sus resultados, u omita procesos que se iniciaron mientras se estaba ejecutando (pero que el núcleo no devolvió al enumerar el contenido de/proc).Siempre supuse que si un proceso está allí antes de
pscomenzar y sigue ahí después de que se haya hecho, entonces no se lo perderá, supuse que el núcleo garantizaría que siempre se incluirían, incluso si hay una gran cantidad de otros procesos siendo creado y destruido. Lo que estás describiendo implica que ese no es el caso. Todavía estoy escéptico sobre eso, pero dado que hay condiciones de carrera conocidas en cuanto a cómopsfunciona, supongo que es al menos plausible que la lista de PIDs/procpueda perder una existente debido a esas condiciones de carrera.Sería posible verificar eso comprobando la fuente del kernel de Linux, pero no lo he hecho (todavía), así que realmente no puedo decir con certeza si existe una condición de carrera que fallaría un proceso de larga ejecución, como tú describes.
La otra parte es la forma en que
psfunciona. Incluso si le está pasando un PID único con el-pargumento, sigue enumerando todos los PID existentes, aunque solo esté interesado en ese único. Definitivamente, podría tomar un atajo en ese caso y omitir la lista de las entradas/proce ir directamente a/proc/$pid.No puedo decir por qué se implementó de esta manera. Quizás porque la mayoría de las
psopciones son "filtros" en los procesos, por lo que implementarlo de-pla misma manera fue más fácil, tomar un atajo para ir directamente/proc/$pidpodría involucrar una ruta de código separada o duplicación de código ... Otra hipótesis es que algunos casos que incluyen-pmás opciones adicionales terminan requiriendo una lista, por lo que quizás sea complejo determinar qué casos exactos permitirían tomar el acceso directo y cuáles no.Lo que nos lleva a la solución alternativa, yendo directamente
/proc/$pid, sin enumerar el conjunto completo de PID del sistema, evitando todas las razas conocidas y simplemente obteniendo la información que necesita directamente de la fuente.Es un poco feo, pero el problema que describe realmente existe, debería ser una forma confiable de obtener esa información.
fuente