El Sistema de Archivos /proc en Profundidad

El sistema de archivos /proc es un sistema de archivos virtual del kernel Linux que expone información del sistema y de los procesos en ejecución como archivos y directorios. No ocupa espacio real en disco—sus contenidos se generan dinámicamente por el kernel—y sirve como interfaz principal para monitorear el sistema, ajustar parámetros del kernel en tiempo real con sysctl, y diagnosticar problemas de rendimiento y hardware. Esta guía explora en profundidad la estructura y uso de /proc para administración y optimización de sistemas Linux.

Requisitos Previos

  • Cualquier distribución Linux con kernel 3.x o superior
  • Acceso al sistema (algunos archivos requieren root)
  • Conocimientos básicos de la línea de comandos

Estructura de /proc

# Ver la estructura principal de /proc
ls /proc/

# Directorios numerados = información de procesos por PID
ls /proc/ | grep '^[0-9]' | head -10

# Archivos y directorios principales:
# /proc/cpuinfo     - Información del CPU
# /proc/meminfo     - Información de memoria
# /proc/net/        - Estadísticas de red
# /proc/sys/        - Parámetros del kernel (modificables)
# /proc/filesystems - Sistemas de archivos soportados
# /proc/mounts      - Sistemas de archivos montados
# /proc/uptime      - Tiempo de actividad del sistema
# /proc/loadavg     - Carga promedio del sistema
# /proc/version     - Versión del kernel
# /proc/cmdline     - Parámetros del kernel al arrancar

Información de Procesos

Cada proceso en ejecución tiene un directorio /proc/PID/ con su información:

# Ver el PID de un proceso
pidof nginx
PID=$(pidof -s nginx)  # Solo el primer PID

# Estructura de /proc/PID/
ls /proc/$PID/
# cmdline   - Línea de comandos completa con argumentos
# cwd       - Directorio de trabajo actual (enlace simbólico)
# environ   - Variables de entorno
# exe       - Enlace al ejecutable
# fd/       - Descriptores de archivo abiertos
# fdinfo/   - Información detallada de descriptores
# maps      - Mapas de memoria
# mem       - Memoria del proceso
# net/      - Estadísticas de red del proceso
# oom_adj   - Ajuste OOM killer
# oom_score - Puntuación actual del OOM killer
# smaps     - Mapas de memoria detallados
# stat      - Estado del proceso (para programas)
# status    - Estado legible del proceso
# wchan     - Función del kernel donde está esperando

# Ver la línea de comando de un proceso
cat /proc/$PID/cmdline | tr '\0' ' '
# O con xargs
tr '\0' ' ' < /proc/$PID/cmdline

# Ver directorio de trabajo actual de un proceso
readlink /proc/$PID/cwd

# Ver el ejecutable de un proceso
readlink /proc/$PID/exe

# Ver archivos abiertos por un proceso
ls -la /proc/$PID/fd/
# Equivalente a: lsof -p $PID

Estado y Estadísticas de Procesos

# Ver estado legible del proceso
cat /proc/$PID/status

# Información clave en /proc/PID/status:
# Name:     nombre del proceso
# State:    S (sleeping), R (running), D (disk sleep), Z (zombie), T (stopped)
# VmRSS:    memoria RAM usada (Resident Set Size)
# VmSize:   memoria virtual total
# Threads:  número de hilos
# Uid:      UID real, efectivo, guardado

# Ver estadísticas detalladas del proceso
cat /proc/$PID/stat
# 44 campos separados por espacios con toda la info del proceso

# Uso de memoria detallado por región
cat /proc/$PID/smaps | head -30

# Calcular uso total de memoria de un proceso desde smaps
awk '/^Rss:/{sum+=$2} END{print "RSS total:", sum, "kB"}' /proc/$PID/smaps

Monitorear Todos los Procesos

# Script para monitorear uso de recursos de todos los procesos
cat > /usr/local/bin/proc-monitor.sh << 'EOF'
#!/bin/bash
# Monitoreo de procesos usando /proc
echo "=== Monitor de Procesos via /proc ==="
printf "%-8s %-20s %-10s %-10s %s\n" "PID" "NOMBRE" "RSS(MB)" "ESTADO" "CMD"

