¿Cómo va ahora mismo?
De referencia
Registro cómo se comporta la plataforma hoy, antes de tocar nada. Esa fotografía me sirve de referencia para comparar todo lo que venga después, y casi nunca existe cuando llego.
Moodle · Rendimiento y capacidad
No reduzco una prueba de carga en Moodle a lanzar cientos de usuarios virtuales contra la portada y comprobar si el servidor sigue respondiendo. Eso produce una gráfica vistosa y casi ninguna información sobre la capacidad real.
Construyo escenarios con la proporción real de operaciones, pausas entre acciones y estados distintos para cada usuario virtual. Aumento la concurrencia de forma gradual con Apache JMeter, Gatling o Locust y observo a la vez los percentiles, la capa web, la base de datos, la caché, las sesiones, las tareas y las integraciones.
Mi trayectoriaMe preguntan por la capacidad casi siempre antes de una fecha y casi nunca con tiempo. Estas son las situaciones en las que recibo la pregunta.
Un examen, la apertura de matrícula o el comienzo de un curso concentran la actividad en una franja estrecha. Todo el mundo entra, abre el mismo curso y empieza la misma actividad. No uso la media diaria para calcular la carga porque no refleja lo que ocurre en esa franja.
Después de un incidente, nadie quiere afrontar de nuevo la misma fecha sin saber qué aguanta la plataforma. La prueba me permite recrear el problema sin afectar al servicio real, siempre que el entorno esté aislado, los datos estén protegidos y las integraciones externas se hayan neutralizado.
Antes de desplegar una extensión, actualizar la versión o cambiar la infraestructura, tomo una medida de referencia. Así compruebo si el cambio mejora el rendimiento, lo empeora o no lo altera.
Obtengo con la prueba un número defendible para que quien debe firmar la factura de infraestructura decida sin recurrir a una estimación por analogía.
Con la prueba verifico los tiempos de respuesta bajo la carga acordada; la disponibilidad se acredita con la monitorización y el periodo de medida definidos en el contrato.
Suelo encontrarme con estos cuatro planteamientos en los intentos previos; aunque todos ofrecen datos, son cifras engañosas.
No uso la portada para inferir la capacidad del flujo de examen: suele estar almacenada en caché y no activa las operaciones más costosas del sistema. Mil usuarios leyendo esa página no generan la misma carga que mil usuarios enviando un cuestionario a la vez. Limitar el ensayo a la portada puede crear una falsa sensación de seguridad; una prueba representativa permite estimar el margen disponible dentro de las condiciones y diferencias documentadas.
No uso una base recién instalada para predecir la capacidad de producción: las tablas son pequeñas, los índices pueden caber en memoria, no hay histórico y apenas existen contextos de permisos. Sí puede servir para una prueba de humo, una comparación controlada o el aislamiento de un coste concreto, siempre que ese alcance quede declarado.
Decir que una plataforma soporta mil usuarios concurrentes es una métrica casi vacía. Separo usuarios autenticados, sesiones activas, peticiones por segundo, operaciones de negocio por minuto y concurrencia sobre una acción concreta.
Compruebo que añadir servidores mejora el arranque de la prueba, pero no evita la degradación posterior: suelo encontrar el cuello de botella en la base de datos, las sesiones, la caché o una extensión. Cuando añado procesos, aumento la presión sobre el componente que ya iba justo.
Antes de montar nada decido qué clase de prueba necesito, porque cada una responde a una pregunta y mezclarlas produce conclusiones falsas.
¿Cómo va ahora mismo?
Registro cómo se comporta la plataforma hoy, antes de tocar nada. Esa fotografía me sirve de referencia para comparar todo lo que venga después, y casi nunca existe cuando llego.
¿Este cambio mejora o empeora?
Compruebo si una actualización, una extensión, un cambio de código o un cambio de infraestructura mejora o empeora el comportamiento de la plataforma. Solo considero válida la comparación si mantengo el mismo escenario y los mismos datos que en la prueba de referencia.
¿Hasta dónde aguanta?
Mido hasta qué carga cumple el sistema el objetivo de servicio. El resultado permite estimar el margen para la convocatoria dentro del escenario y las diferencias documentadas; no garantiza el comportamiento futuro de producción.
Construyo los escenarios a partir del comportamiento observable de la plataforma, no de una estimación genérica. Sigo este recorrido.
Reparto la carga entre perfiles: quien inicia sesión y entra en sus cursos, quien consulta el catálogo, quien navega por una actividad, quien reproduce contenido, quien hace un cuestionario, quien entrega una tarea y quien consulta informes. En paralelo ejecuto las sincronizaciones y las tareas programadas, que en producción también compiten con esas acciones.
Una persona real no abre diez páginas por segundo. Por eso introduzco pausas entre acciones. Sin ellas, provoco un bombardeo que me permite encontrar el punto de rotura, pero no reproducir la concurrencia real.
Distribuyo los estados cuando el uso real es heterogéneo. Si una convocatoria concentra a muchas personas en el mismo curso y la misma acción, reproduzco esa concentración. Después mido a partir de qué caudal o concurrencia se incumplen los umbrales.
Busco el punto a partir del cual, al aumentar la carga, la latencia crece de forma acusada y el caudal deja de aumentar al mismo ritmo. Después contrasto la hipótesis de saturación con las colas, las conexiones, los tiempos de espera y cualquier variación coincidente del escenario.
Observo durante la carga la utilización y la saturación de la CPU, la memoria y la presión sobre la memoria de intercambio. También vigilo los procesos disponibles para ejecutar PHP y la cola de peticiones que espera turno en PHP-FPM, el gestor que organiza esos procesos; las conexiones, los bloqueos y las consultas lentas de la base de datos; los aciertos y la latencia de la caché; la lectura y la escritura en disco y la latencia del almacenamiento compartido. Reviso además la ejecución de las tareas programadas y los errores y tiempos de los servicios externos. Sin esas métricas, solo veo que la plataforma se ralentiza.
Distribuyo las acciones por perfiles, ya que no tiene nada que ver tener a mil usuarios consultando una página almacenada en caché que a mil personas enviando respuestas al mismo tiempo. Esta es la lista de operaciones que incluyo; en cada prueba completo la mezcla con porcentajes observados por perfil, tasa de llegada, pausas, rampa de concurrencia y duración.
Introduzco pausas acordes con el comportamiento observado. Si las elimino, la prueba deja de representar esa concurrencia y pasa a buscar el punto de rotura.
Pregunto cuál de estas cinco cosas cuenta quien me dice que su plataforma soporta mil usuarios concurrentes.
Sé que el entorno condiciona las conclusiones. Resuelvo estas preguntas antes de lanzar la prueba.
Es verdad que a veces no queda más remedio que validar en producción ciertos factores imposibles de replicar fuera, como la latencia real de red, los límites de la nube o el comportamiento exacto del almacenamiento compartido.
Preparo los datos antes de lanzar la carga, porque el volumen y la antigüedad cambian el coste de las consultas.
Solo denomino anónima una copia cuando una evaluación documentada concluye que la reidentificación no es razonablemente posible. No basta con cambiar nombres y correos: reviso perfiles, campos personalizados, mensajes, foros, entregas, respuestas abiertas, registros, credenciales, configuración de extensiones, direcciones internas y ficheros. Si la copia es seudonimizada o conserva cualquier dato personal, defino la finalidad, el acceso, el aislamiento, la conservación y la supresión. También neutralizo las integraciones para que no envíen correos ni sincronicen matrículas reales.
Si no puedo usar una copia, genero volumen. Evito crear cien mil usuarios idénticos y matricularlos a todos en un curso: eso da volumen, pero no reproduce el comportamiento. Mantengo la distribución de cursos por categoría, de usuarios activos e históricos, de matriculaciones por curso, de tamaños de grupo, de actividades, intentos, preguntas, entregas, calificaciones, registros, roles y ficheros.
Distingo una plataforma con varios años de uso de otra con los mismos usuarios creados ayer: no se comportan igual. Tengo en cuenta cómo el histórico cambia el coste de las consultas, el tamaño de los índices y el peso de los registros de actividad.
Parto de una base coherente y multiplico ciertos volúmenes respetando relaciones y distribuciones. Así pruebo un crecimiento futuro: qué pasa si el número de personas se triplica o si se duplican los intentos de cuestionario.
Encuentro estos patrones en las plataformas que reviso. No son fallos exóticos: son las formas habituales en que una plataforma que funciona deja de funcionar al crecer.
Con unos pocos cursos funcionan bien, aunque recorren todos los usuarios, todas las matrículas o todas las actividades en cada petición. Durante el desarrollo, el conjunto de datos es pequeño y oculta el problema. Miro el número de consultas por petición: muchas veces el problema no es una consulta lenta, sino cientos de consultas pequeñas repetidas sin necesidad.
Añadir un índice no es una solución automática. Compruebo el patrón de filtrado, el orden de las columnas, la selectividad, el coste de escritura y si el plan de ejecución lo utiliza. Un índice puede mejorar una consulta y penalizar el resto de operaciones, así que lo valido con planes de ejecución y pruebas comparativas.
Estos informes recorren grandes volúmenes de datos y pueden competir con la actividad del alumnado. Separo la carga analítica de la transaccional cuando el caso lo justifica. Para ello uso réplicas de lectura, procesos de extracción, tablas agregadas o un almacén analítico. El alumnado puede notar esa competencia cuando la consulta analítica consume suficiente capacidad de la base operativa.
Reviso el dimensionado de la caché antes de dar por hecho que resuelve el problema. Encuentro instancias demasiado pequeñas, expulsiones continuas, latencias altas, claves con demasiada variedad, sesiones guardadas en ubicaciones que no corresponden y extensiones que invalidan la caché con demasiada frecuencia. En la prueba mido la tasa de aciertos y la latencia durante el pico; no me limito a comprobar que la caché está instalada.
No doy por estable una plataforma que solo he probado con las tareas detenidas. En producción, esas tareas compiten por CPU, memoria, base de datos y almacenamiento. Incluyo pruebas donde la carga de usuarios coincide con sincronizaciones, procesamiento de finalización, generación de informes, envío de notificaciones y limpieza de datos. Dimensiono contando con esas tareas, no con el sistema en reposo.
Considero los cuestionarios el escenario más sensible porque concentran sesiones, navegación, escritura frecuente, guardado automático, reglas de acceso, preguntas aleatorias y calificación. Pruebo el guardado concurrente y el envío final; durante este último pueden aparecer bloqueos, por lo que los vigilo de forma específica.
Reviso el almacenamiento de objetos, la red de distribución, la descarga acelerada, las direcciones firmadas, las peticiones por rango y la separación entre carga dinámica y distribución de ficheros cuando hay un gran volumen de vídeo, documentos o paquetes. Ampliar los servidores de aplicaciones no garantiza que la descarga mejore y será ineficaz si el límite está en la red, el almacenamiento o la distribución.
Una integración lenta mantiene ocupados los procesos y reduce la capacidad de toda la plataforma, aunque Moodle y la base de datos tengan recursos libres. Simulo latencia, errores intermitentes, agotamiento de los tiempos de espera, entrega parcial de datos, restricciones de caudal y caídas temporales. Cuando la operación no necesita respuesta inmediata, la saco del flujo mediante colas y procesamiento diferido.
Caso · pico de accesos y uso simultáneo de cuestionarios
Dónde
Este es un relato profesional sin identificar al cliente. Las cifras proceden de un informe interno no incorporado a la página: explican el método aplicado, pero no constituyen evidencia independiente, un valor de referencia ni una garantía. El escenario era una plataforma de formación corporativa con un volumen elevado de usuarios, miles de cursos activos, años de datos acumulados y diversas extensiones a medida.
Qué pasaba
En determinadas convocatorias vi cómo la actividad se concentraba en una franja muy estrecha: todo el mundo iniciaba sesión, entraba en el mismo curso y empezaba la evaluación. Los tiempos de respuesta subían. Algunas páginas tardaban varios segundos y otras peticiones agotaban el tiempo de espera. La gente volvía a intentarlo, justo lo peor que podía pasar: cada reintento añadía carga a un sistema que ya no daba abasto.
Qué parecía
Partí de la hipótesis habitual: asumí que PHP se veía desbordado por el volumen simultáneo y que la solución pasaba por dimensionar al alza la capa web. Las métricas decían otra cosa. Los servidores registraban carga, pero ninguno alcanzaba el límite ni se mantenía en él. Comprobé que añadir capacidad mejoraba el arranque de la prueba, lo que aliviaba el arranque del examen pero dejaba intacto el colapso posterior.
Qué probé
Reproduje el flujo entero: autenticación, área personal, entrada al curso, apertura del cuestionario, navegación entre preguntas, guardado de respuestas y envío del intento. Subí la carga de forma gradual para localizar la zona en la que la latencia aumentaba de forma acusada y el caudal dejaba de crecer al mismo ritmo. Evité realizar las pruebas sobre una base de datos vacía o recién instalada. Usé un conjunto de datos del mismo orden de magnitud que el de producción —decenas de miles de personas, miles de cursos y años de histórico—, con matrículas, intentos previos, calificaciones, registros y preguntas suficientes para aproximar la carga real. Así pude comparar el comportamiento entre ejecuciones, sin presentar el entorno de prueba como idéntico al de producción. Durante la prueba seguí a la vez los percentiles, la tasa de error, los procesos de PHP, las conexiones y los bloqueos de la base de datos. También revisé las consultas lentas, la caché, la lectura y escritura en disco y la ejecución de tareas programadas.
Qué salió
Comprobé que el cuello de botella no estaba solo en la capa web. Encontré varias causas acumuladas: consultas repetidas de una extensión propia, una consulta cuyo coste crecía con el histórico, presión sobre determinadas tablas durante el guardado simultáneo de respuestas, sesiones y cachés mal configuradas y tareas programadas que coincidían con la evaluación. La extensión, además, recalculaba en cada carga de página datos que bien podría haber mantenido en caché de forma persistente. Ordené el diagnóstico a partir de un dato: el percentil 95 —el tiempo que no supera el 95 % de las peticiones— ya era varias veces superior a su valor normal cuando la CPU todavía no alcanzaba ni la mitad de su máximo. Con ese dato descarté que ampliar servidores resolviera el problema de fondo.
Qué cambié
Comencé perfilando el plugin para eliminar las consultas redundantes y optimizar los planes de ejecución e índices de la base de datos. Reduje el volumen de datos por petición mediante caché de aplicación y desplacé las tareas intensivas fuera de la franja del examen. Finalmente, tras reajustar los procesos de PHP, las conexiones y el almacenamiento de sesiones, dimensioné solo los elementos donde los datos acreditaban falta de capacidad, estableciendo además los umbrales de referencia para futuros despliegues.
Qué cambió después
En una repetición comparable, la configuración corregida soportó la concurrencia objetivo y mantuvo el percentil 95 y la tasa de error dentro de los umbrales de aceptación del escenario. El aumento de carga empezó a provocar una degradación progresiva en lugar del colapso repentino observado al principio. La concurrencia, los umbrales y los resultados anteriores y posteriores forman parte del informe confidencial y no se publican en esta página; por eso este caso explica el método, no permite reproducir la medición. Descarté explicar el problema con un simple «hacen falta más servidores» y distinguí qué parte correspondía a la capacidad, cuál a la configuración y cuál al código.
Relaciono cada decisión con la medida que la justifica.
La media aporta información, pero puede ocultar las esperas que sufre una parte de la gente. La acompaño de la mediana, los percentiles 90, 95 y 99, la tasa de error, el caudal y la capacidad restante de cada componente. También sigo cómo cambian esos valores durante la prueba.
Señalo la carga a partir de la cual la latencia se dispara y nombro el primer componente que agota su capacidad y empieza a formar colas. Sin ese punto, una prueba solo dice que la plataforma iba bien mientras iba bien.
Comparo el punto de saturación con la actividad prevista en la franja crítica. Con ese margen tomo una decisión de capacidad basada en la prueba, no en una opinión.
Separo lo que corrijo con una consulta, un índice, una caché bien usada o una llamada sacada del flujo síncrono —para que la petición no se quede esperando a un sistema externo— de lo que solo mejora al ampliar la infraestructura. Confundir ambas cosas sale caro todos los meses.
Señalo la operación más frágil y la métrica que me alerta antes de que el problema se note: la cola de PHP, los bloqueos que se generan en la base de datos, la latencia de la caché o el retraso de las tareas.
Dejo versionados los scripts de carga, fijo los umbrales exigibles y detallo las métricas que se van a monitorizar. Tras una actualización, el equipo puede repetir la siguiente medición sin volver a empezar.
Defino requisitos comprobables y exigibles.
Esta lista no repite el procedimiento: fija las condiciones que deben quedar acreditadas al cerrar el trabajo.
Reviso qué operación concentra la actividad, cuántas personas se esperan en esa franja y qué histórico tiene la plataforma. Con esos datos decido qué medir primero.
Escríbeme