Configuración de OPcache para PHP
Introducción
OPcache es un potente motor de caché de códigos de operación integrado en PHP desde la versión 5.5. Mejora drásticamente el rendimiento de PHP al almacenar el bytecode de scripts precompilados en memoria compartida, eliminando la necesidad de analizar y compilar scripts PHP en cada solicitud. Esta optimización puede reducir los tiempos de respuesta en un 30-70% y aumentar el rendimiento en 2-5x, convirtiéndola en una de las mejoras de rendimiento más impactantes disponibles para aplicaciones PHP.
Sin OPcache, PHP debe leer, analizar y compilar scripts en cada solicitud, consumiendo recursos significativos de CPU y agregando latencia. Con OPcache habilitado y configurado correctamente, esta compilación ocurre una vez, y el bytecode optimizado se reutiliza en miles o millones de solicitudes. Para sitios web de alto tráfico, esto se traduce en ganancias masivas de rendimiento y reducción de carga del servidor.
Esta guía completa cubre la arquitectura de OPcache, opciones de configuración, técnicas de optimización, monitoreo y solución de problemas. Aprenderás cómo configurar correctamente OPcache para maximizar el rendimiento mientras evitas problemas comunes que pueden causar código obsoleto, agotamiento de memoria o problemas de seguridad.
Comprensión de OPcache
Cómo Funciona OPcache
- Primera Solicitud: PHP analiza y compila el script a código de operación
- Almacenamiento: El código de operación compilado se almacena en memoria compartida
- Solicitudes Posteriores: El código de operación se recupera directamente de la memoria
- Optimización: OPcache aplica optimizaciones adicionales al código de operación
Impacto en el Rendimiento
Sin OPcache:
Solicitud → Analizar PHP → Compilar a Opcode → Ejecutar → Respuesta
Tiempo: 50ms análisis + 100ms ejecución = 150ms total
Con OPcache:
Solicitud → Recuperar Opcode de Memoria → Ejecutar → Respuesta
Tiempo: 0.5ms recuperación + 100ms ejecución = 100.5ms total
33% más rápido en tiempo de respuesta
Componentes de OPcache
- Caché de Opcode: Almacena bytecode compilado
- Buffer de Cadenas Internadas: Almacena cadenas inmutables (reduce memoria)
- Caché de Archivos: Caché persistente opcional basado en archivos
- Pases de Optimización: Algoritmos de optimización de código
Instalación y Verificación
Verificar Estado de OPcache
# Verificar si OPcache está instalado
php -m | grep -i opcache
# Ver configuración de OPcache
php --ri opcache
# Verificar mediante script PHP
php -r "var_dump(opcache_get_status());"
# Ver configuración de OPcache
php -i | grep -i opcache
Habilitar OPcache
# Ubuntu/Debian
apt-get install php8.3-opcache -y
# CentOS/Rocky Linux
dnf install php-opcache -y
# Verificar que la extensión esté cargada
php -m | grep OPcache
# Ubicación del archivo de configuración
# Ubuntu/Debian: /etc/php/8.3/mods-available/opcache.ini
# CentOS/Rocky: /etc/php.d/10-opcache.ini
Pruebas de Rendimiento Antes de la Optimización
Prueba de Rendimiento Base
# Crear script de prueba
cat > /var/www/html/opcache-test.php << 'EOF'
<?php
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
$data = [
'id' => $i,
'name' => 'User ' . $i,
'email' => 'user' . $i . '@example.com'
];
json_encode($data);
}
echo "Tiempo de ejecución: " . (microtime(true) - $start) . " segundos\n";
EOF
# Probar sin OPcache
php -d opcache.enable=0 /var/www/html/opcache-test.php
# Resultado: 0.045 segundos
# Probar con OPcache
php -d opcache.enable=1 /var/www/html/opcache-test.php
# Resultado: 0.012 segundos (73% más rápido)
Prueba de Carga del Servidor Web
# Instalar Apache Bench
apt-get install apache2-utils -y
# Probar con OPcache deshabilitado
ab -n 1000 -c 100 http://localhost/index.php
# Resultados base (OPcache deshabilitado):
# Solicitudes por segundo: 450
# Tiempo por solicitud: 222ms (promedio)
# Uso de memoria: Alto
# Uso de CPU: 85%
# Probar con OPcache habilitado
ab -n 1000 -c 100 http://localhost/index.php
# Resultados optimizados (OPcache habilitado):
# Solicitudes por segundo: 1,850 (mejora del 311%)
# Tiempo por solicitud: 54ms (76% más rápido)
# Uso de memoria: Menor
# Uso de CPU: 42% (reducción del 50%)
Configuración Esencial de OPcache
Configuración Básica
; /etc/php/8.3/mods-available/opcache.ini
[opcache]
; Habilitar OPcache
opcache.enable=1
opcache.enable_cli=0
; Configuración de memoria
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
; Configuración de rendimiento
opcache.revalidate_freq=60
opcache.fast_shutdown=1
; Características avanzadas
opcache.save_comments=1
opcache.enable_file_override=0
Configuración de Memoria
; Asignación de memoria de OPcache (MB)
; Predeterminado: 128MB
; Recomendado: 128-512MB según el tamaño de la aplicación
opcache.memory_consumption=256
; Buffer de cadenas internadas (MB)
; Almacena cadenas inmutables, reduce la duplicación de memoria
; Predeterminado: 8MB
; Recomendado: 16-32MB para aplicaciones grandes
opcache.interned_strings_buffer=16
; Número máximo de archivos en caché
; Predeterminado: 10000
; Calcular: contar todos los archivos .php en tu aplicación
; Agregar 20-30% de margen
opcache.max_accelerated_files=20000
Calcular max_accelerated_files:
# Contar archivos PHP en la aplicación
find /var/www/html -type f -name "*.php" | wc -l
# Salida: 14,523
# Agregar 30% de margen: 14,523 × 1.3 = 18,879
# Redondear al primo más cercano: 20,000 (más cercano disponible)
opcache.max_accelerated_files=20000
# Valores disponibles: 200, 1000, 2000, 4000, 8000, 16000, 32768
Validación y Revalidación
; Frecuencia de revalidación (segundos)
; Con qué frecuencia OPcache verifica si los archivos han cambiado
; Predeterminado: 2
; Producción: 60-3600 (mayor = mejor rendimiento)
; Desarrollo: 0 (verificar siempre)
opcache.revalidate_freq=60
; Validar marcas de tiempo
; Habilitar verificación de cambios en archivos
; Producción: 1 (habilitado)
; Producción de alto tráfico: 0 (deshabilitado, usar reinicio manual de caché)
opcache.validate_timestamps=1
; Tamaño máximo de archivo a almacenar en caché (bytes)
; Predeterminado: 0 (ilimitado)
; Establecer si tienes archivos PHP extremadamente grandes
opcache.max_file_size=0
Configuraciones Optimizadas por Entorno
Entorno de Desarrollo
; /etc/php/8.3/mods-available/opcache.ini
[opcache]
; Habilitar OPcache
opcache.enable=1
opcache.enable_cli=0
; Memoria (asignación más pequeña)
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
; Validar en cada solicitud (detectar cambios de código inmediatamente)
opcache.revalidate_freq=0
opcache.validate_timestamps=1
; Nivel de optimización
opcache.optimization_level=0x7FFFBFFF
; Manejo de errores
opcache.log_verbosity_level=4
error_log=/var/log/php-opcache-errors.log
; Depuración
opcache.consistency_checks=1
Entorno de Producción (Tráfico Medio)
[opcache]
; Habilitar OPcache
opcache.enable=1
opcache.enable_cli=0
; Asignación de memoria
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
; Revalidación (verificar cada minuto)
opcache.revalidate_freq=60
opcache.validate_timestamps=1
; Rendimiento
opcache.fast_shutdown=1
opcache.enable_file_override=0
; Optimización
opcache.optimization_level=0x7FFFBFFF
opcache.save_comments=1
; Monitoreo
opcache.log_verbosity_level=1
; Caché de archivos (opcional, para reinicios más rápidos)
opcache.file_cache=/tmp/opcache
opcache.file_cache_consistency_checks=1
Entorno de Producción (Alto Tráfico)
[opcache]
; Habilitar OPcache
opcache.enable=1
opcache.enable_cli=0
; Asignación de memoria grande
opcache.memory_consumption=512
opcache.interned_strings_buffer=32
opcache.max_accelerated_files=32768
; Rendimiento máximo (deshabilitar validación de marca de tiempo)
opcache.revalidate_freq=0
opcache.validate_timestamps=0
; Optimizaciones de rendimiento
opcache.fast_shutdown=1
opcache.enable_file_override=0
opcache.huge_code_pages=1
; Optimización máxima
opcache.optimization_level=0x7FFFBFFF
opcache.save_comments=1
; Caché de archivos para reinicios más rápidos
opcache.file_cache=/var/cache/opcache
opcache.file_cache_only=0
; Registro mínimo
opcache.log_verbosity_level=1
Resultados de Rendimiento:
Configuración de Tráfico Medio:
- Solicitudes/seg: 1,850
- Tiempo de respuesta: 54ms
- CPU: 42%
Configuración de Alto Tráfico (marcas de tiempo deshabilitadas):
- Solicitudes/seg: 2,470 (33% más)
- Tiempo de respuesta: 40ms (26% más rápido)
- CPU: 31% (26% menos)
Opciones de Configuración Avanzadas
Nivel de Optimización
; Nivel de optimización (máscara de bits)
; Predeterminado: 0x7FFFBFFF (todas las optimizaciones)
opcache.optimization_level=0x7FFFBFFF
; Deshabilitar optimizaciones específicas (si causan problemas):
; 0x7FFFFFFF = todas las optimizaciones excepto pase 9
; 0x7FFFFEFF = deshabilitar pase 8
; Típicamente, usar predeterminado a menos que se depuren problemas específicos
Configuración JIT (PHP 8.0+)
; JIT (compilación Just-In-Time) - PHP 8.0+
; Habilitado por defecto en PHP 8, proporciona rendimiento adicional
; Tamaño del buffer JIT (MB)
opcache.jit_buffer_size=128
; Modo JIT
; 1255 = tracing JIT (recomendado para la mayoría de aplicaciones)
; 1205 = function JIT
; 0 = deshabilitado
opcache.jit=1255
; Nivel de depuración JIT
opcache.jit_debug=0
Impacto de Rendimiento de JIT:
# Probar tarea intensiva en CPU
ab -n 1000 -c 100 http://localhost/compute.php
# Sin JIT:
# Solicitudes/seg: 1,450
# Tiempo por solicitud: 69ms
# Con JIT (1255):
# Solicitudes/seg: 3,280 (mejora del 126%)
# Tiempo por solicitud: 30ms (56% más rápido)
Configuración de Caché de Archivos
; Caché de archivos persistente (sobrevive reinicios de PHP-FPM)
; Ruta al directorio de caché de archivos
opcache.file_cache=/var/cache/opcache
; Usar caché de archivos como respaldo
opcache.file_cache_fallback=1
; Verificaciones de consistencia
opcache.file_cache_consistency_checks=1
; Solo usar caché de archivos (sin memoria compartida)
; Útil para entornos restrictivos
opcache.file_cache_only=0
# Crear y configurar directorio de caché de archivos
mkdir -p /var/cache/opcache
chown www-data:www-data /var/cache/opcache
chmod 755 /var/cache/opcache
Soporte de Páginas Enormes
; Habilitar páginas enormes para mejor rendimiento
; Requiere configuración del sistema
opcache.huge_code_pages=1
# Habilitar páginas enormes en el sistema
echo "vm.nr_hugepages=128" >> /etc/sysctl.conf
sysctl -p
# Verificar páginas enormes
cat /proc/meminfo | grep Huge
# Salida esperada:
# HugePages_Total: 128
# HugePages_Free: 120
# Hugepagesize: 2048 kB
Gestión de Caché
Reinicio Manual de Caché
# Reiniciar OPcache mediante script PHP
cat > /var/www/html/opcache-reset.php << 'EOF'
<?php
if (function_exists('opcache_reset')) {
opcache_reset();
echo "OPcache reiniciado exitosamente\n";
} else {
echo "OPcache no disponible\n";
}
EOF
# Asegurar el script de reinicio (restringir acceso)
# O usar desde línea de comandos:
php -r "opcache_reset();"
# Reiniciar mediante recarga de PHP-FPM (gradual)
systemctl reload php8.3-fpm
Estrategia de Despliegue
#!/bin/bash
# script de despliegue con gestión de OPcache
# Desplegar nuevo código
git pull origin main
# Opción 1: Limpiar OPcache (para validate_timestamps=0)
php -r "opcache_reset();"
# Opción 2: Recargar PHP-FPM (gradual, sin tiempo de inactividad)
systemctl reload php8.3-fpm
# Opción 3: Reiniciar PHP-FPM (reinicio completo)
# systemctl restart php8.3-fpm
# Verificar despliegue
curl http://localhost/health-check.php
Precarga (PHP 7.4+)
; Precargar archivos usados frecuentemente
; Cargado una vez en el inicio de PHP-FPM
opcache.preload=/var/www/html/preload.php
opcache.preload_user=www-data
<?php
// /var/www/html/preload.php
// Precargar framework y archivos usados frecuentemente
opcache_compile_file('/var/www/html/vendor/autoload.php');
opcache_compile_file('/var/www/html/app/Kernel.php');
opcache_compile_file('/var/www/html/app/Http/Controllers/Controller.php');
// Precargar todos los controladores
$files = glob('/var/www/html/app/Http/Controllers/*.php');
foreach ($files as $file) {
opcache_compile_file($file);
}
Monitoreo de OPcache
Habilitar Página de Estado de OPcache
<?php
// /var/www/html/opcache-status.php
// ¡Restringir acceso en producción!
if (!in_array($_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1'])) {
die('Acceso denegado');
}
$status = opcache_get_status();
$config = opcache_get_configuration();
echo "<h1>Estado de OPcache</h1>";
// Uso de memoria
echo "<h2>Uso de Memoria</h2>";
echo "Usado: " . round($status['memory_usage']['used_memory'] / 1024 / 1024, 2) . " MB<br>";
echo "Libre: " . round($status['memory_usage']['free_memory'] / 1024 / 1024, 2) . " MB<br>";
echo "Desperdiciado: " . round($status['memory_usage']['wasted_memory'] / 1024 / 1024, 2) . " MB<br>";
echo "Desperdiciado %: " . round($status['memory_usage']['current_wasted_percentage'], 2) . "%<br>";
// Tasa de aciertos
$hits = $status['opcache_statistics']['hits'];
$misses = $status['opcache_statistics']['misses'];
$total = $hits + $misses;
$hit_rate = ($total > 0) ? ($hits / $total * 100) : 0;
echo "<h2>Tasa de Aciertos</h2>";
echo "Aciertos: " . number_format($hits) . "<br>";
echo "Fallos: " . number_format($misses) . "<br>";
echo "Tasa de Aciertos: " . round($hit_rate, 2) . "%<br>";
// Estado de caché
echo "<h2>Estado de Caché</h2>";
echo "Scripts en caché: " . $status['opcache_statistics']['num_cached_scripts'] . "<br>";
echo "Claves en caché: " . $status['opcache_statistics']['num_cached_keys'] . "<br>";
echo "Claves máximas en caché: " . $status['opcache_statistics']['max_cached_keys'] . "<br>";
// Cadenas internadas
echo "<h2>Cadenas Internadas</h2>";
echo "Tamaño de buffer: " . round($status['interned_strings_usage']['buffer_size'] / 1024 / 1024, 2) . " MB<br>";
echo "Usado: " . round($status['interned_strings_usage']['used_memory'] / 1024 / 1024, 2) . " MB<br>";
echo "Libre: " . round($status['interned_strings_usage']['free_memory'] / 1024 / 1024, 2) . " MB<br>";
echo "Cadenas: " . number_format($status['interned_strings_usage']['number_of_strings']) . "<br>";
?>
Script de Monitoreo
#!/bin/bash
# /usr/local/bin/opcache-monitor.sh
STATUS=$(php -r "var_export(opcache_get_status());")
# Analizar métricas clave
MEMORY_USED=$(echo "$STATUS" | grep -A1 "'used_memory'" | tail -n1 | grep -oP '\d+')
MEMORY_FREE=$(echo "$STATUS" | grep -A1 "'free_memory'" | tail -n1 | grep -oP '\d+')
MEMORY_WASTED=$(echo "$STATUS" | grep -A1 "'wasted_memory'" | tail -n1 | grep -oP '\d+')
HITS=$(echo "$STATUS" | grep -A1 "'hits'" | tail -n1 | grep -oP '\d+')
MISSES=$(echo "$STATUS" | grep -A1 "'misses'" | tail -n1 | grep -oP '\d+')
# Calcular métricas
TOTAL=$((HITS + MISSES))
if [ $TOTAL -gt 0 ]; then
HIT_RATE=$(awk "BEGIN {printf \"%.2f\", ($HITS/$TOTAL)*100}")
else
HIT_RATE="0"
fi
MEMORY_USED_MB=$(awk "BEGIN {printf \"%.2f\", $MEMORY_USED/1024/1024}")
WASTED_PCT=$(awk "BEGIN {printf \"%.2f\", ($MEMORY_WASTED/($MEMORY_USED+$MEMORY_FREE+$MEMORY_WASTED))*100}")
# Registrar métricas
echo "$(date) - Memoria: ${MEMORY_USED_MB}MB, Desperdiciado: ${WASTED_PCT}%, Tasa de Aciertos: ${HIT_RATE}%" >> /var/log/opcache-monitor.log
# Alertar si hay problemas
if (( $(echo "$WASTED_PCT > 10" | bc -l) )); then
echo "ADVERTENCIA: Memoria desperdiciada de OPcache en ${WASTED_PCT}%" | mail -s "Alerta de OPcache" [email protected]
fi
if (( $(echo "$HIT_RATE < 95" | bc -l) )); then
echo "ADVERTENCIA: Tasa de aciertos de OPcache en ${HIT_RATE}%" | mail -s "Alerta de OPcache" [email protected]
fi
Métricas Clave a Monitorear
- Tasa de Aciertos: Debe ser > 99% en producción
- Uso de Memoria: No debe exceder el 80% de lo asignado
- Memoria Desperdiciada: Debe ser < 5%
- Scripts en Caché: Monitorear cambios inesperados
- Eventos de Caché Lleno: Debe ser 0
Solución de Problemas
Problema 1: Tasa de Aciertos Baja
Diagnóstico:
# Verificar tasa de aciertos
php -r "var_dump(opcache_get_status()['opcache_statistics']);"
# Causas de tasa de aciertos baja:
# 1. OPcache demasiado pequeño
# 2. Caché limpiada frecuentemente
# 3. revalidate_freq demasiado bajo
Soluciones:
; Aumentar memoria
opcache.memory_consumption=512
opcache.max_accelerated_files=32768
; Aumentar frecuencia de revalidación
opcache.revalidate_freq=300
; Deshabilitar validación de marca de tiempo en producción
opcache.validate_timestamps=0
Problema 2: Desperdicio Alto de Memoria
Diagnóstico:
# Verificar porcentaje de memoria desperdiciada
php -r "var_dump(opcache_get_status()['memory_usage']);"
# Memoria desperdiciada > 5% indica fragmentación
Soluciones:
# Reiniciar OPcache para desfragmentar
php -r "opcache_reset();"
# O reiniciar PHP-FPM
systemctl restart php8.3-fpm
# Programar reinicios regulares durante períodos de bajo tráfico
# 0 4 * * * systemctl restart php8.3-fpm
Problema 3: Código Obsoleto Después del Despliegue
Síntomas: Código antiguo ejecutándose después del despliegue
Soluciones:
# Opción 1: Reiniciar OPcache manualmente
php -r "opcache_reset();"
# Opción 2: Recargar PHP-FPM
systemctl reload php8.3-fpm
# Opción 3: Habilitar validación de marca de tiempo
# En php.ini:
opcache.validate_timestamps=1
opcache.revalidate_freq=2
# Opción 4: Usar script de despliegue
#!/bin/bash
git pull
php -r "opcache_reset();"
systemctl reload php8.3-fpm
Problema 4: Errores de Falta de Memoria
Diagnóstico:
# Verificar si OPcache está lleno
php -r "
\$status = opcache_get_status();
\$used = \$status['memory_usage']['used_memory'];
\$total = \$used + \$status['memory_usage']['free_memory'];
echo 'Uso: ' . round(\$used/\$total*100, 2) . '%';
"
Soluciones:
; Aumentar memoria de OPcache
opcache.memory_consumption=512
; Aumentar máximo de archivos
opcache.max_accelerated_files=32768
; Aumentar buffer de cadenas internadas
opcache.interned_strings_buffer=32
Comparación de Rendimiento
Pruebas de Aplicaciones del Mundo Real
Sitio WordPress:
# Sin OPcache
ab -n 1000 -c 100 http://localhost/
# Solicitudes/seg: 42
# Tiempo por solicitud: 2,381ms
# CPU: 92%
# Con OPcache (optimizado)
ab -n 1000 -c 100 http://localhost/
# Solicitudes/seg: 187 (mejora del 345%)
# Tiempo por solicitud: 535ms (77% más rápido)
# CPU: 45% (reducción del 51%)
Aplicación Laravel:
# Sin OPcache
ab -n 5000 -c 500 http://localhost/api/users
# Solicitudes/seg: 285
# Tiempo por solicitud: 1,754ms
# Con OPcache + JIT
ab -n 5000 -c 500 http://localhost/api/users
# Solicitudes/seg: 1,340 (mejora del 370%)
# Tiempo por solicitud: 373ms (79% más rápido)
Mejores Prácticas
Directrices de Configuración
-
Asignación de Memoria
- Desarrollo: 128-256 MB
- Producción (pequeña): 256-512 MB
- Producción (grande): 512-1024 MB
-
Límites de Archivos
- Contar tus archivos PHP
- Agregar 30% de margen
- Usar el primo/potencia de 2 más cercano
-
Revalidación
- Desarrollo: 0 (verificar siempre)
- Producción (moderado): 60-300 segundos
- Producción (alto tráfico): deshabilitar validación
-
Monitoreo
- Verificar tasa de aciertos diariamente
- Monitorear uso de memoria
- Rastrear memoria desperdiciada
- Alertar sobre anomalías
-
Despliegue
- Siempre reiniciar caché después de cambios de código
- Usar recarga gradual de PHP-FPM
- Probar en staging primero
- Monitorear después del despliegue
Conclusión
OPcache es una de las optimizaciones de rendimiento de PHP más efectivas disponibles. La configuración adecuada ofrece beneficios sustanciales:
Mejoras de Rendimiento:
- Tiempos de respuesta: 30-70% más rápidos
- Rendimiento: aumento de 2-5x
- Uso de CPU: reducción del 40-60%
- Capacidad del servidor: 3-10x más solicitudes por servidor
Factores Clave de Éxito:
- Habilitar OPcache en todos los servidores de producción
- Asignar memoria suficiente según el tamaño de la aplicación
- Optimizar para tu entorno (dev vs producción)
- Monitorear continuamente para detectar problemas
- Gestionar caché adecuadamente durante despliegues
Resumen de Configuración Esencial:
; Producción (alto tráfico)
opcache.enable=1
opcache.memory_consumption=512
opcache.max_accelerated_files=32768
opcache.revalidate_freq=0
opcache.validate_timestamps=0
opcache.interned_strings_buffer=32
opcache.fast_shutdown=1
opcache.jit_buffer_size=128
opcache.jit=1255
Al implementar estas optimizaciones de OPcache, puedes mejorar drásticamente el rendimiento de aplicaciones PHP, reducir costos de infraestructura y proporcionar mejor experiencia de usuario con cambios mínimos de configuración.


