Planteamiento y roles aplicables
Un servicio de API en Linux se ejecuta bajo tráfico constante durante varias horas y luego comienza a rechazar nuevas conexiones. Las llamadas a servicios upstream y los intentos de abrir archivos de registro también empiezan a fallar. Sabes que:
- el proceso del servicio tiene un
RLIMIT_NOFILEsoft de 8,192 y un límite hard de 65,536; - inicia con unos 400 file descriptors abiertos y luego crece aproximadamente 25 por minuto;
- justo antes del incidente,
/proc/<pid>/fdcontiene cerca de 8,192 entradas y los registros contienenEMFILE: Too many open files; - reiniciar el proceso restablece el servicio de inmediato, pero el crecimiento reaparece;
- el
/proc/sys/fs/file-nrdel host permanece muy por debajo de/proc/sys/fs/file-max.
Explica la relación entre un file descriptor, la tabla de file descriptors del proceso y una open file description. Explica por qué los archivos regulares, sockets, pipes y epoll consumen descriptores, y distingue EMFILE de ENFILE. Luego, proporciona una secuencia de diagnóstico segura para producción, decide si se trata de una fuga de FD o de concurrencia legítima que excede la capacidad, propone mitigaciones y soluciones definitivas, y explica cómo demostrarías que el incidente está resuelto.
Esta pregunta es adecuada para entrevistas de backend, SRE, infraestructura, sistemas e ingeniería de software general. Los valores 8,192, 65,536, 400 y 25 por minuto son datos hipotéticos de entrevista, no recomendaciones universales. Una respuesta real también debe tener en cuenta el administrador de servicios, el runtime de contenedores, los permisos del proceso y el modelo de concurrencia de la aplicación.
Qué está evaluando el entrevistador
Primero, ¿puede el candidato explicar que un file descriptor es un índice entero pequeño dentro de un proceso, y no la ruta, el inodo o el objeto del kernel en sí? Una respuesta sólida dibuja la cadena “tabla de FD del proceso → open file description → archivo, socket, pipe u otro objeto” y sabe que los descriptores creados mediante dup o heredados a través de fork pueden hacer referencia a la misma open file description.
Segundo, ¿puede el candidato separar los alcances de los límites? EMFILE significa que el proceso actual alcanzó RLIMIT_NOFILE; ENFILE significa que se alcanzó el límite de archivos abiertos a nivel de todo el sistema. Ni fs.file-max por sí solo ni ulimit -n en una shell no relacionada prueban el límite efectivo del proceso que falla.
Tercero, ¿el diagnóstico cubre conteo, composición y tendencia? Una sola captura de lsof solo muestra un instante. Determinar una fuga requiere muestrear el total y los tipos de objetos bajo tráfico estable, para luego correlacionar el crecimiento con pools de conexiones, ciclos de vida de solicitudes, rotación de logs, procesos secundarios y rutas de error.
Cuarto, ¿puede el candidato separar la capacidad temporal de la corrección de la causa raíz? Aumentar un límite puede abrir una ventana de respuesta al incidente o ser parte de una planificación de capacidad válida, pero no cierra recursos cuya propiedad se perdió. Una pendiente positiva fija eventualmente consumirá también el límite mayor.
Finalmente, ¿existe un ciclo de verificación? “El error dejó de ocurrir” no es suficiente. Una respuesta sólida valida la utilización y pendiente de FDs, tipos de objetos, errores en solicitudes, latencia de cola (tail latency), estado de los pools y eventos de ciclo de vida repetidos bajo el tráfico pico objetivo y fallas inyectadas.
Preguntas a aclarar antes de responder
- ¿Cuál es el errno exacto? Confirma
EMFILEoENFILEa partir del error de la aplicación o de la llamada al sistema, en lugar de inferir el alcance a partir del mensaje legible para humanos. - ¿Qué PID está fallando? Un supervisor, worker, sidecar y proceso secundario de corta duración pueden heredar límites distintos y retener recursos diferentes.
- ¿Qué inicia el servicio? Una shell interactiva, systemd, un runtime de contenedores y un administrador de procesos pueden establecer diferentes límites soft y hard. Un comando en la shell no puede cambiar retroactivamente un servicio en ejecución.
- ¿Qué se mueve a la par del crecimiento de FDs? Alínealo con conexiones concurrentes, solicitudes upstream, profundidad de colas, rotación de logs, recargas, cantidad de procesos hijos y tasa de errores.
- ¿Qué tipo de objeto está creciendo? Sockets, archivos regulares, pipes,
anon_inode:[eventpoll], objetos inotify y archivos eliminados apuntan a diferentes rutas de propiedad. - ¿Cuál es el modelo de capacidad legítimo? Un proxy de alta concurrencia puede necesitar legítimamente muchos sockets. Un conteo elevado no es automáticamente una fuga; debe coincidir con la concurrencia configurada y estabilizarse cuando la carga disminuye.
- ¿Se puede inspeccionar
/procde forma segura? Leer los descriptores de otro usuario puede estar restringido por permisos y reglas de ptrace. La investigación en producción debe utilizar el privilegio mínimo necesario y evitar un rastreo prolongado de alto overhead.
Respuesta de 30 segundos
“Un file descriptor es un índice entero no negativo en la tabla de FD de un proceso. La entrada de la tabla hace referencia a una open file description a nivel de sistema, que almacena el offset del archivo y los flags de estado, y a su vez apunta a un archivo regular, socket, pipe u otro objeto de E/S del kernel. EMFILE significa que este proceso alcanzó RLIMIT_NOFILE; ENFILE significa que el host alcanzó su límite de archivos abiertos a nivel de todo el sistema.
Confirmaría el PID que falla y el errno, leería /proc/<pid>/limits, contaría y clasificaría /proc/<pid>/fd, muestrearía las categorías a lo largo del tiempo y revisaría /proc/sys/fs/file-nr. Una pendiente positiva fija bajo tráfico constante, que se reinicia con el reinicio del servicio y se concentra en un tipo de objeto, indica una fuga. Un conteo que sigue la concurrencia, alcanza una meseta definida y cae después indica presión de capacidad. Puedo aplicar rate-limiting, reiniciar instancias de forma escalonada y aumentar el límite real del servicio tras validar la capacidad, pero la solución duradera radica en la propiedad de recursos, limpieza en rutas de falla, pools delimitados y herencia correcta. Lo demuestro con la utilización y pendiente de FDs, la liberación de objetos y cero errores relacionados en carga pico.”
Análisis paso a paso a profundidad
Paso 1: Construir el modelo de referencia de tres capas
En caso de éxito, open() devuelve un entero no negativo. Linux normalmente selecciona el número de descriptor más bajo que el proceso no esté utilizando en ese momento. Por convención, 0, 1 y 2 son la entrada estándar, salida estándar y error estándar. Los números posteriores siguen siendo solo índices en ese proceso.
La relación central es:
process FD-table entry → open file description → underlying object
Las capas mantienen estados distintos:
| Capa | Qué contiene | Propiedad importante |
|---|---|---|
| Entrada en la tabla de FD del proceso | Número de descriptor y flags del descriptor como close-on-exec | El número solo tiene significado en el contexto de la tabla de FD de ese proceso |
| Open file description | Offset actual del archivo y flags de estado de archivo abierto | Un objeto a nivel de sistema que múltiples descriptores pueden compartir |
| Objeto subyacente | Inodo, socket, pipe, dispositivo u objeto anónimo del kernel | Define el comportamiento real de E/S |
Dos llamadas independientes a open() sobre la misma ruta normalmente crean open file descriptions separadas. Un descriptor devuelto por dup() hace referencia a la misma open file description, por lo que ambos descriptores comparten el offset y los flags de estado del archivo. Después de fork(), los descriptores correspondientes del padre y del hijo también hacen referencia a las mismas open file descriptions. Los flags específicos del descriptor, como close-on-exec, están separados de ese estado compartido.
Por esto, “FD 42” no tiene un significado estable entre procesos y agrupar solo por ruta puede ocultar el problema. La misma ruta puede abrirse independientemente muchas veces, mientras que diferentes números de descriptores pueden compartir un único estado abierto.
Paso 2: Comprender qué recursos consumen descriptores
Las interfaces tipo Unix exponen muchos recursos de E/S mediante descriptores legibles, escribibles o en los que se puede esperar:
- archivos regulares y directorios;
- sockets TCP, UDP y de dominio Unix;
- pipes anónimos y FIFOs con nombre;
- terminales, dispositivos y algunos pseudoarchivos;
- objetos anónimos del kernel como
epoll,eventfd,timerfd,signalfde inotify.
/proc/<pid>/fd contiene un enlace simbólico por cada descriptor abierto en el proceso. Un archivo regular suele mostrar una ruta. Los sockets y pipes suelen aparecer como socket:[inode] y pipe:[inode]. Los objetos sin un inodo correspondiente pueden aparecer como anon_inode:[eventpoll] u otro tipo de anon_inode.
Crear un descriptor epoll para un event loop no significa que miles de conexiones monitoreadas dejen de consumir descriptores. Cada socket monitoreado sigue teniendo su propio FD. Por el contrario, unas pocas entradas de anon_inode:[eventpoll] no prueban por sí solas una fuga en el event loop; identifica la categoría cuyo conteo realmente está creciendo.
Paso 3: Separar EMFILE, ENFILE y los techos de límites
RLIMIT_NOFILE tiene un límite soft y un límite hard. El kernel aplica el límite soft. El límite hard es el techo hasta el cual un proceso sin privilegios puede elevar el límite soft. Linux define el valor como uno más que el número de descriptor más alto que el proceso puede abrir.
Los límites principales son:
| Señal | Significado | Primera evidencia a inspeccionar |
|---|---|---|
EMFILE | Este proceso alcanzó RLIMIT_NOFILE | /proc/<pid>/limits y /proc/<pid>/fd |
ENFILE | El host alcanzó el límite de archivos abiertos a nivel de todo el sistema | /proc/sys/fs/file-nr, file-max y registros del kernel |
/proc/sys/fs/nr_open | Techo del kernel para aumentar RLIMIT_NOFILE | Verificar cuando falla el aumento del límite hard |
El primer campo en /proc/sys/fs/file-nr es el número de file handles asignados; el tercero corresponde a file-max. Este es un conteo de open file descriptions a nivel de sistema, por lo que no tiene que ser igual a la suma del conteo de FDs de cada proceso: múltiples descriptores pueden compartir una open file description.
El enunciado reporta explícitamente EMFILE, mientras que el uso en todo el sistema permanece muy por debajo de file-max. Por lo tanto, la vía principal es un límite por proceso. Modificar fs.file-max no resuelve este fallo.
Paso 4: Recopilar primero evidencia comparable y de bajo riesgo
Tras confirmar el PID y los permisos, comienza con una captura de bajo overhead de /proc:
pid=12345
grep 'Max open files' /proc/"$pid"/limits
find /proc/"$pid"/fd -maxdepth 1 -type l 2>/dev/null | wc -l
find /proc/"$pid"/fd -maxdepth 1 -type l -exec readlink {} \; 2>/dev/null |
sed -E 's/socket:\[[0-9]+\]/socket:[id]/; s/pipe:\[[0-9]+\]/pipe:[id]/' |
sort | uniq -c | sort -nr | head -20
cat /proc/sys/fs/file-nr
cat /proc/sys/fs/file-max/proc es una vista en vivo. El proceso puede abrir o cerrar descriptores durante el recorrido, y las entradas de corta duración pueden desaparecer. Trata estos comandos como diagnósticos de tendencia, no como una auditoría atómica. Muestrea totales y categorías a intervalos fijos con marcas de tiempo, y luego alinéalos con las métricas de la aplicación.
Si los sockets dominan el incremento, inspecciona la dirección de la conexión, el destino y el estado de TCP. Si crecen los archivos regulares, agrupa las rutas alrededor de logs, archivos temporales o recargas de configuración. Si crecen los pipes, inspecciona procesos secundarios y ciclos de vida de IPC. Si crecen los objetos anon_inode, localiza el registro y liberación en event loops, watchers o temporizadores.
Herramientas como lsof -p <pid>, ss -tanp o un rastreo acotado de llamadas al sistema pueden aportar detalle después de que /proc y las métricas de la aplicación reduzcan la búsqueda. El rastreo prolongado puede añadir overhead en producción y seguir siendo incompleto sin los permisos suficientes.
Paso 5: Usar conteo, composición, pendiente y recuperación para clasificar el problema
Un conteo actual elevado por sí solo no demuestra una fuga. Haz cuatro preguntas:
- ¿El conteo coincide con la concurrencia esperada? El presupuesto incluye sockets en escucha, conexiones aceptadas, pools salientes, archivos, pipes, objetos de eventos y margen de seguridad.
- ¿La composición coincide con la arquitectura? Si un pool hacia un upstream tiene un tope de 500 pero los descriptores hacia ese destino llegan a 5,000, investiga las rutas de retorno y cierre.
- ¿La pendiente se mantiene positiva bajo carga estable? Si la tasa de solicitudes y la concurrencia son planas pero los FDs siguen creciendo a 25 por minuto, la evidencia de una fuga es contundente.
- ¿El uso vuelve a una meseta cuando la carga cae? Los archivos con alcance de solicitud, conexiones cortas y pipes temporales deben liberarse. Las conexiones de pools de larga duración pueden mantenerse, pero dentro de un límite explícito.
En el planteamiento, el servicio inicia alrededor de 400, crece a una tasa fija, se restablece con el reinicio y se repite. Ese patrón apunta fuertemente a una fuga. Aún se requiere clasificar los objetos para no confundir el calentamiento natural de un pool de conexiones con un archivo no cerrado.
La capacidad insuficiente suele verse diferente: el uso sigue a la concurrencia, alcanza una meseta cerca de los límites configurados de pools y conexiones, y cae después de que la carga o los timeouts disminuyen. La mezcla de objetos coincide con el diseño y la falla solo aparece cuando la demanda pico legítima supera el presupuesto original. Aumentar límites, añadir procesos o reducir el costo por conexión pueden ser entonces cambios de capacidad duraderos.
Paso 6: Rastrear la propiedad de los recursos a través de rutas de fuga comunes
Una respuesta sólida pregunta “¿quién lo crea, quién es su dueño y quién lo cierra tras una falla?” en lugar de quedarse solo en comandos. Las causas comunes incluyen:
- un cliente HTTP no cierra el cuerpo de la respuesta, por lo que la conexión no puede reutilizarse ni liberarse a tiempo;
- una conexión a base de datos, caché o upstream se extrae pero no se devuelve tras un timeout o excepción;
- la rotación de logs o la recarga de configuración abre repetidamente un archivo nuevo sin cerrar el handle anterior;
- cada solicitud crea un temporizador, watcher, pipe u objeto de evento pero la cancelación omite la limpieza;
- los procesos padre e hijo mantienen abiertos extremos no utilizados de flujos estándar o pipes IPC;
- un descriptor sobrevive inesperadamente a
exec, por lo que otro proceso mantiene vivo un recurso; - la lógica de reintento crea una nueva conexión mientras el intento anterior sigue pendiente.
Haz que la propiedad del ciclo de vida sea visible en la estructura del código. Utiliza defer, finally, RAII o la gestión de recursos con alcance del framework. Establece la limpieza inmediatamente después de la adquisición. Delimita pools, concurrencia, colas y reintentos. Enruta las vías de cancelación, timeout y retorno temprano a través de la misma lógica de limpieza.
En un programa multihilo, llamar a open() y configurar FD_CLOEXEC en una operación posterior crea una ventana en la que otro hilo puede ejecutar fork y exec. Donde esté soportado, configura O_CLOEXEC de forma atómica al momento de la creación. Eso evita una condición de carrera en la herencia; no reemplaza la propiedad ordinaria de close().
Paso 7: Separar la mitigación del incidente de la solución definitiva
Dependiendo del riesgo, la mitigación del incidente puede incluir:
- aplicar rate-limiting al trabajo entrante o reducir la concurrencia por instancia antes de que el proceso pierda la capacidad de abrir logs, conexiones de control y archivos de configuración;
- reiniciar de forma escalonada (rolling restart) las instancias con fugas preservando al menos una muestra para diagnóstico y evitando un reinicio simultáneo;
- aumentar los límites soft y hard reales del proceso del servicio tras verificar memoria, overhead del kernel y capacidad downstream;
- añadir instancias para que la concurrencia legítima se distribuya entre más procesos.
Cambiar ulimit -n en la terminal actual no afecta a un servicio que ya se encuentra en ejecución. Modifica el administrador de servicios, contenedor o runtime que crea realmente el proceso, reinícialo y verifica /proc/<new-pid>/limits. Editar un archivo de configuración por sí solo no es prueba de que el nuevo límite esté activo.
La solución definitiva debe apuntar al objeto confirmado en crecimiento: completar rutas de cierre, delimitar pools y concurrencia, reparar ciclos de vida de rotación o watchers, establecer timeouts adecuados, evitar la herencia no deseada y exponer conteos actuales más contadores de creación/liberación para las principales categorías de recursos.
Paso 8: Demostrar la solución con un presupuesto de capacidad y pendiente
Crea un presupuesto de FDs por instancia:
baseline FDs + peak inbound connections + peak outbound connections + pools and files + IPC/event objects + safety headroom
El presupuesto debe derivar de la arquitectura real y de pruebas de carga. No existe un porcentaje de utilización universal para todos los servicios. El límite también debe reservar espacio para diagnósticos, health checks, registros y conexiones de control durante un incidente.
La verificación debe cubrir al menos:
- bajo el tráfico pico objetivo y fallas inyectadas, el uso total de FDs sube hasta una meseta estable;
- tras la caída de la carga y la expiración de timeouts, los descriptores de corta duración regresan a la línea base esperada;
- el tipo de objeto que antes crecía ya no tiene una pendiente positiva persistente;
EMFILE,ENFILE, fallas de conexión y fallas al abrir archivos se mantienen en cero;- el p95/p99 de solicitudes, el tiempo de espera en pools y el volumen de reintentos no empeoran debido a límites excesivamente agresivos;
- despliegues repetidos, rotaciones de logs, recargas de configuración y lanzamientos de procesos secundarios no generan un crecimiento en escalera;
- el monitoreo incluye
process_open_fds,process_max_fds, utilización, tasa de crecimiento y principales pools de objetos.
“Una prueba de carga de diez minutos pasó con éxito” puede pasar por alto una fuga lenta. Ejecútala el tiempo suficiente para cubrir la cantidad de crecimiento que causó el incidente original, o amplifica la ruta sospechosa y demuestra que los contadores de creación y liberación se equilibran.
Ejemplo de respuesta sólida
“Primero confirmaría que el errno sea EMFILE y que el worker de la API sea el que está fallando. Un file descriptor es un índice no negativo en la tabla de FD del proceso. La entrada de la tabla hace referencia a una open file description a nivel de sistema, que almacena el offset y los flags de estado del archivo y luego apunta a un archivo regular, socket, pipe u objeto anónimo del kernel. dup y fork pueden hacer que múltiples descriptores compartan una misma open file description, por lo que el conteo de FDs del proceso y el conteo de file handles a nivel de sistema son métricas diferentes.
EMFILE significa que este proceso alcanzó RLIMIT_NOFILE; ENFILE significa que el host alcanzó file-max. Aquí, el límite soft es 8,192, el conteo previo al incidente está cerca de ese valor y file-nr está muy por debajo de file-max, por lo que cambiar el límite del sistema no es la acción adecuada.
Leería /proc/<pid>/limits y luego muestrearía el conteo y los destinos de los enlaces simbólicos en /proc/<pid>/fd, agrupados en sockets, pipes, archivos regulares y objetos anon_inode. Alinearía la pendiente de cada categoría con conexiones entrantes, pools hacia upstreams, rotación de archivos, procesos secundarios y errores. Iniciar cerca de 400 y crecer 25 por minuto bajo tráfico estable, reiniciándose tras el restart, sugiere fuertemente una fuga. Si predominan los sockets hacia un upstream, inspeccionaría el cierre de cuerpos de respuesta, cancelación de timeouts y rutas de retorno al pool en lugar de asumir que cada conexión refleja tráfico válido.
Para mitigar, aplicaría rate-limiting y reiniciaría instancias de forma escalonada preservando una muestra para diagnóstico. Si el análisis de capacidad lo permite, puedo aumentar temporalmente el límite en el administrador de servicios real o en la configuración del contenedor, pero debo verificar el /proc/<pid>/limits del nuevo proceso. La solución duradera hace que la propiedad de recursos y la limpieza sean estructurales, delimita pools, reintentos, temporizadores y watchers, y evita la herencia involuntaria con close-on-exec.
Verificaría bajo carga pico objetivo y rutas de falla. El uso de FDs debería alcanzar la meseta planificada y volver a la línea base al caer la carga. La categoría que antes crecía debe dejar de acumularse, EMFILE debe permanecer en cero y la latencia de cola y esperas en pools no deben degradarse. Esos resultados demuestran una solución; un reinicio o un límite mayor solo demuestran que el agotamiento se pospuso.”
Errores comunes
- Tratar un FD como una ruta o inodo → es un índice en una tabla de proceso → explica la tabla de FD, open file description y el objeto subyacente.
- Asumir que solo los archivos de disco consumen FDs → sockets, pipes,
epoll, temporizadores y watchers también los usan → clasifica los destinos en/proc/<pid>/fd. - Modificar
fs.file-maxante cualquier error Too many open files →EMFILEyENFILEtienen alcances diferentes → confirma primero el errno y el PID que falla. - Usar el
ulimit -nde la shell actual como el límite del servicio → el servicio en ejecución puede haber sido iniciado en otro entorno → lee/proc/<pid>/limits. - Declarar una fuga solo porque el conteo es alto → una concurrencia alta y válida puede generar una meseta elevada → compara el modelo de capacidad, la mezcla de tipos, la pendiente y la recuperación tras la carga.
- Limitarse a aumentar de 8,192 a 65,536 → una pendiente fija de fuga consumirá también el nuevo límite → trata el aumento como capacidad validada o margen temporal.
- Revisar únicamente la ruta de retorno normal → timeouts, cancelaciones, reintentos y retornos tempranos suelen omitir la limpieza → define creador, dueño y limpieza en rutas de falla para cada recurso.
- Usar una sola captura de
lsof→ una captura no puede demostrar acumulación → muestrea a intervalos fijos y correlaciona con la carga de trabajo y pools. - Aceptar la desaparición temporal del error → reiniciar y elevar límites pueden retrasar la reaparición → verifica tipo de objeto, pendiente, recuperación y eventos repetidos de ciclo de vida.
Preguntas de seguimiento
Pregunta de seguimiento 1: ¿Por qué ulimit -n muestra 65,536 mientras el servicio sigue fallando en 8,192?
ulimit normalmente reporta la shell actual y afecta a los descendientes creados a partir de ese momento. Un servicio ya iniciado por systemd, un runtime de contenedores u otro administrador de procesos no se modifica retroactivamente. Un supervisor y sus workers también pueden tener configuraciones distintas. Lee /proc/<pid>/limits del PID que falla, actualiza el entorno real de lanzamiento y verifica el nuevo PID.
Pregunta de seguimiento 2: ¿Por qué dos descriptores para el mismo archivo pueden afectar la posición de lectura del otro?
Si provienen de dup, o del mismo descriptor antes de fork, hacen referencia a la misma open file description y por lo tanto comparten el offset y los flags de estado del archivo. Si el programa llama a open() dos veces, la misma ruta normalmente produce dos open file descriptions independientes con offsets independientes. Una ruta compartida no prueba un estado abierto compartido.
Pregunta de seguimiento 3: ¿Por qué un proceso aún puede usar un archivo mediante un FD después de que el archivo fue eliminado?
El descriptor hace referencia a una open file description; la E/S no vuelve a resolver la ruta cada vez. Eliminar la entrada del directorio no invalida las referencias existentes. El objeto subyacente puede permanecer hasta que se cierre la última referencia. La rotación de logs que desvincula (unlink) un archivo antiguo sin hacer que el proceso lo cierre puede consumir tanto un descriptor como espacio en disco.
Pregunta de seguimiento 4: ¿Por qué podría fallar el aumento de RLIMIT_NOFILE a un número muy grande?
Un proceso sin privilegios no puede elevar el límite soft por encima del límite hard ni aumentar libremente su límite hard. Linux también limita RLIMIT_NOFILE mediante /proc/sys/fs/nr_open. Un administrador de servicios, contenedor o límite de permisos puede añadir restricciones. Revisa errores de inicio y los límites efectivos del nuevo proceso tras cada cambio.
Pregunta de seguimiento 5: Si una sola instancia de epoll observa muchas conexiones, ¿por qué el proceso aún puede agotar los FDs?
La propia instancia de epoll consume un FD y aparece como anon_inode:[eventpoll]. Cada socket monitoreado sigue siendo un FD separado. epoll hace eficiente la espera sobre muchas conexiones; no combina miles de sockets en un solo descriptor ni los cierra en lugar de la aplicación.
Pregunta de seguimiento 6: ¿Cómo alertarías sobre el uso de FDs?
Monitorea los descriptores abiertos actuales, el máximo del proceso, la utilización y la tasa de crecimiento por instancia. La utilización detecta la cercanía al agotamiento; la pendiente detecta fugas lentas de forma temprana. Los pools de conexiones, archivos y watchers también deben exponer sus propios conteos actuales. Establece umbrales a partir de presupuestos pico, tiempo de escalado y tiempo de reacción ante incidentes en lugar de copiar un porcentaje universal.