Enfoques de arquitectura para el proceso en soluciones multiinquilino

La mayoría de las soluciones basadas en la nube se componen de recursos de proceso de algún tipo, como los niveles web y de aplicación, los procesadores por lotes, los trabajos programados e incluso recursos especializados como las GPU y la informática de alto rendimiento (HPC). Las soluciones multiinquilino suelen aprovechar las ventajas de los recursos de proceso compartidos, ya que una mayor densidad de inquilinos para la infraestructura reduce el costo operativo y la administración. Debe tener en cuenta los requisitos de aislamiento y las implicaciones de la infraestructura compartida.

En este artículo se proporcionan instrucciones sobre las consideraciones y los requisitos que son esenciales para que los arquitectos de soluciones se consideren al planear un nivel de proceso multiinquilino. Esto incluye algunos patrones comunes para aplicar el multiinquilinato a los servicios de proceso, junto con algunos antipatrones que se deben evitar.

Consideraciones clave y requisitos

El multiinquilinato y el modelo de aislamiento que seleccione afectan al escalado, el rendimiento, la administración de estados y la seguridad de los recursos de proceso. En esta sección, se revisan algunas de las principales decisiones que debe tomar al planear una solución de proceso multiinquilino.

Escala

Los sistemas deben tener un rendimiento adecuado con una demanda cambiante. A medida que aumentan el número de inquilinos y la cantidad de tráfico, es posible que tenga que aumentar la capacidad de los recursos para mantenerse al día con el creciente número de inquilinos y mantener una tasa de rendimiento aceptable. De forma similar, cuando disminuye el número de usuarios activos o la cantidad de tráfico, debe reducir automáticamente la capacidad de proceso para reducir los costos, pero debe reducir la capacidad con un impacto mínimo en los usuarios.

Si implementa recursos dedicados para cada inquilino, tiene la flexibilidad de escalar los recursos de cada inquilino de forma independiente. En una solución en la que los recursos de proceso se comparten entre varios inquilinos, si escala esos recursos, todos esos inquilinos pueden usar la nueva escala. Sin embargo, también se verán afectados cuando la escala no sea suficiente para controlar la carga general. Para más información, consulte Antipatrón Vecino ruidoso.

Al crear soluciones en la nube, puede elegir si quiere escalar horizontal o verticalmente. En una solución multiinquilino con un número creciente de inquilinos, el escalado horizontal normalmente proporciona una mayor flexibilidad y un mayor límite de escala general.

Los problemas de rendimiento a menudo permanecen sin detectar hasta que una aplicación está en situaciones de carga. Puede usar un servicio totalmente administrado, como Azure Load Testing, para obtener información sobre cómo se comporta la aplicación en situaciones de esfuerzo.

Desencadenadores de escalado

Sea cual sea el enfoque que use para escalar, normalmente debe planear los desencadenadores que hacen que los componentes se escalen. Cuando se tienen componentes compartidos, tenga en cuenta los patrones de carga de trabajo de todos los inquilinos que usan los recursos, con el fin de asegurarse de que la capacidad aprovisionada pueda satisfacer la capacidad total necesaria y para minimizar la posibilidad de que un inquilino experimente el antipatrón Vecino ruidoso. También puede planear la capacidad de escalado en función del número de inquilinos. Por ejemplo, si mide los recursos que usa para dar servicio a 100 inquilinos, a medida que incorpora más inquilinos, puede planear el escalado para que los recursos se dupliquen por cada 100 inquilinos adicionales.

State

Los recursos de proceso pueden ser sin estado o pueden ser con estado. Los componentes sin estado no mantienen ningún dato entre solicitudes. Desde una perspectiva de escalabilidad, los componentes sin estado suelen ser fáciles de escalar horizontalmente, ya que puede agregar rápidamente nuevos roles, instancias o nodos de trabajo que pueden empezar inmediatamente a procesar solicitudes. Si la arquitectura lo permite, también puede reasignar instancias que están asignadas a un inquilino y asignarlas a otro inquilino.