for dir in /proc/[0-9]*/; do
    PID=$(basename "$dir")
    [ -f "$dir/status" ] || continue
    
    NOMBRE=$(awk '/^Name:/{print $2}' "$dir/status" 2>/dev/null)
    ESTADO=$(awk '/^State:/{print $2}' "$dir/status" 2>/dev/null)
    RSS=$(awk '/^VmRSS:/{printf "%.1f", $2/1024}' "$dir/status" 2>/dev/null)
    CMD=$(tr '\0' ' ' < "$dir/cmdline" 2>/dev/null | cut -c1-50)
    
    [ -n "$NOMBRE" ] && [ -n "$RSS" ] && \
        printf "%-8s %-20s %-10s %-10s %s\n" "$PID" "$NOMBRE" "${RSS:-0}" "$ESTADO" "$CMD"
done | sort -k3 -rn | head -20
EOF
chmod +x /usr/local/bin/proc-monitor.sh

Información del Sistema y Hardware

CPU

# Información detallada del CPU
cat /proc/cpuinfo

# Extraer información específica
grep "model name" /proc/cpuinfo | head -1  # Modelo del CPU
grep -c "processor" /proc/cpuinfo          # Número de CPUs/núcleos lógicos
grep "cpu MHz" /proc/cpuinfo               # Frecuencia actual de cada núcleo

# Estadísticas de uso del CPU por tiempo
cat /proc/stat | grep "^cpu"
# Formato: cpu user nice system idle iowait irq softirq steal guest guest_nice

# Calcular uso de CPU en tiempo real (diferencia entre dos lecturas)
read CPU1 < <(awk '/^cpu /{print $2+$3+$4+$5+$6+$7+$8; exit}' /proc/stat)
read IDLE1 < <(awk '/^cpu /{print $5; exit}' /proc/stat)
sleep 1
read CPU2 < <(awk '/^cpu /{print $2+$3+$4+$5+$6+$7+$8; exit}' /proc/stat)
read IDLE2 < <(awk '/^cpu /{print $5; exit}' /proc/stat)
echo "CPU uso: $(( (CPU2-CPU1-IDLE2+IDLE1) * 100 / (CPU2-CPU1) ))%"

Memoria

# Información de memoria completa
cat /proc/meminfo

# Extraer información clave
awk '/MemTotal/{total=$2} /MemFree/{free=$2} /MemAvailable/{avail=$2} /Cached:/{cached=$2}
END{printf "Total: %.1f GB\nLibre: %.1f GB\nDisponible: %.1f GB\nCaché: %.1f GB\n",
total/1024/1024, free/1024/1024, avail/1024/1024, cached/1024/1024}' /proc/meminfo

# Información de swap
grep -E "SwapTotal|SwapFree|SwapCached" /proc/meminfo

# Ver páginas de memoria hugepages
grep -i huge /proc/meminfo

# Información de NUMA (si el sistema tiene múltiples sockets)
cat /proc/zoneinfo | head -50

Información del Sistema

# Tiempo de actividad del sistema
cat /proc/uptime
# Formato: segundos_activo segundos_idle_total

# Convertir a formato legible
awk '{d=int($1/86400); h=int(($1%86400)/3600); m=int(($1%3600)/60);
printf "Uptime: %d días %d horas %d minutos\n", d, h, m}' /proc/uptime

# Carga promedio del sistema
cat /proc/loadavg
# Formato: 1min 5min 15min procesos_ejecutando/total_procesos último_pid_creado

# Información del kernel
cat /proc/version
cat /proc/sys/kernel/ostype
cat /proc/sys/kernel/osrelease
cat /proc/sys/kernel/hostname

# Número máximo de procesos
cat /proc/sys/kernel/pid_max

# Dispositivos de hardware
cat /proc/devices      # Dispositivos de bloque y carácter registrados
cat /proc/bus/pci/devices  # Dispositivos PCI

Parámetros del Kernel con sysctl

/proc/sys/ expone parámetros del kernel modificables en tiempo real:

