Sitio Web Lento: Análisis de Rendimiento

Introducción

El rendimiento del sitio web impacta directamente la experiencia del usuario, tasas de conversión y rankings en motores de búsqueda. Un sitio web lento frustra a los usuarios, aumenta las tasas de rebote y cuesta ingresos a las empresas. Cuando el rendimiento del sitio web se degrada, identificar el cuello de botella rápidamente - ya sean recursos del servidor, consultas de base de datos, problemas de red o código de aplicación - es crítico para mantener la satisfacción del usuario.

Esta guía integral proporciona a administradores de sistemas y desarrolladores metodologías sistemáticas para diagnosticar problemas de rendimiento del sitio web. Aprenderás a usar herramientas de línea de comandos, analizar logs de servidores web, perfilar rendimiento de base de datos e identificar las causas raíz de cargas lentas de páginas, permitiéndote optimizar tu infraestructura web efectivamente.

La lentitud del sitio web puede originarse de numerosas fuentes: servidores sobrecargados, consultas de base de datos ineficientes, assets grandes sin optimizar, caché mal configurado o latencia de red. Esta guía te enseña a eliminar sistemáticamente posibilidades y señalar cuellos de botella exactos de rendimiento usando técnicas de diagnóstico probadas.

Entendiendo el Rendimiento del Sitio Web

Métricas de Rendimiento

Indicadores clave de rendimiento:

  • Time to First Byte (TTFB): Tiempo de respuesta del servidor
  • Page Load Time: Tiempo completo de renderizado de página
  • Time to Interactive: Cuando la página se vuelve utilizable
  • Server Response Time: Tiempo de procesamiento backend
  • Database Query Time: Tiempo de ejecución SQL
  • Network Latency: Retrasos de conexión

Líneas Base de Rendimiento

Umbrales aceptables:

  • TTFB: < 200ms (excelente), < 500ms (bueno)
  • Page Load: < 2s (excelente), < 3s (aceptable)
  • Database Queries: < 100ms (mayoría), < 1s (complejas)
  • Server Response: < 500ms para contenido dinámico

Evaluación Inicial de Rendimiento

Verificación Rápida de Rendimiento

# Probar tiempo de respuesta del sitio web
time curl -I https://example.com

# Con timing detallado
curl -w "@-" -o /dev/null -s https://example.com << 'EOF'
    time_namelookup:  %{time_namelookup}s\n
       time_connect:  %{time_connect}s\n
    time_appconnect:  %{time_appconnect}s\n
   time_pretransfer:  %{time_pretransfer}s\n
      time_redirect:  %{time_redirect}s\n
 time_starttransfer:  %{time_starttransfer}s (TTFB)\n
                    ----------\n
         time_total:  %{time_total}s\n
EOF

# Verificar carga del servidor
uptime
top -bn1 | head -15

# Conexiones del servidor web
ss -tan | grep :80 | wc -l
ss -tan | grep :443 | wc -l

# Verificar consultas lentas
tail -100 /var/log/mysql/slow-query.log

# I/O de disco
iostat -x 1 3

Paso 1: Análisis del Servidor Web

Rendimiento de Apache

# Estado de Apache
systemctl status apache2

# Conexiones actuales
apachectl status
# o vía URL
curl http://localhost/server-status

# Conteo de conexiones
ss -tan | grep :80 | wc -l

# Procesos de Apache
ps aux | grep apache2 | wc -l

# Log de errores de Apache
tail -100 /var/log/apache2/error.log

# Encontrar peticiones lentas
tail -10000 /var/log/apache2/access.log | \
    awk '{print $NF, $7}' | \
    sort -rn | \
    head -20

# Tasa de peticiones
tail -10000 /var/log/apache2/access.log | \
    awk '{print $4}' | \
    cut -d: -f1-3 | \
    uniq -c | \
    tail -20

# IPs que más solicitan
awk '{print $1}' /var/log/apache2/access.log | \
    sort | uniq -c | \
    sort -rn | \
    head -20

# Verificación de configuración
apache2ctl -t
apache2ctl -S

