Apache Bench (ab) es una herramienta de línea de comandos que lanza un número fijo de peticiones HTTP contra una URL, con la concurrencia que indiques, y resume cuántas peticiones por segundo atendió el servidor y cuánto tardaron. Funciona contra cualquier servidor web, no solo Apache, y es útil para comparar el antes y el después de un cambio de configuración: activar OPcache, ajustar PHP-FPM o añadir una caché. En este tutorial instalarás ab en Ubuntu 24.04, lanzarás pruebas bien planteadas, interpretarás su salida y aprenderás a detectar cuándo el cuello de botella es el propio cliente y no el servidor.
Requisitos previos
Para seguir esta guía necesitas:
- Una máquina con Ubuntu 24.04 LTS desde la que lanzar las pruebas y un usuario con privilegios
sudo. Lo ideal es que sea distinta del servidor que vas a medir, por ejemplo un segundo VPS de CubePath en la misma región. - Un servidor web accesible por HTTP o HTTPS (
your_domain) que sea tuyo o que tengas permiso para probar.
Advertenciauna prueba de carga contra un servidor ajeno puede considerarse un ataque de denegación de servicio. Mide solo tus propios servidores y, si están en producción, hazlo en horas de poco tráfico.
Paso 1: Instalar Apache Bench
ab forma parte del paquete apache2-utils, que no instala el servidor Apache:
sudo apt update
sudo apt install apache2-utils
Comprueba la versión:
ab -V
This is ApacheBench, Version 2.3 <$Revision: 1903618 $>
Paso 2: Lanzar la primera prueba
Las dos opciones básicas son -n, el número total de peticiones, y -c, cuántas se hacen a la vez. Lanza 1.000 peticiones con 10 conexiones concurrentes:
ab -n 1000 -c 10 https://your_domain/
La URL debe incluir la ruta. ab https://your_domain sin la barra final falla con ab: invalid URL.
Mientras la prueba corre, ab muestra el progreso cada 10 % de las peticiones y al final imprime un informe como este (resumido):
Server Software: nginx/1.24.0
Server Hostname: your_domain
Server Port: 443
SSL/TLS Protocol: TLSv1.3,TLS_AES_256_GCM_SHA384,2048,256
Document Path: /
Document Length: 18432 bytes
Concurrency Level: 10
Time taken for tests: 4.812 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 18771000 bytes
HTML transferred: 18432000 bytes
Requests per second: 207.81 [#/sec] (mean)
Time per request: 48.120 [ms] (mean)
Time per request: 4.812 [ms] (mean, across all concurrent requests)
Transfer rate: 3809.43 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 6 14 5.1 13 41
Processing: 21 34 11.8 31 162
Waiting: 20 32 11.5 29 160
Total: 28 48 13.2 45 189
Percentage of the requests served within a certain time (ms)
50% 45
66% 49
75% 52
80% 54
90% 63
95% 74
98% 92
99% 118
100% 189 (longest request)
Paso 3: Interpretar los resultados
Los valores que realmente importan:
- Failed requests: debe ser 0. Si no lo es, las demás cifras no son fiables (ver la sección de problemas).
- Non-2xx responses: solo aparece si hubo respuestas con error, redirecciones o códigos distintos de 2xx. Una prueba contra una URL que devuelve
301mide la redirección, no tu página. - Requests per second: el rendimiento (throughput) medio. Es la cifra que más se compara, pero por sí sola no dice nada de la experiencia del usuario.
- Time per request (mean): el tiempo medio que ha esperado cada cliente. El segundo valor, "across all concurrent requests", es simplemente el tiempo total dividido entre el número de peticiones.
- Connection Times:
Connectes el tiempo de establecer la conexión TCP y TLS;Waitinges el tiempo hasta el primer byte de la respuesta, que refleja lo que tarda la aplicación;Processingincluye además la descarga. - Percentiles: el 95 % de las peticiones terminó en 74 ms o menos. Los percentiles 95 y 99 muestran las peticiones lentas que la media esconde, y son los que conviene vigilar al optimizar.
En el ejemplo, Connect supone casi un tercio del tiempo total porque cada petición abre una conexión TLS nueva. Eso lleva a la siguiente opción.
Paso 4: Usar keep-alive y cabeceras realistas
Por defecto ab abre una conexión nueva por cada petición, algo que un navegador no hace. Con -k reutiliza las conexiones mediante keep-alive, lo que se parece más al tráfico real y mide mejor el tiempo de la aplicación:
ab -n 1000 -c 10 -k https://your_domain/
Keep-Alive requests: 1000
Requests per second: 412.37 [#/sec] (mean)
ab tampoco pide respuestas comprimidas por defecto. Si quieres medir con compresión, como haría un navegador, añade la cabecera con -H:
ab -n 1000 -c 10 -k -H 'Accept-Encoding: gzip, br' https://your_domain/
Otras opciones útiles:
| Opción | Uso |
|---|---|
-t 30 | Dura 30 segundos en lugar de un número fijo de peticiones |
-s 60 | Tiempo máximo de espera por respuesta en segundos (por defecto 30) |
-C 'nombre=valor' | Envía una cookie, por ejemplo para medir páginas de un usuario autenticado |
-H 'Cabecera: valor' | Añade una cabecera; se puede repetir |
-l | Acepta respuestas de longitud variable sin contarlas como fallidas |
-e resultados.csv | Guarda en CSV el tiempo de cada percentil del 0 al 100 |
Paso 5: Probar peticiones POST
Para medir un endpoint que recibe datos, guarda el cuerpo en un fichero e indica el tipo de contenido con -T. Por ejemplo, para una API JSON:
echo '{"query": "test"}' > ~/body.json
ab -n 500 -c 10 -k -p ~/body.json -T 'application/json' https://your_domain/api/search
Ten en cuenta que cada petición se ejecuta de verdad: no hagas pruebas POST contra endpoints que crean pedidos, envían correos o escriben datos en producción.
Paso 6: Comparar configuraciones de forma fiable
Una medida aislada vale poco; lo útil es comparar. Para que la comparación sea válida:
- Lanza una prueba corta de calentamiento y descártala. Las primeras peticiones llenan cachés como OPcache y el buffer de la base de datos.
- Repite cada prueba al menos tres veces con los mismos parámetros y quédate con la mediana.
- Cambia una sola cosa entre una tanda y la siguiente.
- Sube la concurrencia de forma escalonada para ver dónde deja de crecer el rendimiento. Un bucle sencillo:
for c in 1 10 25 50 100; do
printf 'c=%-4s ' "$c"
ab -n 2000 -c "$c" -k https://your_domain/ 2>/dev/null | grep -E 'Requests per second'
done
c=1 Requests per second: 96.40 [#/sec] (mean)
c=10 Requests per second: 412.37 [#/sec] (mean)
c=25 Requests per second: 538.12 [#/sec] (mean)
c=50 Requests per second: 551.03 [#/sec] (mean)
c=100 Requests per second: 549.87 [#/sec] (mean)
En este ejemplo el servidor se satura en torno a 25-50 conexiones concurrentes: más concurrencia ya no aumenta las peticiones por segundo, solo la latencia. Mientras corre la prueba, observa el servidor con htop o vmstat 1 para ver si el límite es la CPU, la memoria o los procesos de PHP-FPM.
Limitaciones de Apache Bench
- Usa HTTP/1.0 y un solo hilo. En servidores muy rápidos, o con HTTPS y mucha concurrencia, el cuello de botella puede ser el propio
ab. Si ves queabconsume el 100 % de un núcleo en la máquina cliente, los resultados miden al cliente, no al servidor. - Pide una sola URL, sin cargar imágenes, CSS ni JavaScript, y no ejecuta JavaScript. No sustituye a una prueba con navegador.
- Medir desde el mismo servidor elimina la red y compite por la CPU con el servidor web. Úsalo solo para pruebas rápidas.
Para cargas más altas, herramientas como wrk (disponible en Ubuntu con sudo apt install wrk) usan varios hilos y generan mucha más carga desde la misma máquina.
Solución de problemas
Failed requestsconLengthdistinto de 0: la página devuelve contenido de tamaño variable (fechas, tokens CSRF, anuncios) yablo cuenta como fallo al compararlo con la primera respuesta. Si el contenido es correcto, repite la prueba con-l.socket: Too many open files (24): la concurrencia supera el límite de descriptores de fichero de tu sesión. Súbelo antes de lanzar la prueba conulimit -n 10000.apr_socket_recv: Connection reset by peer (104): el servidor ha cerrado conexiones, normalmente por un límite de conexiones, un rate limit o un cortafuegos que ha detectado la prueba. Revisa los logs del servidor web y reduce la concurrencia.apr_pollset_poll: The timeout specified has expired (70007): el servidor tarda más de 30 segundos en responder. Súbelo con-ssi es esperado o investiga la causa en el servidor.
Conclusión
Ya sabes lanzar pruebas de carga con Apache Bench, leer las cifras que importan (errores, peticiones por segundo y percentiles de latencia) y comparar configuraciones de forma fiable. Como siguientes pasos, usa estas mediciones para validar cambios como activar OPcache, ajustar los pools de PHP-FPM o añadir una caché con Memcached, y prueba wrk cuando necesites generar más carga de la que ab puede producir.