Los recursos con estado se pueden subdividir aún más, en función del tipo de estado que mantienen. El estado persistente son los datos que se deben almacenar permanentemente. En las soluciones en la nube, debe evitar almacenar un estado persistente en el nivel de proceso. En su lugar, use servicios de almacenamiento, como bases de datos o cuentas de almacenamiento. El estado transitorio son los datos que se almacenan temporalmente e incluyen las caché en memoria de solo lectura y el almacenamiento de archivos temporales en discos locales.

El estado transitorio suele ser útil para mejorar el rendimiento del nivel de aplicación, ya que reduce el número de solicitudes a los servicios de almacenamiento de back-end. Por ejemplo, cuando se usa una caché en memoria, es posible que pueda atender solicitudes de lectura sin conectarse a una base de datos y sin realizar una consulta intensiva que realizó recientemente cuando atendía otra solicitud.

En las aplicaciones sensibles a la latencia, el costo de la hidratación de la memoria caché puede ser significativo. Una solución multiinquilino puede complicar este problema si cada inquilino requiere que se almacenen en caché datos diferentes. Para mitigar este problema, algunas soluciones usan la afinidad de sesión para asegurarse de que el mismo nodo de trabajo de proceso procese todas las solicitudes de un usuario o inquilino específicos. Aunque la afinidad de sesión puede mejorar la capacidad del nivel de aplicación para usar su caché de forma eficaz, también dificulta el escalado y el equilibrio de la carga de tráfico entre los roles de trabajo. Este inconveniente se debe tener en cuenta cuidadosamente. Para muchas aplicaciones, no es necesaria la afinidad de sesión.

También es posible almacenar los datos en memorias caché externas, como Azure Cache for Redis. Las memorias caché externas están optimizadas para la recuperación de datos de baja latencia, a la vez que mantienen el estado aislado de los recursos de proceso, por lo que se pueden escalar y administrar por separado. En muchas soluciones, las memorias caché externas le permiten mejorar el rendimiento de la aplicación y a la vez mantener el nivel de proceso sin estado.

Importante

Evite la filtración de datos entre inquilinos siempre que use cachés en memoria u otros componentes que mantengan el estado. Por ejemplo, considere la posibilidad de anteponer un identificador de inquilino a todas las claves de la memoria caché para asegurarse de que los datos estén separados para cada inquilino.

Aislamiento

Al diseñar un nivel de proceso multiinquilino, a menudo se tienen muchas opciones que se deben tener en cuenta para el nivel de aislamiento entre inquilinos, incluida la implementación de recursos de proceso compartidos para que los utilicen todos los inquilinos, recursos de proceso dedicados para cada inquilino o una situación intermedia entre ambos extremos. Cada opción tiene sus inconvenientes. Para ayudarle a decidir qué opción se adapta mejor a su solución, tenga en cuenta sus requisitos de aislamiento.

Es posible que le preocupe el aislamiento lógico de los inquilinos y cómo separar las responsabilidades de administración o las directivas que se aplican a cada inquilino. Como alternativa, es posible que tenga que implementar configuraciones de recursos distintas para inquilinos específicos, como la implementación de una SKU de máquina virtual específica para adaptarla a la carga de trabajo de un inquilino.

Independientemente del modelo de aislamiento que seleccione, asegúrese de comprobar que los datos del inquilino permanezcan correctamente aislados incluso cuando los componentes no estén disponibles o no funcionen correctamente. Considere la posibilidad de usar Azure Chaos Studio como parte del proceso de pruebas automatizadas normales para introducir deliberadamente errores que simulan interrupciones del mundo real y comprobar que la solución no filtre datos entre inquilinos y funcione correctamente incluso bajo presión.

Enfoques y patrones que se deben tener en cuenta

Escalado automático

Los servicios de proceso de Azure proporcionan diferentes funcionalidades para escalar las cargas de trabajo. Muchos servicios de proceso admiten el escalado automático, lo que requiere que tenga en cuenta cuándo se debe escalar y los niveles mínimo y máximo de escala. Las opciones específicas disponibles para el escalado dependen de los servicios de proceso que use. Consulte los siguientes servicios de ejemplo:

Patrón de stamps de implementación

Para obtener más información sobre cómo se puede usar el patrón de stamps de implementación para admitir una solución multiinquilino, consulte Información general.

Patrón Compute Resource Consolidation