Rendimiento de Nginx

# Estado de Nginx
systemctl status nginx

# Conexiones activas
curl http://localhost/nginx_status

# Conteo de conexiones
ss -tan | grep :80 | wc -l

# Procesos worker
ps aux | grep "nginx: worker" | wc -l

# Log de errores
tail -100 /var/log/nginx/error.log

# Peticiones lentas
tail -10000 /var/log/nginx/access.log | \
    awk '{print $NF, $7}' | \
    sort -rn | \
    head -20

# Análisis de timing de peticiones
awk '{print $NF}' /var/log/nginx/access.log | \
    awk '{sum+=$1; count++} END {print "Avg:", sum/count "s"}'

# Tiempos de respuesta upstream
grep "upstream_response_time" /var/log/nginx/access.log | \
    tail -100

# Prueba de configuración
nginx -t
nginx -T  # Volcado completo de config

Paso 2: Rendimiento de Aplicaciones

Análisis de PHP-FPM

# Estado de PHP-FPM
systemctl status php7.4-fpm

# Estado del pool
curl http://localhost/fpm-status

# Procesos activos
ps aux | grep php-fpm | wc -l

# Scripts PHP lentos
tail -100 /var/log/php7.4-fpm-slow.log

# Errores PHP
tail -100 /var/log/php7.4-fpm.log

# Analizar peticiones lentas
cat /var/log/php7.4-fpm-slow.log | \
    grep "script_filename" | \
    sort | uniq -c | \
    sort -rn

# Configuración de PHP-FPM
cat /etc/php/7.4/fpm/pool.d/www.conf | \
    grep -E "pm.max_children|pm.start_servers|pm.min_spare|pm.max_spare"

# Probar tiempo de ejecución PHP
time php -r "sleep(1); echo 'test';"

# Verificar módulos PHP
php -m

Perfilado de Aplicaciones

# Habilitar slow log en php.ini
slowlog = /var/log/php-fpm-slow.log
request_slowlog_timeout = 5s

# Instalar perfilador Xdebug
apt install php-xdebug

# Habilitar en php.ini
xdebug.profiler_enable=1
xdebug.profiler_output_dir="/tmp/xdebug"

# Analizar perfiles con webgrind o KCacheGrind

# Integración New Relic APM
# Instalar agente PHP de New Relic
echo 'deb http://apt.newrelic.com/debian/ newrelic non-free' | \
    tee /etc/apt/sources.list.d/newrelic.list
apt update && apt install newrelic-php5

Paso 3: Rendimiento de Base de Datos

Análisis de Consultas MySQL

# Verificar estado de MySQL
systemctl status mysql

# Conexiones activas
mysql -e "SHOW PROCESSLIST;"

# Consultas lentas
mysql -e "SHOW VARIABLES LIKE 'slow_query%';"

# Habilitar slow query log
mysql -e "SET GLOBAL slow_query_log = 'ON';"
mysql -e "SET GLOBAL long_query_time = 1;"

# Analizar slow query log
tail -100 /var/log/mysql/slow-query.log

# Usar mysqldumpslow
mysqldumpslow -s t -t 10 /var/log/mysql/slow-query.log

# Verificar bloqueos de tabla
mysql -e "SHOW OPEN TABLES WHERE In_use > 0;"

# Estado InnoDB
mysql -e "SHOW ENGINE INNODB STATUS\G"

# Estadísticas de query cache
mysql -e "SHOW STATUS LIKE 'Qcache%';"

# Estadísticas de conexiones
mysql -e "SHOW STATUS LIKE 'Threads%';"
mysql -e "SHOW STATUS LIKE 'Connections';"

Optimización de Base de Datos

# Analizar consulta específica
mysql -e "EXPLAIN SELECT * FROM table WHERE condition;"

# Verificar índices
mysql -e "SHOW INDEX FROM table_name;"

# Optimización de tabla
mysql -e "OPTIMIZE TABLE table_name;"

# Analizar tabla
mysql -e "ANALYZE TABLE table_name;"

