¿Monitorear eficientemente el número de Open FD por proceso?

¿Monitorear eficientemente el número de Open FD por proceso?

Quiero poder monitorear la cantidad de archivos abiertos en Linux. Actualmente estoy contando la cantidad de archivos en /proc/<pid>/fdy fdinfo.

Mi balanceador de carga tiene alrededor de un millón de FD. Entonces esto termina tardando unos 20 segundos en realizarse.

Sin embargo, esto da como resultado un uso elevado de la CPU:47.18% [kernel] [k] __d_lookup

¿Existe una forma más eficiente de obtener este número?

Respuesta1

Para un balanceador de carga dedicado, realizaría un seguimiento del total de archivos abiertos en el sistema, en lugar de desperdiciar recursos de E/S y CPU contándolos por proceso. Los archivos abiertos restantes por procesos no deseados no deberían tener ningún valor para el resultado deseado.

Para conocer los archivos abiertos globalmente por el sistema Linux, no es necesario contarlos; El kernel de Linux realiza un seguimiento de cuántos archivos tiene abiertos.

Para saber eso, ejecute:

cat /proc/sys/fs/file-nr | awk ' { print $1 } '

o

sysctl fs.file-nr | awk ' { print $1 } '

Esto es mucho más eficiente que contar todos los archivos abiertos con la salida de lsof, que viajarán por todos /proc/$PID/fdlos directorios y afectarán negativamente los recursos de E/S/CPU de su sistema.

Respuesta2

Lo simple:

lsof | wc -l

le dirá la cantidad de archivos abiertos en el sistema.

Respuesta3

¿Qué tan eficiente es este código SystemTap para su caso de uso? No es una vista perfecta ya que solo rastrea los cambios desde el inicio (por lo que todo lo que se haya abierto antes del inicio se perderá) y necesitará trabajo adicional para que la salida sea más legible o adecuada.

global procfdcount

probe begin {
    printf("begin trace...\n\n")
}

probe syscall.open {
    procfdcount[pid()]++
}

probe syscall.close {
    p = pid()
    procfdcount[p]--
    if (procfdcount[p] < 0) {
        procfdcount[p] = 0
    }
}

probe kprocess.exit {
    p = pid()
    if (p in procfdcount) {
        delete procfdcount[p]
    }
}

probe timer.s(60) {
    foreach (p in procfdcount- limit 20) {
        printf("%d %lu\n", p, procfdcount[p])
    }
    printf("\n")
}

Ejecute a través de algo como:

... (install systemtap here) ...
# stap-prep
... (fix any reported systemtap issues here) ...
# stap procfdcount.stp

La desventaja de este método es la necesidad de identificar todos los "archivos abiertos" (sockets, etc.) y luego ajustar el recuento mediante los ganchos de llamada del sistema apropiados (si están disponibles); lo anterior solo rastrea archivos de archivos. Otra opción sería solicitar task_open_file_handlestareas que lleguen a la CPU y mostrar periódicamente los recuentos más recientes.

global taskopenfh

probe begin {
    printf("begin trace...\n\n");
}

probe scheduler.cpu_on {
    p = pid();
    if (p == 0) next;
    taskopenfh[p] = task_open_file_handles(pid2task(p));
}

probe timer.s(60) {
    foreach (p in taskopenfh-) {
        printf("%d %lu\n", p, taskopenfh[p]);
    }
    delete taskopenfh;
    printf("\n");
}

Sin embargo, esto perdería todo lo que no estuviera en la CPU; Sería necesario realizar un recorrido completo de los procesos y luego de las tareas para obtener una lista completa, aunque eso podría ser demasiado lento o demasiado costoso si tiene millones de FD.

Además, estas sondas no parecen ser estables, entonces ¿tal vez eBPF o algo así en el futuro? Por ejemplo, el segundo en Centos 7 explota después de un tiempo.

ERROR: read fault [man error::fault] at 0x0000000000000008 (((&(fs->fdt))))
near identifier 'task_open_file_handles' at
/usr/share/systemtap/tapset/linux/task.stp:602:10

información relacionada