El pilar de rendimiento se centra en el diseño, desarrollo, validación y operaciones de soluciones que cumplen con sus requisitos no funcionales de rendimiento de la solución (normalmente asociados con los tiempos de respuesta), capacidad (magnitudes de carga admitidas, base de usuarios y rendimiento logrado) y escalabilidad (capacidad de adaptarse orgánicamente a la demanda variable y al aumento de las cargas). A diferencia de un entorno informático "tradicional" compuesto por una infraestructura de capacidad fija, un entorno de nube híbrida permite a las soluciones escalar dinámicamente su capacidad y consumo de recursos de manera ascendente y descendente a medida que la demanda aumenta y disminuye; siempre que las soluciones estén diseñadas para usar estas capacidades.
El análisis de rendimiento también permite mejorar la experiencia del usuario mediante mejoras basadas en la evidencia en el diseño del producto, y alcanzar los objetivos empresariales gracias a la escalabilidad y capacidad integradas.
Recopile las expectativas de los usuarios en la etapa de definición del producto, cuantifique los requisitos de negocio y utilice esta información como base para la arquitectura y el diseño posteriores del producto.
Los componentes dentro de una solución bien diseñada se pueden escalar de forma independiente; por ejemplo, agregar otra instancia de un servicio, pero agregar o eliminar componentes puede tener efectos en otras partes de la solución; por ejemplo, agregar otro servidor web para atender un pico en el tráfico web puede requerir más colas de mensajes para comunicarse con los servicios de backend. Conocer las dependencias de escalado de antemano puede ayudar a comprender el comportamiento operativo de la solución y evitar el agotamiento de los recursos mediante el escalado excesivo de un solo recurso.
Las soluciones de nube híbrida bien diseñadas usan las arquitecturas multiplataforma para escalar y aplicar estrategias de expansión para optimizar el rendimiento, así como la seguridad, los costos operativos y las expectativas del usuario final; por ejemplo, ejecutar cargas de trabajo en una infraestructura on premises con sólidas garantías de rendimiento y costos operativos fijos y usar un servicio en la nube durante periodos de máxima carga de trabajo.
Mover datos es costoso. Las soluciones bien diseñadas usan la portabilidad y la movilidad de las cargas de trabajo en contenedores y sitúan los servicios lo más cerca posible de los datos que consumen.
Las soluciones deben elegir la plataforma y los recursos adecuados para maximizar el valor de sus arquitecturas. Una solución de nube híbrida es capaz de abarcar múltiples nubes, incluyendo la infraestructura on premises, lo que da a los arquitectos la libertad de seleccionar la combinación óptima de recursos que satisfaga las necesidades de rendimiento de su solución.
El rendimiento debe estar "integrado" en una solución desde el principio de su diseño. Dejar las consideraciones de rendimiento para el final del diseño de la solución, o peor aún, la implementación, a menudo da como resultado un rendimiento subóptimo que no se puede solucionar sin revisar grandes partes de la arquitectura de la solución. Las prácticas de diseño de soluciones ayudan a los arquitectos a crear soluciones de alto rendimiento y a evitar enfoques de diseño que puedan limitar el rendimiento de la solución.
Las soluciones deben diseñarse para aumentar o reducir su capacidad de procesamiento agregando o eliminando unidades discretas (servidores, servicios, interfaces de red, etc.) en lugar de cambiar la capacidad de las unidades existentes; por ejemplo, agregando más CPU a un servidor. Para lograr esto, las soluciones deben adoptar los siguientes principios de arquitectura:
Los componentes sin estado son componentes que no conservan el estado del cliente o de la sesión (por ejemplo, una identidad de usuario o las entradas de datos proporcionadas en la llamada anterior) entre interacciones, eliminando las dependencias entre los clientes y cualquier instancia específica de un componente. Esta falta de dependencia entre los componentes y sus consumidores significa que la solución puede ampliarse o reducirse agregando o eliminando instancias de componentes sin afectar a los consumidores de los servicios de los componentes. Un buen ejemplo de un componente sin estado es un cajero en una tienda de abarrotes; siempre que haya al menos un cajero disponible, los compradores pueden pagar sus compras y los cajeros se pueden agregar y eliminar según lo exija el volumen de compradores. Lo contrario de esto es si a los compradores se les asignara un cajero específico al comienzo de su recorrido de compras. Si el cajero asignado se atasca o, peor aún, no está disponible, los compradores tienen que esperar o comenzar de nuevo y el rendimiento general de la tienda de abarrotes (medido en compradores por hora) se ve afectado.
Evitar las tareas que tardan mucho tiempo en completarse. Si una solución debe admitir tareas de larga duración (por ejemplo, realizar un cálculo científico complejo), la tarea debe diseñarse para admitir la ampliación o reducción a través de una instalación de interrupción y punto de control que permita que la solución apague y reinicie la tarea a medida que se agregan recursos y se eliminan de la solución.
Datos en los extremos. Los componentes sin estado pueden, en teoría, escalar infinitamente y son reutilizables entre clientes. Las soluciones de alto rendimiento envían el estado, es decir, los datos de usuario y aplicación, a la aplicación cliente y a las bases de datos en los extremos de la arquitectura de la solución y no mantienen ningún estado en las capas de arquitectura intermedias.
Recursos:
Stateful vs Stateless
El diseño de soluciones como un conjunto de componentes altamente cohesivos y poco acoplados permite que los componentes se escalen de forma independiente en relación con la demanda del servicio que brindan. Los enfoques de arquitectura, como la arquitectura orientada a servicios y los microservicios, incorporan esta práctica como un principio de diseño central, es decir, un conjunto de servicios altamente cohesivos que se comunican a través de API de alto nivel y poco acopladas.
El traslado de datos entre los componentes de una solución suele ser el elemento que más tiempo consume en una transacción. Los componentes deben diseñarse para optimizar la frecuencia y el volumen de las comunicaciones para el ancho de banda disponible. Por ejemplo, una aplicación que realiza llamadas repetidas para recuperar valores individuales de una base de datos podría funcionar "lo suficientemente bien" cuando se despliega en una red local, pero podría retrasarse cuando el componente de la base de datos se reubica en un proveedor de servicios en la nube.
El estilo arquitectónico de transferencia de estado representacional (REST) que se usa comúnmente en aplicaciones basadas en la web es un buen ejemplo del tipo de equilibrio que exhibe una solución bien diseñada; el estado representativo completo de un recurso se transfiere como un JSON, XML u otro documento que equilibra la cantidad de información que se transfiere contra la latencia elevada de una interacción basada en la web.
El almacenamiento en caché ayuda a limitar la demanda de recursos y servicios que producen datos. Considere el uso del almacenamiento en caché para datos de larga duración y relativamente estáticos, o datos que son “costosos” de producir. Las soluciones bien diseñadas implementan mecanismos de almacenamiento en caché en todas las capas de la arquitectura de la solución, colocando las cachés lo más cerca posible del consumidor para limitar las comunicaciones entre el consumidor y la caché y mejorar el tiempo de respuesta general.
Los arquitectos deben tener en cuenta que el almacenamiento en caché puede ser excesivo. Un mecanismo de almacenamiento en caché mal diseñado o una caché demasiado grande pueden afectar negativamente el rendimiento general de la solución. Los arquitectos deben evaluar el tipo y la estrategia de almacenamiento en caché y, a continuación, medir la eficacia de la caché durante las pruebas y el análisis de rendimiento.
La mensajería asíncrona mediante colas de mensajes, modelos de devolución de llamada u otros medios permite que las soluciones escalen de forma eficiente y se degraden de manera uniforme bajo carga si se agotan los recursos. Las soluciones bien diseñadas usan la comunicación asíncrona, especialmente las colas de mensajes, para dar a los usuarios finales una experiencia de usuario receptiva y evitar "perder" las solicitudes de usuario si un componente falla. Este mismo mecanismo también se puede utilizar para interconectar sistemas que tienen diferentes niveles de servicio u horario de funcionamiento; por ejemplo, una aplicación web 24x7 conectada a un sistema de registro de 9 a 5 con una cola de mensajes permite que la aplicación web acepte solicitudes de usuarios finales incluso cuando el sistema de registro no está disponible.
Las soluciones cambian con el tiempo y su rendimiento puede cambiar junto con ellas. La incorporación de instrumentos de medición del rendimiento que permiten a los equipos de desarrollo, pruebas y operaciones recopilar de forma no intrusiva métricas de rendimiento de las aplicaciones ayuda a desarrollar y probar un producto robusto que utiliza métodos basados en pruebas. La instrumentación también ayuda en pruebas funcionales y análisis de defectos, y es una ayuda invaluable para mantener el rendimiento de una solución e identificar las fuentes de problemas de rendimiento en producción. La instrumentación configurable y no intrusiva admite el monitoreo del producto, garantizando la observabilidad de la solución en las operaciones, apoyando así a los equipos de DevOps y ingeniería de confiabilidad de sitios (SRE).
La planificación, las pruebas y el análisis del rendimiento son un conjunto de prácticas y enfoques que se aplican a las soluciones de TI con el fin de garantizar la calidad de la solución y su capacidad para alcanzar los resultados empresariales esperados.
Por lo general, el análisis se aplica a atributos de calidad tales como el rendimiento de la solución, la capacidad, la escalabilidad y algunos aspectos de la disponibilidad, la continuidad de negocio y la sustentabilidad en general. El análisis incluye la identificación y cuantificación de los requisitos empresariales relacionados con la calidad, el diseño y la ejecución de las pruebas para obtener métricas específicas que reflejen el rendimiento de la solución frente a una serie de expectativas, como los tiempos de respuesta, los rendimientos o las cargas admitidas.
Además, en un sentido más amplio, el alcance del rendimiento incluye el análisis de la capacidad de una solución, las unidades totales de trabajo que la solución puede atender y su escalabilidad (qué tan bien responde a los cambios en la demanda). El análisis de rendimiento también sirve para demostrar que los productos siguen siendo funcionales y estables en condiciones de operaciones extremas. Se espera que el objetivo del análisis de rendimiento no sea solo capturar la imagen del rendimiento de la solución, sino identificar los cuellos de botella y colaborar con los stakeholders para mejorar la calidad y la usabilidad de la solución.
Teniendo en cuenta la naturaleza compleja y holística del rendimiento del producto y la gestión de la capacidad, debe abarcar las diferentes fases del SLDC, desde el diseño del producto hasta el soporte de operaciones y la SRE. Esto garantiza tanto una gestión adecuada de los requisitos del cliente como la detección temprana de problemas y una respuesta rápida a los incidentes de producción.
Desde la perspectiva empresarial, es importante el rendimiento de la solución en su conjunto, lo que debe reflejarse en requisitos no funcionales holísticos. Sin embargo, para las pruebas de rendimiento a nivel unitario, las pruebas de rendimiento tempranas que implementan el paradigma de desplazamiento a la izquierda y para el análisis de la causa principal de los problemas de rendimiento, es posible que sea necesario especificar requisitos de bajo nivel, limitando la duración de las llamadas individuales, la latencia de la red, etc.
Por lo tanto, los requisitos de rendimiento de alto nivel generalmente se proporcionan a nivel de proceso o transacción, por ejemplo: "El proceso de originación del préstamo debe completarse en menos de 2 minutos", sin tener en cuenta cómo el rendimiento de los pasos y subprocesos individuales del proceso contribuye a el resultado final. Crear un presupuesto de rendimiento que asigne objetivos a cada paso dentro del proceso en la etapa de desarrollo proporciona objetivos medibles para los equipos de desarrollo de características, y ayuda a identificar posibles áreas problemáticas y enfocar los esfuerzos de optimización y corrección del rendimiento donde son más beneficiosos.
Los presupuestos de rendimiento deben tener en cuenta todas las capas de la solución, desde el hardware hasta el código de la aplicación. Omitir cualquiera de estos riesgos es que la solución no pueda satisfacer las expectativas de los usuarios.
Al probar el rendimiento, la evidencia está en su consumo; es decir, solo probando la solución de extremo a extremo podemos estar seguros de que cumple con sus requisitos. Esto refleja la naturaleza holística del análisis del rendimiento. Las pruebas de componentes individuales (por ejemplo, bases de datos, middleware, etc.) proporcionan insight valioso sobre el análisis de rendimiento de una solución y ayudan a identificar los cuellos de botella de rendimiento. Pero las pruebas de componentes por sí solas no son suficientes, ya que las interacciones entre los componentes pueden provocar cuellos de botella inesperados u otros impedimentos que pueden dar lugar a resultados subóptimos.
Centrarse en la percepción del usuario significa centrarse principalmente en los tiempos de respuesta percibidos y la capacidad de respuesta general de la interfaz de usuario. La degradación de la capacidad suele ser invisible para los usuarios hasta que el rendimiento del producto se ve afectado. Un estudio realizado en 1968 reveló que existen tres órdenes de magnitud distintos en las interacciones entre humanos y computadoras:
A partir de esto, se postuló que un tiempo de respuesta de 2 segundos sería ideal y, por lo tanto, 2 segundos o un poco más es un buen objetivo de tiempo de respuesta para las soluciones de nube híbrida, siempre que sea posible. Por supuesto, las expectativas de los usuarios dependen de lo que estén haciendo; por ejemplo, nadie espera que una animación de pulsación de botón dure 2 segundos, pero 2-3 segundos es un buen objetivo general para aplicaciones orientadas al usuario.
A partir de este principio, las soluciones deben incorporar pruebas de tiempo de respuesta del usuario como parte de su ciclo de garantía de calidad mediante el uso de herramientas de prueba de interfaz de usuario. Por mucho que las latencias de las llamadas a la API sean importantes para el rendimiento general del producto, el rendimiento percibido por el usuario es clave para atraer y retener a la base de usuarios.
Los usuarios suelen tener diferentes expectativas de lo que constituye un "buen" rendimiento. Por ejemplo, un "usuario avanzado" que usa una aplicación varias veces al día de manera cotidiana tiene expectativas de rendimiento muy diferentes a las de alguien que usa la misma aplicación tal vez una vez al mes. Los usuarios también suelen tener el desafío de cuantificar lo que significa un "buen" rendimiento para ellos, y a menudo se atascan en requisitos como "lo suficientemente rápido" (que es un objetivo difícil de cumplir). Además, la percepción individual del rendimiento del producto orientado al usuario es diferente para distintas personas. Por ejemplo, para algunas, un tiempo de inicio de sesión de 10 segundos es aceptable (especialmente si se trata de un evento singleton) y para otras podría ser demasiado lento (especialmente si el inicio de sesión es una parte frecuente del flujo de trabajo).
Para ayudar a cuantificar y gestionar las expectativas de los usuarios, se recomienda:
Monitorear y comunicar los límites de rendimiento a los clientes.
El uso incorrecto o la configuración inadecuada de un producto o componente de una solución pueden ser la causa de un rendimiento deficiente y una experiencia de usuario negativa. Para evitar esta situación, los arquitectos deben:
Ser conscientes de las limitaciones de rendimiento dentro de la solución y comunicarlas de forma proactiva a los usuarios. Por ejemplo, si una solución utiliza un canal de comunicación lento o de bajo ancho de banda, deben concientizar a los usuarios finales de que la descarga de imágenes de alta resolución se verá afectada.
Permitir que los sistemas detecten y se comuniquen cuando las solicitudes estén fuera de los parámetros de diseño de la solución siempre que sea posible. Por ejemplo, hacer que el sistema advierta activamente a los usuarios cuando intenten descargar archivos grandes a través de un canal lento.
Un enfoque común para las pruebas de rendimiento es probar que la solución cumpla con sus objetivos de tiempo de respuesta con la carga máxima esperada para la solución; se supone que si la solución funciona bien con la carga máxima esperada, será buena para cargas menores. El desafío con este enfoque es que solo proporciona un punto de datos por carga máxima probada, casi como un ejercicio de aprobación/rechazo.
Una solución bien diseñada se prueba mediante el enfoque exploratorio para determinar su capacidad de respuesta en una variedad de cargas que varían en tamaño, combinación de tipos de usuarios y combinación de funciones probadas. Esto proporciona al equipo de soluciones información valiosa multifacética sobre cómo interactúan los componentes de la solución para afectar el rendimiento, los posibles cuellos de botella y cómo escalar la solución para abordar cargas de trabajo menores o mayores.
Este enfoque permite evitar pruebas adicionales si cambian los objetivos de carga previstos y es necesario recopilar métricas de rendimiento en diferentes condiciones de carga. La interpolación/extrapolación de las dependencias existentes de rendimiento en las magnitudes de carga permite calcular métricas de rendimiento para cualquier carga dentro del espectro de las cargas probadas inicialmente (desde cero hasta las magnitudes del punto de interrupción y superiores).
El enfoque típico de las pruebas de rendimiento sigue el patrón simplificado "medir los tiempos de respuesta con cargas/rendimientos determinados". Este enfoque responde a la pregunta de si el tiempo de respuesta de las transacciones clave en magnitudes máximas satisface los acuerdos de nivel de servicio (SLAs) existentes. Y, por lo general, las magnitudes probadas se limitan a "baja", "pico" y "estrés". Este enfoque puede responder a las preguntas sobre los tiempos de respuesta con cargas típicas, pero no ofrece una visión completa del rendimiento del sistema en todas las situaciones posibles.
El enfoque más avanzado de *pruebas exploratorias de rendimiento* tiene como objetivo la creación de la *instantánea de rendimiento* de la solución probada. La instantánea incluye un conjunto completo de métricas de rendimiento, recopiladas en el espectro de cargas más amplio admitido, desde mediciones de un solo usuario hasta cargas posteriores al punto de interrupción (cuando es posible, excepto cuando el sistema falla). Esto incluye una recopilación de los tiempos de respuesta de las transacciones, los rendimientos de transacciones y datos de los datos de consumo de recursos reunidos en condiciones de carga cada vez mayor. Por "transacción" entendemos un trabajo finito por parte del sistema, desde transacciones macro como inicio de sesión o actualización de cuenta, hasta subtransacciones individuales (como llamada de autenticación dentro de la transacción de inicio de sesión) o simples visitas http.
El conjunto completo de datos de rendimiento, instantánea de rendimiento, incluye las métricas de rendimiento anteriores para el rango de carga "lineal" de baja carga (donde los subprocesos procesados individualmente no sienten la presencia de los demás y los tiempos de respuesta no aumentan con el aumento de la carga ), el rango "no lineal" donde los tiempos de respuesta crecen a medida que aumenta la carga, los puntos de saturación, donde los rendimientos dejan de aumentar con el incremento de la carga y alcanzan niveles de saturación, y el rango posterior a la interrupción donde el rendimiento disminuye después de que los rendimientos alcanzan el máximo y los tiempos de respuesta superan los niveles de SLA.
Cubrir toda la gama de cargas generalmente no requiere más esfuerzo de los equipos de prueba que las meras pruebas en las magnitudes "pico" y "estrés" y las pruebas de resistencia, ya que se utilizan los mismos scripts de prueba (y el esfuerzo principal generalmente es para crear esos scripts). Sin embargo, las ventajas de crear una instantánea del rendimiento son las siguientes:
No es necesario dedicar tiempo y esfuerzo a intentar adivinar la configuración de prueba adecuada que produzca el rendimiento de transacciones "correcto" ("pico" o "estrés"); solo tiene que incrementar la carga y cubrir *todas* las magnitudes de carga y rendimientos compatibles.
Se puede establecer a qué cargas comienzan a crecer los tiempos de respuesta, dónde superan los niveles de SLA y dónde los rendimientos alcanzan niveles máximos.
Esto permite medir directamente la capacidad del sistema; por ejemplo, la magnitud de la carga en la que se alcanza la condición del punto de interrupción (el tiempo de respuesta supera el SLA, o los rendimientos alcanzan los niveles máximos, o el uso de recursos del sistema entra en la "zona roja" especificada; por ejemplo el uso de la CPU alcanza el 90 % o el sistema falla, lo que ocurra primero). Esto significa que no es necesario utilizar los enfoques típicos basados en conjeturas para el análisis y la planificación de la capacidad.
En caso de que las condiciones esperadas de la operación de producción cambien (por ejemplo, las cargas promedio y pico esperadas son redefinidas por el negocio), no es necesario volver a ejecutar las pruebas de rendimiento: las métricas de rendimiento buscadas para las diferentes magnitudes de carga se pueden obtener simplemente por interpolación o extrapolación de los resultados de las pruebas existentes.
Cubrir todo el espectro de cargas en lugar de algunas magnitudes predefinidas permite garantizar que tenemos una visión completa del rendimiento del sistema y no pasar por alto ningún posible problema de rendimiento al no probar el producto en condiciones extremas.
Garantizar que las pruebas incluyan alcanzar los puntos de interrupción de rendimiento del sistema significa que sabemos dónde están los cuellos de botella de rendimiento, qué enlace, componente o capa fallará primero a medida que aumentan las cargas. Esto permite proporcionar un feedback útil y basado en evidencia a los equipos de arquitectura y diseño para mejorar la solidez y el rendimiento del producto.
Existen varios tipos de pruebas de rendimiento que se pueden ejecutar en una solución. Una solución bien diseñada hace uso de todos ellos.
Procure aprovechar al máximo la variedad de datos de rendimiento obtenidos en las pruebas: