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.

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 301 mide 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: Connect es el tiempo de establecer la conexión TCP y TLS; Waiting es el tiempo hasta el primer byte de la respuesta, que refleja lo que tarda la aplicación; Processing incluye 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ónUso
-t 30Dura 30 segundos en lugar de un número fijo de peticiones
-s 60Tiempo 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
-lAcepta respuestas de longitud variable sin contarlas como fallidas
-e resultados.csvGuarda 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:

  1. 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.
  2. Repite cada prueba al menos tres veces con los mismos parámetros y quédate con la mediana.
  3. Cambia una sola cosa entre una tanda y la siguiente.
  4. 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 que ab consume 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 requests con Length distinto de 0: la página devuelve contenido de tamaño variable (fechas, tokens CSRF, anuncios) y ab lo 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 con ulimit -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 -s si 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.