El patrón de consolidación de recursos de proceso ayuda a lograr una mayor densidad de inquilinos para la infraestructura de proceso al compartir los recursos de proceso subyacentes. Al compartir los recursos de proceso, a menudo puede reducir el costo directo de esos recursos. Además, los costos de administración suelen ser menores porque hay menos componentes que administrar.

Sin embargo, la consolidación de recursos de proceso aumenta la probabilidad del antipatrón Vecino ruidoso. La carga de trabajo de cualquier inquilino podría consumir una cantidad desproporcionada de la capacidad de proceso disponible. A menudo, puede mitigar este riesgo asegurándose de escalar la solución correctamente y aplicando controles, como cuotas y límites de API, para evitar que los inquilinos consuman más de su cuota equitativa de la capacidad.

Este patrón se logra de maneras diferentes, en función del servicio de proceso que use. Consulte los siguientes servicios de ejemplo:

  • Azure App Service y Azure Functions: implemente planes compartidos de App Service, que representan la infraestructura del servidor de hospedaje.
  • Azure Container Apps: implemente entornos compartidos.
  • Azure Kubernetes Service (AKS): implemente pods compartidos con una aplicación que tenga en cuenta la arquitectura multiinquilino.
  • Máquinas virtuales: implemente un único conjunto de máquinas virtuales para que todos los inquilinos las usen.

Recursos de proceso dedicados para cada inquilino

También puede implementar recursos de proceso dedicados para cada inquilino. Los recursos dedicados mitigan el riesgo del problema del vecino ruidoso al garantizar que los recursos de proceso de cada inquilino estén aislados de los demás. También permite implementar una configuración distinta para los recursos de cada inquilino en función de sus requisitos. Sin embargo, los recursos dedicados suelen tener un costo mayor, ya que tiene una menor densidad de inquilinos para los recursos.

En función de los servicios de proceso de Azure que use, debe implementar diferentes recursos dedicados, como se muestra a continuación:

  • Azure App Service y Azure Functions: implemente planes de App Service independientes para cada inquilino.
  • Azure Container Apps: implemente entornos independientes para cada inquilino.
  • Azure Kubernetes Service (AKS): implemente clústeres dedicados para cada inquilino.
  • Máquinas virtuales: implemente máquinas virtuales dedicadas para cada inquilino.

Recursos de proceso semi-aislados

Los enfoques semi-aislados requieren que implemente aspectos de la solución en una configuración aislada, mientras comparte los demás componentes.

Al trabajar con App Service y Azure Functions, puede implementar aplicaciones distintas para cada inquilino y hospedar las aplicaciones en planes compartidos de App Service. Este enfoque reduce el costo del nivel de proceso, ya que los planes de App Service representan la unidad de facturación. También permite aplicar distintas directivas y configuraciones a cada aplicación. Sin embargo, este enfoque presenta el riesgo del antipatrón Vecino ruidoso.

Azure Container Apps permite implementar varias aplicaciones en un entorno compartido y, a continuación, usar Dapr y otras herramientas para configurar cada aplicación por separado.

Azure Kubernetes Service (AKS) y Kubernetes de forma más amplia, proporcionan una variedad de opciones para el multiinquilinato, entre las que se incluyen las siguientes:

  • Espacios de nombres específicos del inquilino para el aislamiento lógico de los recursos específicos del inquilino, que se implementan en clústeres compartidos y grupos de nodos.
  • Nodos específicos del inquilino o grupos de nodos en un clúster compartido.
  • Pods específicos del inquilino que podrían usar el mismo grupo de nodos.

AKS también le permite aplicar la gobernanza de nivel de pod para mitigar el antipatrón Vecino ruidoso. Para más información, consulte Procedimientos recomendados para desarrolladores de aplicaciones para administrar recursos en Azure Kubernetes Service (AKS).

También es importante tener en cuenta los componentes compartidos de un clúster de Kubernetes y cómo podrían verse afectados estos componentes por el multiinquilinato. Por ejemplo, el servidor de API de Kubernetes es un servicio compartido que se usa en todo el clúster. Incluso si proporciona grupos de nodos específicos del inquilino para aislar las cargas de trabajo de aplicación de los inquilinos, el servidor de API podría experimentar contención debido a un gran número de solicitudes entre todos los inquilinos.

Antipatrones que se deben evitar

Antipatrón Vecino ruidoso