# Ver todos los parámetros del kernel
sysctl -a 2>/dev/null | head -30

# O directamente en /proc/sys/
ls /proc/sys/
# kernel/  - Parámetros del kernel
# net/     - Parámetros de red
# vm/      - Parámetros de memoria virtual
# fs/      - Parámetros del sistema de archivos

# Leer un parámetro
cat /proc/sys/kernel/hostname
sysctl kernel.hostname

# Modificar un parámetro (temporal, hasta reinicio)
echo 1 > /proc/sys/net/ipv4/ip_forward
sysctl -w net.ipv4.ip_forward=1

# Parámetros de rendimiento comunes
cat /proc/sys/vm/swappiness          # Agresividad del uso de swap (0-100)
cat /proc/sys/vm/dirty_ratio         # % memoria sucia antes de forzar escritura
cat /proc/sys/fs/file-max            # Máximo de archivos abiertos en el sistema

# Optimizaciones típicas de red para servidores
sysctl -w net.core.somaxconn=65535
sysctl -w net.ipv4.tcp_max_syn_backlog=65535
sysctl -w net.core.netdev_max_backlog=5000

# Hacer permanentes los cambios
cat >> /etc/sysctl.d/99-optimizaciones.conf << 'EOF'
# Optimizaciones de red para servidor web
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.core.netdev_max_backlog = 5000
# Reutilizar puertos en TIME_WAIT más agresivamente
net.ipv4.tcp_tw_reuse = 1
# Reducir memoria de buffer de envío/recepción mínima
net.ipv4.tcp_rmem = 4096 65536 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
EOF
sysctl -p /etc/sysctl.d/99-optimizaciones.conf

Estadísticas de Red

# Estadísticas de interfaces de red
cat /proc/net/dev
# Bytes, paquetes, errores y drops por interfaz

# Estadísticas TCP
cat /proc/net/tcp   # Conexiones TCP IPv4 en hex
cat /proc/net/tcp6  # Conexiones TCP IPv6

# Ver conexiones TCP en formato legible (equivalente a ss/netstat)
awk 'NR>1{
    # Convertir hex a IP:Puerto
    split($2, local, ":");
    split($3, remote, ":");
    printf "Local: %d.%d.%d.%d:%d\n",
        strtonum("0x"substr(local[1],7,2)),
        strtonum("0x"substr(local[1],5,2)),
        strtonum("0x"substr(local[1],3,2)),
        strtonum("0x"substr(local[1],1,2)),
        strtonum("0x"local[2])
}' /proc/net/tcp | head -10

# Estadísticas detalladas del protocolo TCP
cat /proc/net/snmp | grep -A2 "^Tcp:"

# Estadísticas de UDP
cat /proc/net/udp

# Tabla de ruteo
cat /proc/net/route

# Tabla ARP
cat /proc/net/arp

# Estadísticas de netfilter (iptables)
cat /proc/net/nf_conntrack | wc -l  # Número de conexiones trackeadas
cat /proc/sys/net/netfilter/nf_conntrack_count  # Conexiones actuales
cat /proc/sys/net/netfilter/nf_conntrack_max    # Límite máximo

Monitoreo de Rendimiento

Script de Dashboard de /proc

cat > /usr/local/bin/proc-dashboard.sh << 'EOF'
#!/bin/bash
# Dashboard de rendimiento usando solo /proc