# Verificar fragmentación
mysql -e "SELECT TABLE_NAME,
    DATA_FREE/1024/1024 AS FragmentedMB
    FROM information_schema.TABLES
    WHERE TABLE_SCHEMA = 'database_name'
    AND DATA_FREE > 0
    ORDER BY FragmentedMB DESC;"

# Uso de memoria
mysql -e "SHOW VARIABLES LIKE '%buffer%';"

Paso 4: Análisis de Recursos del Servidor

Análisis de CPU

# Uso de CPU
top -bn1 | grep "Cpu(s)"
mpstat -P ALL 1 3

# Procesos con mayor CPU
ps aux --sort=-%cpu | head -10

# Tiempo de espera CPU
iostat -c 1 3

# CPU por proceso
pidstat -u 1 5

# Uso CPU de Apache/Nginx
ps aux | grep -E "apache2|nginx" | \
    awk '{sum+=$3} END {print "CPU:", sum "%"}'

Análisis de Memoria

# Uso de memoria
free -h

# Mayores consumidores de memoria
ps aux --sort=-%mem | head -10

# Uso de swap
swapon --show
vmstat 1 5

# Estado de caché
cat /proc/meminfo | grep -E "Cached|Buffers"

# Memoria de PHP-FPM
ps aux | grep php-fpm | \
    awk '{sum+=$6} END {print "Memory:", sum/1024 "MB"}'

Análisis de I/O de Disco

# Estadísticas de I/O
iostat -x 1 5

# I/O por proceso
iotop -o

# Utilización de disco
df -h

# Encontrar procesos intensivos en I/O
pidstat -d 1 5

# Verificar espera alta de I/O
top -bn1 | grep "Cpu(s)" | awk '{print $10}'

Paso 5: Análisis de Red

Análisis de Conexiones

# Conexiones activas
ss -s
netstat -an | awk '{print $6}' | sort | uniq -c

# Conexiones por IP
netstat -ntu | awk '{print $5}' | \
    cut -d: -f1 | sort | uniq -c | \
    sort -rn | head -20

# Estados de conexión
ss -tan state established | wc -l
ss -tan state time-wait | wc -l

# Throughput de red
iftop -i eth0
nethogs

# Uso de ancho de banda
vnstat -i eth0

Pruebas de Latencia

# Probar latencia al sitio web
ping -c 10 example.com | tail -1

# Medir búsqueda DNS
time nslookup example.com

# Prueba completa de conexión
curl -w "@-" -o /dev/null -s https://example.com << 'EOF'
time_namelookup:    %{time_namelookup}s\n
time_connect:       %{time_connect}s\n
time_appconnect:    %{time_appconnect}s\n
time_pretransfer:   %{time_pretransfer}s\n
time_starttransfer: %{time_starttransfer}s\n
time_total:         %{time_total}s\n
EOF

# MTR para verificar ruta de red
mtr -c 100 example.com

Paso 6: Análisis de Caché

Caché del Servidor Web

