Locust describe usuarios virtuales en Python y mide la respuesta de un sistema a la carga. Un escenario útil representa recorridos reales y responde una pregunta, como cuándo la latencia supera un límite.
Crear un locustfile
python -m pip install locust
from locust import HttpUser, between, task
class Lector(HttpUser):
wait_time = between(1, 3)
@task(3)
def listar_posts(self) -> None:
self.client.get("/api/posts", name="GET /api/posts")
@task
def abrir_post(self) -> None:
self.client.get("/api/posts/python", name="GET /api/posts/:slug")
Los pesos aproximan frecuencias y wait_time evita un bucle irreal. Agrupar URLs dinámicas con name mantiene informes legibles.
Ejecutar con seguridad
Empieza con pocos usuarios y aumenta gradualmente. El modo headless permite umbrales repetibles en CI. Observa percentiles, fallos, throughput, recursos del servidor y límites del generador.
Nunca apuntes a producción sin autorización, ventana acordada, límites y mecanismo de parada. Usa cuentas propias y valida primero el recorrido funcional.
La guía de seguridad de APIs Python revisa riesgos, y métricas con Prometheus ayuda a observar el servidor.
La documentación oficial de Locust, consultada el 22 de julio de 2026, cubre HttpUser, tareas, ejecución headless y carga distribuida. Registra configuración, versiones, datos y entorno.
Definir el objetivo y el perfil
Empieza con una hipótesis medible: la búsqueda debe sostener 80 peticiones por segundo durante diez minutos, con p95 inferior a 400 ms y menos de 1% de fallos. Así quedan definidos recorrido, duración y aprobación. Distingue carga, que comprueba tráfico previsto; estrés, que encuentra un límite; y resistencia, que descubre fugas o colas crecientes. Registra commit, infraestructura, datos y configuración del generador.
Modelar estado y datos
Los recorridos reales necesitan autenticación o datos previos. on_start prepara cada usuario virtual:
class Comprador(HttpUser):
wait_time = between(2, 5)
def on_start(self) -> None:
respuesta = self.client.post(
"/api/login",
json={"email": "[email protected]", "password": "secreto-de-prueba"},
name="POST /api/login",
)
respuesta.raise_for_status()
self.token = respuesta.json()["token"]
@task
def consultar_carrito(self) -> None:
self.client.get(
"/api/carrito",
headers={"Authorization": f"Bearer {self.token}"},
name="GET /api/carrito",
)
Usa credenciales exclusivas del entorno de prueba y entrega secretos mediante variables de entorno. No compartas una cuenta entre miles de usuarios si las sesiones reales son independientes. Prepara suficientes identificadores y restaura la base cuando el escenario cambia estado.
Validar el éxito funcional
Una API puede responder 200 con un cuerpo incompleto. catch_response permite clasificarla según el contrato:
@task
def buscar(self) -> None:
with self.client.get(
"/api/busqueda?q=python",
name="GET /api/busqueda",
catch_response=True,
) as respuesta:
if respuesta.status_code != 200:
respuesta.failure(f"HTTP {respuesta.status_code}")
elif "elementos" not in respuesta.json():
respuesta.failure("respuesta sin elementos")
Mantén la validación ligera para no convertir el generador en el cuello de botella. Las reglas detalladas pertenecen a pruebas funcionales; bajo carga, comprueba solo lo necesario para distinguir un éxito real.
Ejecutar sin interfaz con una rampa
locust -f locustfile.py \
--headless \
--host https://api.staging.example \
--users 100 \
--spawn-rate 5 \
--run-time 10m \
--csv resultados
--users significa usuarios concurrentes, no peticiones por segundo. El rendimiento también depende de espera y latencia. spawn-rate controla la rampa, no el nivel final. Realiza primero un ensayo pequeño para comprobar autenticación, agrupación y limpieza. En CI, aplica límites explícitos y conserva los CSV.
Interpretar percentiles y límites
La mediana describe la petición central; p95 y p99 revelan la cola lenta. Léelos con throughput, fallos y cifras por endpoint. Correlaciona el mismo intervalo con CPU, memoria, conexiones, colas y base de datos. Si el throughput deja de crecer cuando se satura la CPU del generador, el cliente puede ser el límite.
Crea una referencia, cambia una variable y repite. El calentamiento de caché, el escalado y el recolector de basura producen fases distintas. Un informe fiable conserva la cronología en vez de elegir un número favorable.
Distribuir y repetir
Locust coordina un maestro y varios workers cuando una máquina no basta. Todos deben ejecutar la misma versión y tener relojes sincronizados. Separa los generadores de la infraestructura evaluada para evitar competencia. Monitoriza su CPU y comprueba que DNS, balanceadores y límites de red reproducen la ruta deseada.
Antes de probar, documenta autorización, destino, datos, límites y parada de emergencia. Durante la ejecución, observa servicio y generadores. Después, conserva configuración, commit, horarios, CSV e incidentes. El resultado debe conducir a una decisión: aceptar el límite, investigar un endpoint, ajustar capacidad o plantear otra hipótesis. Aporta evidencia sobre condiciones registradas, no una garantía absoluta.
Evitar conclusiones engañosas
No mezcles endpoints rápidos y lentos en una sola media. Analiza cada operación y su proporción en el recorrido. Comprueba si fallos de autenticación, límites de tasa o caché redujeron artificialmente el trabajo del servidor. Miles de respuestas 401 rápidas no miden la capacidad de la operación protegida.
Repite la ejecución para separar variación normal de regresión. Informa repeticiones, intervalo observado y cambios entre ellas. Si el entorno compartido recibió otro tráfico, registra esa limitación. La incertidumbre transparente resulta más útil que una falsa precisión.
Conserva también las unidades y la zona horaria del informe para que otra persona pueda auditarlo.