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:
- Medir primero: Establecer líneas base antes de optimizar
- Identificar cuellos de botella: Usar herramientas de perfilado para encontrar componentes lentos
- Optimizar bases de datos: Las consultas lentas matan el rendimiento
- Habilitar caché: Reducir procesamiento redundante
- Monitorear continuamente: Detectar degradación temprano
- Pruebas de carga: Verificar mejoras bajo condiciones realistas
- 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.