while true; do
    clear
    echo "=== Dashboard del Sistema via /proc - $(date) ==="

    # Uptime
    echo ""
    awk '{d=int($1/86400); h=int(($1%86400)/3600); m=int(($1%3600)/60);
    printf "Uptime: %d días %02d:%02d horas\n", d, h, m}' /proc/uptime

    # Carga del sistema
    echo ""
    echo "=== Carga del Sistema ==="
    read L1 L5 L15 RUNNING TOTAL LASTPID < /proc/loadavg
    printf "Carga: %.2f (1m) %.2f (5m) %.2f (15m) | Procesos: %s/%s\n" \
        $L1 $L5 $L15 $RUNNING $TOTAL

    # Memoria
    echo ""
    echo "=== Memoria ==="
    awk '/MemTotal/{t=$2} /MemAvailable/{a=$2} /SwapTotal/{st=$2} /SwapFree/{sf=$2}
    END{
        printf "RAM: %.1f/%.1f GB (%.0f%% libre)\n", (t-a)/1048576, t/1048576, a/t*100;
        if(st>0) printf "Swap: %.1f/%.1f GB\n", (st-sf)/1048576, st/1048576;
    }' /proc/meminfo

    # CPU (lectura simple de /proc/stat)
    echo ""
    echo "=== CPU ==="
    awk '/^cpu /{idle1=$5; total1=$2+$3+$4+$5+$6+$7+$8}' /proc/stat
    sleep 0.5
    awk '/^cpu /{idle2=$5; total2=$2+$3+$4+$5+$6+$7+$8}
    END{printf "CPU uso: %.1f%%\n", (1-(idle2-idle1)/(total2-total1))*100}' \
        <(cat /proc/stat) /proc/stat 2>/dev/null

    # Red
    echo ""
    echo "=== Red (bytes/s) ==="
    awk 'NR>2{gsub(/:/, " "); printf "%-12s RX:%s TX:%s\n",$1,$2,$10}' /proc/net/dev | \
        grep -v "lo"

    sleep 5
done
EOF
chmod +x /usr/local/bin/proc-dashboard.sh

Configuración del Sistema en Tiempo Real

# Ajustar swappiness para servidores de base de datos (valor bajo = menos swap)
echo 10 > /proc/sys/vm/swappiness

# Aumentar el límite de archivos abiertos
echo 1000000 > /proc/sys/fs/file-max

# Deshabilitar el tiempo de acceso en i-nodes para reducir escrituras
# (configurar en /etc/fstab con opción 'noatime')

# Ajustar el OOM killer para un proceso específico (más negativo = menos probable matar)
PID=$(pidof mi-proceso-critico)
echo -17 > /proc/$PID/oom_adj  # -17 = nunca matar (obsoleto)
echo -1000 > /proc/$PID/oom_score_adj  # Interfaz moderna (-1000 = nunca matar)

# Ver puntuación actual del OOM killer para un proceso
cat /proc/$PID/oom_score

# Forzar liberación de caché de páginas
# 1=pagecache, 2=dentries+inodes, 3=todo
echo 1 > /proc/sys/vm/drop_caches

Solución de Problemas

No se puede leer un archivo en /proc/PID/:

# Muchos archivos requieren root
sudo cat /proc/1/environ
# Los archivos de /proc de otros usuarios requieren permisos elevados
sudo cat /proc/$PID/maps

"Too many open files" en una aplicación:

# Ver el límite actual del sistema
cat /proc/sys/fs/file-max
# Ver archivos abiertos actualmente
cat /proc/sys/fs/file-nr
# Formato: abiertos en uso / 0 / máximo

# Ver límite del proceso específico
cat /proc/$PID/limits | grep "open files"
# Aumentar para la sesión actual
ulimit -n 65535

/proc/net/conntrack lleno (error de seguimiento de conexiones):

# Ver límite actual
cat /proc/sys/net/netfilter/nf_conntrack_max
cat /proc/sys/net/netfilter/nf_conntrack_count
# Aumentar el límite
echo 262144 > /proc/sys/net/netfilter/nf_conntrack_max
# Permanente
echo "net.netfilter.nf_conntrack_max = 262144" >> /etc/sysctl.conf

Conclusión

El sistema de archivos /proc es una ventana directa al interior del kernel Linux, proporcionando acceso a información de procesos, estadísticas de hardware, parámetros de red y configuración del sistema en tiempo real. Comprender su estructura permite realizar diagnósticos profundos sin herramientas adicionales y ajustar el comportamiento del kernel para optimizar el rendimiento según las necesidades específicas de cada carga de trabajo. Muchas herramientas de monitoreo como top, free, netstat y ps leen directamente de /proc, por lo que dominar esta interfaz proporciona capacidades de diagnóstico equivalentes pero con mayor control y flexibilidad.