# Verificar caché de Nginx
du -sh /var/cache/nginx/*

# Ratio de aciertos de caché
grep -E "HIT|MISS" /var/log/nginx/access.log | \
    awk '{print $NF}' | sort | uniq -c

# Estadísticas de Varnish (si está instalado)
varnishstat
varnishlog

# Verificar cabeceras de caché
curl -I https://example.com | grep -i cache

Caché de Aplicación

# Estado de Redis
redis-cli info stats
redis-cli --stat

# Estadísticas de Memcached
echo stats | nc localhost 11211

# Estado de OPcache (PHP)
php -r "print_r(opcache_get_status());"

# Tamaño de caché de archivos
du -sh /var/cache/application/*

Paso 7: Pruebas de Carga

Apache Bench

# Instalar ab
apt install apache2-utils

# Prueba de carga básica
ab -n 1000 -c 10 https://example.com/

# Con keep-alive
ab -k -n 1000 -c 10 https://example.com/

# Prueba de petición POST
ab -n 100 -c 10 -p post.txt -T "application/x-www-form-urlencoded" https://example.com/api

# Guardar resultados
ab -n 1000 -c 50 https://example.com/ > ab-results.txt

Usando wrk

# Instalar wrk
apt install wrk

# Prueba básica
wrk -t12 -c400 -d30s https://example.com/

# Con script personalizado
wrk -t4 -c100 -d30s -s script.lua https://example.com/

# Prueba de larga duración
wrk -t12 -c400 -d5m https://example.com/

Soluciones y Optimización

Optimización del Servidor Web

Ajuste de Apache:

# Editar /etc/apache2/mods-available/mpm_prefork.conf
<IfModule mpm_prefork_module>
    StartServers             5
    MinSpareServers          5
    MaxSpareServers         10
    MaxRequestWorkers      150
    MaxConnectionsPerChild 3000
</IfModule>

# Habilitar mod_expires
a2enmod expires
cat >> /etc/apache2/apache2.conf << 'EOF'
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpg "access plus 1 year"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/gif "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
</IfModule>
EOF

# Habilitar compresión
a2enmod deflate

Ajuste de Nginx:

# Editar /etc/nginx/nginx.conf
worker_processes auto;
worker_connections 2048;
keepalive_timeout 30;

# Compresión Gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript;

# Caché de navegador
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

# Recargar
nginx -t && systemctl reload nginx

Optimización de Base de Datos

# Ajuste de MySQL (/etc/mysql/my.cnf)
[mysqld]
innodb_buffer_pool_size = 4G
innodb_log_file_size = 256M
max_connections = 200
query_cache_size = 128M
query_cache_limit = 2M
tmp_table_size = 128M
max_heap_table_size = 128M

# Reiniciar MySQL
systemctl restart mysql

# Agregar índices para consultas lentas
ALTER TABLE users ADD INDEX idx_email (email);
ALTER TABLE posts ADD INDEX idx_created (created_at);

Optimización de PHP-FPM

# Editar /etc/php/7.4/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500

# Configuración de OPcache (/etc/php/7.4/fpm/php.ini)
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2

systemctl restart php7.4-fpm

Monitoreo y Prevención

Script de Monitoreo de Rendimiento

cat > /usr/local/bin/performance-monitor.sh << 'EOF'
#!/bin/bash

LOG_FILE="/var/log/performance-monitor.log"
URL="https://example.com"

# Medir tiempo de respuesta
RESPONSE_TIME=$(curl -w "%{time_total}" -o /dev/null -s $URL)

echo "$(date): Response time: ${RESPONSE_TIME}s" >> "$LOG_FILE"

# Alertar si está lento
if (( $(echo "$RESPONSE_TIME > 2.0" | bc -l) )); then
    echo "Slow response: ${RESPONSE_TIME}s on $(hostname)" | \
        mail -s "Performance Alert" [email protected]
fi

# Verificar recursos del servidor
CPU=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
LOAD=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | cut -d',' -f1)

echo "CPU: $CPU%, Load: $LOAD" >> "$LOG_FILE"
EOF

chmod +x /usr/local/bin/performance-monitor.sh
echo "*/5 * * * * /usr/local/bin/performance-monitor.sh" | crontab -

Conclusión

La optimización del rendimiento de sitios web requiere análisis sistemático de múltiples capas - servidor web, aplicación, base de datos e infraestructura. Conclusiones clave:

  1. Medir primero: Establecer líneas base antes de optimizar
  2. Identificar cuellos de botella: Usar herramientas de perfilado para encontrar componentes lentos
  3. Optimizar bases de datos: Las consultas lentas matan el rendimiento
  4. Habilitar caché: Reducir procesamiento redundante
  5. Monitorear continuamente: Detectar degradación temprano
  6. Pruebas de carga: Verificar mejoras bajo condiciones realistas
  7. Optimizar iterativamente: Hacer un cambio a la vez, medir resultados

El monitoreo regular de rendimiento, estrategias adecuadas de caché y comprensión de estas herramientas de diagnóstico aseguran sitios web rápidos y responsivos que proporcionan excelentes experiencias de usuario.