Ir al contenido principal
Laravel, shipping fast.
Capitulo 6 · Rendimiento y optimizacion

El tamano de la carga tambien es latencia

Julian Beaujardin

Una consulta lenta es un problema de rendimiento obvio. Una respuesta grande lo es menos, pero sigue siendo latencia: cada byte tiene que transmitirse, recibirse y analizarse antes de que quien consume pueda actuar.

GzipResponseMiddleware se encarga automáticamente de la mitad de la transmisión, y está registrado globalmente y no por ruta:

// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    $middleware->append([
        SetRequestLocaleMiddleware::class,
        GzipResponseMiddleware::class,
    ]);
})

$minSize: las respuestas pequeñas se saltan la compresión. Gzip tiene su propia sobrecarga, y comprimir un cuerpo de error de 200 bytes no ahorra nada a nadie.

append(), no un alias por ruta: esto corre en cada respuesta de la aplicación, el valor por defecto correcto para algo que no tiene nada que ver con la lógica de negocio de ningún endpoint.

La compresión arregla los bytes que ya estás enviando. No arregla enviar bytes que no hacía falta enviar. Si un LicenseResource incluye campos que ningún consumidor lee, eso es carga que comprimes, transmites y analizas para nada. El arreglo ahí no es middleware: es disciplina en la capa de Resources.

Saber que la optimizacion funciono

Aquí el capítulo cierra el bucle que abrió. Para cualquier cosa que pase por la capa HTTP, mediste antes de tocar nada porque LogApiRequestsMiddleware ya registraba execution_time y response_size. Publica el arreglo y comprueba el mismo campo.

No todo pasa por ese middleware. ReconcileDomainsCommand es un comando de consola, no una petición HTTP, así que nunca toca execution_time. Eso no significa que no se mida: significa que lo mides como mides cualquier cosa, envolviendo la ejecución en un cronómetro y contando las consultas antes de cambiar nada. Misma disciplina, distinta superficie.

Si el número que vigilas no se mueve, una de tres cosas es cierta: optimizaste la consulta equivocada, el cuello de botella nunca fue la base de datos (probablemente una llamada HTTP externa), o el arreglo no llegó a publicarse. Las tres ganan a «añadí agrupación, debería ir más rápido ahora».

Lista de comprobacion de rendimiento

Antes de tocar nada:

  • [X] Confirma la petición lenta en execution_time, no lo adivines por una sensación
  • [X] Identifica si el coste es la base de datos, una llamada externa o el tamaño de la carga

Patrones de consulta:

  • [X] Agrupa o precarga cualquier consulta que si no correría una vez por fila de un bucle
  • [X] Precarga la cadena de relaciones completa por adelantado
  • [X] Pon techo al tamaño de página de cualquier endpoint paginado que controle un cliente

Cacheo:

  • [X] Cachea llamadas genuinamente caras (E/S de red), no búsquedas locales que ya son rápidas
  • [X] Cada escritura en caché tiene su Cache::forget() correspondiente en el sitio que la invalida
  • [X] No existe ninguna clave de caché que no puedas rastrear hasta la escritura que la limpia

Índices:

  • [X] Cada índice corresponde a una cláusula WHERE real, en el orden de columnas por el que filtra la consulta
  • [X] Ningún índice añadido por suposición

Después de publicar:

  • [X] Confirma que execution_time se movió de verdad
  • [X] Si no lo hizo, averigua por qué antes de seguir

El trabajo de rendimiento que no se mide no es trabajo de rendimiento. Es sólo código que cambiaste y sobre el que albergaste esperanzas.