Cada vez que implementa componentes que se comparten entre inquilinos, el antipatrón Vecino ruidoso es un riesgo potencial. Asegúrese de incluir la supervisión y la gobernanza de los recursos para mitigar el riesgo de que la carga de trabajo de proceso de un inquilino se vea afectada por la actividad de otros inquilinos.

Filtración de datos entre inquilinos

Los niveles de proceso pueden estar sujetos a filtración de datos entre inquilinos si no se administran correctamente. Por lo general, esto no es algo que se deba tener en cuenta cuando se usa un servicio multiinquilino en Azure, ya que Microsoft proporciona protecciones en la capa de plataforma. Sin embargo, al desarrollar su propia aplicación multiinquilino, tenga en cuenta si los recursos compartidos (como cachés de disco local, RAM y cachés externas) pueden contener datos que otro inquilino pueda ver o modificar involuntariamente.

Antipatrón Busy Front End

Para evitar el antipatrón Front-end ocupado, evite que el nivel de front-end haga gran parte del trabajo que podrían hacer otros componentes o niveles de la arquitectura. Este antipatrón es especialmente importante cuando se crean front-ends compartidos para una solución multiinquilino, ya que un front-end ocupado degradará la experiencia de todos los inquilinos.

En su lugar, considere la posibilidad de usar el procesamiento asincrónico mediante colas u otros servicios de mensajería. Este enfoque también le permite aplicar controles de calidad de servicio (QoS) para los distintos inquilinos en función de sus requisitos. Por ejemplo, todos los inquilinos pueden compartir un nivel de front-end común, pero los inquilinos que pagan un nivel de servicio superior podrían tener un mayor conjunto de recursos dedicados para procesar el trabajo de sus mensajes en cola.

Escalado inelástico o insuficiente

Las soluciones multiinquilino suelen estar sujetas a patrones de escalado a ráfagas. Los componentes compartidos son especialmente susceptibles a este problema, ya que el ámbito de las ráfagas es mayor y el impacto es mayor cuando tiene más inquilinos con patrones de uso distintos.

Asegúrese de hacer un buen uso de la elasticidad y la escala de la nube. Considere si debe usar el escalado horizontal o vertical, y usar el escalado automático para controlar automáticamente los picos de carga. Pruebe la solución para comprender cómo se comporta con distintos niveles de carga. Asegúrese de incluir los volúmenes de carga que se esperan en producción y el crecimiento esperado. Puede usar un servicio totalmente administrado, como Azure Load Testing, para obtener información sobre cómo se comporta la aplicación en situaciones de esfuerzo.

Antipatrón No Caching

El antipatrón Sin almacenamiento en caché se produce cuando el rendimiento de la solución se degrada porque el nivel de aplicación solicita o vuelve a procesar repetidamente información que se podría reutilizar entre solicitudes. Si tiene datos que se pueden compartir, ya sea entre inquilinos o entre usuarios dentro de un solo inquilino, es probable que merezca la pena almacenarlos en caché para reducir la carga en el nivel de back-end y base de datos.

Estado innecesario

El corolario del antipatrón Sin almacenamiento en caché es que también debe evitar almacenar un estado innecesario en el nivel de proceso. Sea explícito sobre dónde mantener el estado y por qué. Los niveles de aplicación y de front-end con estado pueden reducir la capacidad de escalado. Por lo general, los niveles de proceso con estado también requieren afinidad de sesión, lo que puede reducir la capacidad de equilibrar la carga del tráfico entre los nodos o los roles de trabajo de forma eficaz.

Tenga en cuenta las ventajas e inconvenientes de cada parte del estado que se mantiene en el nivel de proceso y si afecta a la capacidad de escalar o crecer a medida que cambian los patrones de carga de trabajo de los inquilinos. También puede almacenar el estado en una caché externa, como Azure Cache for Redis.

Colaboradores

Microsoft mantiene este artículo. Originalmente lo escribieron los siguientes colaboradores.

Creadores de entidad de seguridad:

  • Dixit Arora | Senior Customer Engineer, FastTrack for Azure
  • John Downs | Ingeniero de clientes principal, FastTrack for Azure

Otros colaboradores:

Pasos siguientes

Revise las instrucciones específicas del servicio para los servicios de proceso: