Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Cloud de
arquitectura
Application
de aplicaciones
Architecture
en el cloud
Guide
PUBLICADO POR
Microsoft Press
Una división de Microsoft Corporation
One Microsoft Way
Redmond, Washington 98052-6399
Todos los derechos reservados. Ninguna parte del contenido de este libro puede reproducirse ni
transmitirse en forma alguna ni por ningún medio sin la autorización previa por escrito de la editorial.
Los libros de Microsoft Press están a la venta en librerías y distribuidores de todo el mundo. Si
tiene alguna duda relativa a este libro, escriba un correo electrónico a Microsoft Press Support a la
dirección mspinput@microsoft.com. Denos su opinión acerca de este libro en http://aka.ms/tellpress.
Este libro se proporciona “tal cual” y expresa los puntos de vista y opiniones de los autores. Los
puntos de vista, las opiniones y la información vertidos en este libro, incluidas las direcciones URL
y otras referencias a sitios web de Internet, pueden cambiar sin previo aviso.
Algunos ejemplos recogidos en este libro tienen un carácter únicamente ilustrativo y son ficticios.
No debe suponerse ni derivarse ninguna asociación o conexión real.
Editor de adquisiciones:
Christopher Bennage
Editores de desarrollo:
Mike Wasson, Masashi Narumoto y el equipo de modelos y prácticas de Microsoft
Producción editorial:
Phil Evans
Corrector de estilo:
Jamie Letain
i
Contenido
Información general ��������������������������������������������������������������������������������������������������������������������������� vii
Introducción ������������������������������������������������������������������������������������������������������������������������������������������������������������������� viii
Capítulo 1: Elección de un estilo de arquitectura ����������������������������������������������������������������������������� 1
Recorrido rápido por los estilos �������������������������������������������������������������������������������������������������������������������������������� 2
Los estilos de arquitectura como restricciones ���������������������������������������������������������������������������������������������������� 4
Consideración de las dificultades y las ventajas ������������������������������������������������������������������������������������������������� 5
Capítulo 1a: Estilo de arquitectura N-tier ����������������������������������������������������������������������������������������� 6
Cuándo utilizar esta arquitectura ������������������������������������������������������������������������������������������������������������������������������ 7
Ventajas ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 7
Dificultades ������������������������������������������������������������������������������������������������������������������������������������������������������������������������ 7
Procedimientos recomendados ��������������������������������������������������������������������������������������������������������������������������������� 8
La arquitectura N-tier en máquinas virtuales ������������������������������������������������������������������������������������������������������� 8
Consideraciones adicionales ��������������������������������������������������������������������������������������������������������������������������������������� 9
Capítulo 1b: Estilo de arquitectura Web-Queue-Worker �������������������������������������������������������������� 10
Cuándo utilizar esta arquitectura ��������������������������������������������������������������������������������������������������������������������������� 11
Ventajas ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 11
Dificultades ��������������������������������������������������������������������������������������������������������������������������������������������������������������������� 11
Procedimientos recomendados ������������������������������������������������������������������������������������������������������������������������������ 11
Web-Queue-Worker en Azure App Service ������������������������������������������������������������������������������������������������������� 12
Consideraciones adicionales ������������������������������������������������������������������������������������������������������������������������������������ 12
Capítulo 1c: Estilo de arquitectura de microservicios �������������������������������������������������������������������� 14
Cuándo utilizar esta arquitectura ��������������������������������������������������������������������������������������������������������������������������� 15
Ventajas ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 15
Dificultades ��������������������������������������������������������������������������������������������������������������������������������������������������������������������� 16
Procedimientos recomendados ������������������������������������������������������������������������������������������������������������������������������ 17
Microservicios a través de Azure Container Service ��������������������������������������������������������������������������������������� 19
Capítulo 1d: Estilo de arquitectura CQRS ���������������������������������������������������������������������������������������� 20
Cuándo utilizar esta arquitectura ��������������������������������������������������������������������������������������������������������������������������� 21
Ventajas ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 21
Dificultades ��������������������������������������������������������������������������������������������������������������������������������������������������������������������� 22
Procedimientos recomendados ������������������������������������������������������������������������������������������������������������������������������ 22
CQRS en microservicios ��������������������������������������������������������������������������������������������������������������������������������������������� 22
ii Contenido
Capítulo 1e: Estilo de arquitectura controlada por eventos ��������������������������������������������������������� 24
Cuándo utilizar esta arquitectura ��������������������������������������������������������������������������������������������������������������������������� 25
Ventajas ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 25
Dificultades ��������������������������������������������������������������������������������������������������������������������������������������������������������������������� 25
Arquitecturas IoT ���������������������������������������������������������������������������������������������������������������������������������������������������������� 26
Capítulo 1f: Estilo de arquitectura de Big Data ������������������������������������������������������������������������������ 27
Ventajas ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 29
Dificultades ��������������������������������������������������������������������������������������������������������������������������������������������������������������������� 29
Procedimientos recomendados ������������������������������������������������������������������������������������������������������������������������������ 30
Capítulo 1g: Estilo de arquitectura de Big Compute ���������������������������������������������������������������������� 31
Cuándo utilizar esta arquitectura ��������������������������������������������������������������������������������������������������������������������������� 32
Ventajas ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 32
Dificultades ��������������������������������������������������������������������������������������������������������������������������������������������������������������������� 32
Big Compute con Azure Batch �������������������������������������������������������������������������������������������������������������������������������� 33
Big Compute en máquinas virtuales ��������������������������������������������������������������������������������������������������������������������� 33
Capítulo 2: Elección de las tecnologías de proceso y de almacén de datos �������������������������������� 35
Capitulo 2a: Información general de las opciones de proceso ����������������������������������������������������� 37
Capítulo 2b: Comparación de procesos ������������������������������������������������������������������������������������������� 39
Modelo de hosting ������������������������������������������������������������������������������������������������������������������������������������������������������ 39
DevOps ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 40
Escalabilidad ������������������������������������������������������������������������������������������������������������������������������������������������������������������� 41
Disponibilidad ���������������������������������������������������������������������������������������������������������������������������������������������������������������� 41
Seguridad ������������������������������������������������������������������������������������������������������������������������������������������������������������������������ 42
Otros ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 42
Capítulo 2c: Información general de almacén de datos ���������������������������������������������������������������� 43
Sistemas de administración de bases de datos relacionales ����������������������������������������������������������������������� 44
Almacenes de pares clave-valor ����������������������������������������������������������������������������������������������������������������������������� 44
Bases de datos de documentos ������������������������������������������������������������������������������������������������������������������������������ 45
Bases de datos de gráficos ��������������������������������������������������������������������������������������������������������������������������������������� 46
Bases de datos de familias de columnas ������������������������������������������������������������������������������������������������������������� 47
Análisis de datos ����������������������������������������������������������������������������������������������������������������������������������������������������������� 48
Bases de datos de motores de búsqueda ����������������������������������������������������������������������������������������������������������� 48
Bases de datos de series temporales �������������������������������������������������������������������������������������������������������������������� 48
Almacenamiento de objetos ������������������������������������������������������������������������������������������������������������������������������������ 49
Archivos compartidos ������������������������������������������������������������������������������������������������������������������������������������������������� 49
Capítulo 2d: Comparación de almacenes de datos ������������������������������������������������������������������������ 50
Criterios para la elección de un almacén de datos ����������������������������������������������������������������������������������������� 50
Consideraciones generales ��������������������������������������������������������������������������������������������������������������������������������������� 50
Sistemas de administración de bases de datos relacionales (RDBMS) ��������������������������������������������������� 52
Bases de datos de documentos ������������������������������������������������������������������������������������������������������������������������������ 53
Almacenes de pares clave-valor ����������������������������������������������������������������������������������������������������������������������������� 54
iii Contenido
Bases de datos de gráficos ��������������������������������������������������������������������������������������������������������������������������������������� 55
Bases de datos de familias de columnas ������������������������������������������������������������������������������������������������������������� 56
Bases de datos de motores de búsqueda ����������������������������������������������������������������������������������������������������������� 57
Almacenamiento de datos ���������������������������������������������������������������������������������������������������������������������������������������� 57
Bases de datos de series temporales �������������������������������������������������������������������������������������������������������������������� 58
Almacenamiento de objetos ������������������������������������������������������������������������������������������������������������������������������������ 58
Archivos compartidos ������������������������������������������������������������������������������������������������������������������������������������������������� 59
Capítulo 3: Diseño de la aplicación Azure: principios de diseño �������������������������������������������������� 60
Capítulo 3a: Diseño para la recuperación automática ������������������������������������������������������������������� 62
Recomendaciones �������������������������������������������������������������������������������������������������������������������������������������������������������� 62
Capítulo 3b: Hacer que todo sea redundante ��������������������������������������������������������������������������������� 64
Recomendaciones �������������������������������������������������������������������������������������������������������������������������������������������������������� 64
Capítulo 3c: Reducción de la coordinación ������������������������������������������������������������������������������������� 66
Recomendaciones �������������������������������������������������������������������������������������������������������������������������������������������������������� 67
Capítulo 3d: Diseño pensando en la escalabilidad ������������������������������������������������������������������������� 69
Recomendaciones �������������������������������������������������������������������������������������������������������������������������������������������������������� 69
Capítulo 3e: Creación de particiones para evitar límites ��������������������������������������������������������������� 71
Recomendaciones �������������������������������������������������������������������������������������������������������������������������������������������������������� 72
Capítulo 3f: Diseño para el equipo de operaciones ����������������������������������������������������������������������� 73
Recomendaciones �������������������������������������������������������������������������������������������������������������������������������������������������������� 73
Capítulo 3g: Uso de servicios administrados ���������������������������������������������������������������������������������� 75
Capítulo 3h: Uso del mejor almacén de datos para el trabajo ������������������������������������������������������ 76
Recomendaciones �������������������������������������������������������������������������������������������������������������������������������������������������������� 77
Capítulo 3i: Diseño para permitir la evolución ������������������������������������������������������������������������������� 78
Recomendaciones �������������������������������������������������������������������������������������������������������������������������������������������������������� 78
Capítulo 3j: Desarrollo en función de las necesidades del negocio ��������������������������������������������� 80
Recomendaciones �������������������������������������������������������������������������������������������������������������������������������������������������������� 80
Capítulo 3k: Diseño de aplicaciones resistentes para Azure ��������������������������������������������������������� 82
¿Qué entendemos por resistencia? ����������������������������������������������������������������������������������������������������������������������� 82
Proceso para obtener resistencia ��������������������������������������������������������������������������������������������������������������������������� 83
Definición de los requisitos de resistencia ��������������������������������������������������������������������������������������������������������� 83
Diseño para garantizar la resistencia �������������������������������������������������������������������������������������������������������������������� 87
Estrategias de resistencia ����������������������������������������������������������������������������������������������������������������������������������������� 87
Implementación resistente ��������������������������������������������������������������������������������������������������������������������������������������� 91
Supervisión y diagnóstico ���������������������������������������������������������������������������������������������������������������������������������������� 92
Respuestas manuales ante errores ������������������������������������������������������������������������������������������������������������������������ 93
Resumen �������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 94
Capítulo 4: Diseño de la aplicación Azure: uso de los pilares de la calidad �������������������������������� 95
Escalabilidad ������������������������������������������������������������������������������������������������������������������������������������������������������������������� 96
Disponibilidad ���������������������������������������������������������������������������������������������������������������������������������������������������������������� 98
Resistencia ����������������������������������������������������������������������������������������������������������������������������������������������������������������������� 99
iv Contenido
Administración y DevOps ���������������������������������������������������������������������������������������������������������������������������������������� 100
Seguridad ���������������������������������������������������������������������������������������������������������������������������������������������������������������������� 101
Capítulo 5: Diseño de la aplicación Azure: patrones de diseño �������������������������������������������������� 103
Dificultades en el desarrollo en el cloud ����������������������������������������������������������������������������������������������������������� 103
Administración de datos ����������������������������������������������������������������������������������������������������������������������������������������� 104
Diseño e implementación ��������������������������������������������������������������������������������������������������������������������������������������� 104
Mensajería ��������������������������������������������������������������������������������������������������������������������������������������������������������������������� 105
Administración y supervisión �������������������������������������������������������������������������������������������������������������������������������� 106
Rendimiento y escalabilidad ���������������������������������������������������������������������������������������������������������������������������������� 107
Resistencia ��������������������������������������������������������������������������������������������������������������������������������������������������������������������� 108
Seguridad ���������������������������������������������������������������������������������������������������������������������������������������������������������������������� 109
Capítulo 6: Catálogo de patrones ��������������������������������������������������������������������������������������������������� 110
Patrón embajador ������������������������������������������������������������������������������������������������������������������������������������������������������� 110
Patrón de capa para evitar daños ������������������������������������������������������������������������������������������������������������������������ 112
Patrón Back-ends for Front-ends �������������������������������������������������������������������������������������������������������������������������� 114
Patrón bulkhead ���������������������������������������������������������������������������������������������������������������������������������������������������������� 116
Patrón Cache-Aside ��������������������������������������������������������������������������������������������������������������������������������������������������� 119
Patrón de interruptor de circuito �������������������������������������������������������������������������������������������������������������������������� 124
Patrón CQRS ����������������������������������������������������������������������������������������������������������������������������������������������������������������� 132
Patrón de transacciones de compensación ������������������������������������������������������������������������������������������������������ 139
Patrón de consumidores competitivos �������������������������������������������������������������������������������������������������������������� 143
Patrón de consolidación de recursos de proceso ������������������������������������������������������������������������������������������ 148
Patrón de abastecimiento de eventos ���������������������������������������������������������������������������������������������������������������� 156
Patrón de almacén de configuración externa ������������������������������������������������������������������������������������������������� 162
Patrón de identidad federada �������������������������������������������������������������������������������������������������������������������������������� 170
Patrón de Gatekeeper ����������������������������������������������������������������������������������������������������������������������������������������������� 174
Patrón de agregación de puerta de enlace ������������������������������������������������������������������������������������������������������ 176
Patrón de descarga de puerta de enlace ���������������������������������������������������������������������������������������������������������� 180
Patrón de enrutamiento de puerta de enlace ������������������������������������������������������������������������������������������������� 182
Patrón de supervisión de puntos de conexión de estado �������������������������������������������������������������������������� 185
Patrón de tabla de índice ���������������������������������������������������������������������������������������������������������������������������������������� 191
Patrón de elección del líder ������������������������������������������������������������������������������������������������������������������������������������ 197
Patrón de vistas materializadas ����������������������������������������������������������������������������������������������������������������������������� 204
Patrón de canalizaciones y filtros ������������������������������������������������������������������������������������������������������������������������� 208
Patrón de colas de prioridad ���������������������������������������������������������������������������������������������������������������������������������� 215
Patrón de nivelación de carga basada en cola ������������������������������������������������������������������������������������������������ 221
Patrón de reintento ���������������������������������������������������������������������������������������������������������������������������������������������������� 224
Patrón de programador-agente-supervisor ����������������������������������������������������������������������������������������������������� 227
Patrón de particionamiento ����������������������������������������������������������������������������������������������������������������������������������� 234
Patrón de sidecar �������������������������������������������������������������������������������������������������������������������������������������������������������� 243
v Contenido
Patrón de hosting de contenido estático ���������������������������������������������������������������������������������������������������������� 246
Patrón de estrangulador ������������������������������������������������������������������������������������������������������������������������������������������ 250
Patrón de limitación �������������������������������������������������������������������������������������������������������������������������������������������������� 252
Patrón de llave de valet �������������������������������������������������������������������������������������������������������������������������������������������� 256
Capítulo 7: Listas de comprobación de revisión del diseño �������������������������������������������������������� 263
Lista de comprobación de DevOps ��������������������������������������������������������������������������������������������������������������������� 264
Lista de comprobación de disponibilidad �������������������������������������������������������������������������������������������������������� 270
Lista de comprobación de escalabilidad ����������������������������������������������������������������������������������������������������������� 276
Lista de comprobación de resistencia ���������������������������������������������������������������������������������������������������������������� 276
Servicios de Azure ������������������������������������������������������������������������������������������������������������������������������������������������������ 286
Capítulo 8: Resumen������������������������������������������������������������������������������������������������������������������������� 291
Capítulo 9: Arquitecturas de referencia de Azure ������������������������������������������������������������������������ 292
Administración de identidades ����������������������������������������������������������������������������������������������������������������������������� 293
Red híbrida �������������������������������������������������������������������������������������������������������������������������������������������������������������������� 298
Red DMZ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������ 303
Aplicación web administrada ��������������������������������������������������������������������������������������������������������������������������������� 306
Ejecución de cargas de trabajo en máquina virtual de Linux �������������������������������������������������������������������� 310
Ejecución de cargas de trabajo en máquina virtual de Windows ����������������������������������������������������������� 315
vi Contenido
Guía de arquitectura
de aplicaciones en el
cloud
Esta guía presenta un enfoque estructurado para el diseño de aplicaciones
en el cloud escalables, resistentes y con una elevada disponibilidad. Las
recomendaciones de este libro electrónico pretenden ayudarle a tomar
decisiones de arquitectura independientemente de la plataforma del cloud,
aunque utilizaremos Azure para poder compartir los procedimientos
recomendados derivados de muchos años de relaciones con nuestros clientes.
1. Elección del estilo de arquitectura correcto para una aplicación en función del
tipo de solución que se está construyendo.
4. Uso de los cinco pilares de calidad del software para garantizar el éxito.
vii Introducción
Introducción
El cloud está cambiando la forma en que se diseñan las aplicaciones. En lugar
de monolitos, las aplicaciones se descomponen en servicios más pequeños
y descentralizados. Estos servicios se comunican a través de API o mediante
mensajería asincrónica o eventos. Las aplicaciones crecen horizontalmente,
agregando nuevas instancias a medida que crece la demanda.
Estas tendencias comportan nuevas dificultades. El estado de las aplicaciones se distribuye. Las
operaciones se realizan en paralelo y de forma asincrónica. El sistema en su conjunto debe ser flexible
cuando surgen errores. Las implementaciones deben ser automáticas y predecibles. La supervisión y la
telemetría son críticas para un mayor conocimiento del sistema. La Guía de arquitectura de aplicaciones
Azure está diseñada para ayudarle a incorporar estos cambios.
El cloud está cambiando la forma en que se diseñan las aplicaciones. En lugar de monolitos, las
aplicaciones se descomponen en servicios más pequeños y descentralizados. Estos servicios se comunican
a través de API o mediante mensajería asincrónica o eventos. Las aplicaciones crecen horizontalmente,
agregando nuevas instancias a medida que crece la demanda.
Estas tendencias comportan nuevas dificultades. El estado de las aplicaciones se distribuye. Las operaciones
se realizan en paralelo y de forma asincrónica. El sistema en su conjunto debe ser flexible cuando surgen
errores. Las implementaciones deben ser automáticas y predecibles. La supervisión y la telemetría son
críticas para un mayor conocimiento del sistema. La Guía de arquitectura de aplicaciones en el cloud está
diseñada para ayudarle a entender e incorporar estos cambios.
viii
Estilos de arquitectura. La primera decisión es la más importante. ¿Qué tipo de arquitectura construye?
Podría ser una arquitectura de microservicios, una aplicación N-tier más tradicional o una solución de
Big Data. Hemos identificado siete estilos de arquitectura distintos. Cada uno de ellos tiene ventajas
y dificultades.
Opciones de tecnología. Existen dos opciones de tecnología sobre las que cabe tomar una decisión
desde el principio, porque afectan a toda la arquitectura. Se trata de la elección de las tecnologías
de proceso y almacenamiento. El término "proceso" se refiere al modelo de hosting de los recursos
informáticos sobre los que se ejecutan las aplicaciones. El almacenamiento incluye las bases de datos, pero
también el almacenamiento de colas de mensajes, cachés, datos de IoT, datos de registro no estructurados
y cualquier otra cosa que una aplicación pueda almacenar de forma persistente.
Principios de diseño. Durante el proceso de diseño, tenga presentes estos diez principios de diseño de
alto nivel.
Pilares. Una aplicación de cloud con éxito está centrada en estos cinco pilares de la calidad del software:
escalabilidad, disponibilidad, resistencia, administración y seguridad.
●● Utilice nuestras listas comprobación para la revisión del diseño y revise su diseño de acuerdo con
estos pilares de la calidad.
Patrones de diseño del cloud. Estos patrones de diseño son útiles para construir aplicaciones de Azure
fiables, escalables y seguras. Cada patrón describe un problema, un patrón que aborda el problema y un
ejemplo basado en Azure.
Antes de comenzar
Obtenga
ayuda de los
Si todavía no lo ha hecho, crea una cuenta de Azure gratuita para poder
empezar a trabajar con este libro electrónico.
ix Introducción
1
Elección de un estilo
de arquitectura
La primera decisión que debe tomar al diseñar una aplicación en el cloud
se refiere a la arquitectura. Elija la mejor arquitectura para la aplicación
que está creando en función de su complejidad, el tipo de dominio, si es
una aplicación de IaaS o PaaS y lo que hará la aplicación. También debe
tener en cuenta los conocimientos de los equipos de desarrolladores
y DevOps, y si la aplicación cuenta con una arquitectura existente.
Esta sección describe los diez principios de diseño que debe tener en cuenta durante el desarrollo. Seguir
estos principios le ayudará a crear una aplicación más escalable, resistente y administrable.
N-tier
N-tier es una arquitectura tradicional para aplicaciones empresariales. Las dependencias se gestionan
dividiendo la aplicación en capas que realizan funciones lógicas, como presentación, lógica de negocio y
acceso a los datos. Una capa solo puede hacer llamadas a las capas que tienen por debajo. Sin embargo, esta
estratificación horizontal por capas puede convertirse en un pasivo. Puede ser difícil introducir cambios en una
parte de la aplicación sin tocar el resto de la aplicación. Esto convierte las actualizaciones frecuentes son todo
un reto y limita la rapidez con que se introducen las nuevas características.
El uso de N-tier es apropiado para migrar las aplicaciones existentes que ya utilizan una arquitectura en
capas. Por este motivo, N-tier se ve más a menudo en soluciones de infraestructura como servicio (IaaS)
o aplicaciones que utilizan una mezcla de IaaS y servicios gestionados.
Web-Queue-Worker
Para una solución plenamente PaaS, considere una arquitectura de tipo Web-Queue-Worker.
En este estilo, la aplicación cuenta con un front-end web que controla las solicitudes HTTP y un trabajo
de back-end que realiza tareas que requieren un uso intenso de la CPU u operaciones de larga duración.
El front-end se comunica con el trabajo a través de una cola de mensajes asincrónicos.
El modelo Web-Queue-Worker es apropiado para dominios relativamente simples con algunas tareas
que requieren un uso de recursos intensivo. Al igual que N-tier, la arquitectura es fácil de entender. El uso
de servicios gestionados simplifica la implementación y las operaciones. Pero con dominios complejos,
puede ser difícil administrar las dependencias. El front-end y el trabajo pueden convertirse fácilmente en
componentes grandes y monolíticos, difíciles de mantener y actualizar. Igual que sucede con N-tier, esto
puede reducir la frecuencia de las actualizaciones y limitar la innovación.
Cada servicio lo puede crear un pequeño equipo de desarrollo especializado. Es posible implementar
servicios individuales sin demasiada coordinación entre los equipos, lo que anima a realizar
actualizaciones frecuentes. Una arquitectura de microservicios es más compleja de construir y manejar que
una arquitectura N-tier o web-queue-worker. Requiere una cultura de desarrollo y DevOps madura. Pero
bien hecho, este estilo de arquitectura permite ganar velocidad, innovar con mayor rapidez y contar con
una arquitectura más resistente.
CQRS
El estilo CQRS (Command and Query Responsibility Segregation) separa las operaciones de lectura y
escritura en modelos separados. De esta forma se aíslan las partes del sistema que actualizan los datos de
las partes que leen los datos. Además, las lecturas pueden ejecutarse en una vista materializada que está
físicamente separada de la base de datos de escritura. Esto permite escalar las cargas de trabajo de lectura
y escritura de forma independiente y optimizar la vista materializada para consultas.
El uso de CQRS es más lógico cuando se aplica a un subsistema de una arquitectura más grande. Por
lo general, no debe imponerse en toda la aplicación pues solo provocaría una complejidad innecesaria.
Considere su uso en dominios colaborativos donde muchos usuarios acceden a los mismos datos.
Plantéese el uso de una arquitectura controlada por eventos para aquellas aplicaciones que ingieren y
procesan un gran volumen de datos con una latencia muy baja, como las soluciones de IoT. Este estilo
también es útil cuando diferentes subsistemas deben realizar diferentes tipos de procesamiento para los
mismos datos de evento.
Respetando estas restricciones, lo que surge es un sistema en el que los servicios pueden
implementarse de forma independiente, se aíslan los errores, permite actualizaciones frecuentes y resulta
fácil introducir nuevas tecnologías en la aplicación.
La tabla siguiente resume cómo se ocupa de las dependencias cada estilo y los tipos de dominio más
adecuados para cada uno.
Web-Queue-Worker Trabajos de front-end y back-end, desacoplados Dominio relativamente simple con algunas tareas
mediante mensajería asincrónica. que requieren un uso de recursos intensivo.
CQRS Segregación de lectura y escritura. El esquema y la Dominio colaborativo en el que muchos usuarios
escala se optimizan por separado. acceden a los mismos datos.
Arquitectura controlada por Productor/consumidor. Vista independiente por IoT y sistemas en tiempo real.
eventos subsistema.
Divide un enorme conjunto de datos en trozos pequeños. Análisis de datos en tiempo real y por lotes. Análisis
Big Data Procesamiento paralelo en conjuntos de datos locales. predictivo con ML.
Big Compute Asignación de datos a miles de núcleos. Dominios de proceso intensivo como la simulación.
Estas son algunas de las dificultades que cabe considerar al seleccionar un estilo de arquitectura:
●● Complejidad. ¿La complejidad de la arquitectura está justificada para su dominio? O, por el contrario,
¿el estilo es demasiado sencillo para su dominio? En ese caso, corre el riesgo de acabar en un barrizal,
porque la arquitectura no le ayudará a administrar adecuadamente las dependencias.
●● Facilidad de uso. ¿Es difícil administrar la aplicación, supervisarla, implementar las actualizaciones,
etc.?
Estilo de arquitectura
N-tier
Una arquitectura N-tier divide una aplicación en capas lógicas y niveles físicos.
Las capas son una manera de separar responsabilidades y gestionar dependencias. Cada capa tiene una
responsabilidad específica. Una capa superior puede utilizar los servicios de una capa más baja, pero no al
revés.
Los niveles están físicamente separados y se ejecutan en máquinas independientes. Un nivel puede
llamar directamente a otro nivel o utilizar la mensajería asincrónica (cola de mensajes). Aunque cada capa
puede estar alojada en su propio nivel, no es obligatorio. Varias capas pueden alojarse en el mismo nivel.
Separar físicamente los niveles mejora la escalabilidad y la resistencia, pero también añade la latencia de la
comunicación de red adicional.
Una aplicación tradicional de tres niveles tiene un nivel de presentación, un nivel intermedio y un nivel de
base de datos. El nivel intermedio es opcional. Las aplicaciones más complejas pueden tener más de tres
niveles. El diagrama superior muestra una aplicación con dos niveles intermedios en los que se encapsulan
diferentes áreas de funcionalidad.
●● En una arquitectura de capa cerrada, una capa solo puede llamar a la siguiente capa inmediatamente
por debajo
●● En una arquitectura de capa abierta, una capa puede llamar a cualquiera de las capas situadas por
debajo de ella.
Una arquitectura de capa cerrada limita las dependencias entre las capas, pero puede crear tráfico de red
innecesario si una capa se limita a pasar las solicitudes a la capa siguiente.
Las arquitecturas N-tier son muy comunes en las aplicaciones tradicionales locales, por lo que son una
elección natural para la migración de las cargas de trabajo existentes a Azure.
Ventajas
●● Portabilidad entre cloud y local, y entre plataformas del cloud.
●● Menor curva de aprendizaje para la mayoría de desarrolladores.
●● Evolución natural del modelo tradicional de aplicaciones.
●● Abierta a entornos heterogéneos (Windows/Linux)
Dificultades
●● Es fácil terminar con un nivel intermedio que simplemente realiza operaciones de CRUD en la base de
datos y agrega latencia adicional sin hacer ningún trabajo útil.
Esta sección describe una arquitectura N-tier recomendada en ejecución en máquinas virtuales. Cada nivel
consta de dos o más máquinas virtuales, en un conjunto de disponibilidad o un conjunto de escalado de
máquinas virtuales. Múltiples máquinas virtuales ofrecen resistencia en caso de que una máquina virtual falle.
Se utilizan equilibradores de carga para distribuir solicitudes a las máquinas virtuales de un nivel. Un nivel
puede escalarse horizontalmente añadiendo más máquinas virtuales al grupo.
Cada nivel se ubica también dentro de su propia subred, lo que significa que sus direcciones IP internas
se engloban dentro del mismo rango de direcciones. De esta forma resulta fácil aplicar reglas de grupo de
seguridad de red (NSG) y tablas de ruta a niveles individuales.
Los niveles de web y empresarial no tienen estado. Cualquier máquina virtual puede ocuparse de cualquier
solicitud de ese nivel. El nivel de datos debe consistir en una base de datos replicada. Para Windows,
recomendamos SQL Server, utilizando Grupos de disponibilidad AlwaysOn para alta disponibilidad. Para
Linux, elija una base de datos que permita la replicación, como Apache Cassandra.
Los Grupos de seguridad de red (NSG) restringen el acceso a cada nivel. Por ejemplo, el nivel de base de
datos solo permite el acceso desde el nivel empresarial.
Consideraciones adicionales
●● Las arquitecturas N-tier no están restringidas a tres niveles. Para aplicaciones más complejas, es
habitual tener más niveles. En ese caso, plantéese utilizar el enrutamiento de capa 7 para enrutar
solicitudes a un nivel particular.
●● Los niveles son los límites de escalabilidad, fiabilidad y seguridad. Plantéese tener niveles separados
para servicios con requisitos diferentes en esas áreas.
●● Busque lugares en la arquitectura donde pueda utilizar un servicio gestionado sin una refactorización
importante. En concreto, analice el almacenamiento en caché, la mensajería, el almacenamiento y las
bases de datos.
●● Para mayor seguridad, coloque una red DMZ frente a la aplicación. La DMZ incluye dispositivos de
red virtuales (NVA) que implementan la funcionalidad de seguridad como firewalls e inspección de
paquetes. Para obtener más información, vea Arquitectura de referencia de la red DMZ.
●● Para alta disponibilidad, coloque dos o más NVA en un conjunto de disponibilidad, con un
equilibrador de cargas externas para distribuir las solicitudes de Internet en las instancias. Para
obtener más información, vea Implementar dispositivos virtuales de red de alta disponibilidad.
●● No permita el acceso directo de RDP o SSH a máquinas virtuales que ejecutan el código de la
aplicación. En lugar de ello, los operadores deben iniciar sesión en un jumpbox, también conocido
como pasarela de aplicaciones. Se trata de una máquina virtual en la red que los administradores
utilizan para conectarse a las otras máquinas virtuales. El jumpbox tiene un NSG que permite RDP o
SSH solo desde direcciones IP públicas aprobadas.
●● Puede extender la red virtual de Azure a su red local usando una red privada virtual (VPN) de sitio
a sitio o Azure ExpressRoute. Para obtener más información, vea Arquitectura de referencia de red
híbrida.
●● Si su organización utiliza Active Directory para administrar la identidad, puede que desee extender
su entorno de Active Directory a la Azure VNet. Para obtener más información, vea Arquitectura de
referencia de administración de identidad.
●● Si necesita mayor disponibilidad que la que ofrece el SLA de Azure para máquinas virtuales, replique
la aplicación en dos regiones y utilice Traffic Manager de Azure para conmutación por error. Para
obtener más información, vea Ejecutar máquinas virtuales de Windows en varias regiones o
Ejecutar máquinas virtuales de Linux en varias regiones.
Estilo de arquitectura
Web-Queue-Worker
Los componentes básicos de esta arquitectura son un front-end web
que sirve las solicitudes del cliente y un trabajo que realiza tareas que
requieren un uso intensivo de recursos, flujos de trabajo de larga duración
o trabajos por lotes. El front-end web se comunica con el trabajo a través
de una cola de mensajes.
El front-end puede consistir en una API web. En el lado del cliente, la API web se puede usar con una
aplicación de una sola página que realiza las llamadas AJAX o con una aplicación cliente nativa.
Ventajas
●● Arquitectura relativamente sencilla y fácil de entender.
●● Fácil de implementar y administrar.
●● Clara separación de problemas.
●● El front-end se desacopla del trabajo por medio de la mensajería asincrónica.
●● El front-end y el trabajo pueden escalarse de forma independiente.
Dificultades
●● Sin un diseño cuidadoso, el front-end y el trabajo pueden convertirse en componentes grandes y
monolíticos difíciles de mantener y actualizar.
Procedimientos recomendados
●● Utilice la persistencia políglota cuando sea apropiado. Vea Uso del mejor almacén de datos para el
trabajo.
●● Para ver los artículos de procedimientos recomendados que ofrecen orientación específica sobre el
escalado automático, el almacenamiento en caché, la partición de datos, el diseño API y más, vaya a
https://docs.microsoft.com/en-us/azure/architecture/best-practices/index.
El front-end se implementa como una aplicación web de Azure App Service y el trabajo se implementa
como un WebJob. La aplicación web y el WebJob se asocian con un plan de servicios de aplicaciones que
proporciona las instancias de máquina virtual.
Puede utilizar colas de Azure Service Bus o Azure Storage para la cola de mensajes. (El diagrama muestra
una cola de Azure Storage).
Azure Redis Cache almacena el estado de la sesión y otros datos que necesitan acceso de baja latencia.
Azure CDN se utiliza para almacenar en caché contenido estático como imágenes, CSS o HTML.
Para el almacenamiento, elija las tecnologías de almacenamiento que mejor se adapten a las necesidades
de la aplicación. Puede utilizar múltiples tecnologías de almacenamiento (persistencia políglota). Para
ilustrar esta idea, el diagrama muestra Azure SQL Database y Azure Cosmos DB.
Para obtener más información, vea Arquitectura de referencia de aplicación web administrada.
Consideraciones adicionales
●● No todas las transacciones deben pasar por la cola y el trabajo para el almacenamiento. El front-end
web puede realizar operaciones sencillas de lectura/escritura directamente. Los trabajos están diseñados
para tareas que requieren un uso intensivo de recursos o flujos de trabajo de larga duración. En algunos
casos, quizás no necesite un trabajo en absoluto.
●● Utilice la función integrada de escalado integrado de App Service para ampliar el número de
instancias de máquina virtual. Si la carga de la aplicación sigue patrones predecibles, utilice el
escalado automático basado en programación. Si la carga es impredecible, utilice reglas de escalado
automático basado en métricas.
●● Utilice planes independientes de App Service para la producción y las pruebas. De lo contrario,
si utiliza el mismo plan para producción y pruebas, significa que las pruebas se ejecutan en sus
máquinas virtuales de producción.
●● Utilice ranuras de implementación para administrar las implementaciones. Esto permite implementar
una versión actualizada en un período de ensayo y, posteriormente, cambiar a la nueva versión.
También le permite volver a la versión anterior si ha habido algún problema en la actualización.
Estilo de arquitectura
de microservicios
Una arquitectura de microservicios consiste en una colección de
servicios pequeños y autónomos. Cada servicio es autónomo y debería
implementar una única capacidad empresarial.
De alguna manera, los microservicios son la evolución natural de las arquitecturas orientadas a servicios
(SOA) pero existen diferencias entre los microservicios y las SOA. Estas son algunas características
definitorias de un microservicio:
●● Cada servicio es una base de código independiente que puede administrar un pequeño equipo de
desarrollo.
●● Los servicios son responsables de conservar sus propios datos o estado externo. Esto difiere del
modelo tradicional, donde una capa de datos independiente se ocupa de la persistencia de los datos.
●● No es necesario que los servicios compartan el mismo conjunto de tecnologías, bibliotecas o marcos
de trabajo.
Además de los propios servicios, en una arquitectura típica de microservicios aparecen otros
componentes:
Detección de servicios. Mantiene una lista de servicios y los nodos en que se encuentran. Permite la
búsqueda de servicios para encontrar el punto de conexión de un servicio.
Puerta de enlace de API. La puerta de enlace API es el punto de entrada para los clientes. Los clientes no
llaman directamente a los servicios. En su lugar, llaman a la puerta de enlace API, que remite la llamada a
los servicios apropiados en el back-end. La puerta de enlace API podría agregar las respuestas de varios
servicios y devolver la respuesta agregada.
Estas son algunas de las ventajas de utilizar una puerta de enlace de API:
●● Desvincula a los clientes de los servicios. Los servicios pueden versionarse o reestructurarse sin
necesidad de actualizar todos los clientes.
●● Los servicios pueden utilizar protocolos de mensajería que no son aptos para el web, como AMQP.
●● La puerta de enlace API puede realizar otras funciones transversales como autenticación, registro,
terminación SSL y equilibrio de carga.
Ventajas
●● Implementaciones independientes. Puede actualizar un servicio sin volver a implementar toda la
aplicación y revertir o recuperar una actualización si algo sale mal. Las correcciones de errores y los
lanzamientos de características son más manejables y entrañan menos riesgos.
●● Aislamiento de errores. Si un servicio falla, no arrastrará consigo a toda la aplicación. Pero eso
no quiere decir que obtenga resistencia a cambio de nada. Deberá seguir los procedimientos
recomendados y los patrones de diseño para poder beneficiarse de dicha resistencia. Vea Diseño de
aplicaciones resistentes para Azure.
●● Pilas de tecnología mixta. Los equipos pueden elegir la tecnología que mejor se adapte a su servicio.
●● Escalado pormenorizado. Los servicios pueden escalarse de forma independiente. Al mismo tiempo,
existe una mayor densidad de servicios por máquina virtual, lo que significa que los recursos de la
máquina virtual se aprovechan plenamente. Las restricciones de emplazamiento permiten emparejar
un servicio con un perfil de máquina virtual (uso elevado de la CPU, uso elevado de la memoria y así
sucesivamente).
Dificultades
●● Complejidad. Una aplicación de microservicios tiene más partes móviles que la aplicación monolítica
equivalente. Los servicios individuales son más simples, pero todo el sistema en conjunto es más
complejo.
●● Desarrollo y pruebas. El desarrollo sobre la base de las dependencias de los servicios requiere un
enfoque diferente. Las herramientas existentes no están diseñadas necesariamente para trabajar
con las dependencias de los servicios. Una refactorización que se extienda más allá de los límites de
servicio puede ser difícil. También resulta complicado comprobar las dependencias de los servicios,
especialmente si la aplicación evoluciona rápidamente.
●● Integridad de los datos. Con cada microservicio responsable de su propia persistencia de datos.
Como resultado, puede ser complicado garantizar la consistencia de los datos. Adopte la coherencia
entre eventos siempre que sea posible.
●● Administración. Tener éxito con los microservicios requiere una cultura de DevOps madura.
El registro correlacionado entre servicios puede ser complicado. Por lo general, el registro debe
correlacionar múltiples llamadas de servicio para una operación de un solo usuario.
●● Control de versiones. Las actualizaciones de un servicio no deben romper los servicios que
dependen de él. En cualquier momento podrían actualizarse múltiples servicios, por lo que sin
un diseño cuidadoso podría tener problemas de compatibilidad hacia delante o hacia atrás.
●● Conjunto de habilidades. Los microservicios son sistemas altamente distribuidos. Evalúe con
atención si el equipo cuenta con las habilidades y la experiencia para tener éxito.
●● Descentralícelo todo. Los equipos individuales son responsables del diseño y la construcción de
servicios. Evite compartir esquemas de código o datos.
●● El almacenamiento de los datos debe ser privado para el servicio que posee los datos. Utilice el mejor
almacenamiento para cada tipo de servicio y de datos.
●● Los servicios se comunican a través de API bien diseñadas. Evite la filtración de detalles de la
implementación. Las API deben modelar el dominio, no la implementación interna del servicio.
●● Descargue las cuestiones de transversalidad, tales como autenticación y terminación SSL, a la puerta
de enlace.
●● Mantenga el conocimiento del dominio fuera de la puerta de enlace. La puerta de enlace debe
manejar y enrutar las solicitudes del cliente, sin conocimiento de las reglas de negocio o la lógica de
dominio. De lo contrario, la puerta de enlace se convierte en una dependencia y puede provocar el
acoplamiento entre servicios.
●● Los servicios deben contar con un acoplamiento flexible y una alta cohesión funcional. Las funciones
que pueden cambiar juntas deben empaquetarse e implementarse juntas. Si residen en diferentes
servicios, dichos servicios terminan asociados entre sí de una forma muy estrecha porque un cambio
en un servicio requerirá la actualización del otro servicio. Una comunicación demasiado locuaz entre
dos servicios puede ser un síntoma de baja cohesión y emparejamiento inflexible.
●● Aísle los errores Utilice estrategias de resistencia para evitar errores dentro de un servicio derivados de
un efecto en cascada. Vea el diseño de aplicaciones resistentes.
Para acceder a una lista y resumen de los patrones de resistencia disponibles en Azure, acceda a
https://docs.microsoft.com/en-us/azure/architecture/patterns/category/resiliency.
Nodos públicos. Estos nodos son accesibles a través de un equilibrador de cargas público. La puerta de
enlace de API se aloja en estos nodos.
Nodos de back-end. En estos nodos se ejecutan servicios a los que los clientes acceden a través de la
puerta de enlace de API. Estos nodos no reciben directamente el tráfico de Internet. Los nodos de back-end
pueden incluir más de una agrupación de máquinas virtuales, cada una con un perfil de hardware diferente.
Por ejemplo, podría crear agrupaciones separadas para cargas de trabajo de procesos generales, cargas de
trabajo que requieran un consumo intensivo de la CPU y cargas de trabajo que hagan un uso intensivo de la
memoria.
Administración de máquinas virtuales. En estas máquinas virtuales se ejecutan los nodos maestros para
el organizador de contenedores.
Redes. Los nodos públicos, los nodos de back-end y las máquinas virtuales de administración se ubican en
subredes independientes dentro de la misma red virtual (VNet).
Equilibradores de cargas. Un equilibrador de cargas externo se ubica delante de los nodos públicos.
Distribuye las solicitudes de Internet a los nodos públicos. Otro equilibrador de cargas se coloca delante
de las máquinas virtuales de administración para permitir el tráfico de shell seguro (ssh) a las máquinas
virtuales de administración utilizando reglas de NAT.
Para mayor fiabilidad y escalabilidad, cada servicio se replica en múltiples máquinas virtuales. Puesto
que los servicios son también relativamente ligeros (en comparación con una aplicación monolítica),
normalmente se agrupan múltiples servicios en una única máquina virtual. Una mayor densidad permite
una mejor utilización de los recursos. Si un determinado servicio no usa muchos recursos, no es necesario
que dedique una máquina virtual completa a la ejecución de dicho servicio.
El clúster Service Fabric se implementa en uno o más conjuntos de escalado de máquinas virtuales. Puede
tener más de un conjunto de escalado de máquina virtual en el clúster para tener una combinación de
tipos de máquinas virtuales. Una puerta de enlace de API se coloca delante del clúster Service Fabric, con
un equilibrador de cargas externo para recibir las solicitudes del cliente.
El tiempo de ejecución Service Fabric se ocupa de la administración del clúster, incluyendo la colocación
de servicios, la conmutación por error en nodos y la supervisión del estado. El tiempo de ejecución se
implementa en los propios nodos del clúster. No existe un conjunto independiente de máquinas virtuales
de administración de clústeres.
Los servicios se comunican entre ellos utilizando el proxy inverso integrado en Service Fabric. Service
Fabric ofrece un servicio de detección que puede resolver el punto de conexión para un servicio
determinado.
Estilo de arquitectura
CQRS
CQRS (Command and Query Responsibility Segregation) es un estilo de
arquitectura que separa las operaciones de lectura de las de escritura.
En las arquitecturas tradicionales, se utiliza el mismo modelo de datos para consultar y actualizar una base de
datos. Es un procedimiento sencillo y funciona bien para las operaciones básicas de CRUD. En aplicaciones
más complejas, pero este procedimiento puede llegar a ser difícil de manejar. Por ejemplo, en el lado de la
lectura, la aplicación puede realizar muchas consultas diferentes, devolviendo objetos de transferencia de
datos (DTO) con formas diferentes. La asignación de objetos puede llegar a ser complicada. En el lado de la
escritura, el modelo puede implementar una lógica validación y de negocio compleja. El resultado puede ser
un modelo excesivamente complejo que hace demasiado.
Otro problema potencial es que las cargas de trabajo de lectura y escritura a menudo son asimétricas, con
requerimientos de rendimiento y escala muy diferentes.
CQRS aborda estos problemas separando la lectura y la escritura en modelos diferentes mediante
comandos que actualizan los datos y consultas que los leen.
●● Los comandos deben estar basados en tareas, en lugar de centrarse en los datos. ("Reservar
habitación de hotel" en lugar de "establecer EstadoReserva en Reservado"). Los comandos pueden
colocarse en una cola para su procesamiento asincrónico, en lugar de procesarse sincrónicamente.
●● Las consultas nunca modifican la base de datos. Una consulta devuelve un DTO que no encapsula
ningún conocimiento del dominio.
Algunas implementaciones de CQRS utilizan el patrón de abastecimiento de eventos. Con este patrón, el
estado de la aplicación se almacena como una secuencia de eventos. Cada evento representa un conjunto de
cambios de los datos. El estado actual se construye mediante la reproducción de los eventos. En un contexto
CQRS, una de las ventajas del abastecimiento de eventos es que pueden utilizarse los mismos eventos para
notificar otros componentes, en particular, para notificar el modelo de lectura. El modelo de lectura utiliza los
eventos para crear una instantánea del estado actual, que es más eficiente para consultas. De todos modos,
el abastecimiento de eventos complica el diseño.
CQRS no es una arquitectura de alto nivel válida para todo un sistema. Utilice CQRS solo en aquellos
subsistemas en los que la separación de la lectura y la escritura resulte en un beneficio claro. De lo
contrario, creará mayor complejidad y no obtendrá ningún beneficio.
Ventajas
●● Escalado independiente. CQRS permite el escalado independiente de las cargas de trabajo de lectura
y escritura y puede desencadenar menos contenciones de bloqueos.
●● Esquemas de datos optimizados. El lado de lectura puede utilizar un esquema que esté optimizado
para las consultas, mientras que el lado de la escritura utiliza un esquema optimizado para las
actualizaciones.
●● Seguridad. Es más fácil garantizar que solo las entidades de dominio adecuadas escriben en los datos.
Dificultades
●● Complejidad. La idea básica de CQRS es sencilla. Pero puede llevar a un diseño de aplicaciones más
complejo, especialmente si incluyen el patrón de abastecimiento de eventos.
●● Mensajería. Aunque CQRS no requiere mensajería, es habitual utilizar la mensajería para procesar
comandos y publicar eventos de actualización. En ese caso, la aplicación debe gestionar errores de
mensajes o mensajes duplicados.
●● Coherencia entre eventos. Si se separan las bases de datos de lectura y escritura, los datos de lectura
pueden quedar obsoletos.
Procedimientos recomendados
●● Para obtener más información sobre la implementación de CQRS, vaya a https://docs.microsoft.com/
en-us/azure/architecture/patterns/cqrs.
●● Para obtener información sobre cómo utilizar el patrón de abastecimiento de eventos para evitar
conflictos de actualización, vaya a https://docs.microsoft.com/en-us/azure/architecture/patterns/
event-sourcing.
●● Para obtener información sobre cómo utilizar el patrón de vista materializada para el modelo de
lectura, para optimizar el esquema para consultas, vaya a https://docs.microsoft.com/en-us/azure/
architecture/patterns/materialized-view.
CQRS en microservicios
CQRS puede ser especialmente útil en una arquitectura de microservicios. Uno de los principios de los
microservicios es que un servicio no puede acceder directamente al almacén de datos de otro servicio.
Estilo de arquitectura
controlada por eventos
Una arquitectura controlada por eventos consiste en productores de
eventos que generan un flujo de eventos y consumidores de eventos
que atienden los eventos.
Los eventos se entregan prácticamente en tiempo real, por lo que los consumidores pueden
responder inmediatamente a los eventos que se producen. Los productores están desvinculados de los
consumidores, es decir un productor no sabe qué consumidores reciben los eventos. Los consumidores
también están desvinculados unos de otros y cada consumidor ve todos los eventos. Es diferente del
patrón de consumidores competitivos, en el que los consumidores extraen mensajes de una cola y cada
mensaje se procesa solo una vez (suponiendo que no hay errores). En algunos sistemas, tales como IoT,
es preciso ingerir eventos a volúmenes muy altos.
Una arquitectura controlada por eventos puede utilizar un modelo de publicación-suscripción (pub/sub)
o un modelo de flujo de eventos.
●● Streaming de eventos: los eventos se escriben en un registro. Los eventos se ordenan estrictamente
(dentro de una partición) y son duraderos. Los clientes no se suscriben a un flujo, sino que un cliente
puede leer desde cualquier parte del flujo. El cliente se ocupa de avanzar su posición en el flujo.
Eso significa que un cliente puede unirse en cualquier momento y puede reproducir eventos.
●● Procesamiento de flujo de eventos. Utilice una plataforma de streaming de datos, como Azure
IoT Hub o Apache Kafka, como canalización para ingerir eventos y alimentarlos a procesadores de
flujos. Los procesadores de flujo actúan para procesar o transformar el flujo. Puede haber múltiples
procesadores de flujo para diferentes subsistemas de la aplicación. Este enfoque es adecuado para las
cargas de trabajo de IoT.
El origen de los eventos puede ser externo al sistema, como dispositivos físicos de una solución de IoT. En
ese caso, el sistema debe ser capaz de introducir los datos en el volumen y con la capacidad que requiere
el origen de datos.
En el diagrama lógico anterior, cada tipo de consumidor se muestra como un cuadro único. En la práctica,
es habitual tener varias instancias de un consumidor para evitar que se convierta en un punto único
de error del sistema. También pueden ser necesarias varias instancias para gestionar el volumen y la
frecuencia de eventos. Además, un único consumidor puede procesar eventos en varios subprocesos. Esto
puede crear problemas si los eventos deben procesarse en orden o deben procesarse exactamente una
vez. Vea Reducción de la coordinación.
Ventajas
●● Los productores y consumidores se desvinculan.
●● No existen las integraciones punto a punto. Es fácil añadir nuevos consumidores en el sistema.
●● Los consumidores pueden responder a los eventos inmediatamente a medida que llegan.
●● Altamente escalable y distribuida.
●● Los subsistemas tienen vistas independientes del flujo de eventos.
Dificultades
●● Entrega garantizada. En algunos sistemas, especialmente en los escenarios de IoT, es crucial garantizar
que se entregan los eventos.
●● Procesamiento de eventos en orden o exactamente una vez. Cada tipo de consumidor normalmente
se ejecuta en múltiples instancias, para mayor resistencia y escalabilidad. Esto puede plantear una
dificultad si los eventos deben procesarse en orden (dentro de un tipo de consumidor) o si la lógica
de procesamiento no es idempotente.
La puerta de enlace del cloud introduce eventos de dispositivo en el límite del cloud con un sistema de
mensajería de baja latencia.
Los dispositivos pueden enviar eventos directamente a la puerta de enlace del cloud o a través de
una puerta de enlace in situ. Una puerta de enlace in situ es un dispositivo o software especializado,
normalmente colocado con los dispositivos, que recibe eventos y los reenvía a la puerta de enlace del
cloud. La puerta de enlace in situ también puede preprocesar los eventos de dispositivos raw y realizar
funciones tales como filtración, agregación o transformación del protocolo.
Después de su introducción, los eventos pasan por uno o más procesadores de flujos que pueden
enrutar los datos (por ejemplo, al almacenamiento) o realizar el análisis y otros procesos.
A continuación encontrará una lista con algunos tipos comunes de procesamiento. (Esta lista no es
exhaustiva).
●● Análisis de ruta de acceso activa, analizando el flujo de eventos en tiempo (casi) real, para detectar
anomalías, reconocer patrones a lo largo de ventanas temporales graduales o desencadenar alertas
cuando se produce una situación específica en el flujo.
●● Gestión de tipos especiales de mensajes que no son de telemetría procedentes de dispositivos tales
como notificaciones y alarmas.
Machine learning.
Los cuadros sombreados en gris muestran los componentes de un sistema IoT que no están directamente
relacionados con la transmisión de eventos, pero se incluyen para garantizar la integridad.
●● El registro de dispositivos es una base de datos de los dispositivos suministrados, que incluye los ID
del dispositivo y metadatos del dispositivo, tales como la ubicación.
Estilo de arquitectura
de Big Data
Una arquitectura de Big Data está diseñada para gestionar la
introducción, procesamiento y análisis de datos demasiado voluminosos
o demasiado complejos para los sistemas de base de datos tradicionales.
Las soluciones de Big Data generalmente involucran uno o más de los siguientes tipos de carga de trabajo:
La mayoría de arquitecturas de Big Data incluyen algunos de los siguientes componentes o todos ellos:
●● Orígenes de datos: todas las soluciones de Big Data comienzan con uno o más orígenes de datos.
Ejemplos:
• Almacenes de datos de aplicaciones, como bases de datos relacionales.
• Archivos estáticos producidos por aplicaciones, como archivos de registro de servidor web.
• Orígenes de datos en tiempo real, tales como dispositivos de IoT.
●● Almacenamiento de datos: los datos para las operaciones de procesamiento por lotes normalmente
se almacenan en un almacén de archivos distribuidos que puede contener grandes volúmenes de
archivos de gran tamaño en distintos formatos. Este tipo de almacén a menudo se denomina "lago de
datos". Las opciones para la implementación de este almacenamiento incluyen Azure Data Lake Store
o contenedores de blobs en Azure Storage.
●● Procesamiento de flujos. Después de capturar mensajes en tiempo real, la solución debe procesarlos
para filtrarlos, agregar y preparar de otros modos los datos para el análisis. Los datos de flujo
procesados se escriben entonces en un receptor de salida. Azure Stream Analytics proporciona un
servicio de procesamiento de flujo administrado basado en la ejecución perpetua de consultas SQL
que funcionan en flujos sin límites. También puede utilizar tecnologías Apache de streaming de código
abierto como Storm y Spark Streaming en un clúster HDInsight.
●● Almacén de datos analíticos. Muchas soluciones de Big Data preparan los datos para el análisis y sirven
estos datos procesados en un formato estructurado que se puede consultar utilizando herramientas
analíticas. El almacén de datos analíticos utilizado para servir estas consultas puede ser un almacén
de datos relacionales de estilo Kimball, como el de la mayoría de soluciones de Business intelligence
(BI) tradicionales. También es posible presentar los datos a través de una tecnología de NoSQL de
baja latencia como HBase o una base de datos Hive interactiva que proporciona una abstracción de
metadatos de los archivos de datos en el almacén de datos distribuidos. El almacenamiento de datos
SQL de Azure proporciona un servicio administrado para el almacenamiento de datos a gran escala,
basado en el cloud. HDInsight es compatible con Interactive Hive, HBase y Spark SQL, que también
pueden utilizarse para servir datos para el análisis.
Azure incluye muchos servicios que pueden utilizarse en una arquitectura de Big Data. Se engloban
básicamente en dos categorías:
●● Servicios administrados, incluyendo Azure Data Lake Store, Azure Data Lake Analytics, Azure Data
Warehouse, Azure Stream Analytics, Azure Event Hub, Azure IoT Hub y Azure Data Factory.
Estas opciones no son mutuamente excluyentes y muchas soluciones combinan tecnologías de código
abierto con los servicios de Azure.
Ventajas
●● Opciones de tecnología. Es posible mezclar y combinar servicios administrados de Azure y
tecnologías Apache en clústeres HDInsight para aprovechar los conocimientos existentes o las
inversiones en tecnología.
●● Rendimiento mediante el paralelismo. Las soluciones de Big Data aprovechan el paralelismo, que
permite soluciones de alto rendimiento que se adaptan a grandes volúmenes de datos.
●● Escala elástica. Todos los componentes de la arquitectura de Big Data admiten el aprovisionamiento
de escalado horizontal de forma que pueda ajustar su solución a cargas de trabajo pequeñas
o grandes y pagar solo por los recursos que utiliza.
●● Interoperabilidad con las soluciones existentes. Los componentes de la arquitectura de Big data
también se utilizan para soluciones de procesamiento de IoT y BI empresarial, y permiten crear una
solución integrada a través de cargas de trabajo de datos.
Dificultades
●● Complejidad. Las soluciones de Big data pueden ser extremadamente complejas, con numerosos
componentes para controlar la ingestión de datos procedentes de múltiples orígenes de datos.
Construir, probar y solucionar problemas de procesos de Big Data puede ser todo un reto. Por otra
parte, puede haber un gran número de opciones de configuración en múltiples sistemas que deberán
utilizarse para optimizar el rendimiento.
●● Madurez de la tecnología. Muchas de las tecnologías que se usan en Big Data están evolucionando.
Aunque algunas tecnologías Hadoop tales como Hive y Pig se han estabilizado, las tecnologías
emergentes tales como Spark introducen grandes cambios y mejoras en cada nuevo lanzamiento.
Los servicios administrados como Azure Data Lake Analytics y Azure Data Factory son relativamente
jóvenes, en comparación con otros servicios de Azure y probablemente evolucionarán con el tiempo.
●● Seguridad. Las soluciones de Big Data generalmente se basan en almacenar todos los datos estáticos
en un data lake centralizado. Garantizar el acceso a estos datos puede ser difícil, especialmente
cuando hay múltiples plataformas y aplicaciones en las que ingerir y que consumen estos datos,
●● Proceso de datos local. Las soluciones de BI tradicionales suelen utilizan un proceso de extracción,
transformación y carga (ETL) para trasladar los datos a un almacén de datos. Con datos de volúmenes
más grandes y una mayor variedad de formatos, las soluciones de Big Data generalmente utilizan
variaciones de ETL, como la transformación, extracción y carga (TEL). Con este enfoque, los datos se
procesan dentro del almacén de datos distribuidos, transformándolos en la estructura requerida antes
de transferir los datos transformados a un almacén de datos analíticos.
●● Equilibrio y costes temporales. Para los trabajos de procesamiento por lotes, es importante
considerar dos factores: el coste por unidad de los nodos de proceso y el coste por minuto del uso de
esos nodos para completar el trabajo. Por ejemplo, un trabajo por lotes puede tardar ocho horas con
cuatro nodos de clúster. Sin embargo, podría ser que el trabajo utilizara los cuatro nodos solo durante
las dos primeras horas y que después solo necesitara dos nodos. En ese caso, ejecutar todo el trabajo
en dos nodos aumentaría el tiempo total del trabajo, pero no lo multiplicaría por dos, por lo que el
coste total sería menor. En algunos escenarios empresariales, un tiempo de procesamiento más largo
puede ser preferible al mayor coste del uso de recursos de clúster infrautilizados.
●● Limpiar los datos confidenciales al principio. El flujo de trabajo de ingesta de datos debe limpiar
los datos confidenciales al principio del proceso, para evitar almacenarlos en el data lake.
Estilo de arquitectura
de Big Compute
El término Big Compute describe cargas de trabajo a gran escala que requieren
una gran cantidad de núcleos, en ocasiones centenares o miles de ellos. Entre
los escenarios se incluyen el procesamiento de imágenes, la dinámica de
fluidos, el modelado de riesgos financieros, la prospección petrolífera, el diseño
de medicamentos y el análisis de estrés de ingeniería, entre otros.
A continuación se presentan algunas de las características típicas de las aplicaciones Big Compute:
●● El trabajo se puede dividir en tareas discretas, que se pueden ejecutar en varios núcleos al mismo tiempo.
●● Cada tarea es finita. Acepta datos de entrada, hace algún procesamiento y produce una salida. Toda
la aplicación se ejecuta durante un periodo de tiempo finito (de minutos a días). Un patrón común
consiste en aprovisionar una gran cantidad de núcleos en un pico de demanda y reducir a cero una
vez que se completa la aplicación.
●● La aplicación no necesita estar activa ininterrumpidamente. Sin embargo, el sistema debe controlar los
errores de los nodos o los bloqueos de las aplicaciones.
●● En el caso de algunas aplicaciones, las tareas son independientes y se pueden ejecutar en paralelo.
En otros casos, las tareas están asociadas entre sí de forma estrecha, lo que significa que deben
interactuar o intercambiar resultados intermedios. En ese caso, considere la posibilidad de usar
tecnologías de red de alta velocidad, como InfiniBand, y el acceso directo a memoria remota (RDMA).
●● En función de la carga de trabajo, puede utilizar tamaños de máquina virtual de uso intensivo de
proceso (H16r, H16mr y A9).
●● Simulaciones que hacen un uso intensivo de computación y se deben dividir en varias CPU en
diferentes equipos (de decenas a miles).
●● Simulaciones que requieren demasiada memoria para un equipo y deben dividirse en varios equipos.
●● Cálculos con tiempos de ejecución largos que tardan demasiado en completarse en un solo equipo.
●● Cálculos más pequeños que se deben ejecutar cientos o miles de veces, como las simulaciones de
Monte Carlo.
Ventajas
●● Alto rendimiento con procesamiento "incómodamente paralelo".
●● Puede aprovechar centenares o miles de núcleos de equipo para resolver más rápidamente los
problemas grandes.
●● Acceso a hardware de alto rendimiento especializado, con redes InfiniBand de alta velocidad dedicadas.
●● Pueden aprovisionar tantas máquinas virtuales como sean necesarias para realizar el trabajo y,
después, quitarlas.
Dificultades
●● Administrar la infraestructura de máquinas virtuales.
●● En el caso de las tareas asociadas entre sí de forma estrecha, la adición de más núcleos puede tener
menos rendimiento. Tal vez deba experimentar para encontrar el número óptimo de núcleos.
Con Azure Batch, se configura un grupo de máquinas virtuales y se cargan las aplicaciones y los archivos
de datos. A continuación, el servicio Batch aprovisiona las máquinas virtuales, les asigna tareas, ejecuta
las tareas y supervisa el progreso. Batch puede escalar horizontalmente las máquinas virtuales como
respuesta a la carga de trabajo. Batch también proporciona programación de trabajos.
Elección de las
tecnologías de proceso
y de almacén de datos
Elija las tecnologías adecuadas para las aplicaciones de Azure.
Al diseñar una solución para Azure, existen dos decisiones de tecnología que debe tomar al principio del
proceso de diseño, porque afectan a toda la arquitectura. Se trata de la elección de las tecnologías de
proceso y de almacén de datos.
La opción de proceso consiste en decidir el modelo de hosting para los recursos informáticos en los
que se ejecuta su aplicación. En un sentido más amplio, la decisión se toma entre IaaS (infraestructura
como servicio), PaaS (plataforma como servicio) o FaaS (funciones como servicio), y todas las opciones
intermedias. En Azure actualmente se puede elegir entre siete opciones de proceso principales. Para
elegir una, tenga en cuenta las características adecuadas y las limitaciones del servicio, la disponibilidad
y escalabilidad, el coste y las consideraciones de DevOps. Las tablas de comparación de esta sección le
ayudarán a reducir las opciones.
El almacén de datos incluye cualquier tipo de datos que su aplicación deba administrar, procesar y generar,
o que los usuarios deban crear. Los tipos más habituales son los datos de empresa, la memoria caché,
los datos de IoT, la telemetría y los datos de registro no estructurados, y las aplicaciones suelen contener
más de un tipo de datos. Los distintos tipos de datos tienen requisitos de procesamiento diferentes, y
debe elegir el almacén adecuado para cada tipo con el fin de obtener los mejores resultados. Algunas
tecnologías de almacén de datos admiten varios modelos de almacenamiento. Use la información de
esta sección para elegir primero qué modelo de almacenamiento es el más adecuado a sus requisitos.
Después, plantéese un determinado almacén de datos en esa categoría, en función de factores tales como
el conjunto de características, el coste y la facilidad de administración.
●● En los criterios para elegir una opción de proceso se comparan servicios de proceso de Azure
específicos en diferentes ejes, incluido el modelo de hosting, DevOps, disponibilidad y escalabilidad.
●● En los criterios de comparación para elegir un almacén de datos se describen algunos de los factores
que se deben tener en cuenta al elegir un almacén de datos.
Para obtener más información sobre estas opciones de proceso, vaya a: https://docs.microsoft.com/
en-us/azure/#pivot=services.
36
2a
Información general de
las opciones de proceso
El término proceso se refiere al modelo de hosting de los recursos
informáticos en los que se ejecuta la aplicación.
En un extremo del espectro está la infraestructura como servicio (IaaS). Con IaaS, se aprovisionan
las máquinas virtuales necesarias, junto con los componentes de red y de almacenamiento asociados.
Después, se implementan el software y las aplicaciones que se desean en esas máquinas virtuales. Este
modelo es el más parecido a un entorno local tradicional, con la excepción de que Microsoft administra la
infraestructura. El usuario sigue administrando las máquinas virtuales individuales.
La plataforma como servicio (PaaS) proporciona un entorno de hosting administrado, donde puede
implementar su aplicación sin necesidad de administrar máquinas virtuales o recursos de red. Por ejemplo,
en lugar de crear máquinas virtuales individuales, puede especificar un recuento de instancias y el servicio
aprovisionará, configurará y administrará los recursos necesarios. Azure App Service es un ejemplo de
servicio PaaS.
Hay varias alternativas intermedias entre IaaS y PaaS puro. Por ejemplo, las máquinas virtuales de Azure se
pueden escalar automáticamente mediante conjuntos de escalado de máquinas virtuales. Esta capacidad
de escalado automático no es estrictamente PaaS, pero es el tipo de característica de administración que
se podría encontrar en un servicio PaaS.
Las funciones como servicio (FaaS) van más lejos en la despreocupación por el entorno de hosting. En
lugar de crear calcular instancias de proceso e implementar código en ellas, simplemente se implementa
el código y el servicio lo ejecuta automáticamente. No es necesario administrar los recursos de proceso.
Estos servicios utilizan una arquitectura sin servidor y se amplían o reducen sin problemas al nivel que sea
necesario para controlar el tráfico. Azure Functions es un servicio FaaS.
IaaS ofrece más control, flexibilidad y portabilidad. FaaS proporciona simplicidad, escalado elástico
y posibilidad de ahorro, porque solo se paga por el tiempo que se ejecuta el código.
PaaS se encuentra en medio de los dos. En general, cuanta más flexibilidad proporciona un servicio, más
responsabilidad tiene el usuario para configurar y administrar los recursos. Los servicios FaaS administran
de forma automática prácticamente todos los aspectos de la ejecución de una aplicación, mientras
que las soluciones IaaS necesitan que aprovisione, configure y administre las máquinas virtuales y los
componentes de red que ha creado.
A continuación se presentan las opciones de proceso principales que están disponibles en Azure:
●● Virtual Machines es un servicio IaaS, que le permite implementar y administrar las máquinas virtuales
en una red virtual (VNet).
●● Service Fabric es una plataforma de sistemas distribuidos que se puede ejecutar en numerosos
entornos, incluido Azure o de forma local. Service Fabric es un organizador de microservicios en un
clúster de máquinas.
●● Azure Container Service permite crear, configurar y administrar un clúster de máquinas virtuales que
están preconfiguradas para ejecutar aplicaciones de contenedor.
●● Azure Batch es un servicio administrado para ejecutar aplicaciones de informática de alto rendimiento
(HPC) en paralelo y a gran escala.
●● Cloud Services es un servicio administrado para ejecutar aplicaciones en el cloud. Usa un modelo de
hosting de PaaS.
Al seleccionar una opción de proceso, le indicamos algunos factores que debe tener en cuenta:
●● Modelo de hosting. ¿Cómo se hospeda el servicio? ¿Qué requisitos y limitaciones impone este
entorno de hosting?
●● DevOps. ¿Está integrada la compatibilidad con las actualizaciones de las aplicaciones? ¿Cuál es el
modelo de implementación?
●● Escalabilidad. ¿Cómo controla el servicio la adición o eliminación de instancias? ¿Se puede escalar
automáticamente según la carga y otras métricas?
●● Coste. Además del coste del propio servicio, tenga en cuenta el coste operativo para administrar una
solución basada en ese servicio. Por ejemplo, soluciones IaaS podrían tener un mayor coste operativo.
38
2b
Comparación de
procesos
El término "proceso" se refiere al modelo de hosting de los recursos
informáticos sobre los que se ejecutan las aplicaciones. En las tablas siguientes
se comparan los servicios de proceso de Azure en varios ejes. Consúltelas
cuando vaya a seleccionar una opción de proceso para su aplicación.
Modelo de hosting
Azure
Virtual Azure Cloud
Criterios App Service Service Fabric Container Azure Batch
Machines Functions Services
Services
Servicios,
Composición Trabajos
Independiente Aplicaciones ejecutables de Funciones Contenedores Roles
de aplicaciones programados
invitado
Varias
Una
aplicaciones Varios Varios
Varios servicios instancia
por instancia Sin instancias contenedores contenedores
Densidad Independiente por máquina de rol por
mediante dedicadas por máquina por máquina
virtual máquina
planes de virtual virtual
virtual
aplicación
¿Se puede
implementar en
Admitido Admitido Admitido No admitido Admitido Admitido Admitido
una red virtual 6
dedicada?
Conectividad
Admitido Admitido Admitido No admitido Admitido Admitido Admitido
híbrida 8
DevOps
Azure
Virtual Cloud Azure
Criterios App Service Service Fabric Azure Functions Container
Machines Services Batch
Services
Tiempo de
Depuración IIS Express, Clúster de CLI de Azure ejecución de Emulador No
Independiente
local otros nodos locales Functions contenedor local admitido
local
Ejecutable
Aplicación web,
de invitado, Aplicación
trabajos web
Modelo de modelo de Funciones con Rol web, rol de la
Independiente para las tareas Independiente
programación servicio, modelo desencadenadores de trabajo línea de
en segundo
de actores, comandos
plano
contenedores
Administrador 2
Admitido Admitido Admitido Admitido Admitido Limitado Admitido
de recursos
Notas:
1. Entre las opciones se incluyen IIS Express para ASP.NET o node.js (iisnode), servidor web PHP,
kit de herramientas de Azure para IntelliJ y kit de herramientas de Azure para Eclipse. App
Service también admite la depuración remota de la aplicación web implementada.
Equilibrador Equilibrador
Equilibrador Equilibrador de Equilibrador de
Integrado de carga de Integrado de carga de Integrado
de carga carga de Azure carga de Azure
Azure Azure
Límite de 20
Imagen de
20 núcleos de forma
plataforma:
instancias, Sin límite predeterminada.
1000 nodos por
Límite de 50 con el 100 nodos 1 definido, Póngase en
VMSS, imagen Infinito 100
escala Entorno del por VMSS 200 máximo contacto con el
personalizada:
Servicio de recomendado servicio al cliente
100 nodos por
aplicaciones para solicitar un
VMSS
aumento.
Notas:
Disponibilidad
Azure
Virtual Azure Cloud
Criterios App Service Service Fabric Container Azure Batch
Machines Functions Services
Services
Conmutación Administrador
por error Administrador Administrador de tráfico, No Administrador Administrador
No admitido
de varias de tráfico de tráfico clúster de varias admitido de tráfico de tráfico
regiones regiones
Notas:
1. Para obtener más información sobre SLA específicos, vaya a https://azure.microsoft.com/
en-us/support/legal/sla/.
Configurado Configurado
SSL en la máquina Admitido Admitido Admitido en la máquina Admitido Admitido
virtual virtual
Otros
Azure
Virtual Service Cloud Azure
Criterios App Service Azure Functions Container
Machines Fabric Services Batch
Services
Precios de
Precios de
Windows, Precios de Precios de Azure Precios de
Coste Service Admitido
Linux App service Azure Functions Container Cloud Services
Fabric
Service
Estilos
de Microservicios, Web-Queue Big
Admitido Admitido Admitido Admitido
arquitectura EDA Worker Compute
adecuados
Notas:
Información general
de almacén de datos
Elegir el almacén de datos correcto.
Los sistemas empresariales modernos administran volúmenes de datos cada vez más grandes. Los datos
se pueden obtener de servicios externos, los puede generar el sistema o los pueden crear los usuarios.
Estos conjuntos de datos pueden tener características y requisitos de procesamiento extremadamente
variados. Las empresas usan datos para evaluar tendencias, desencadenar procesos de negocio, auditar
sus operaciones, analizar el comportamiento de los clientes y mucho más.
Esta heterogeneidad implica que un solo almacén de datos normalmente no es el mejor planteamiento. En
su lugar, suele ser mejor guardar los diferentes tipos de datos en almacenes de datos distintos, cada uno
centrado en una carga de trabajo o patrón de uso específicos. El término "persistencia políglota" se usa
para describir las soluciones que usan una combinación de tecnologías de almacén de datos.
La selección del almacén de datos adecuado a los requisitos es una decisión de diseño clave. Hay
literalmente cientos de implementaciones para elegir entre las bases de datos SQL y NoSQL. Los
almacenes de datos se suelen clasificar por el modo en que estructuran los datos y los tipos de
operaciones que admiten. En este artículo se describen varios de los modelos de almacenamiento más
habituales. Tenga en cuenta que una determinada tecnología de almacén de datos puede admitir varios
modelos de almacenamiento. Por ejemplo, un sistema de administración de bases de datos relacionales
(RDBMS) también puede admitir un almacenamiento de pares clave-valor o gráfico. De hecho, existe una
tendencia general para la compatibilidad multimodelo, en la que un solo sistema de base de datos admite
varios modelos. Pero sigue siendo útil conocer los diferentes modelos a grandes rasgos.
No todos los almacenes de datos de una categoría determinada proporcionan el mismo conjunto de
características. La mayoría de los almacenes de datos proporcionan funcionalidad del lado servidor
para consultar y procesar los datos. En ocasiones, esta funcionalidad está integrada en el motor
de almacenamiento de datos. En otros casos, el almacenamiento de datos y las capacidades de
procesamiento están separadas, y puede haber varias opciones de procesamiento y de análisis.
Los almacenes de datos también admiten diferentes interfaces de programación y administración.
Por lo general, debe empezar por analizar qué modelo de almacenamiento resulta más adecuado según
sus requisitos. Después, plantéese un determinado almacén de datos en esa categoría, en función de
factores tales como el conjunto de características, el coste y la facilidad de administración.
Un RDBMS normalmente admiten un modelo de esquema de escritura, por el que la estructura de datos
se define con anterioridad y todas las operaciones de lectura o escritura deben usar el esquema. Por el
contrario, en la mayoría de los almacenes de datos NoSQL, en concreto los de tipo de pares clave-valor, el
modelo de esquema de lectura supone que el cliente impondrá su propio esquema de interpretación en
los datos procedentes de la base de datos y es independiente del formato de datos que se va a escribir.
Un RDBMS es muy útil cuando es importante la garantía de una coherencia sólida, en la que todos los
cambios son atómicos y las transacciones siempre dejan los datos en estado coherente. Sin embargo,
las estructuras subyacentes no se prestan al escalado mediante la distribución del almacenamiento
y el procesamiento en varios equipos. Además, la información almacenada en un RDBMS debe tener
una estructura relacional según el proceso de normalización. Aunque este proceso se entiende bien,
puede provocar ineficiencias debido a la necesidad de separar las entidades lógicas en filas de tablas
independientes y, a continuación, volver a combinar los datos al ejecutar consultas.
La mayoría de los almacenes de pares clave-valor solo admiten las operaciones simples de consulta,
inserción y eliminación. Para modificar un valor, tanto parcial como completamente, la aplicación debe
sobrescribir los datos existentes de todo el valor. En la mayoría de las implementaciones, la lectura o la
escritura de un solo valor es una operación atómica. Si el valor es grande, la escritura puede tardar cierto
tiempo.
Una aplicación puede almacenar datos arbitrarios como un conjunto de valores, aunque algunos almacenes
de pares clave-valor imponen límites en el tamaño máximo de los valores. Los valores almacenados son
opacos para el software de sistema de almacenamiento. La aplicación debe proporcionar e interpretar la
información de esquema. Esencialmente, los valores son blobs y el almacén de pares clave-valor se limita
a recuperar o almacenar el valor por clave.
Un almacén de pares clave-valor puede ser muy escalable, ya que puede distribuir fácilmente los datos en
varios nodos en máquinas independientes.
Normalmente, un documento contiene todos los datos de una entidad. Los elementos que constituyen
una entidad son específicos de la aplicación. Por ejemplo, una entidad podría contener los datos de un
cliente, un pedido o una combinación de ambos. Un solo documento puede contener información que se
repartiría en varias tablas relacionales en un RDBMS.
Un almacén de documentos no requiere que todos los documentos tengan la misma estructura. Este
enfoque de formato libre proporciona una gran flexibilidad. Las aplicaciones pueden almacenar diferentes
datos en los documentos a medida que cambian los requisitos empresariales.
La aplicación puede recuperar los documentos mediante su clave. Se trata de un identificador único del
documento, al que se suele aplicar el algoritmo hash, como ayuda para distribuir los datos uniformemente.
Algunas bases de datos de documentos crean automáticamente la clave de documento. Otras permiten al
usuario especificar un atributo del documento que se usará como clave. La aplicación también puede consultar
los documentos según el valor de uno o varios campos. Algunas bases de datos de documentos admiten la
indexación para facilitar la búsqueda rápida de documentos en función de uno o varios campos indexados.
Servicio relevante de Azure: Cosmos DB. Para obtener información, vaya a https://azure.microsoft.com/
services/cosmos-db
Se puede considerar que una base de datos de familias de columnas contiene datos tabulares con filas
y columnas, pero las columnas están divididas en grupos denominados familias de columnas. Cada una
de estas familias contiene un conjunto de columnas que están relacionadas entre sí de forma lógica y se
suelen recuperar o manipular como una unidad. Otros datos a los que se accede por separado se pueden
almacenar en familias de columnas independientes. En una familia de columnas, las columnas nuevas se
pueden agregar dinámicamente y las filas pueden estar dispersas (es decir, no es necesario que una fila
tenga valores para cada columna).
En el diagrama siguiente se muestra un ejemplo con dos familias de columnas: Identidad e Información
de contacto. Los datos de una sola entidad tienen la misma clave de fila en cada familia de columnas.
Esta estructura, en la que las filas de un determinado objeto de una familia de columnas pueden variar
dinámicamente, es una ventaja importante del enfoque de familia de columnas y convierte a este tipo de
almacén de datos en una forma muy adecuada para almacenar datos volátiles estructurados.
A diferencia de un almacén de clave y valor o una base de datos de documentos, la mayoría de bases de
datos de familias de columnas almacenan los datos en el orden de la clave, en lugar de calcular el código
hash. Muchas implementaciones permiten crear índices para columnas específicas de una familia de columnas.
Los índices le permiten recuperar datos en función del valor de las columnas, en lugar de la clave de fila.
Las operaciones de lectura y escritura para una fila suelen ser atómicas, con una sola familia de columnas,
aunque algunas implementaciones proporcionan atomicidad para toda la fila y abarcan varias familias de
columnas.
Las características clave de una base de datos de motores de búsqueda son la capacidad de almacenar e
indexar información muy rápidamente y la capacidad de proporcionar tiempos de respuesta rápidos para
las solicitudes de búsqueda. Los índices pueden ser multidimensionales y muchos admiten las búsquedas
de texto libre en grandes volúmenes de datos de texto. La indexación puede realizarse utilizando un
modelo de extracción (pull), desencadenado por la base de datos del motor de búsqueda, o utilizar un
modelo de inserción (push), iniciado por el código de la aplicación externa.
La búsqueda puede ser exacta o difusa. Una búsqueda parcial encuentra documentos que coinciden
con un conjunto de términos y calcula su semejanza. Algunos motores de búsqueda también admiten el
análisis lingüístico que puede devolver coincidencias basándose en sinónimos, expansiones de género
(por ejemplo, asociar perros con animales domésticos) y derivados (asociar palabras con la misma raíz).
Las bases de datos de series temporales son adecuadas para almacenar datos de telemetría, como
sensores de IoT o contadores de aplicación/sistema.
Archivos compartidos
En ocasiones, utilizar archivos planos simples puede ser el medio más eficaz de almacenar y recuperar
información. El uso compartido de archivos permite acceder a los archivos a través de una red. Con
mecanismos apropiados de seguridad y control de acceso concurrentes, el uso compartido de los datos
de esta manera permite habilitar servicios distribuidos para proporcionar acceso a los datos altamente
escalable para la realización de operaciones básicas y de bajo nivel, como solicitudes de lectura y escritura.
Comparación de
almacenes de datos
Criterios para la elección de un almacén de datos
Azure es compatible con muchos tipos de soluciones de almacenamiento de datos, cada una de ellas
con características y capacidades diferentes. Este artículo describe los criterios de comparación que debe
utilizar al evaluar un almacén de datos. El objetivo es ayudarle a determinar qué tipo de almacenamiento
de datos puede cumplir los requisitos de su solución.
Consideraciones generales
Para iniciar la comparación, recoja tanta información como pueda sobre sus necesidades de datos, según
se indica a continuación. Esta información le ayudará a determinar qué tipos de almacenamiento de datos
se ajustan a sus necesidades.
Requisitos funcionales
●● Formato de datos. ¿Qué tipo de datos pretende almacenar? Habitualmente suelen ser datos
transaccionales, objetos JSON, telemetría, índices de búsqueda o archivos planos.
●● Tamaño de datos. ¿Cuál es el tamaño de las entidades que debe almacenar? ¿Estas entidades
tendrán que mantenerse como un solo documento o pueden dividirse en múltiples documentos,
tablas, colecciones y otros?
●● Escala y estructura. ¿Cuál es la cantidad total de capacidad de almacenamiento que necesita? ¿Prevé
particionar sus datos?
●● Relaciones de datos. ¿Sus datos deben ser compatibles con las relaciones de uno a muchos o de
muchos a muchos? ¿Las propias relaciones son una parte importante de los datos? ¿Necesita unir o
combinar de algún otro modo datos desde el interior del propio conjunto de datos o de conjuntos de
datos externos?
●● Modelo de coherencia. ¿Es importante que las actualizaciones hechas en un nodo aparezcan en
otros nodos antes de proseguir con otros cambios? ¿Puede aceptar la coherencia al cabo del tiempo?
¿Necesita garantías ACID para las transacciones?
●● Flexibilidad de esquema. ¿Qué tipo de esquemas aplicará a sus datos? ¿Utilizará un esquema fijo, un
enfoque de esquema en escritura o de esquema en lectura?
●● Movimiento de datos. ¿La solución deberá realizar tareas de ETL para mover los datos a otros
almacenes o almacenes de datos?
●● Ciclo de vida de los datos. ¿Se trata de datos que se escriben una vez y se leen muchas veces?
¿Pueden trasladarse a un almacenamiento de acceso poco frecuente?
Requisitos no funcionales
●● Rendimiento y escalabilidad. ¿Cuáles son sus requisitos de rendimiento de datos? ¿Tiene requisitos
específicos en cuanto a las tasas de ingestión de datos y de procesamiento de datos? ¿Cuáles son los
tiempos de respuesta aceptables para consulta y agregación de los datos tras su ingestión? ¿A qué tamaño
necesitará escalar el almacén de datos? ¿Su carga de trabajo se basa más en la lectura o en la escritura?
●● Fiabilidad. ¿Qué SLA general necesita que se admita? ¿Qué nivel de tolerancia a errores necesita
proporcionar a los consumidores de datos? ¿Qué tipo de funcionalidad de copias de seguridad y
restauración necesita?
●● Replicación. ¿Sus datos necesitarán distribuirse entre múltiples réplicas o regiones? ¿Qué tipo de
funcionalidad de replicación de datos necesita?
●● Límites. Los límites de un almacén de datos en particular, ¿admitirán sus requisitos de escala, número
de conexiones y rendimiento?
Administración y coste
●● Servicio administrado. Cuando sea posible, utilice un servicio de datos administrados, a menos
que requiera funcionalidades específicas que solo se puedan encontrar en un almacén de datos
hospedados en IaaS.
●● Portabilidad. ¿Necesitará migrar los datos a centros de datos locales, centros de datos externos
u otros entornos de hosting en el cloud?
●● Concesión de licencias. ¿Tiene preferencia por un tipo de licencia de propiedad frente a una de OSS?
¿Hay otras restricciones externas sobre el tipo de licencia que puede utilizar?
●● Coste total. ¿Cuál es el coste total del uso del servicio en el marco de su solución? ¿Cuántas instancias
deberán ejecutarse para dar soporte a sus requisitos de disponibilidad y rendimiento? Considere los
costes de las operaciones en este cálculo. Una razón para preferir los servicios administrados es el
menor coste operativo.
●● Rentabilidad. ¿Puede crear particiones de sus datos para almacenarlos de forma más rentable? Por
ejemplo, ¿puede mover objetos grandes de una base de datos relacional cara a un almacén de objetos?
●● Requisitos de redes. ¿Necesita restringir o administrar de otro modo el acceso a los datos desde
otros recursos de red? ¿Es necesario tener acceso a los datos solo desde el interior del entorno
de Azure? ¿Es necesario tener acceso a los datos desde direcciones IP o subredes específicas? ¿Es
necesario tener acceso a ellos desde aplicaciones o servicios hospedados localmente o en otros
centros de datos externos?
DevOps
●● Habilidades. ¿Existen lenguajes de programación, sistemas operativos u otra tecnología en particular
que su equipo domine especialmente? ¿Hay otros con los que sería difícil para su equipo trabajar?
●● Clientes. ¿Existe una buena compatibilidad con clientes de los lenguajes de desarrollo?
En las secciones siguientes se comparan varios modelos de almacenes de datos en términos de perfiles de
cargas de trabajo, tipos de datos y ejemplos de casos de uso.
Tipo de datos
●● Los datos están altamente normalizados.
●● Las restricciones se definen en el esquema y se imponen a todos los datos de la base de datos.
●● Los datos requieren una elevada integridad. Los índices y las relaciones deben mantenerse con precisión.
Ejemplos
●● Línea de negocio (gestión del capital humano, gestión de relaciones con clientes, planificación de
recursos empresariales)
●● Administración de inventarios
●● Base de datos de informes
●● Contabilidad
●● Administración de activos
●● Gestión de fondos
●● Gestión de pedidos
●● Las operaciones de inserción y actualización son comunes. Tanto la creación de nuevos registros como
las actualizaciones de los datos existentes se producen periódicamente.
Tipo de datos
●● Los datos pueden administrarse de forma desnormalizada.
●● El tamaño de los datos de los documentos individuales es relativamente pequeño.
●● Cada tipo de documento puede utilizar su propio esquema.
●● Los documentos pueden incluir campos opcionales.
●● Los datos de documento son semiestructurados, lo que significa que los tipos de datos de cada
campo no están definidos de forma estricta.
●● Se admite la agregación de datos.
Tipo de datos
●● El tamaño de los datos tiende a ser grande.
●● Cada clave está asociada con un único valor, que es un BLOB de datos no administrados.
●● No hay ninguna aplicación de esquema.
●● No hay relaciones entre entidades.
Ejemplos
●● Almacenamiento en caché de datos
●● Administración de sesiones
●● Administración de preferencias y perfiles de usuario
●● Recomendación de productos y entrega de publicidad
●● Diccionarios
Tipo de datos
●● Los datos se componen de nodos y relaciones.
●● Los nodos son similares a las filas de tabla o a los documentos JSON.
●● Las relaciones son igual de importantes que los nodos y se exponen directamente en el lenguaje de
consulta.
●● Los objetos compuestos, por ejemplo, una persona con varios números de teléfono, tienden a
dividirse en nodos aparte más pequeños, combinados con relaciones transitables.
Ejemplos
●● Organigramas
●● Gráficos sociales
●● Detección de fraudes
●● Análisis
●● Motores de recomendaciones
Tipo de datos
●● Los datos se almacenan en tablas que constan de una columna de clave y una o más familias de
columnas.
●● Determinadas columnas pueden variar según filas individuales.
●● Se obtiene acceso a las celdas individuales mediante comandos Get y Put
●● Se devuelven varias filas con un comando Scan.
Ejemplos
●● Recomendaciones
●● Personalización
●● Datos de sensores
●● Telemetría
●● Mensajería
●● Análisis de redes sociales
●● Análisis web
●● Supervisión de la actividad
●● El tiempo y otros datos de series temporales
Tipo de datos
●● Semiestructurados o no estructurados
●● Texto
●● Texto con referencia a datos estructurados
Ejemplos
●● Catálogos de productos
●● Búsqueda de sitios
●● Registro
●● Análisis
●● Sitios de compras
Almacenamiento de datos
Carga de trabajo
●● Análisis de datos
●● BI empresarial
Tipo de datos
●● Datos históricos de varios orígenes.
●● Generalmente desnormalizados en un esquema "estrella" o "copo de nieve" que consiste en tablas de
hechos y dimensiones.
●● Generalmente se cargan con datos nuevos periódicamente.
●● Las tablas de dimensiones a menudo incluyen varias versiones históricas de una entidad, lo que se
denomina dimensión de variación lenta.
Ejemplos
●● Almacén de datos empresariales que proporciona datos para modelos analíticos, informes y paneles.
Tipo de datos
●● Marca de tiempo que se utiliza como clave principal y mecanismo de ordenación.
●● Medidas de la entrada o descripciones de lo que representa la entrada.
●● Etiquetas que definen la información adicional sobre el tipo, el origen y otra información sobre la
entrada.
Ejemplos
●● Supervisión y telemetría de eventos.
●● Datos de sensores u otros datos de IoT.
Almacenamiento de objetos
Carga de trabajo
●● Identificado por clave.
●● Se puede tener acceso a los objetos de forma pública o privada.
●● El contenido suele ser un activo, como una hoja de cálculo, una imagen o un archivo de vídeo.
●● El contenido debe ser duradero (persistente) y externo a cualquier capa de aplicación o máquina virtual.
Tipo de datos
●● El tamaño de datos es grande.
●● Datos de blob.
●● El valor es opaco.
Archivos compartidos
Carga de trabajo
●● Migración de aplicaciones existentes que interactúan con el sistema de archivos.
●● Requiere interfaz de SMB.
Tipo de datos
●● Archivos en un conjunto jerárquico de carpetas.
●● Accesible con bibliotecas estándar de E/S.
Ejemplos
●● Archivos heredados.
●● Contenido compartido accesible entre un número de máquinas virtuales o instancias de aplicación.
Diseño de la
aplicación Azure:
principios de diseño
Ahora que ha elegido la arquitectura y las tecnologías de cálculo y
almacén de datos, está listo para comenzar a diseñar y construir la
aplicación en el cloud. Esta sección y las dos siguientes proporcionan
orientación y recursos para el diseño óptimo de aplicaciones para el cloud.
Esta sección describe los diez principios de diseño que debe tener en cuenta durante el desarrollo. Seguir
estos principios le ayudará a crear una aplicación más escalable, resistente y administrable.
2. Hacer que todo sea redundante. Cree redundancia en la aplicación para evitar puntos únicos de
error.
3. Minimice la coordinación. Minimice la coordinación entre los servicios de aplicación para obtener
escalabilidad.
5. Cree particiones para evitar límites. Puede utilizar particiones para evitar los límites de bases de
datos, redes y procesos.
6. Diseñe para el equipo de operaciones. Diseñe la aplicación para que el equipo de operaciones
cuente con las herramientas que necesita.
7. Use servicios administrados. Cuando sea posible, utilice el modelo de plataforma como servicio
(PaaS) en lugar del de infraestructura como servicio (IaaS).
8. Use el mejor almacén de datos para el trabajo. Elija la tecnología de almacenamiento que mejor se
adapte a los datos y la forma en que se utilizarán.
9. Diseñe para permitir la evolución. Todas las aplicaciones de éxito cambian con el tiempo. Un diseño
evolutivo es clave para la innovación continua.
10. Desarrolle según las necesidades de negocio. Cada decisión de diseño debe estar justificada por un
requisito de negocio.
Diseño para la
recuperación automática
Diseñe la aplicación para que se recupere de forma automática cuando se
produzcan errores
En un sistema distribuido se producen errores. El hardware puede fallar. La red puede tener errores
transitorios. En contadas ocasiones, todo un servicio o una región puede experimentar interrupciones,
pero incluso estas deben haberse planeado.
Por lo tanto, diseñe la aplicación para que se recupere de forma automática cuando se produzcan errores.
Esto requiere un enfoque triple:
La forma en que responda a un tipo particular de error puede depender de los requisitos de disponibilidad
de la aplicación. Por ejemplo, si requiere una disponibilidad muy alta, puede conmutar automáticamente
a una región secundaria durante una interrupción regional. Sin embargo, esto supondrá un coste más
elevado que una implementación de una sola región.
Además, no considere solamente los eventos importantes, como las interrupciones regionales, que por
lo general son poco frecuentes. Debe concentrarse tanto o más en gestionar los errores locales de corta
duración, tales como los errores de conectividad de red o los errores de conexiones de base de datos.
Recomendaciones
Reintente las operaciones con error. Para obtener más información, consulte Patrón de reintento y vaya a
https://docs.microsoft.com/en-us/azure/architecture/best-practices/transient-faults.
Proteja los servicios remotos con errores (interruptor de circuito). Es bueno volver a intentarlo
después de un error transitorio, pero si el error persiste, puede terminar con demasiados llamadores
que repiten llamadas a un servicio con error. Esto puede ocasionar errores en cascada a medida que las
solicitudes crean copias de seguridad. Utilice el patrón de interruptor de circuito para que el error se
produzca rápidamente (sin realizar la llamada remota) cuando es probable que una operación genere
errores.
Aislar los recursos críticos (bulkhead). A veces, los errores de un subsistema pueden propagarse. Puede
suceder si un error provoca que algunos recursos, como los subprocesos o los sockets, no se liberen
a tiempo, lo que provoca el agotamiento de los recursos. Para evitarlo, puede crear particiones de un
sistema en grupos aislados, de modo que un error en una partición no haga caer todo el sistema.
Conmutación por error. Si no puede tener acceso a una instancia, realice una conmutación por error a
otra instancia. En el caso de elementos sin estado, como un servidor web, ponga varias instancias detrás
de un equilibrador de carga o administrador de tráfico. En el caso de elementos que guarda el estado,
como una base de datos, utilice réplicas y conmutación por error. Según el almacén de datos y cómo este
se replica, puede ser necesario que la aplicación se ocupe de aspectos de coherencia final.
Compense las transacciones erróneas. En general, evite las transacciones distribuidas, puesto que
requieren la coordinación entre servicios y recursos. En su lugar, forme una operación a partir de
transacciones individuales más pequeñas. Si se producen errores en la operación a medio camino,
utilice transacciones de compensación para deshacer cualquier paso que ya se haya completado.
Cree puntos de control para transacciones de larga duración. Los puntos de control pueden
proporcionar resistencia si una operación de larga duración genera errores. Cuando se reinicia la operación
(por ejemplo, otra máquina virtual la recoge), se puede reanudar desde el último punto de control.
Limite los clientes. A veces un número reducido de usuarios crea una carga excesiva, lo que puede
reducir la disponibilidad de la aplicación para otros usuarios. En esta situación, limite el cliente durante
un tiempo. Consulte Patrón de limitación.
Bloquee los actores dañinos. El hecho de limitar un cliente no significa que este estuviera actuando
maliciosamente. Solo significa que el cliente ha superado su cuota de servicio. Pero si un cliente supera
constantemente su cuota o presenta otro tipo de mal comportamiento, puede bloquearlo. Defina un
proceso fuera de banda para que el usuario solicite su desbloqueo.
Utilice la elección de líder. Cuando necesite para coordinar una tarea, utilice la elección de líder para
seleccionar un coordinador. Así, el coordinador no será un punto único de error. Si se producen errores
con el coordinador, se selecciona uno nuevo. En lugar de implementar un algoritmo de elección de líder
desde cero, considere una solución comercial como Zookeeper.
Haga pruebas con la introducción de errores. Con demasiada frecuencia, la ruta correcta está bien
probada pero no la ruta que genera errores. Un sistema podría estar funcionando durante mucho tiempo
en un entorno de producción antes de poner en práctica una vía para superar los errores. Utilice la
introducción de errores para probar la resistencia del sistema a los errores, ya sea mediante la activación
de errores reales o simulándolos.
Adopte la ingeniería del caos. La ingeniería del caos amplía la noción de la introducción de errores
introduciendo errores o condiciones anómalas en instancias de producción.
Para ver un enfoque estructurado del modo de recuperar las aplicaciones automáticamente, consulte
Diseño de aplicaciones flexibles para Azure.
Recomendaciones
Considere los requisitos de negocio. La cantidad de redundancia integrada en un sistema puede afectar
a los costes y la complejidad. La arquitectura debe fundamentarse en sus requisitos de negocio, por
ejemplo, el objetivo de tiempo de recuperación (RTO). Una implementación de varias regiones es más
cara que la implementación de una sola región, por ejemplo, y es más complejo administrarla. Necesitará
procedimientos operativos para gestionar la conmutación por error y la conmutación por recuperación. El
coste y la complejidad adicionales podrían estar justificados para algunos escenarios empresariales y para
otros no.
Coloque máquinas virtuales detrás de un equilibrador de carga. No utilice una sola máquina virtual
para cargas de trabajo críticas. En su lugar, coloque varias máquinas virtuales detrás de un equilibrador de
carga. Si alguna máquina virtual deja de estar disponible, el equilibrador de carga distribuye el tráfico a
las máquinas virtuales restantes que están en buenas condiciones. Para obtener información sobre cómo
implementar esta configuración, consulte Varias máquinas virtuales para escalabilidad y disponibilidad.
Cree particiones para mayor disponibilidad. La partición de bases de datos suele utilizarse para mejorar la
escalabilidad, pero también puede mejorar la disponibilidad. Si cae una partición, las otras particiones siguen
estando disponibles. Un error en una partición solo interrumpirá un subconjunto del total de las transacciones.
Implemente más de una región. Para conseguir la máxima disponibilidad, implemente la aplicación
en más de una región. Así, en el caso poco habitual en que un problema afecte a toda una región, la
aplicación puede conmutar por error a otra región. El siguiente diagrama muestra una aplicación en varias
regiones que usa Azure Traffic Manager para gestionar la conmutación por error.
Sincronice la conmutación por error de front-end y back-end. Use Azure Traffic Manager para
conmutar por error el front-end. Si el front-end pasa a no estar disponible en una región, Traffic Manager
redirigirá las solicitudes nuevas a la región secundaria. Según la solución de base de datos, deberá
coordinar la conmutación por error de la base de datos.
Utilice la conmutación por error automática pero la conmutación por recuperación manual.
Utilice Traffic Manager para la conmutación por error automática, pero no para la conmutación por
recuperación automática. La conmutación por recuperación automática conlleva el riesgo de conmutar
a la región principal antes de que las condiciones de sean completamente correctas. En su lugar, antes
de la conmutación por recuperación manual, verifique que todos los subsistemas de la aplicación sean
correctos. Asimismo, según la base de datos, puede que necesite comprobar la coherencia de los datos
antes de la conmutación por recuperación.
Incluya redundancia para Traffic Manager. Traffic Manager es un punto de posibles errores. Revise el
acuerdo de nivel de servicio de Traffic Manager y determine si el uso de Traffic Manager solo cumple los
requisitos de negocio para la alta disponibilidad. Si no, considere la adición de otra solución de administración
de tráfico como una conmutación por recuperación. Si el servicio de Azure Traffic Manager presenta errores,
cambie los registros de CNAME en DNS para que haga referencia a otro servicio de administración de tráfico.
Reducción de la
coordinación
Minimice la coordinación entre los servicios de aplicación para obtener
escalabilidad.
La mayoría de las aplicaciones en el cloud constan de varios servicios de aplicación: front-ends web, bases
de datos, procesos de negocio, informes y análisis, etc. Para alcanzar una escalabilidad y fiabilidad, cada
uno de esos servicios debe ejecutarse en varias instancias.
¿Qué sucede cuando dos instancias intentan realizar operaciones simultáneas que afectan algunos estados
compartidos? En algunos casos, debe haber coordinación entre los nodos, por ejemplo, para preservar las
garantías ACID. En este diagrama, Nodo2 espera a que Nodo1 libere un bloqueo de base de datos:
La coordinación limita las ventajas del escalado horizontal y crea cuellos de botella. En este ejemplo, al
ampliar la aplicación y añadir más instancias, verá un aumento de la contención de bloqueos. En el peor
de los casos, las instancias de front-end pasarán la mayor parte de su tiempo esperando en los bloqueos.
Otro origen frecuente de la coordinación es la semántica "exactamente una vez". Por ejemplo, un pedido
debe procesarse exactamente una vez. Dos trabajos están a la espera de nuevos pedidos. El Trabajo1
selecciona un pedido para procesarlo. La aplicación debe garantizar que el Trabajo2 no duplique el trabajo,
pero también que si el Trabajo1 experimenta un bloqueo, el pedido no se pierda.
Recomendaciones
Adopte la coherencia final. Cuando los datos están distribuidos, se necesita coordinación para cumplir
unas garantías de coherencia sólidas. Supongamos, por ejemplo, que una operación actualiza dos bases
de datos. En vez de colocarlas en el ámbito de una sola transacción, es mejor si el sistema puede tener
en cuenta la coherencia final, quizá utilizando el patrón de transacciones de compensación para poder
revertir de forma lógica después de un error.
Utilice eventos del dominio para sincronizar el estado. Un evento del dominio es un evento que
registra cuando sucede algo que tiene importancia dentro del dominio. Los servicios interesados pueden
escuchar el evento, en lugar de utilizar una transacción global para coordinar varios servicios. Si se utiliza
este enfoque, el sistema debe admitir la coherencia final (consulte el punto anterior).
Considere los patrones como el de CQRS y el de abastecimiento de eventos. Estos dos patrones
pueden ayudar a reducir la contención entre las cargas de trabajo de lectura y las de escritura.
●● El patrón CQRS separa las operaciones de lectura de las operaciones de escritura. En algunas
implementaciones, los datos de lectura están físicamente separados de los datos de escritura.
●● En el patrón de abastecimiento de eventos se registran los cambios de estado como una serie de
eventos para un almacén de datos solo de anexos. Anexar un evento a la secuencia es una operación
atómica que requiere un bloqueo mínimo.
Estos dos patrones se complementan. Si el almacén de solo escritura en CQRS utiliza el abastecimiento de
eventos, el almacén de solo lectura puede escuchar los mismos eventos para crear una instantánea legible
del estado actual, optimizada para consultas. Antes de adoptar el CQRS o el abastecimiento de eventos,
sin embargo, sea consciente de los desafíos que supone este enfoque. Para obtener más información,
consulte Estilo de arquitectura CQRS.
Datos de partición. Evite poner todos los datos en un único esquema de datos compartido en muchos
servicios de aplicación. Una arquitectura de microservicios aplica este principio al hacer que cada servicio
sea responsable de su propio almacén de datos. Dentro de una misma base de datos, la creación de
particiones de los datos puede mejorar la simultaneidad, porque un servicio que escribe en una partición
no afecta al servicio que escribe en otra partición distinta.
Diseñe operaciones idempotentes. Cuando sea posible, diseñe operaciones que sean idempotentes.
Así, se pueden gestionar usando la semántica "al menos una vez". Puede poner, por ejemplo, elementos
de trabajo en una cola. Si un trabajo experimenta un bloqueo en medio de una operación, otro trabajo
simplemente selecciona ese elemento de trabajo.
Utilice un procesamiento paralelo asincrónico. Si una operación requiere varios pasos que se realizan
de forma asincrónica (como las llamadas de servicio remoto), el usuario podría llamarlas en paralelo y, a
continuación, agregar los resultados. Este enfoque supone que ningún paso depende de los resultados del
paso anterior.
Use la simultaneidad optimista cuando sea posible. El control de simultaneidad pesimista utiliza
bloqueos de base de datos para evitar conflictos. Esto puede causar un rendimiento bajo y reducir
la disponibilidad. Con el control de simultaneidad optimista, cada transacción modifica una copia
o instantánea de los datos. Cuando la transacción se confirma, el motor de base de datos valida la
transacción y rechaza todas las transacciones que puedan afectar a la coherencia de la base de datos.
Considere MapReduce u otros algoritmos distribuidos paralelos. En función de los datos y el tipo de
trabajo que realizar, puede dividir el trabajo en tareas independientes que se puedan realizar con varios
nodos trabajando en paralelo. Consulte Estilo de arquitectura de Big Compute.
Utilice la elección de líder para la coordinación. En casos en los que deben coordinarse las operaciones,
asegúrese de que el coordinador no se convierta en un punto único de error en la aplicación. Si utiliza el
patrón de elección del líder, una instancia es el líder en cada momento y actúa como coordinador. Si se
produce un error en el líder, se elige una nueva instancia para ser el líder.
Diseño pensando en
la escalabilidad
Diseñe la aplicación para que pueda escalarse horizontalmente.
Una de las principales ventajas del cloud es el escalado flexible, es decir, la posibilidad de usar tanta
capacidad como se necesite mediante el escalado horizontal a medida que aumenta la carga y la
reducción horizontal cuando no se necesite la capacidad adicional. Diseñe la aplicación para que se
pueda escalar horizontalmente añadiendo o eliminando nuevas instancias según la demanda.
Recomendaciones
Evite la permanencia de la instancia. La permanencia o afinidad de sesión se produce cuando las
solicitudes del mismo cliente se dirigen siempre al mismo servidor. La permanencia limita la capacidad de
escalado horizontal de la aplicación. Por ejemplo, el tráfico procedente de un usuario de alto volumen no
se distribuirá entre las instancias. Entre las causas de la permanencia se encuentran el almacenamiento del
estado de sesión en memoria y el uso de claves específicas del equipo para el cifrado. Asegúrese de que
cualquier instancia pueda gestionar cualquier solicitud.
Identifique los cuellos de botella. El escalado horizontal no es una solución mágica para todos los
problemas de rendimiento. Por ejemplo, si la base de datos de back-end es el cuello de botella, no
ayudará a añadir más servidores web. Identifique y resuelva los cuellos de botella en el sistema en primer
lugar, antes de añadir más situaciones al problema. Las partes con estado de un sistema son la causa más
probable de los cuellos de botella.
Descomponga las cargas de trabajo por requisitos de escalabilidad. Las aplicaciones suelen constar de
varias cargas de trabajo con diferentes requisitos de escalado. Por ejemplo, una aplicación podría tener un
sitio público y un sitio de administración aparte. El sitio público puede experimentar oleadas repentinas de
tráfico, mientras que el sitio de administración tiene una carga más pequeña y predecible.
Descargue las tareas de uso intensivo de recursos. Las tareas que requieren muchos recursos de CPU
o E/S deben moverse a trabajos en segundo plano siempre que sea posible para minimizar la carga en el
front-end que gestiona solicitudes de usuario.
Diseñe pensando en la reducción horizontal. Recuerde que con la escala flexible, la aplicación tendrá
períodos de reducción horizontal, cuando se quiten instancias. La aplicación debe poder gestionar con
facilidad las instancias que se quiten. He aquí algunas maneras de gestionar la reducción horizontal:
●● Escuche eventos de cierre (si están disponibles) y realice los cierres de forma limpia.
●● Los clientes/consumidores de un servicio deberían asistir a un control de errores y un procedimiento
de reintento transitorios.
●● Para tareas de larga duración, piense en dividir el trabajo y en utilizar puntos de control o el patrón
Pipes and Filters.
●● Ponga los elementos de trabajo en una cola, de modo que otra instancia pueda asumir el trabajo si se
elimina una instancia en mitad del procesamiento.
Creación de particiones
para evitar límites
Puede utilizar particiones para evitar los límites de bases de datos, redes
y procesos.
Una de las principales ventajas del cloud es el escalado flexible, es decir, la posibilidad de usar tanta
capacidad como se necesite mediante el escalado horizontal a medida que aumenta la carga y la
reducción horizontal cuando no se necesite la capacidad adicional. Diseñe la aplicación para que se
pueda escalar horizontalmente añadiendo o eliminando nuevas instancias según la demanda.
En el cloud, todos los servicios tienen limitada su capacidad de escalado vertical. Límites de servicio
de Azure están documentados en los límites, las cuotas y las restricciones de suscripción y servicio de
Azure. Entre los elementos limitados se incluyen el número de núcleos, el rendimiento de consultas y el
rendimiento de red. Si su sistema crece lo suficiente, puede que se encuentre con uno o varios de estos
límites. Puede utilizar la creación de particiones para evitarlos.
Diseñe la clave de partición para evitar zonas activas. Si crea una partición en una base de datos, pero
una de las particiones sigue recibiendo la mayor parte de las solicitudes, no habrá resuelto el problema. Lo
ideal es que la carga se distribuya uniformemente en todas las particiones. Por ejemplo, cree los hash por
ID de cliente y no por la primera letra del nombre del cliente, ya que algunas letras son más frecuentes. El
mismo principio se aplica al crear una partición de una cola de mensajes. Elija una clave de partición que
provoque a una distribución uniforme de los mensajes en todo el conjunto de colas. Para obtener más
información, consulte Particionamiento.
Cree particiones para evitar los límites de suscripción y servicio de Azure. Los servicios y los
componentes individuales tienen límites, pero también las suscripciones y los grupos de recursos. En el
caso de aplicaciones muy grandes, puede que necesite crear particiones para evitar esos límites.
●● Implementación
●● Supervisión
●● Escalación
●● Respuesta a incidentes
●● Auditoría de seguridad
Recomendaciones
Haga que todo se pueda observar. Cuando se implementa y se pone en funcionamiento una solución,
los registros y el seguimiento son la fuente de conocimiento principal sobre el sistema. El seguimiento
registra una ruta a través de todo el sistema y resulta útil para localizar cuellos de botella, problemas
de rendimiento y puntos de error. El registro captura eventos individuales, como cambios de estado
de la aplicación, errores y excepciones. Registre la actividad en producción; de lo contrario, perderá
conocimiento cuando más lo necesite.
Dótese de instrumentos de supervisión. La supervisión aporta conocimiento sobre lo bien (o mal) que
funciona una aplicación en términos de disponibilidad, rendimiento y estado del sistema. Por ejemplo,
mediante la supervisión podrá saber si está cumpliendo su SLA. La supervisión se realiza durante el
funcionamiento normal del sistema. Debe realizarse en tiempo real tanto como sea posible, de modo que
el personal de operaciones pueda reaccionar rápidamente ante los problemas. En una situación ideal, la
supervisión puede ayudarle a evitar problemas antes de que causen un error crítico. Para obtener más
información, visite https://docs.microsoft.com/en-us/azure/architecture/best-practices/monitoring.
Utilice seguimiento distribuido. Utilice un sistema de seguimiento distribuido que admita simultaneidad,
asincronía y escala en el cloud. Los seguimientos deben incluir un ID de correlación que se extienda a
través de los límites de servicio. Una sola operación puede incluir llamadas a múltiples servicios de la
aplicación. Si una operación falla, el ID de correlación ayuda a identificar la causa del error.
Estandarice los registros y las métricas. El equipo de operaciones necesitará acumular registros de los
distintos servicios que tenga en la solución. Si cada servicio utiliza su propio formato de registro, se hace
difícil o imposible obtener información útil de ellos. Defina un esquema común que incluya campos como
el ID de correlación, el nombre del evento, la dirección IP del remitente y así sucesivamente. Los servicios
individuales pueden derivar esquemas personalizados que heredan el esquema base y contienen campos
adicionales.
Trate la configuración como código. Compruebe los archivos de configuración en un sistema de control
de versiones, de modo que pueda hacer un seguimiento y crear versiones de sus cambios y volver atrás si
es necesario.
Uso de servicios
administrados
Cuando sea posible, utilice el modelo de plataforma como servicio
(PaaS) en lugar del de infraestructura como servicio (IaaS).
La IaaS es como tener una caja de piezas. Se puede construir cualquier cosa, pero hay que montarla uno
mismo. Los servicios gestionados son fáciles de configurar y administrar. No hay que aprovisionarse de
máquinas virtuales, configurar VNets, administrar parches y actualizaciones ni asumir todos los demás
gastos asociados con la ejecución de software en una máquina virtual.
Por ejemplo, supongamos que su aplicación necesita una cola de mensajes. Podría configurar su propio
servicio de mensajería en una VM, con algo como RabbitMQ. Sin embargo, Azure Service Bus ya ofrece
mensajería fiable como servicio y es más sencillo de configurar. No tiene más que crear un espacio de
nombres de Service Bus (lo que puede hacerse como parte de un script de implementación) y luego
llamar a Service Bus usando el SDK cliente.
Naturalmente, su aplicación puede tener requisitos específicos que hagan que un enfoque de IaaS
resulte más conveniente. Sin embargo, aunque su aplicación se base en IaaS, identifique aquellos lugares
donde puede ser natural incorporar servicios administrados. Entre ellos se incluyen la caché, las colas y el
almacenamiento de datos.
La IaaS es como tener una caja de piezas. Se puede construir cualquier cosa, pero hay que montarla uno
mismo. Los servicios gestionados son fáciles de configurar y administrar. No hay que aprovisionarse de
máquinas virtuales, configurar VNets, administrar parches y actualizaciones ni asumir todos los demás
gastos asociados con la ejecución de software en una máquina virtual.
Por ejemplo, supongamos que su aplicación necesita una cola de mensajes. Podría configurar su propio
servicio de mensajería en una VM, con algo como RabbitMQ. Sin embargo, Azure Service Bus ya ofrece
mensajería fiable como servicio y es más sencillo de configurar. No tiene más que crear un espacio de
nombres de Service Bus (lo que puede hacerse como parte de un script de implementación) y luego
llamar a Service Bus usando el SDK cliente.
Naturalmente, su aplicación puede tener requisitos específicos que hagan que un enfoque de IaaS
resulte más conveniente. Sin embargo, aunque su aplicación se base en IaaS, identifique aquellos lugares
donde puede ser natural incorporar servicios administrados. Entre ellos se incluyen la caché, las colas y el
almacenamiento de datos.
Los días en los que se plasmaban todos los datos en una gran base de datos SQL relacional ya son cosa
del pasado. Las bases de datos relacionales son muy buenas en su objetivo, proporcionar garantías ACID
para transacciones sobre datos relacionales. Sin embargo, tienen algunos inconvenientes:
En soluciones grandes, es probable que una única tecnología de almacén de datos no satisfaga todas sus
necesidades. Entre las alternativas a las bases de datos relacionales se incluyen los almacenes de claves/
valores, las bases de datos de documentos, las bases de datos de motores de búsqueda, las bases de
datos de series temporales, las bases de datos de familias de columnas y las bases de datos de gráficos.
Cada una tiene pros y contras, y los diferentes tipos de datos se ajustan más naturalmente a unas u otras.
Por ejemplo, podría almacenar un catálogo de productos en una base de datos de documentos,
como Cosmos DB, que permite un esquema flexible. En ese caso, cada descripción de producto es un
documento autónomo. Para consultas sobre el catálogo completo, puede indexar el catálogo y almacenar
el índice en Búsqueda de Azure. El inventario de productos podría guardarse en una base de datos SQL, ya
que los datos requieren garantías ACID.
Recomendaciones
No use una base de datos relacional para todo. Piense en otros tipos de almacenes de datos si es
conveniente. Vea Elija el almacén de datos correcto.
Adopte la persistencia políglota. En soluciones grandes, es probable que una única tecnología de
almacén de datos no satisfaga todas sus necesidades.
Tenga en cuenta el tipo de datos. Por ejemplo, ponga los datos transaccionales en SQL, ponga los
documentos JSON en una base de datos de documentos, ponga los datos de telemetría en una base de
datos de serie temporal, ponga los registros de la aplicación en Elasticsearch y ponga los blobs en Azure
Blob Storage.
Opte por la disponibilidad en lugar de por la coherencia (fuerte). El teorema del CAP implica que un
sistema distribuido debe realizar compensaciones entre la disponibilidad y la coherencia. (Las particiones
de red, el otro pilar del teorema del CAP, nunca se pueden evitar completamente). A menudo se puede
lograr mayor disponibilidad mediante la adopción de un modelo de coherencia eventual.
Use transacciones compensatorias. Un efecto secundario de la persistencia políglota es que una sola
transacción podría escribir datos en varios almacenes. Si algo falla, use transacciones compensatorias para
deshacer los pasos que ya haya completado.
Analice los contextos limitados. "Contexto limitado" es un término procedente del diseño basado en
dominio. Un contexto limitado es una acotación explícita en torno a un modelo de dominio y define a qué
partes del dominio se aplica el modelo. Idealmente, un contexto limitado se asigna a un subdominio del
dominio de negocio. Los contextos limitados en el sistema son un lugar natural que tener en cuenta para
la persistencia políglota. Por ejemplo, los "productos" pueden aparecer en el subdominio de catálogo de
productos y el subdominio de inventario de productos, pero es muy probable que estos dos subdominios
tengan diferentes requisitos de almacenamiento, actualización y consulta de productos.
Todas las aplicaciones que tienen éxito cambian con el tiempo, ya sea para solucionar problemas, agregar
nuevas características, adoptar nuevas tecnologías o hacer que los sistemas existentes sean más escalables
y resistentes. Si todas las partes de una aplicación están emparejadas de forma inflexible, será muy
complicado introducir cambios en el sistema. Un cambio en una parte de la aplicación puede alterar otra
parte o provocar que los cambios se propaguen por todo el código base.
Este problema no se limita a las aplicaciones monolíticas. Una aplicación se puede descomponer en
servicios pero seguir mostrando el tipo de emparejamiento inflexible que hace que el sistema sea rígido
y quebradizo. Sin embargo, cuando los servicios están diseñados para evolucionar, los equipos pueden
innovar y ofrecer continuamente nuevas características.
Los microservicios se están convirtiendo en una forma popular de lograr un diseño evolutivo, porque
responden a muchas de las consideraciones mencionadas anteriormente.
Recomendaciones
Fomente una alta cohesión y un emparejamiento flexible. Un servicio está cohesionado si proporciona
una funcionalidad que se corresponde con él de forma lógica. Los servicios están emparejados de forma
flexible si se puede cambiar un servicio sin cambiar el otro. Una cohesión alta generalmente significa que los
cambios en una función requerirán cambios en otras funciones relacionadas. Si percibe que la actualización de
un servicio requiere actualizaciones coordinadas en otros servicios, puede ser una señal de que sus servicios
no están cohesionados. Uno de los objetivos del diseño basado en dominio (DDD) es identificar esos límites.
Utilice mensajería asincrónica. La mensajería asincrónica es una forma de desvincular el productor del
mensaje del consumidor. El productor no depende de que el consumidor responda al mensaje o realice
ninguna acción particular. Con una arquitectura de publicaciones y envíos (pub/sub), el productor puede
no saber quién está consumiendo el mensaje. Los nuevos servicios pueden consumir fácilmente los
mensajes sin modificaciones en el productor.
Exponga interfaces abiertas. Evite la creación de capas de traducción personalizadas que se encuentren
entre servicios. Por el contrario, un servicio debe exponer una API con un contrato de API bien definido.
La API debe estar versionada, de modo que pueda hacer evolucionar la API mientras que mantiene su
compatibilidad con versiones anteriores. Así, puede actualizar un servicio sin coordinar las actualizaciones
de todos los servicios ascendentes que dependen de ella. Los servicios de orientación pública deben
exponer una API RESTful por HTTP. Los servicios de back-end pueden utilizar un protocolo de mensajería
de estilo RPC por motivos de rendimiento.
Realice los diseños y pruebas con los contratos de servicio. Cuando los servicios exponen API bien
definidas, puede realizar el desarrollo y las pruebas con esas API. Así, podrá desarrollar y probar un
servicio individual sin sincronizar todos sus servicios dependientes. (Naturalmente, seguiría teniendo que
realizar las pruebas de integración y carga con los servicios reales).
Abstraiga la infraestructura de la lógica del dominio. No permita que la lógica del dominio se mezcle
con funcionalidades relacionadas con la infraestructura, como la mensajería o la persistencia. De lo
contrario, los cambios en la lógica del dominio requerirán actualizaciones en las capas de infraestructura y
viceversa.
Descargue las cuestiones de transversalidad a un servicio independiente. Por ejemplo, si hay varios
servicios que necesitan autenticar solicitudes, podría desplazar esta funcionalidad a su propio servicio.
Así, podría hacer evolucionar el servicio de autenticación, por ejemplo añadiendo un nuevo flujo de
autenticación, sin tocar ninguno de los servicios que lo utilizan.
Implemente los servicios de forma independiente. Cuando el equipo de DevOps puede implementar
un servicio independientemente de otros servicios de la aplicación, las actualizaciones pueden realizarse
de forma más rápida y segura. Las correcciones de errores y la implementación de nuevas características
se pueden realizar con una cadencia más regular. Diseñe tanto el proceso de la aplicación como el de
publicación para que admitan actualizaciones independientes.
Este principio de diseño podría parecer obvio, pero es esencial tenerlo en cuenta al diseñar una solución.
¿Prevé que tendrá millones de usuarios o solo un puñado de miles? ¿Es aceptable una interrupción de la
aplicación de una hora? ¿Espera que se produzcan grandes picos de tráfico o la carga de trabajo será muy
predecible? Al final, cada decisión de diseño debe estar justificada por una necesidad de negocio.
Recomendaciones
Defina objetivos de negocio. Incluidos el objetivo de tiempo de recuperación (RTO), el objetivo de
punto de recuperación (RPO) y la interrupción máxima tolerable (MTO). Estos números deben determinar
las decisiones acerca de la arquitectura. Por ejemplo, para lograr un RTO bajo, podría implementar una
conmutación por error automatizada a una región secundaria. Sin embargo, si la solución puede tolerar un
RTO mayor, ese grado de redundancia podría ser innecesario.
Documente los acuerdos de nivel de servicio (SLA) y los objetivos de nivel de servicio (SLO).
Incluidas métricas de disponibilidad y rendimiento. Podría desarrollar una solución que ofrezca una
disponibilidad del 99,95 %. ¿Es eso suficiente? La respuesta es una decisión empresarial.
Modele la aplicación en torno al dominio empresarial. Empiece por analizar los requisitos del negocio.
Utilice estos requisitos para modelar la aplicación. Piense en adoptar un enfoque de diseño basado en
dominio (DDD) para crear modelos de dominios que reflejen los procesos de negocio y los casos de uso.
Aborde tanto requisitos funcionales como no funcionales. Los requisitos funcionales le permiten juzgar
si la aplicación hace lo correcto. Los requisitos no funcionales le permiten juzgar si la aplicación hace bien
esas cosas. En particular, asegúrese de que comprende sus necesidades de escalabilidad, disponibilidad y
latencia. Estos requisitos influirán en las decisiones de diseño y la selección de la tecnología.
Descomponga por carga de trabajo. El término "carga de trabajo" en este contexto significa una
capacidad o tarea de proceso discreta, que puede separarse de forma lógica de otras tareas. Las diferentes
cargas de trabajo pueden tener requisitos diferentes de disponibilidad, escalabilidad, coherencia de los
datos y recuperación ante desastres.
Plan de crecimiento. Puede que una solución satisfaga sus necesidades actuales en términos de número
de usuarios, volumen de transacciones, almacenamiento de datos y así sucesivamente. Sin embargo, una
aplicación robusta puede asumir el crecimiento sin grandes cambios arquitectónicos. Consulte Diseño
pensando en la escalabilidad y Creación de particiones para evitar límites. Piense también que su modelo
de negocio y sus requisitos empresariales probablemente cambiarán con el tiempo. Si el modelo de
Administre los costes. En una aplicación local tradicional, se paga por adelantado el coste del hardware
(gasto de capital). En una aplicación en el cloud, paga por los recursos que consume. Asegúrese de que
comprende el modelo de precios para los servicios que consume. El coste total incluirá el uso del ancho
de banda de red, el almacenamiento, las direcciones IP, el consumo de servicios y otros factores. Consulte
Precios de Azure para obtener más información. Tenga en cuenta también los costes de sus operaciones.
En el cloud, no tendrá que gestionar el hardware ni ninguna otra infraestructura, pero aún necesitará
administrar sus aplicaciones, incluidos DevOps, respuesta a incidentes, recuperación ante desastres y así
sucesivamente.
Diseño de
aplicaciones flexibles
para Azure
En lugar de comprar hardware de alta gama para escalar verticalmente, en un entorno de cloud debe
escalar horizontalmente. Los costes de los entornos de cloud se mantienen al mínimo y el objetivo es
minimizar el efecto de un error.
En un sistema distribuido, se producen errores. El hardware puede fallar. La red puede tener errores
transitorios. En contadas ocasiones, todo un servicio o una región puede experimentar interrupciones,
pero incluso estas deben haberse planeado.
La creación de una aplicación fiable en el cloud es algo diferente a crear una aplicación fiable en un
entorno empresarial. Aunque, históricamente, puede que haya comprado hardware de alta gama para
escalar verticalmente, en un entorno de cloud debe realizar el escalado en horizontal. Los costes de los
entornos de cloud se mantienen bajos con el uso de hardware básico. En lugar de centrarse en evitar
errores y optimizar el "tiempo medio entre errores", en este nuevo entorno el foco cambia al "tiempo
medio de restauración". El objetivo es minimizar el efecto de un error.
Este artículo proporciona información general sobre cómo desarrollar aplicaciones flexibles en
Microsoft Azure. Comienza con una definición del término "resistencia" y sus conceptos relacionados. A
continuación, describe el proceso para conseguir resistencia, utilizando un enfoque estructurado durante
el periodo de vida de una aplicación, desde el diseño y la implementación hasta el despliegue y las
operaciones.
Dos aspectos importantes de la resistencia son la alta disponibilidad y la recuperación ante desastres.
●● La alta disponibilidad (HA, por sus siglas en inglés) es la capacidad de la aplicación de seguir
funcionando en un estado correcto, sin un tiempo de inactividad significativo. Entendemos por
"estado correcto" aquel en el que la aplicación responde y los usuarios pueden conectarse a la
aplicación e interactuar con ella.
Al diseñar una aplicación para ser flexible, es necesario entender sus requisitos de disponibilidad.
¿Cuánto tiempo de inactividad es aceptable? Esto depende parcialmente del coste. ¿Cuánto costará el
tiempo de inactividad potencial a su empresa? ¿Cuánto debe invertir en hacer que la aplicación tenga
alta disponibilidad? También tiene que definir qué implica que la aplicación esté disponible. Por ejemplo,
¿la aplicación se considerará "inactiva" si un cliente puede enviar un pedido, pero el sistema no puede
procesarlo dentro del plazo normal? Tenga también en cuenta la probabilidad de que se produzca un
determinado tipo de interrupción y si es rentable una estrategia de mitigación.
Otro término común es la continuidad del negocio (BC, por sus siglas en inglés), que es la capacidad de
realizar las funciones de negocio esenciales durante y después de condiciones adversas, como un desastre
natural o un servicio interrumpido. La BC cubre todo el funcionamiento del negocio, incluyendo las
instalaciones físicas, el personal, las comunicaciones, el transporte y la informática. Este artículo se centra
en las aplicaciones en el cloud, pero la planificación de la resistencia debe realizarse en el contexto de las
necesidades globales de la BC. Para obtener más información, consulte la [Contingency Planning Guide]
[capacity-planning-guide] del Instituto Nacional de Ciencia y Tecnología de EE. UU. (NIST).
6. Supervise la aplicación para detectar errores. Al supervisar el sistema, puede calibrar el estado de la
aplicación y responder a incidencias en caso necesario.
En el resto de este artículo abordaremos cada uno de estos pasos con más detalle.
Estas cargas de trabajo pueden tener requisitos diferentes de disponibilidad, escalabilidad, coherencia de
los datos, recuperación ante desastres y así sucesivamente. De nuevo, estas son decisiones de negocio.
Piense también en los patrones de uso. ¿Hay ciertos períodos críticos, en los que el sistema debe estar
disponible? Por ejemplo, un servicio de liquidación de impuestos no puede interrumpirse justo antes de
la fecha límite de presentación, un servicio de streaming de vídeo debe estar activo durante un evento
deportivo importante, etcétera. Durante los períodos críticos, podría contar con implementaciones
redundantes en varias regiones, de modo que la aplicación podría conmutar por error si una de las
regiones falla. Sin embargo, una implementación de varias regiones es más cara, por lo que durante
tiempos menos críticos puede ejecutar la aplicación en una sola región.
RTO y RPO
Dos métricas importantes que cabe tener en cuenta son el objetivo de tiempo de recuperación y el
objetivo de punto de recuperación.
●● El objetivo de tiempo de recuperación (RTO) es el tiempo máximo aceptable que una aplicación
puede no estar disponible después de un incidente. Si su RTO es de 90 minutos, debe ser capaz de
restaurar la aplicación a un estado funcional en 90 minutos desde el inicio de un desastre. Si tiene un
RTO muy bajo, puede mantener una segunda implementación funcionando continuamente en modo
de espera para evitar una interrupción regional.
●● El objetivo de punto recuperación (RPO) es la duración máxima de una pérdida de datos aceptable
durante un desastre. Por ejemplo, si almacena datos en una única base de datos, sin replicación en
otras bases de datos, y realiza copias de seguridad cada hora, podría perder hasta una hora de datos.
El RTO y el RPO son requisitos de negocio. La realización de una evaluación de riesgos puede ayudarle a
definir el RTO y el RPO de la aplicación. Otra métrica común es el tiempo medio de recuperación (MTTR, por
sus siglas en inglés), que es el promedio de tiempo que se tarda en restaurar la aplicación después de un error.
El MTTR es un hecho empírico sobre un sistema. Si el MTTR excede el RTO, un error en el sistema causará una
interrupción del negocio inaceptable, ya que no será posible restaurar el sistema en el RTO definido.
SLA
En Azure, el acuerdo de nivel de servicio (SLA, por sus siglas en inglés) describe los compromisos de
Microsoft relativos al tiempo de actividad y la conectividad. Si el SLA para un servicio particular es del
99,9 %, significa que se espera que el servicio esté disponible 99,9 % del tiempo.
Notas:
El SLA de Azure incluye también disposiciones para la obtención de un crédito de servicio si el SLA no se
cumple, además de definiciones específicas de "disponibilidad" para cada servicio. Ese aspecto del SLA
actúa como una política de cumplimiento.
Por supuesto, una mayor disponibilidad es mejor en igualdad del resto de condiciones. Sin embargo,
al crecer el número de nueves en los decimales, el coste y la complejidad de alcanzar ese nivel de
disponibilidad también aumentan. Un tiempo de actividad del 99,99 % se traduce en unos 5 minutos de
inactividad total por mes. ¿Merece la pena la complejidad y el coste adicionales para llegar a cinco 9? La
respuesta depende de los requisitos empresariales.
●● Para lograr cuatro nueves (99,99 %), probablemente no pueda depender de la intervención manual para
recuperarse de errores. La aplicación debe autodiagnosticarse y resolver automáticamente sus problemas.
●● Con más de cuatro nueves es difícil detectar las interrupciones con la suficiente rapidez como para
cumplir con el SLA.
●● Piense en el periodo de tiempo frente al que se mide el SLA. Cuanto menor sea el periodo, más
restrictiva será la tolerancia. Probablemente no tenga sentido definir su SLA en términos de tiempo
de actividad diaria o por hora.
SLA compuestos
Pongamos como ejemplo una aplicación web de App Service que escriba en Azure SQL Database. En el
momento de escribir este artículo, estos servicios de Azure tienen los siguientes SLA:
¿Cuál es el máximo tiempo de inactividad que cabría esperar para esta aplicación? Si cualquiera de los
servicios falla, falla toda la aplicación. En general, la probabilidad de que se produzca un error en cada
servicio es independiente, así que el SLA compuesto para esta aplicación es de 99,95 % × 99,99 % = 99,94 %.
Es inferior a los SLA individuales, lo que no es sorprendente, porque una aplicación que se
basa en múltiples servicios tiene más puntos de error potenciales.
Por otro lado, puede mejorar el SLA compuesto mediante la creación de rutas de reserva independientes.
Por ejemplo, si SQL Database no está disponible, ponga las transacciones en una cola para procesarlas
posteriormente.
Sin embargo, este enfoque implica ciertos sacrificios. La lógica de la aplicación es más compleja, está
pagando por la cola y puede haber problemas de coherencia de datos que deberá tener en cuenta.
Pongamos que N es el SLA compuesto para la aplicación implementada en una región. La expectativa de
que la aplicación falle en ambas regiones al mismo tiempo es de (1 − N) × (1 − N). Por lo tanto,
●● SLA combinado para ambas regiones = 1 − (1 − N)(1 − N) = N + (1 − N)N
Por último, debe tener en cuenta el SLA para Traffic Manager. En el momento de escribir esto, el SLA de
Traffic Manager es del 99,99 %.
Además, la conmutación por error no es instantánea y puede provocar cierto tiempo de inactividad
durante una conmutación por error. Consulte Supervisión de puntos de conexión y conmutación por
error en Traffic Manager.
El SLA calculado es una base útil, pero no aborda todos los aspectos de la disponibilidad. A menudo, una
aplicación puede degradarse correctamente cuando falla una ruta no crítica. Pongamos como ejemplo una
aplicación que muestra un catálogo de libros. Si la aplicación no puede recuperar la imagen en miniatura
de la portada, puede que muestre una imagen de marcador de posición. En ese caso, la no obtención de
la imagen no reduce el tiempo de actividad de la aplicación, aunque afecta a la experiencia del usuario.
Para obtener más información sobre el proceso del FMA, con recomendaciones específicas para Azure,
consulte la Guía de resistencia de Azure: análisis del modo de error.
Durante la fase de diseño, debe realizar un análisis del modo de error (FMA). El objetivo de un FMA es
identificar posibles puntos de error y definir cómo responderá la aplicación a dichos errores.
Para obtener más información sobre el proceso del FMA, con recomendaciones específicas para Azure,
consulte la Guía de resistencia de Azure: análisis del modo de error.
Estrategias de resistencia
En esta sección se ofrece un estudio de algunas estrategias de resistencia comunes. La mayoría de ellas no
se limitan a una tecnología particular. Las descripciones de esta sección resumen de la idea general que
hay detrás de cada técnica, con enlaces a lecturas adicionales.
Cada intento de reintento aumenta la latencia total. Además, muchas solicitudes erróneas pueden
causar un cuello de botella, dado que las solicitudes pendientes se acumulan en la cola. Estas solicitudes
bloqueadas podrían retener recursos críticos del sistema como memoria, subprocesos, conexiones a bases
de datos, etcétera, que pueden causar errores en cascada. Para evitar esto, aumente el retardo entre cada
intento de reintento y limite el número total de solicitudes erróneas.
En términos de escalabilidad, una aplicación en el cloud debe poder escalarse horizontalmente añadiendo
más instancias. Este enfoque también mejora la resistencia, porque las instancias en mal estado pueden
eliminarse de la rotación.
Por ejemplo:
●● Ponga dos o más VM tras un equilibrador de carga. El equilibrador de carga distribuye el tráfico a
todas las VM. Consulte Ejecución de VM con carga equilibrada para escalabilidad y disponibilidad.
●● Escale horizontalmente una aplicación de Azure App Service a varias instancias. App Service equilibra
automáticamente la carga en varias instancias. Consulte Aplicación web básica.
●● Use Azure Traffic Manager para distribuir el tráfico en un conjunto de puntos de conexión.
Es importante tener en cuenta tanto la ruta de lectura como la de escritura. En función de la tecnología de
almacenamiento, puede tener varias réplicas de escritura o una única réplica de escritura y varias réplicas
de solo lectura.
Para aumentar al máximo la disponibilidad, se pueden colocar réplicas en varias regiones. Sin embargo,
esto aumenta la latencia cuando se replican los datos. Por lo general, la replicación entre regiones se
realiza asincrónicamente, lo que implica un modelo de consistencia eventual y posible pérdida de datos si
se produce un error en una réplica.
Degradar correctamente
Si un servicio falla y no hay ninguna ruta de conmutación por error, la aplicación puede degradarse
correctamente y aun así proporcionar una experiencia de usuario aceptable.
Por ejemplo:
Cuando un único cliente realiza un número excesivo de solicitudes, la aplicación podría limitar al cliente
durante un periodo de tiempo determinado. Durante el período de limitación, la aplicación deniega todas
o algunas de las peticiones del cliente (dependiendo de la estrategia de limitación exacta). El umbral para
la limitación puede depender del nivel de servicio del cliente.
La limitación no implica que el cliente actuara necesariamente con intención maliciosa, sino simplemente
que excede su cuota de servicio. En algunos casos, un consumidor podría exceder constantemente su
cuota o mostrar un mal comportamiento de otra naturaleza. En ese caso, podría dar un paso más y
bloquear al usuario. Por lo general, esto se hace mediante el bloqueo de una clave de la API o un intervalo
de direcciones IP.
El patrón de interruptor de circuito puede evitar que una aplicación intente repetidamente una operación
que probablemente fracase. Esto es algo similar a un interruptor de circuito físico, un interruptor que
detiene el flujo de corriente cuando un circuito se sobrecarga.
●● Closed. Este es el estado normal. El interruptor de circuito envía solicitudes al servicio y un contador
controla el número de errores recientes. Si la cuenta de errores supera un umbral dentro de un
periodo de tiempo determinado, el interruptor de circuito pasa al estado Open.
●● Open. En este estado, el interruptor de circuito hace inmediatamente que fallen todas las peticiones,
sin llamar al servicio. La aplicación debe usar una ruta de mitigación, como leer datos de una réplica o
simplemente devolver un error al usuario. Cuando el interruptor de circuito cambia a abierto, se inicia
un temporizador. Cuando el temporizador expira, el interruptor de circuito cambia al estado Half-
Open.
●● Half-Open. En este estado, el interruptor de circuito permite que un número limitado de solicitudes
llegue al servicio. Si lo consiguen, se supone que el servicio se ha recuperado y el interruptor vuelve al
estado Closed. De lo contrario, vuelve al estado Open. El estado Half-Open impide que un servicio de
recuperación se vea inundado de solicitudes de repente.
Para evitar esto, puede utilizar una cola como búfer. Cuando hay un nuevo elemento de trabajo, en lugar
de llamar al servicio de back-end inmediatamente, la aplicación pone en cola un elemento de trabajo para
que se ejecute de forma asincrónica. La cola actúa como un búfer que alisa los picos de la carga.
Para obtener más información, consulte Patrón de nivelación de carga basada en cola.
Para evitar esto, puede crear particiones en un sistema de modo que se organice en grupos aislados, de
modo que un error en una partición no haga caer todo el sistema. Esta técnica se llama a veces patrón
Bulkhead.
Ejemplos:
●● Cree particiones de una base de datos (por ejemplo, por inquilino) y asigne un grupo independiente
de las instancias de servidor web a cada partición.
●● Utilice grupos de subprocesos separados para aislar las llamadas a los distintos servicios. Esto ayuda
a evitar errores en cascada si falla uno de los servicios. Por ejemplo, consulte la biblioteca Netflix
Hystrix.
●● Use contenedores para limitar los recursos disponibles para un subsistema particular.
Una transacción compensatoria es una transacción que permite anular los efectos de otra transacción
completada.
En un sistema distribuido, puede ser muy difícil de conseguir una coherencia transaccional sólida. Las
transacciones compensatorias son una forma de lograr coherencia mediante el uso de una serie de
transacciones individuales y más pequeñas que se pueden deshacer en cada paso.
Por ejemplo, para reservar un viaje, un cliente puede reservar un coche, una habitación de hotel y un
vuelo. Si alguno de estos pasos falla, falla toda la operación. En lugar de intentar utilizar una única
transacción distribuida para toda la operación, puede definir una transacción compensatoria para
cada paso. Por ejemplo, para anular una reserva de un coche, cancele la reserva. Para completar toda
la operación, un coordinador ejecuta cada paso. Si alguno de los pasos falla, el coordinador aplica
transacciones compensatorias para deshacer los pasos que se hayan completado.
Por lo general, no puede comprobar la resistencia de la misma manera que comprueba las funcionalidades
de una aplicación (ejecutando pruebas unitarias, etc.). Debe comprobar cómo se comporta la carga de
trabajo de extremo a extremo en condiciones de error que solo se presentan de forma intermitente.
El proceso de comprobación es iterativo. Compruebe la aplicación, mida los resultados, analice y aborde
los errores resultantes y repita el proceso.
Pruebas de inyección de errores. Puede comprobar la resistencia del sistema durante los errores, ya
sea mediante la activación de errores reales o simulándolos. A continuación figuran algunos escenarios
habituales para comprobar:
Mida los tiempos de recuperación y verifique que se cumplan los requisitos de su negocio. Pruebe
también combinaciones de modos de error. Asegúrese de que los errores no se propaguen en cascada y
se administren de forma aislada.
Este es otro motivo de por qué es importante analizar los puntos de error potenciales durante la fase de
diseño. Los resultados de ese análisis deberían ser entradas de su plan de pruebas.
Comprobación de carga. Puede comprobar la carga de la aplicación con herramientas como Visual
Studio Team Services o Apache JMeter. Las pruebas de carga son esenciales para identificar errores que
solo se producen en condiciones de carga, como que la base de datos del back-end se vea sobrepasada o
que el servicio se vea limitado. Compruebe las cargas máximas con datos de producción o sintéticos tan
parecidos a los datos de producción como sea posible. El objetivo es ver cómo se comporta la aplicación
en condiciones reales.
Implementación resistente
Cuando una aplicación se implementa en versión de producción, las actualizaciones son una fuente de
errores potencial. En el peor de los casos, una mala actualización puede causar tiempo de inactividad.
Para evitarlo, el proceso de implementación debe ser predecible y repetible. La implementación incluye el
aprovisionamiento de recursos de Azure, el despliegue de código de aplicación y la aplicación de ajustes
de configuración. Una actualización puede incluir esos tres aspectos o solo un subconjunto.
El punto crucial es que los despliegues manuales son propensos a causar errores. Por lo tanto, se
recomienda tener un proceso idempotente automatizado que pueda ejecutar bajo demanda y volver a
ejecutar si algo falla.
●● Utilice las plantillas de Resource Manager para automatizar el aprovisionamiento de recursos de Azure.
●● Utilice la configuración de estado deseado (DSC) de Azure Automation para configurar máquinas virtuales.
●● Utilice un proceso de implementación automatizado para el código de la aplicación.
Otra cuestión es cómo llevar a cabo una actualización de la aplicación. Recomendamos técnicas como
la implementación "blue-green" o versiones "canary", que inserta actualizaciones de una forma muy
controlada para minimizar los posibles impactos de una mala implementación.
Sea cual sea el enfoque que adopte, asegúrese de que puede dar marcha atrás hasta la última
implementación que sepa que es funcional, en caso de que la nueva versión no sea operativa. Además, si
se producen errores, los registros de aplicación deben indicar qué versión ha causado el error.
Supervisión y diagnóstico
La supervisión y el diagnóstico resultan cruciales para la resistencia. Si se produce algún error, debe saber
qué ha sido lo que ha fallado y necesita conocer la causa del error.
La supervisión de un sistema distribuido a gran escala presenta un desafío significativo. Piense en una
aplicación que se ejecute en unas cuantas máquinas virtuales. No resultará práctico iniciar sesión en cada
una de ellas, una por una, y analizar los archivos de registro, intentando resolver un problema. Además,
probablemente el número de instancias de VM no sea estático. Las VM se añaden y eliminan a medida
que la aplicación se escala o reduce horizontalmente, y hay veces en las que una instancia puede fallar y
necesitar que se vuelva a aprovisionar. Además, una aplicación en el cloud típica podría utilizar múltiples
almacenes de datos (almacenamiento de Azure, SQL Database, Cosmos DB, caché Redis) y una acción de
un solo usuario podría abarcar varios subsistemas.
Puede concebir el proceso de supervisión y diagnóstico como una canalización con varias fases distintas:
La supervisión no es igual que la detección de errores. Por ejemplo, la aplicación puede detectar un error
transitorio y volver a intentarlo, con lo que dará como resultado la ausencia de tiempo de inactividad. Sin
embargo, también debe registrar la operación de reintento, así que podrá supervisar la tasa de error, con
el fin de obtener un panorama general de la salud de la aplicación.
Los registros de aplicaciones son una fuente importante de los datos de diagnóstico. Entre los
procedimientos recomendados para el registro de aplicaciones se incluyen:
●● Registro en producción. De lo contrario, se pierden conocimientos cuando más se necesitan.
●● Eventos de registro en los límites de servicio. Incluyen un ID de correlación que fluye entre varios
límites de servicio. Si una transacción fluye a través de varios servicios y uno de ellos falla, el ID de
correlación le ayudará a determinar por qué ha fallado la operación.
●● Uso del registro semántico, también conocido como registro estructurado. Los registros no
estructurados hacen que sea difícil automatizar el consumo y el análisis de los datos de registro, lo
que es necesario a escala del cloud.
●● Uso de registro asincrónico. De lo contrario, el sistema de registro en sí mismo puede causar un
error en la aplicación, haciendo que las solicitudes creen una copia de seguridad, ya que se bloquean
mientras esperan para escribir un evento de registro.
●● El registro de aplicaciones no es lo mismo que la auditoría. Una auditoría puede hacerse por razones
reglamentarias o normativas. Por tanto, los registros de auditoría deben ser completos y no es
aceptable omitir ningún aspecto de los mismos al procesar transacciones. Si una aplicación requiere
auditoría, se debe realizar por separado con respecto al registro de diagnóstico.
Para obtener más información sobre supervisión y diagnóstico, consulte Guía de supervisión y diagnóstico.
Resumen
En este artículo se ha abordado la resistencia desde una perspectiva completa, destacando algunos de los
desafíos exclusivos del cloud. Entre ellos se incluye la naturaleza distribuida de la computación en el cloud,
el uso de hardware básico y la presencia de errores de red transitorios.
●● La resistencia conduce a una mayor disponibilidad y a un menor tiempo de recuperación ante errores.
Diseño de la
aplicación Azure:
uso de los pilares
de la calidad
Escalabilidad, disponibilidad, resistencia, administración y seguridad son
los cinco pilares de un software de calidad. Si se centra en estos pilares,
podrá diseñar una aplicación en el cloud satisfactoria. Puede usar las listas
de comprobación de esta guía para revisar su aplicación en relación con
estos pilares.
Administración Automatice las implementaciones y haga que sean un proceso rápido y rutinario
para acelerar la publicación de nuevas características o soluciones de errores.
Integre operaciones para avanzar o revertir entre versiones e incluya supervisión
y diagnóstico.
Escalabilidad
La escalabilidad es la capacidad de un sistema de administrar una carga creciente. Hay dos métodos
principales de escalar una aplicación. El escalado vertical (scaling up) implica aumentar la capacidad de un
recurso, por ejemplo mediante el uso de una VM de mayor tamaño. El escalado horizontal (scaling out)
consiste en añadir nuevas instancias de un recurso, como VM o réplicas de bases de datos.
Una de las ventajas del escalado vertical es que se puede realizar sin tener que cambiar la aplicación. Sin
embargo, en algún momento se alcanzará el límite y ya no se podrá seguir escalando verticalmente. En
ese momento, cualquier escalado adicional debe ser horizontal.
El escalado horizontal debe estar diseñado en el sistema. Por ejemplo, se pueden escalar horizontalmente
VM colocándolas tras un equilibrador de carga. Sin embargo, cada VM del grupo debe ser capaz de
administrar cualquier solicitud del cliente, por lo que la aplicación no puede tener un estado, o si lo tiene,
almacenarlo externamente (por ejemplo, en una caché distribuida). Los servicios PaaS administrados
suelen tener escalado horizontal y escalado automáticos integrados. La facilidad de escalar estos servicios
es una ventaja principal del uso de servicios PaaS.
Realice siempre comprobaciones de rendimiento y carga para encontrar estos posibles cuellos de botella.
Las partes con estado de un sistema, como las bases de datos, son la causa más común de cuellos de
botella y requieren un diseño cuidadoso a la hora de escalarlas horizontalmente. Al resolver un cuello de
botella pueden revelarse otros cuellos de botella en otras partes.
Use la Lista de comprobación de escalabilidad para revisar su diseño desde el punto de vista de la
escalabilidad.
Procedimientos recomendados
●● https://docs.microsoft.com/en-us/azure/architecture/best-practices/auto-scaling
●● https://docs.microsoft.com/en-us/azure/architecture/best-practices/background-jobs
●● https://docs.microsoft.com/en-us/azure/architecture/best-practices/caching
●● https://docs.microsoft.com/en-us/azure/architecture/best-practices/cdn
●● https://docs.microsoft.com/en-us/azure/architecture/best-practices/data-partitioning
Una aplicación del cloud debe tener un objetivo del nivel de servicio (SLO) que defina claramente la
disponibilidad esperada y cómo se mide la misma. Al definir la disponibilidad, tenga en cuenta la ruta
crítica. El front-end de la web podría ser capaz de dar servicio a las solicitudes del cliente, pero si cada
transacción falla porque no se puede conectar a la base de datos, la aplicación no estará disponible para
los usuarios.
La disponibilidad se describe a menudo en términos de "nueves", por ejemplo, "cuatro nueves" significa
un 99,99 % de tiempo de actividad. En la siguiente tabla se muestra el tiempo de inactividad potencial
acumulado en los distintos niveles de disponibilidad.
Tiempo de inactividad a la
SLA Tiempo de inactividad al mes Tiempo de inactividad al año
semana
Tenga en cuenta que un tiempo de actividad del 99 % podía traducirse en una interrupción de casi 2 horas
por semana. Para muchas aplicaciones, especialmente las aplicaciones orientadas al consumidor, este no
es un SLO aceptable. Por otra parte, cinco nueves (99,999 %) implica una inactividad menor de 5 minutos
al año. Detectar una interrupción tan rápido ya es todo un reto, por no hablar de resolverla en ese tiempo.
Para obtener una disponibilidad muy alta (99,99 % o superior), no se puede depender de la intervención
manual para recuperarse ante errores. La aplicación debe poder autodiagnosticarse y corregirse
automáticamente, aspectos en los que la resistencia se vuelve crucial.
Procedimientos recomendados
●● https://docs.microsoft.com/en-us/azure/architecture/best-practices/auto-scaling
●● https://docs.microsoft.com/en-us/azure/architecture/best-practices/background-jobs
●● Los sistemas distribuidos son complejos, y un error puntual puede reproducirse por cascada en todo
el sistema.
●● Los costes de entornos en el cloud se mantienen bajos gracias al uso de hardware básico, de modo
que deben esperarse fallos de hardware ocasionales.
●● Las aplicaciones a menudo dependen de servicios externos, que pueden llegar a estar temporalmente
no disponibles o limitar a los usuarios de alto volumen.
●● Los usuarios de hoy en día esperan que una aplicación esté siempre disponible, sin estar nunca offline.
Todos estos factores implican que las aplicaciones en el cloud deben estar diseñadas para anticiparse a
errores ocasionales y recuperarse de ellos. Azul tiene muchas características de resistencia ya incorporadas
en la plataforma. Por ejemplo:
●● Azure Storage, SQL Database y Cosmos DB proporcionan replicación de datos integrada, tanto dentro
de una región como entre regiones.
Dicho esto, aún debe integrar la resistencia en su aplicación. Las estrategias de resistencia se pueden
aplicar a todos los niveles de la arquitectura. Algunas mitigaciones tienen una naturaleza más táctica,
por ejemplo, volver a intentar una llamada remota después de un error de red transitorio. Otras
mitigaciones son más estratégicas, como conmutar por error toda la aplicación a una región secundaria.
Las mitigaciones tácticas pueden marcar una gran diferencia. Aunque es raro que toda una región
experimente una interrupción, los problemas transitorios como la congestión de la red son más comunes,
así que primero se deben abordar estos. Contar con los métodos de supervisión y diagnóstico adecuados
también es importante, tanto para detectar errores cuando se producen como para dar con la causa raíz.
Al diseñar una aplicación para ser resistente, es necesario entender sus requisitos de disponibilidad.
¿Cuánto tiempo de inactividad es aceptable? Esto depende parcialmente del coste. ¿Cuánto costará el
tiempo de inactividad potencial a su empresa? ¿Cuánto debe invertir en hacer que la aplicación tenga alta
disponibilidad?
Use la Lista de comprobación de resistencia para revisar su diseño desde el punto de vista de la
resistencia.
Procedimientos recomendados
●● https://docs.microsoft.com/en-us/azure/architecture/best-practices/transient-faults
●● https://docs.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific
Administración y DevOps
Este pilar abarca los procesos de operaciones que mantienen la ejecución de una aplicación en producción.
Las implementaciones deben ser fiables y predecibles. Deben estar automatizadas para reducir la
posibilidad de error humano. Deben ser un proceso rápido y rutinario, de modo que no retrasen el
lanzamiento de nuevas funciones o correcciones de errores. Igualmente importante, debe poder revertir o
avanzar en los cambios rápidamente si una actualización resulta problemática.
La supervisión y el diagnóstico son cruciales. Para ver procedimientos recomendados sobre supervisión y
diagnóstico, visite https://docs.microsoft.com/en-us/azure/architecture/best-practices/monitoring. Las
aplicaciones en el cloud se ejecutan en un centro de datos remoto en el que no tendrá el control completo
de la infraestructura o, en algunos casos, el sistema operativo. En una aplicación grande, no es práctico
iniciar sesión en varias VM para solucionar un problema o analizar archivos de registro. Con los servicios
PaaS, podría no haber ni siquiera una VM específica en la que iniciar sesión. La supervisión y el diagnóstico
aportan conocimientos sobre el sistema, de modo que podrá saber dónde y cuándo se producen los
errores. Todos los sistemas deben ser observables. Utilice un esquema de registro común y coherente que
le permita correlacionar los eventos en varios sistemas.
Utilice la lista de comprobación de DevOps para revisar su diseño desde un punto de vista de
administración y DevOps.
A continuación presentamos algunos ámbitos de seguridad generales que debería tener en cuenta.
Administración de identidades
Piense en recurrir a Azure Active Directory (Azure AD) para autenticar y autorizar a los usuarios. Azure
AD es un servicio de identidad y gestión de accesos totalmente administrado. Puede utilizarlo para crear
dominios que existan únicamente en Azure, o integrarlo con sus identidades locales de Active Directory.
Azure AD también se integra con Office365, Dynamics CRM Online y muchas aplicaciones SaaS de
terceros. En el caso de las aplicaciones orientadas al consumidor, Azure Active Directory B2C permite
a los usuarios autenticarse con sus cuentas en redes sociales (Facebook, Google o LinkedIn, por ejemplo)
o crear una nueva cuenta de usuario administrada por Azure AD.
Si desea integrar un entorno de Active Directory local con una red Azure, hay varios enfoques posibles,
dependiendo de sus necesidades. Para obtener más información, consulte nuestras arquitecturas de
referencia de administración de identidad.
Protección de su infraestructura
Controle el acceso a los recursos de Azure que implemente. Todas las suscripciones de Azure tienen una
relación de confianza con un inquilino de Azure AD. Utilice el control de acceso basado en roles (RBAC)
para conceder a los usuarios de su organización los permisos correctos para los recursos de Azure. Conceda
accesos asignando un rol de RBAC a usuarios o grupos de un ámbito determinado. Este ámbito puede ser el
de una suscripción, un grupo de recursos o un único recurso. Audite todos los cambios a la infraestructura.
Para obtener más información, visite https://docs.microsoft.com/en-us/azure/active- directory/.
Seguridad de aplicaciones
Por lo general, los procedimientos recomendados de seguridad para desarrollo de aplicaciones siguen
aplicándose al cloud. Entre ellas se incluyen el uso de SSL en todas partes, la protección frente a ataques
CSRF y XSS, la prevención de ataques de inyección por SQL, etc.
Las aplicaciones en el cloud suelen usar servicios administrados con claves de acceso. Nunca las
introduzca en el código fuente. Piense en almacenar los secretos de las aplicaciones en Azure Key Vault.
Puede utilizar Key Vault para proteger claves y secretos criptográficos. Al utilizar Key Vault, podrá cifrar
claves y secretos mediante el uso de claves protegidas por módulos de seguridad de hardware (HSM).
Muchos servicios de almacenamiento y bases de datos de Azure admiten el cifrado de datos en reposo,
incluidos Azure Storage, Azure SQL Database, Azure SQL Data Warehouse y Cosmos DB.
●● https://docs.microsoft.com/en-us/azure/storage/storage-service-encryption
●● https://docs.microsoft.com/en-us/azure/sql-database/sql-database-always-encrypted-azure-key-
vault
●● https://docs.microsoft.com/en-us/azure/data-lake-store/data-lake-store-security-overview#data-
protection
●● https://docs.microsoft.com/en-us/azure/cosmos-db/database-security
Recursos de seguridad
●● Azure Security Center {sin enlace} proporciona supervisión de seguridad integrada y administración
de políticas en todas sus suscripciones de Azure. Visite https://azure.microsoft.com/en-us/services/
security-center/.
●● Para obtener información sobre cómo proteger sus aplicaciones en el cloud, consulte https://docs.
microsoft.com/en-us/azure/security/.
Diseño de la
aplicación Azure:
patrones de diseño
Estos patrones de diseño resultan útiles a la hora de crear aplicaciones
fiables, escalables y seguras en el cloud.
Cada patrón describe el problema que aborda, incluye consideraciones para aplicarlo y un ejemplo basado
en Microsoft Azure. La mayoría de los patrones incluyen ejemplos de código o fragmentos de código que
muestran cómo implementar el patrón en Azure. Sin embargo, la mayoría de los patrones son aptos para
cualquier sistema distribuido, ya se aloje en Azure o en otras plataformas del cloud.
Patrón Resumen
Supervisión de punto Implementa comprobaciones funcionales en una aplicación a la que
de conexión de estado pueden acceder herramientas externas mediante puntos de conexión
expuestos a intervalos regulares.
Nivelación de carga basada Utiliza una cola que actúe como búfer entre una tarea y un servicio
en cola que esta invoque para suavizar cargas intensas intermitentes.
Patrón Resumen
Cache-Aside Carga datos bajo demanda en una caché desde un almacén de datos.
CQRS Segrega las operaciones que leen los datos de las operaciones que
actualizan los datos mediante interfaces separadas.
Tabla de índices Crea índices sobre los campos de los almacenes de datos a los que se suele
hacer referencia en las solicitudes.
Vista materializada Genera vistas precompletadas sobre los datos en uno o más almacenes de
datos cuando los datos no tienen el formato ideal para las operaciones de
consulta necesarias.
Valet Key Utiliza un token o una clave que proporciona a los clientes acceso directo
restringido a un recurso o servicio específicos.
Diseño e implementación
Un buen diseño abarca factores tales como la consistencia y la coherencia en el diseño y la
implementación de componentes, la capacidad de mantenimiento para simplificar la administración
y el desarrollo y la capacidad de reutilización para permitir que los componentes y los subsistemas se
utilicen en otras aplicaciones y en otros escenarios. Las decisiones tomadas durante la fase de diseño e
implementación tienen un impacto enorme en la calidad y el coste total de propiedad de las aplicaciones
y servicios alojados en el cloud.
Patrón Resumen
Embajador Crea servicios auxiliares que envían solicitudes de red en nombre
de un servicio o una aplicación de consumidor.
Capa para evitar daños Implementa una fachada o capa de adaptación entre una aplicación
moderna y un sistema heredado.
Back-ends for Front-ends Crea servicios back-end separados para que los consuman aplicaciones
o interfaces específicas del front-end.
Agregación de puertas Utiliza una puerta de entrada para combinar varias solicitudes individuales
de enlace en una única solicitud.
Enrutamiento de puertas Enruta las solicitudes a varios servicios mediante un único punto de
de enlace conexión.
Elección de líder Coordina las acciones realizadas por una colección de instancias de tareas
colaboración en una aplicación distribuida eligiendo una instancia como
líder que asume la responsabilidad de administrar las demás instancias.
Tuberías y filtros Descompone una tarea que realiza un procesamiento complejo en una
serie de elementos separados que pueden reutilizarse.
Mensajería
La naturaleza distribuida de las aplicaciones en el cloud requiere una infraestructura de mensajería
que conecte los componentes y los servicios, idealmente con un emparejamiento flexible, con el fin
de maximizar la escalabilidad. La mensajería asincrónica se utiliza ampliamente y proporciona muchas
ventajas, pero también presenta grandes desafíos, como el orden de los mensajes, la administración
de mensajes dudosos, la idempotencia y mucho más.
Patrón Resumen
Consumidores en Permite que varios consumidores simultáneos procesen los mensajes
competencia recibidos en el mismo canal de mensajería.
Tuberías y filtros Descompone una tarea que realiza un procesamiento complejo en una serie
de elementos separados que pueden reutilizarse.
Cola de prioridad Prioriza las solicitudes enviadas a los servicios de modo que las solicitudes
con una prioridad más alta se reciban y procesen más rápidamente que las
que tienen menor prioridad.
Administración y supervisión
Las aplicaciones en el cloud se ejecutan en un centro de datos remoto en el que no tendrá el control
completo de la infraestructura o, en algunos casos, el sistema operativo. Esto puede hacer que la
administración y la supervisión sean más difíciles que una implementación local. Las aplicaciones deben
exponer información de tiempo de ejecución que los administradores y operadores puedan utilizar para
administrar y supervisar el sistema, además de para apoyar los cambiantes requisitos empresariales y la
personalización sin necesidad de que la aplicación se detenga o se reimplemente.
Patrón Resumen
Embajador Crea servicios auxiliares que envían solicitudes de red en nombre de un
servicio o una aplicación de consumidor.
Capa para evitar daños Implementa una fachada o capa de adaptación entre una aplicación
moderna y un sistema heredado.
Agregación de puertas Utiliza una puerta de entrada para combinar varias solicitudes individuales
de enlace en una única solicitud.
Enrutamiento de puertas Enruta las solicitudes a varios servicios mediante un único punto de
de enlace conexión.
Patrón Resumen
Cache-Aside Carga datos bajo demanda en una caché desde un almacén de datos.
CQRS Segrega las operaciones que leen los datos de las operaciones que
actualizan los datos mediante interfaces separadas.
Tabla de índices Crea índices sobre los campos de los almacenes de datos a los que se suele
hacer referencia en las solicitudes.
Vista materializada Genera vistas precompletadas sobre los datos en uno o más almacenes de
datos cuando los datos no tienen el formato ideal para las operaciones de
consulta necesarias.
Cola de prioridad Prioriza las solicitudes enviadas a los servicios de modo que las solicitudes
con una prioridad más alta se reciban y procesen más rápidamente que las
que tienen menor prioridad.
Nivelación de carga Utiliza una cola que actúe como búfer entre una tarea y un servicio que esta
basada en cola invoque para suavizar cargas intensas intermitentes.
Patrón Resumen
Bulkhead Aísla los elementos de una aplicación en grupos, de modo que si uno falla,
los demás seguirán funcionando.
Interruptor de circuito Administra los errores que se podría tardar una cantidad de tiempo variable
en arreglar al conectarse a un servicio o recurso remoto.
Transacción de Deshace el trabajo realizado mediante una serie de pasos que, en conjunto,
compensación definen una operación finalmente coherente.
Elección de líder Coordina las acciones realizadas por una colección de instancias de tareas
colaboración en una aplicación distribuida eligiendo una instancia como
líder que asume la responsabilidad de administrar las demás instancias.
Nivelación de carga Utiliza una cola que actúe como búfer entre una tarea y un servicio que esta
basada en cola invoque para suavizar cargas intensas intermitentes.
Reintento Permite que una aplicación pueda manejar los fallos temporales
esperados cuando intenta conectarse a un servicio o recurso de red
volviendo a intentar de manera transparente una operación que ha fallado
anteriormente.
Patrón Resumen
Identidad federada Delega la autenticación a un proveedor de identidad externo.
Valet Key Utiliza un token o una clave que proporciona a los clientes acceso directo
restringido a un recurso o servicio específicos.
Catálogo de patrones
Patrón embajador
Crea servicios auxiliares que envían solicitudes de red en nombre de un servicio o una aplicación de
consumidor. Un servicio de embajador puede considerarse como un proxy fuera de proceso colocado
con el cliente.
Este patrón puede ser útil para la descarga de tareas comunes de conectividad del cliente como la
supervisión, el registro, el enrutamiento, la seguridad (como TLS) y los patrones de resistencia de forma
independiente al lenguaje. A menudo se utiliza con aplicaciones heredadas u otras aplicaciones que
resultan difíciles de modificar, con el fin de ampliar sus capacidades de interconexión. También puede
permitir que un equipo especializado implemente esas características.
Contexto y problema
Las aplicaciones resistentes basadas en el cloud requieren características como interrupción de circuito,
enrutamiento, medición y supervisión, además de la capacidad de realizar actualizaciones de configuración
relacionadas con la red. Puede ser difícil o imposible actualizar aplicaciones heredadas
o bibliotecas de código existentes para añadir estas características, porque el código ya no se mantiene
o no puede ser fácilmente modificado por el equipo de desarrollo.
Las llamadas de red también pueden requerir una labor de configuración sustancial para la conexión,
la autenticación y la autorización. Si estas llamadas se utilizan en varias aplicaciones, se crean utilizando
varios lenguajes y marcos, las llamadas deben configurarse para cada una de estas instancias. Además,
la funcionalidad de red y seguridad debe estar administrada por un equipo central dentro de su
organización. Con una base de código grande, puede resultar arriesgado que ese equipo actualice
el código de la aplicación si no está familiarizado con él.
Solución
Ponga los marcos y las bibliotecas del cliente en un proceso externo que actúa como proxy entre su
aplicación y los servicios externos. Implementa el proxy en el mismo entorno de host que su aplicación,
para permitir el control sobre el enrutamiento, la resistencia y las características de seguridad y para evitar
cualquier restricción de acceso relacionada con el host. También puede utilizar el patrón embajador para
estandarizar y ampliar la instrumentación. El proxy puede supervisar las métricas de rendimiento, como la
latencia o el uso de recursos, y esta supervisión se produce en el mismo entorno del host que la aplicación.
Los servicios de embajador se pueden implementar como sidecar para acompañar el ciclo de vida de
una aplicación o servicio de consumo. Alternativamente, si varios procesos independientes comparten un
embajador en un host común, se puede implementar como un daemon o un servicio de Windows. Si el
servicio de consumo está en contenedor, el embajador debe crearse como un contenedor independiente
en el mismo host, con los enlaces apropiados configurados para la comunicación.
Problemas y consideraciones
●● El proxy añade cierta sobrecarga de latencia. Piense si una biblioteca de cliente, que invoca
directamente la aplicación, es un mejor enfoque.
●● Tenga en cuenta el posible impacto de incluir características generalizadas en el proxy. Por ejemplo,
el embajador podría administrar los reintentos, pero quizás eso no sea seguro, a no ser que todas las
operaciones sean idempotentes.
●● Piense en un mecanismo que permita que el cliente pase contexto al proxy y lo devuelva al cliente.
Por ejemplo, incluya encabezados de solicitud HTTP para poder decidir no reintentar o especifique
el número máximo de reintentos.
●● Piense en la posibilidad de utilizar una única instancia compartida para todos los clientes o una
instancia para cada cliente.
●● Si necesita crear un conjunto común de características de conectividad de cliente para varios lenguajes
o marcos.
●● Si necesita descargar problemas transversales de conectividad del cliente a desarrolladores de
infraestructuras u otros equipos más especializados.
●● Si necesita dar soporte a los requisitos de conectividad del cloud o el clúster en una aplicación
heredada o una aplicación que resulte difícil modificar.
●● Cuando la latencia de la solicitud de red es crítica. Un proxy introducirá sobrecarga, aunque sea
mínima, y en algunos casos esto podría afectar a la aplicación.
●● Cuando las funciones de conectividad del cliente se consumen en un único lenguaje. En ese caso,
podría ser mejor opción una biblioteca cliente que se distribuye a los equipos de desarrollo como
un paquete.
●● Cuando las funciones de conectividad no se pueden generalizar y requieren una integración más
profunda con la aplicación cliente.
Contexto y problema
La mayoría de las aplicaciones dependen de otros sistemas para obtener algunos datos o funcionalidades.
Por ejemplo, cuando una aplicación heredada se migra a un sistema moderno, podría seguir necesitando
los recursos heredados existentes. Las nuevas características deberían poder llamar al sistema heredado.
Esto se pone de especial relevancia en las migraciones graduales, en las que las diversas características
de una aplicación mayor se van desplazando a un sistema moderno a lo largo del tiempo.
A menudo, estos sistemas heredados experimentan problemas de seguridad, como esquemas de datos
enrevesados o API obsoletas. Las características y tecnologías utilizadas en sistemas heredados pueden
variar enormemente de las de los sistemas más modernos. Para interoperar con el sistema heredado,
la nueva aplicación podría necesitar ser compatible con infraestructura, protocolos, modelos de datos,
API u otras características obsoletas que, de lo contrario, no pondría en una aplicación moderna.
El mantenimiento del acceso entre sistemas nuevos y heredados puede forzar que el nuevo sistema
se ajuste a al menos parte de las API u otros elementos semánticos del sistema heredado. Cuando estas
características heredadas tienen problemas de calidad, la compatibilidad con ellas "corrompe" lo que
de lo contrario podría ser una aplicación moderna con un diseño limpio.
Solución
Aísle los sistemas antiguos y los modernos, colocando una capa para evitar daños entre ellos. Esta capa
traduce las comunicaciones entre los dos sistemas, permitiendo que el sistema heredado permanezca sin
cambios, mientras la aplicación moderna puede evitar poner en riesgo su diseño y su enfoque tecnológico.
Problemas y consideraciones
●● La capa para evitar daños podría añadir latencia a las llamadas realizadas entre los dos sistemas.
●● La capa para evitar daños añade un servicio adicional que debe administrarse y mantenerse.
●● Piense si necesita más de una capa para evitar daños. Es posible que quiera descomponer la
funcionalidad en varios servicios con distintas tecnologías o lenguajes, o podría haber otros motivos
para crear particiones en la capa para evitar daños.
●● Piense cómo se administrará la capa para evitar daños en relación con sus otras aplicaciones
o servicios. ¿Cómo se integrará en sus procesos de supervisión, publicación y configuración?
●● Compruebe si su capa para evitar daños ha de administrar toda la comunicación entre los sistemas
heredados y modernos, o simplemente un subconjunto de características.
●● Tenga en cuenta si la capa para evitar daños va a ser permanente o se prevé que se retire tras haber
migrado todas las funcionalidades heredadas.
●● Si se ha previsto una migración en varias etapas, pero debe mantenerse la integración entre los
sistemas nuevos y los heredados.
●● Si el sistema nuevo y el heredado tienen una semántica diferente, pero siguen teniendo que
comunicarse.
Este patrón puede no resultar conveniente si no hay diferencias semánticas significativas entre los sistemas
nuevos y los heredados.
Contexto y problema
Una aplicación podría orientarse inicialmente a una IU web para escritorio. Por lo general, se desarrolla
en paralelo un servicio de back-end que proporciona las características necesarias para esa interfaz de
usuario. A medida que crece la base de usuarios de la aplicación, se desarrolla una aplicación móvil que
debe interactuar con el mismo back-end. El servicio de back-end se convierte en un back-end con fines
generales y que sirve a los requisitos de las interfaces móviles y de escritorio.
Sin embargo, las capacidades de un dispositivo móvil difieren significativamente de las de un navegador de
escritorio, en el tamaño de la pantalla, el rendimiento y las limitaciones de pantalla. Como resultado,
los requisitos para un back-end de una aplicación móvil difieren de la interfaz de usuario web para escritorio.
Estas diferencias resultan en requisitos enfrentados para el back-end. El back-end requiere cambios
regulares y significativos para hacer frente tanto a la IU web como a la aplicación móvil. A menudo,
en cada front-end trabajan equipos de interfaz separados, haciendo que el back-end se convierta en un
cuello de botella en el proceso de desarrollo. Los requisitos de actualización en conflicto y la necesidad
de que el servicio siga trabajando en ambos front-ends pueden dar como resultado una gran inversión
de esfuerzo en un único recurso implementable.
A medida que la actividad de desarrollo se centra en el servicio de back-end, podría quedarse un equipo
independiente para administrar y mantener el back-end. En definitiva, esto resulta en una desconexión
entre los equipos de desarrollo de la interfaz y el back-end, lo que resulta un lastre para el equipo back-end
a la hora de equilibrar los requisitos enfrentados de los diferentes equipos de interfaz de usuario. Cuando
un equipo de interfaz solicita cambios al back-end, esos cambios deben validarse con otros equipos de
interfaz antes de que se puedan integrar en el back-end.
Dado que cada back-end es específico para una interfaz, puede optimizarse para dicha interfaz. Como
resultado, será más pequeño, menos complejo y probablemente más rápido que un back-end genérico
que intente satisfacer las necesidades de todas las interfaces. Cada equipo de interfaz tiene autonomía
para controlar su propio back-end y no depende de un equipo de desarrollo de back-end centralizado.
Esto le da al equipo de interfaz flexibilidad en la selección del lenguaje, la cadencia de lanzamiento,
la priorización de la carga de trabajo y la integración de las características en su back-end.
Problemas y consideraciones
●● Tenga en cuenta cuándos back-ends implementar.
●● Si hay diferentes interfaces (por ejemplo, clientes móviles) que realizarán las mismas solicitudes,
piense si es necesario implementar un back-end para cada interfaz o si bastará con un solo back-end.
●● Los servicios de back-end centrados en front-end solo deben contener lógica y comportamientos
específicos al cliente. La lógica empresarial general y otras características globales deben
administrarse en otras partes de la aplicación.
●● Piense en cómo podría reflejarse este patrón en las responsabilidades de un equipo de desarrollo.
●● Piense en cuánto tiempo tardaría en implementar este patrón. ¿El esfuerzo de construir los nuevos
back-ends le hará incurrir en una deuda técnica, mientras continúa dando soporte al back-end
genérico existente?
●● Debe mantenerse un servicio de back-end de propósito general o compartido con una sobrecarga
de desarrollo significativa.
●● Las personalizaciones se realizan en un back-end de uso general para dar cabida a varias interfaces.
●● Un lenguaje alternativo resulta más adecuado para el back-end de una interfaz de usuario diferente.
Orientación relacionada
●● Patrón de agregación de puerta de enlace
●● Patrón de descarga de puerta de enlace
●● Patrón de enrutamiento de puerta de enlace
Patrón Bulkhead
Aísla los elementos de una aplicación en grupos, de modo que si uno falla, los demás seguirán
funcionando.
Este patrón se denomina Bulkhead (mamparo) porque se asemeja a la división de las secciones del casco
de un barco. Si existe riesgo para el casco de un barco, solo la sección deteriorada se llenará con agua,
lo que evitará que el barco se hunda.
Contexto y problema
Una aplicación basada en el cloud puede incluir múltiples servicios y cada uno de ellos podría tener uno
o varios consumidores. Una carga excesiva o un error en un servicio afectará a todos los consumidores del
servicio.
Además, un consumidor puede enviar solicitudes a varios servicios simultáneamente, utilizando recursos
para cada solicitud. Cuando el consumidor envía una solicitud a un servicio que está mal configurado
o no responde, los recursos utilizados por la solicitud del cliente no pueden liberarse de forma puntual.
A medida que continúan las solicitudes a dicho servicio, los recursos pueden agotarse. Por ejemplo,
el grupo de conexiones del cliente podría agotarse. En ese momento, las solicitudes que realiza
el consumidor a otros servicios se ven afectadas. Finalmente, el consumidor ya no podrá enviar solicitudes
a ningún servicio, no simplemente al servicio que no respondía originalmente.
El mismo problema de agotamiento de recursos afecta a servicios con varios consumidores. Un gran
número de solicitudes procedentes de un cliente puede agotar los recursos disponibles en el servicio.
Otros consumidores ya no podrán consumir el servicio, causando un efecto de error en cascada.
Un consumidor también puede crear particiones de recursos, para garantizar que los recursos utilizados
para llamar a un servicio no afecten a los recursos que utiliza para llamar a otro servicio. Por ejemplo,
a un consumidor que llama a varios servicios se le puede asignar un grupo de conexiones para cada
servicio. Si un servicio empieza a fallar, solo afectará al grupo de conexiones asignado a dicho servicio,
por lo que permitirá al consumidor seguir usando los demás servicios.
El siguiente diagrama muestra a varios clientes llamando a un único servicio. A cada cliente se le asigna
una instancia de servicio independiente. El cliente 1 ha hecho demasiadas solicitudes y ha sobrecargado
su instancia. Dado que cada instancia de servicio está aislada de las demás, los otros clientes pueden
seguir realizando llamadas.
●● Piense en combinar bulkheads con patrones de reintento, interruptor de circuito y limitación para
proporcionar una administración de errores más sofisticada.
●● Al crear particiones en bulkheads de los consumidores, tenga en cuenta el uso de procesos, grupos
de subprocesos y semáforos. Proyectos como Netflix Hystrix y Polly ofrecen un marco para la creación
de bulkheads de consumidores
●● Los servicios que se comunican mediante mensajes asincrónicos pueden aislarse mediante diferentes
conjuntos de colas. Cada cola puede tener un conjunto dedicado de instancias de procesamiento
de mensajes en la cola, o un solo grupo de instancias que utilice un algoritmo para quitar elementos
de la cola y distribuir el procesamiento.
●● Determine el nivel de granularidad de los bulkheads. Por ejemplo, si desea distribuir inquilinos en
varias particiones, podría colocar a cada inquilino en una partición diferente, o a varios inquilinos en
una partición.
apiVersion: v1
kind: Pod
metadata:
name: drone-management
spec:
containers:
- name: drone-management-container
image: drone-service
resources:
requests:
memory: “64Mi”
cpu: “250m”
limits:
memory: “128Mi”
cpu: “1”
Orientación relacionada
Patrón Cache-Aside
Carga datos bajo demanda en una caché desde un almacén de datos. Esto puede mejorar el rendimiento
y también ayuda a mantener la coherencia entre los datos guardados en la caché y los datos guardados
en el almacén de datos subyacente.
Contexto y problema
Las aplicaciones utilizan una memoria caché para mejorar el acceso repetido a la información guardada
en un almacén de datos. Sin embargo, no resulta práctico esperar que los datos almacenados en
caché siempre sean completamente coherentes con los datos en el almacén de datos. Las aplicaciones
deben implementar una estrategia que ayude a garantizar que los datos en la memoria caché están tan
actualizados como sea posible, pero también puede detectar y gestionar las situaciones derivadas de
cuando los datos en caché se vuelven obsoletos.
Solución
Muchos sistemas comerciales de almacenamiento en caché proporcionan operaciones de lectura
sincrónica y escritura sincrónica y asincrónica. En estos sistemas, una aplicación recupera los datos
mediante una referencia a la memoria caché. Si los datos no están en la caché, se recuperan del almacén
de datos y se añaden a la caché. Cualquier modificación a los datos almacenados en la caché se vuelven
a escribir automáticamente también en el almacén de datos.
Si una aplicación actualiza información, puede seguir la estrategia de escritura sincrónica realizando
la modificación al almacén de datos e invalidando el elemento correspondiente en la memoria caché.
Cuando se vuelve a solicitar el elemento, el uso de la estrategia cache-aside hará que los datos
actualizados se recuperen desde el almacén de datos y se vuelva a añadir a la caché.
Problemas y consideraciones
Tenga en cuenta los puntos siguientes a la hora de decidir cómo implementar este patrón:
Vida útil de los datos almacenados en caché. Muchas memorias caché implementan una política de
caducidad que invalida los datos y los elimina de la memoria si no se accede a ellos durante un periodo
determinado. Para que la cache-aside resulte eficaz, asegúrese de que la política de caducidad coincida
con el patrón de acceso de las aplicaciones que usan los datos. No cree un periodo de caducidad
demasiado corto, ya que esto puede provocar que las aplicaciones recuperen datos continuamente del
almacén de datos y los añadan a la caché. Del mismo modo, no haga que el periodo de caducidad sea tan
largo que los datos en caché acaben estando obsoletos. Recuerde que el almacenamiento en caché es más
eficaz para datos relativamente estáticos o para datos que se leen con frecuencia.
Expulsión de datos. La mayoría de cachés tienen un tamaño limitado en comparación con el almacén de
datos en el que se originan los datos y expulsarán datos si fuera necesario. La mayoría de cachés adoptan
una política de "uso más reciente" para seleccionar los elementos que expulsar, pero este comportamiento
se puede personalizar. Configure la propiedad de caducidad global, otras propiedades de la caché y
la propiedad de caducidad de cada elemento en caché para garantizar que la caché sea eficiente. No
siempre es apropiado aplicar una política global de expulsión a cada elemento de la caché. Por ejemplo,
si un elemento almacenado en caché resulta muy costoso de recuperar desde el almacén de datos, puede
ser beneficioso mantener este elemento en la caché a expensas de elementos a los que se accede con más
frecuencia pero que resultan menos costosos.
Almacenamiento en caché local (in-memory) Una caché puede ser local en una instancia de la
aplicación y puede almacenarse in-memory. El cache-aside puede resultar útil en este entorno si una
aplicación accede repetidamente a los mismos datos. Sin embargo, una memoria caché local es privada y,
por tanto, las diferentes instancias de la aplicación podrían tener una copia de los mismos datos en caché.
Estos datos podrían resultar rápidamente incoherentes entre cachés, por lo que podría ser necesario que
caduquen los datos almacenados en una caché privada y actualizarlos más a menudo. En estos escenarios,
valore investigar el uso de un mecanismo de almacenamiento en caché compartido o distribuido.
Vida útil de los datos almacenados en caché. Muchas memorias caché implementan una política de
caducidad que invalida los datos y los elimina de la memoria si no se accede a ellos durante un periodo
determinado. Para que la cache-aside resulte eficaz, asegúrese de que la política de caducidad coincida
con el patrón de acceso de las aplicaciones que usan los datos. No cree un periodo de caducidad
demasiado corto, ya que esto puede provocar que las aplicaciones recuperen datos continuamente del
almacén de datos y los añadan a la caché. Del mismo modo, no haga que el periodo de caducidad sea tan
largo que los datos en caché acaben estando obsoletos. Recuerde que el almacenamiento en caché es más
eficaz para datos relativamente estáticos o para datos que se leen con frecuencia.
Expulsión de datos. La mayoría de cachés tienen un tamaño limitado en comparación con el almacén de
datos en el que se originan los datos y expulsarán datos si fuera necesario. La mayoría de cachés adoptan
una política de "uso más reciente" para seleccionar los elementos que expulsar, pero este comportamiento
se puede personalizar. Configure la propiedad de caducidad global, otras propiedades de la caché y
la propiedad de caducidad de cada elemento en caché para garantizar que la caché sea eficiente. No
siempre es apropiado aplicar una política global de expulsión a cada elemento de la caché. Por ejemplo,
si un elemento almacenado en caché resulta muy costoso de recuperar desde el almacén de datos, puede
ser beneficioso mantener este elemento en la caché a expensas de elementos a los que se accede con más
frecuencia pero que resultan menos costosos.
Desbloqueo de la caché. Muchas soluciones rellenan previamente la memoria caché con los datos que,
probablemente, necesite una aplicación como parte del proceso de arranque. El patrón cache-aside puede
seguir siendo útil si algunos de estos datos caducan o se expulsan.
Almacenamiento en caché local (in-memory). Una caché puede ser local en una instancia de la
aplicación y puede almacenarse in-memory. El cache-aside puede resultar útil en este entorno si una
aplicación accede repetidamente a los mismos datos. Sin embargo, una memoria caché local es privada y,
por tanto, las diferentes instancias de la aplicación podrían tener una copia de los mismos datos en caché.
Estos datos podrían resultar rápidamente incoherentes entre cachés, por lo que podría ser necesario que
caduquen los datos almacenados en una caché privada y actualizarlos más a menudo. En estos escenarios,
valore investigar el uso de un mecanismo de almacenamiento en caché compartido o distribuido.
●● La demanda de recursos es impredecible. Este patrón permite que las aplicaciones carguen los datos
bajo demanda. No realiza ninguna suposición sobre qué datos requerirá una aplicación por adelantado.
Ejemplo
En Microsoft Azure, puede utilizar Azure Redis Cache para crear una memoria caché distribuida que
pueden compartir varias instancias de una aplicación.
Para conectarse a una instancia de Azure Redis Cache, llame al método Connect estático y pase la cadena
de conexión. El método devuelve un ConnectionMultiplexer que representa la conexión. Una forma de
compartir una instancia ConnectionMultiplexer en su aplicación es tener una propiedad estática que
devuelva una instancia conectada, similar al ejemplo siguiente. Este enfoque proporciona una manera
segura para los subprocesos de inicializar solamente una única instancia conectada.
El método GetMyEntityAsync en el ejemplo de código siguiente muestra una implementación del patrón
cache-aside basado en Azure Redis Cache. Este método recupera un objeto de la caché utilizando el
método de lectura sincrónica.
Un objeto se identifica mediante un identificador entero como clave. El método GetMyEntityAsync intenta
recuperar un elemento con esta clave de la memoria caché. Si se encuentra un elemento coincidente,
lo devuelve. Si no hay ninguna coincidencia en la caché, el método GetMyEntityAsync recupera el objeto
de un almacén de datos, lo agrega a la caché y luego lo devuelve. El código que lee realmente los datos
desde el almacén de datos no se muestra aquí, porque depende del almacén de datos. Tenga en cuenta
que el elemento almacenado en caché se configura para caducar, con el fin de evitar que se vuelva
obsoleto si se actualiza en otro lugar.
return value;
}
Los ejemplos utilizan la API de Azure Redis Cache para acceder al almacén y recuperar la información de
la caché. Para obtener más información, consulte Uso de Microsoft Azure Redis Cache y Cómo crear una
aplicación web con Redis Cache.
Nota:
El orden de los pasos es importante. Actualice el almacén de datos antes de quitar el elemento de la caché. Si quita el
elemento en caché en primer lugar, hay un pequeño periodo en el que un cliente podría recuperar el elemento antes
de que el almacén de datos se actualice. Esto provocará un error de caché (porque el elemento se eliminó de la caché),
por lo que la versión anterior del elemento tendrá que recuperarse del almacén de datos y volver a añadirse a la caché.
Como resultado, habrá datos obsoletos en la caché.
●● Introducción a la coherencia de datos. Las aplicaciones en el cloud normalmente utilizan datos que
se encuentran en varios almacenes de datos. La administración y el mantenimiento de la coherencia
de datos en este entorno es un aspecto esencial del sistema, especialmente los problemas de
simultaneidad y disponibilidad que pueden surgir. En esta introducción se describen problemas
relacionados con la coherencia de datos distribuidos y se resume cómo puede implementar una
aplicación coherencia eventual para mantener la disponibilidad de los datos.
Contexto y problema
En un entorno distribuido, las llamadas a servicios y recursos remotos pueden fallar debido a errores
transitorios, como conexiones de red lentas, tiempos de espera o una sobrexplotación o indisponibilidad
temporal de los recursos. Estos errores se suelen corregir solos tras un breve periodo de tiempo, y una
aplicación sólida en el cloud debería estar preparada para afrontarlos mediante una estrategia como el
patrón de reintento.
Sin embargo, también puede haber situaciones en las que los errores se deben a acontecimientos
imprevistos y su corrección podría llevar mucho más tiempo. La gravedad de estos errores puede variar,
desde una pérdida parcial de conectividad hasta el colapso completo de un servicio. En estas situaciones
podría ser inútil que una aplicación reintente continuamente una operación que es poco probable que
tenga éxito. En cambio, la aplicación debe aceptar rápidamente que la operación ha fallado y afrontar
ese error en consecuencia.
Además, si un servicio está muy ocupado, un fallo en una parte del sistema puede provocar errores en
cascada. Por ejemplo, una operación que invoca un servicio puede configurarse para implementar un
tiempo de espera y responder con un mensaje de error si el servicio no responde dentro de este período.
Sin embargo, esta estrategia podría provocar muchas solicitudes simultáneas a la misma operación, de
modo que quede bloqueada hasta que venza el tiempo de espera. Estas solicitudes bloqueadas podrían
retener recursos críticos del sistema como memoria, subprocesos, conexiones de bases de datos, etcétera.
En consecuencia, estos recursos podrían agotarse, lo que causaría un error en otras partes del sistema,
posiblemente no relacionadas, que tengan que usar los mismos recursos. En estas situaciones, sería
preferible que la operación fallara inmediatamente y solo intentara invocar el servicio si es probable que
tenga éxito. Tenga en cuenta que establecer un tiempo de espera más corto podría ayudar a resolver este
problema, pero el tiempo de espera no debería ser tan corto que la operación fallara la mayor parte del
tiempo, incluso aunque la solicitud al servicio tuviera éxito finalmente.
El objetivo del patrón de interruptor de circuito es diferente al del patrón de reintento. El patrón de
reintento permite que una aplicación vuelva a intentar una operación con la expectativa de que tenga
éxito. El patrón de interruptor de circuito impide que una aplicación realice una operación que es probable
que fracase. Una aplicación puede combinar estos dos patrones usando el patrón de reintento para
invocar una operación a través de un interruptor de circuito. Sin embargo, la lógica de reintento debe
ser sensible a las excepciones que devuelve el interruptor de circuito y abandonar los reintentos si el
interruptor indica que el error no es transitorio.
Un interruptor de circuito actúa como un proxy para las operaciones que podrían fallar. El proxy debe
supervisar el número de errores recientes que han ocurrido y utilizar esta información para decidir
si se permite que la operación proceda, o devuelve simplemente una excepción de inmediato.
El proxy puede implementarse como una máquina de estado con los siguientes estados que imitan
la funcionalidad de un interruptor de circuito eléctrico:
● El estado Half-Open es útil para evitar que un servicio de recuperación se vea desbordado
de peticiones de repente. Cuando un servicio se está recuperando, podría aceptar un
volumen limitado de solicitudes hasta que la recuperación se complete, pero mientras la
recuperación sigue en marcha, el flujo de trabajo puede hacer que el servicio agote el tiempo
de espera o vuelva a fallar.
El patrón es personalizable y puede adaptarse según el tipo de error potencial. Por ejemplo, puede
aplicar un temporizador de tiempo de espera ascendente a un interruptor de circuito. Podría colocar
el interruptor de circuito en el estado Open inicialmente durante unos segundos y, si el error no se ha
resuelto, aumentar el tiempo de espera unos minutos y así sucesivamente. En algunos casos, en lugar de
que el estado Open devuelva un error y una excepción, podría ser útil devolver un valor predeterminado
que resulte significativo para la aplicación.
Control de excepciones. Una aplicación que invoca una operación a través de un interruptor de circuito
debe estar preparada para gestionar las excepciones si la operación no está disponible. La forma en que
se gestionan las excepciones es específica a cada aplicación. Por ejemplo, una aplicación podría degradar
temporalmente su funcionalidad, invocar una operación alternativa para tratar de realizar la misma tarea
u obtener los mismos datos o informar de la excepción al usuario y pedirle que lo intente más tarde.
Tipos de excepciones. Una solicitud puede fallar por muchas razones, algunas de las cuales podrían
indicar un tipo de error más grave que otras. Por ejemplo, una solicitud puede fallar debido a la
interrupción de un servicio remoto y tardar varios minutos en recuperarse, o debido a un tiempo de
espera porque el servicio está sobrecargado temporalmente. Un interruptor de circuito podría examinar
los tipos de excepciones que se producen y ajustar su estrategia dependiendo de la naturaleza de estas
excepciones. Por ejemplo, podría requerir un mayor número de excepciones de tiempo de espera para
disparar en el interruptor el estado Open en comparación con el número de errores debidos a que el
servicio esté totalmente no disponible.
Registro. Un interruptor de circuito debe registrar todas las solicitudes erróneas (y posiblemente las
solicitudes correctas) para permitir que un administrador supervise el estado de la operación.
Capacidad de recuperación. Debe configurar el interruptor de circuito para que coincida con el patrón
de recuperación probable de la operación que está protegiendo. Por ejemplo, si el interruptor de circuito
permanece en el estado Open durante un tiempo prolongado, podrían plantearse excepciones aunque la
causa del error se haya resuelto. Del mismo modo, un interruptor de circuito podría fluctuar y reducir los
tiempos de respuesta de las aplicaciones si cambia del estado Open al estado Half-Open demasiado rápido.
Invalidación manual. En un sistema en el que el tiempo de recuperación para una operación errónea
es muy variable, es conveniente facilitar una opción de restablecimiento manual que permita a un
administrador cerrar un interruptor de circuito (y reiniciar el contador de errores). Del mismo modo,
un administrador podría forzar en un interruptor de circuito el estado Open (y reiniciar el temporizador
de tiempo de espera) si la operación protegida por el interruptor de circuito está temporalmente no
disponible.
Simultaneidad. Puede haber un gran número de instancias simultáneas de una aplicación accediendo al
mismo interruptor de circuito a la vez. La aplicación no debería bloquear solicitudes simultáneas ni añadir
una sobrecarga excesiva a cada llamada a una operación.
Diferenciación de recursos. Tenga cuidado al usar un único interruptor de circuito para un tipo de recurso
si puede haber varios proveedores independientes subyacentes. Por ejemplo, en un almacén de datos
que contiene múltiples particiones, una partición puede ser completamente accesible mientras que otra
experimenta un problema temporal. Si se combinan las respuestas a errores en estos escenarios, una
aplicación podría intentar acceder a algunas particiones incluso cuando el error es altamente probable,
mientras que el acceso a otras particiones podría quedar bloqueado aunque su probabilidad de éxito sea alta.
Interrupción de circuito acelerada. A veces una respuesta ante un error puede contener suficiente
información para que el interruptor de circuito se dispare inmediatamente y permanezca activo durante un
tiempo mínimo. Por ejemplo, la respuesta a un error desde un recurso compartido que está sobrecargado
podría indicar que no se recomienda un reintento inmediato y que la aplicación debería volver a intentarlo
en unos minutos.
Ejemplo
En una aplicación web, varias páginas están rellenas con los datos recuperados de un servicio externo. Si el
sistema implementa un almacenamiento en caché mínimo, la mayoría de visitas a estas páginas causarán un
flujo de ida y vuelta al servicio. Las conexiones desde la aplicación web hasta el servicio podrían configurarse
con un período de tiempo de espera (normalmente 60 segundos) y, si el servicio no responde en este
tiempo, la lógica en cada página supondrá que el servicio no está disponible y presentará una excepción.
Sin embargo, si el servicio falla y el sistema está muy ocupado, los usuarios podrían tener que esperar
hasta 60 segundos antes de que se produzca una excepción. Al final, los recursos como la memoria, las
conexiones y los subprocesos podrían agotarse, con lo que se evitaría que otros usuarios se conectaran
al sistema, incluso aunque no accedan a páginas que recuperen datos del servicio.
Si se escala el sistema añadiendo más servidores web e implementando un equilibrio de carga, se podría
retrasar el momento de agotamiento de los recursos, pero no se resolverá el problema, ya que las
solicitudes de usuarios seguirán sin respuesta y, al final, todos los servidores web podrían quedarse sin
recursos.
El ajuste de lógica que conecta con el servicio y recupera los datos en un interruptor de circuito podría
ayudar a solucionar este problema y administrar el error del servicio con más ligereza. Las solicitudes
de usuarios seguirán fallando, pero fallarán más rápido y no bloquearán los recursos.
interface ICircuitBreakerStateStore
{
CircuitBreakerStateEnum State { get; }
void Reset();
void HalfOpen();
La propiedad State indica el estado actual del interruptor de circuito, y será Open, HalfOpen o Closed,
según defina la enumeración CircuitBreakerStateEnum. La propiedad IsClosed debe ser true si el
interruptor de circuito está cerrado, pero false si está abierto o parcialmente abierto. El método Trip
cambia el estado del interruptor de circuito al estado Open y registra la excepción que haya provocado
el cambio en el estado, junto con la fecha y la hora en que ocurrió la excepción. Las propiedades
LastException y LastStateChangedDateUtc devuelven esta información. El método Reset cierra el
interruptor de circuito, y el método HalfOpen establece el interruptor de circuito en el estado HalfOpen.
En el ejemplo siguiente, se muestra el código (que se ha omitido en el ejemplo anterior) que se ejecuta
si el interruptor no está cerrado. Primero comprueba si el interruptor ha estado abierto durante más
tiempo del que se especifica en el campo local OpenToHalfOpenWaitTime en la clase CircuitBreaker. Si es
así, el método ExecuteAction define el interruptor en medio abierto y luego intenta realizar la operación
especificada por el delegado Action.
Si el interruptor solo ha estado abierto durante un breve período de tiempo, menos que lo que indica
el valor de OpenToHalfOpenWaitTime, el método ExecuteAction simplemente produce una excepción
CircuitBreakerOpenException y devuelve el error que hizo que el interruptor pasara al estado abierto.
Asimismo, utiliza un bloqueo para evitar que el interruptor intente realizar llamadas simultáneas a la
operación mientras está medio abierto. Un intento simultáneo de invocar la operación se considerará
como si el interruptor estuviera abierto y fallará con una excepción, como se explica más adelante.
// If this action succeeds, reset the state and allow other operations.
// In reality, instead of immediately returning to the Closed state, a counter
// here would record the number of successful operations and return the
// circuit breaker to the Closed state only after a specified number succeed.
this.stateStore.Reset();
return;
}
catch (Exception ex)
{
// If there’s still an exception, trip the breaker again immediately.
this.stateStore.Trip(ex);
// Throw the exception so that the caller knows which exception occurred.
throw;
}
finally
{
if (lockTaken)
{
Monitor.Exit(halfOpenSyncObject);
}
}
}
}
// The Open timeout hasn’t yet expired. Throw a CircuitBreakerOpen exception to
// inform the caller that the call was not actually attempted,
// and return the most recent exception received.
throw new CircuitBreakerOpenException(stateStore.LastException);
}
...
try
{
breaker.ExecuteAction(() =>
{
// Operation protected by the circuit breaker.
...
});
}
catch (CircuitBreakerOpenException ex)
{
// Perform some different action when the breaker is open.
// Last exception details are in the inner exception.
...
}
catch (Exception ex)
{
...
}
Los patrones siguientes también podrían resultar útiles para implementar este patrón:
●● Patrón de reintento. Describe cómo una aplicación puede manejar los fallos temporales previstos
cuando intenta conectarse a un servicio o recurso de red volviendo a intentar de manera transparente
una operación que ha fallado anteriormente.
●● Patrón de supervisión de puntos de conexión de estado. Un interruptor podría ser capaz de probar
el estado de un servicio mediante el envío de una solicitud a un punto de conexión expuesto por
el servicio. El servicio debería devolver información sobre su estado.
Contexto y problema
En los sistemas de administración de datos tradicionales, ambos comandos (actualizaciones de los datos)
y las consultas (solicitudes de datos) se ejecutan con respecto al mismo conjunto de entidades en un único
repositorio de datos. Estas entidades pueden ser un subconjunto de las filas de una o más tablas de una
base de datos relacional como SQL Server.
Los diseños tradicionales de CRUD funcionan bien cuando se aplica únicamente una lógica de negocio
limitada a las operaciones de datos. Los mecanismos de Scaffold que ofrecen las herramientas de
desarrollo pueden crear muy rápidamente código de acceso a datos, que luego se puede personalizar
como sea preciso.
Para conocer en mayor profundidad los límites del enfoque CRUD, consulte CRUD: solo cuando pueda
permitírselo.
Solución
CQRS (Command and Query Responsibility Segregation) es un patrón que segrega las operaciones que
leen datos (consultas) de las operaciones que actualizan datos (comandos) utilizando interfaces separadas.
Esto significa que los modelos de datos que se utilizan para realizar consultas y actualizaciones son
diferentes. Por tanto, los modelos se pueden aislar, como se muestra en la figura siguiente, aunque esto
no sea un requisito absoluto.
El modelo de consulta para leer datos y el modelo de actualización para escribir datos puede acceder al
mismo almacén físico, tal vez mediante el uso de vistas SQL o generando proyecciones sobre la marcha.
Sin embargo, es común separar los datos en diferentes almacenes físicos para maximizar el rendimiento,
la escalabilidad y la seguridad, como se muestra en la siguiente figura.
El almacén de lectura puede ser una réplica de solo lectura del almacén de escritura o bien los almacenes
de lectura y escritura pueden tener una estructura totalmente diferente. El uso de varias réplicas de
solo lectura del almacén de lectura puede aumentar enormemente el rendimiento de las consultas y la
capacidad de respuesta de la IU de la aplicación, especialmente en escenarios distribuidos donde las
réplicas de solo lectura se encuentran cerca de las instancias de aplicación. Algunos sistemas de bases
de datos (SQL Server) ofrecen funciones adicionales, como las réplicas de conmutación por error, para
maximizar la disponibilidad.
La separación de los almacenes de lectura y escritura también permite que cada uno se pueda escalar de
la manera apropiada para ajustarse a la carga. Por ejemplo, normalmente los almacenes de lectura suelen
encontrarse con una carga mucho mayor que los almacenes de escritura.
●● Para leer una descripción de la coherencia final, consulte Introducción a la coherencia de datos.
●● Piense en la posibilidad de aplicar CQRS en secciones limitadas del sistema, donde sea más valioso.
●● Interfaces de usuario basadas en tareas donde se guía a los usuarios a través de un proceso complejo
como una serie de pasos o con modelos de dominio complejos. Además, es útil para los equipos ya
familiarizados con las técnicas de diseño basadas en dominios (DDD). El modelo de escritura tiene una pila
de procesamiento de comandos completa con lógica de negocio, validación de la entrada y validación de
negocio para asegurarse de que todo sea siempre coherente para cada uno de los agregados (cada grupo
de objetos asociados que se trata como una unidad para los cambios de datos) en el modelo de escritura.
El modelo de lectura no tiene ninguna lógica de negocio ni pila de validación y solo devuelve un DTO para
utilizarlo en un modelo de vista. El modelo de lectura tiene coherente final con el modelo de escritura.
●● Situaciones donde el rendimiento de las lecturas de datos se debe ajustar por separado del
rendimiento de las escrituras de datos, especialmente cuando la relación de lectura y escritura
es muy alta y cuando es necesario realizar escalado horizontal. Por ejemplo, en muchos sistemas,
el número de operaciones de lectura es mucho mayor que el número de operaciones de escritura.
Para adaptarse a esto, piense en la posibilidad de escalar el modelo de lectura, pero ejecutando
el modelo de escritura en solo una instancia o en unas pocas. Un pequeño número de instancias
del modelo de escritura también ayuda a minimizar los conflictos de combinación.
●● Situaciones donde un equipo de desarrolladores puede centrarse en el modelo de dominios
complejos que forma parte del modelo de escritura y otro equipo puede centrarse en el modelo
de lectura y las interfaces de usuario.
●● Situaciones donde el sistema debe evolucionar con el tiempo y puede contener varias versiones
del modelo o donde las reglas de negocio cambian periódicamente.
●● Integración con otros sistemas, especialmente en combinación con el abastecimiento de eventos,
donde el fallo temporal de un subsistema no debería afectar a la disponibilidad de los otros.
El uso del flujo de eventos como almacén de escritura en lugar de los datos reales en un punto del tiempo
evita conflictos de actualización en un agregado único y maximiza el rendimiento y la escalabilidad. Los
eventos pueden utilizarse para generar asíncronamente vistas materializadas de los datos que se utilizan
para llenar el almacén de lectura.
Dado que el almacén de eventos es la fuente oficial de información, es posible borrar las vistas
materializadas y reproducir todos los eventos pasados para crear una nueva representación del estado
actual cuando el sistema evoluciona o cuando el modelo de lectura debe cambiar. Las vistas materializadas
son, en efecto, una caché de solo lectura duradera de los datos.
Ejemplo
El código siguiente muestra algunos extractos de un ejemplo de una implementación de CQRS en la que
se utilizan diferentes definiciones de los modelos de lectura y escritura. Las interfaces del modelo no
determinan las características de los almacenes de datos subyacentes. Pueden evolucionar y se pueden
ajustar de manera independiente porque estas interfaces están separadas. El código siguiente muestra
la definición del modelo de lectura.
El sistema permite a los usuarios calificar los productos. Para ello, el código de la aplicación utiliza
el comando RateProduct que se muestra en el siguiente código.
●● Introducción a la coherencia de datos. Explica los problemas que suelen encontrarse debido a la
coherencia final entre los almacenes de datos de lectura y escritura cuando se usa el patrón CQRS
y cómo pueden resolverse.
●● Guía de partición de datos. Describe cómo los almacenes de datos de lectura y escritura que se
utilizan en el patrón de CQRS pueden dividirse en particiones a las que se puede acceder y administrar
por separado para mejorar la escalabilidad, reducir la contención y optimizar el rendimiento.
●● Patrón de abastecimiento de eventos. Describe más detalladamente cómo se puede utilizar
el abastecimiento de eventos con el patrón CQRS para simplificar tareas en dominios complejos
mejorando el rendimiento, la escalabilidad y la capacidad de respuesta. También explica cómo
proporcionar coherencia para los datos transaccionales manteniendo auditorías e historiales
completos que permiten realizar acciones de compensación.
●● Patrón de vistas materializadas. El modelo de lectura de una implementación de CQRS puede
contener vistas materializadas de los datos del modelo de escritura, o bien se puede utilizar el modelo
de lectura para generar vistas materializadas.
●● La guía de prácticas y patrones de CQRS Journey. En particular, la introducción al patrón CQRS
(Command and Query Responsibility Segregation) explora el patrón y cuándo es útil. El epílogo
sobre las lecciones aprendidas le ayuda a comprender algunos de los problemas que surgen cuando
se usa este patrón.
●● En el post CQRS de Martin Fowler, se explican los fundamentos del patrón y se proporcionan enlaces
a otros recursos útiles.
●● Los post de Greg Young exploran muchos aspectos del patrón de CQRS.
Contexto y problema
Las aplicaciones que se ejecutan en el cloud modifican datos con frecuencia. Estos datos podrían estar
repartidos en diferentes fuentes de datos en distintas ubicaciones geográficas. Para evitar la contención
y mejorar el rendimiento en un entorno distribuido, una aplicación no debería intentar proporcionar una
coherencia transaccional fuerte. Por el contrario, la aplicación debería implementar la coherencia final. En
este modelo, una operación de negocio típica consiste en una serie de pasos distintos. Mientras se realizan
estos pasos, la vista general del estado del sistema podría ser incoherente pero, cuando la operación se ha
completado y se han ejecutado todos los pasos, el sistema debería volver a ser coherente. En Introducción
a la coherencia de datos, se proporciona información acerca de por qué las transacciones distribuidas no
se escalan bien y los principios del modelo de coherencia final.
Si una operación que implementa coherencia final abarca varios almacenes de datos heterogéneos, para
deshacer los pasos de la operación sería necesario visitar cada almacén de datos de uno en uno. El trabajo
que se ha realizado en cada almacén de datos se debe deshacer de forma fiable para evitar que el sistema
siga siendo incoherente.
No todos los datos afectados por una operación que implementa coherencia final se pueden mantener
en una base de datos. En el entorno de una arquitectura orientada a servicios (SOA), una operación podría
invocar una acción en un servicio y provocar un cambio en el estado que mantiene ese servicio. Para
deshacer la operación, este cambio de estado también se debe deshacer. Esto puede suponer que hay
que volver a invocar el servicio y realizar otra acción que invierta los efectos de la primera.
Solución
La solución es implementar una transacción de compensación. Los pasos de una transacción de
compensación deben deshacer los efectos de los pasos de la operación original. Una transacción de
compensación podría no ser capaz de reemplazar simplemente el estado actual por el estado que tenía
el sistema al principio de la operación, porque este enfoque podría sobrescribir los cambios realizados
por otras instancias simultáneas de una aplicación. En su lugar, debe ser un proceso inteligente que tenga
en cuenta cualquier trabajo realizado por instancias simultáneas. Normalmente, este proceso es específico
de la aplicación y se basa en la naturaleza del trabajo realizado por la operación original.
Un enfoque común consiste en utilizar un flujo de trabajo para implementar una operación con coherencia
final que requiere compensación. A medida que avanza la operación original, el sistema registra la
información sobre cada paso y cómo se puede deshacer el trabajo realizado por ese paso. Si la operación
falla en cualquier punto, el flujo de trabajo vuelve atrás en los pasos que ha completado y realiza el trabajo
que invierte cada paso. Tenga en cuenta que es posible que una transacción de compensación no tenga
que deshacer el trabajo en el orden inverso exacto de la operación original y podría ser posible realizar
algunos de los pasos de deshacer en paralelo.
Este enfoque es similar a la estrategia de Sagas que se explica en el blog de Clemens Vasters.
Una transacción de compensación también es una operación con coherencia final y también podría
fallar. El sistema debe ser capaz de reanudar la transacción de compensación en el punto de error
y continuar. Podría ser necesario repetir un paso que ha fallado, por lo que los pasos de una transacción
de compensación deberían definirse como comandos idempotentes. Para obtener más información,
consulte los patrones de idempotencia en el blog de Jonathan Oliver.
En algunos casos, podría no ser posible recuperarse de un paso que ha fallado excepto mediante
la intervención manual. En estas situaciones, el sistema deberá emitir una alerta y proporcionar toda
la información que sea posible sobre el motivo del error.
Debería definir los pasos de una transacción de compensación como comandos idempotentes.
Esto permite que los pasos se repitan si la propia transacción de compensación falla.
La infraestructura que controla los pasos de la operación original y la transacción de compensación deben
ser resistentes. No debe perder la información necesaria para compensar un paso fallido y debe ser capaz
de supervisar de una forma fiable el progreso de la lógica de compensación.
Una transacción de compensación no restablece necesariamente el estado que tenían los datos del
sistema al principio de la operación original. En cambio, compensa el trabajo realizado por los pasos
que ha completado correctamente antes del fallo de la operación.
El orden de los pasos de la transacción de compensación no tiene que ser necesariamente el inverso
exacto de los pasos de la operación original. Por ejemplo, un almacén de datos puede ser más sensible
a las incoherencias que otro y, por tanto, los pasos de la transacción de compensación que deshacen los
cambios en este almacén deben realizarse primero.
Si se coloca un bloqueo basado en un tiempo de espera a corto plazo en cada recurso que debe
completar una operación y se obtienen estos recursos por adelantado, podría aumentar la probabilidad
de que la actividad general se realice correctamente. El trabajo se debe realizar únicamente después
de que se hayan adquirido todos los recursos. Todas las acciones deben finalizarse antes de que caduquen
los bloqueos.
Considere el uso de una lógica de reintento que sea más tolerante de lo habitual para minimizar los
errores que desencadenan una transacción de compensación. Si falla un paso de una operación que
implementa coherencia final, intente tratar el fallo como una excepción transitoria y repítalo. Únicamente
detenga la operación e inicie una transacción de compensación si un paso falla repetidas veces o de
manera irreversible.
Muchos de los problemas de la implementación de una transacción de compensación son los mismos
que los que se producen en la implementación de la coherencia final. Consulte la sección sobre
consideraciones para la implementación de la coherencia final en Introducción a la coherencia de datos
para obtener más información.
Estos pasos constituyen una operación con coherencia final, aunque cada paso es una acción
independiente. Por lo tanto, además de realizar estos pasos, el sistema también debe registrar las
operaciones de contador necesarias para deshacer cada paso en caso de que el cliente decida cancelar
el itinerario. A continuación, los pasos necesarios para realizar las operaciones de contador se pueden
ejecutar como una transacción de compensación.
Observe que los pasos de la transacción de compensación podrían no ser exactamente los inversos a los
pasos originales y la lógica en cada paso de la transacción de compensación debe tener en cuenta las reglas
específicas del negocio. Por ejemplo, si se anula la reserva de un asiento en un vuelo, eso no da derecho al
cliente a la devolución completa del dinero pagado. La figura muestra la generación de una transacción de
compensación para deshacer una transacción de larga ejecución para reservar un itinerario de viaje.
Podría ser posible que los pasos de la transacción de compensación se realizaran en paralelo,
dependiendo de cómo haya diseñado la lógica de compensación para cada paso.
En muchas soluciones de negocio, el fallo de un solo paso no siempre implica que haya que revertir
el sistema utilizando una transacción de compensación. Por ejemplo, si después de haber reservado
los vuelos F1, F2 y F3 en el ejemplo del sitio web de viajes, el cliente no es capaz de reservar una
habitación en el hotel H1, es preferible ofrecer al cliente una habitación en un hotel diferente de la misma
ciudad, en lugar de cancelar los vuelos. El cliente todavía puede decidir cancelar la reserva (en cuyo caso
la transacción de compensación se ejecuta y deshace las reservas de los vuelos F1, F2 y F3), pero esta
decisión debe tomarla el cliente en lugar del sistema.
Contexto y problema
Se espera que una aplicación que se ejecuta en el cloud gestione un gran número de solicitudes.
En lugar de procesar cada solicitud de forma sincrónica, se utiliza una técnica común que consiste en
que la aplicación las pasa a través de un sistema de mensajería a otro servicio (un servicio de consumidor)
que las gestiona de forma asincrónica. Esta estrategia ayuda a garantizar que la lógica de negocio de
la aplicación no se bloquee mientras se procesan las solicitudes.
El número de solicitudes puede variar considerablemente con el tiempo por muchas razones. Un aumento
repentino de la actividad del usuario o solicitudes agregadas que proceden de varios inquilinos pueden
causar una carga de trabajo imprevisible. En las horas pico, puede que un sistema tenga que procesar
cientos de solicitudes por segundo, mientras que en otras ocasiones, la cantidad podría ser muy pequeña.
Además, la naturaleza del trabajo realizado para gestionar estas solicitudes puede ser muy variable. Una
sola instancia del servicio al consumidor puede hacer que esa instancia se inunde de solicitudes o podría
sobrecargar el sistema de mensajería debido a una oleada de mensajes provenientes de la aplicación. Para
gestionar estas fluctuaciones de la carga de trabajo, el sistema puede ejecutar varias instancias del servicio
al consumidor. Sin embargo, estos consumidores deben coordinarse para garantizar que cada mensaje se
entregue solamente a un solo consumidor. La carga de trabajo también tiene que equilibrarse entre los
consumidores para evitar que una instancia se convierta en un cuello de botella.
Solución
Utilice una cola de mensajes para implementar el canal de comunicación entre la aplicación y las instancias
de servicio al consumidor. La aplicación publica las solicitudes en forma de mensajes en la cola y las
instancias del servicio al consumidor reciben mensajes de la cola y los procesan. Este enfoque permite que
el mismo conjunto de instancias del servicio al consumidor gestione mensajes de cualquier instancia de la
aplicación. La figura ilustra el uso de una cola de mensajes para distribuir el trabajo a las instancias de un
servicio.
Problemas y consideraciones
Tenga en cuenta los puntos siguientes a la hora de decidir cómo implementar este patrón:
●● Orden de los mensajes. El orden en el que las instancias del servicio al consumidor reciben los
mensajes no está garantizado y no refleja necesariamente el orden en el que se crearon los mensajes.
Diseñe el sistema para garantizar que el procesamiento de mensajes sea idempotente, porque esto
ayudará a eliminar cualquier dependencia en el orden en el que se gestionan los mensajes. Para
obtener más información, consulte los patrones de idempotencia en el blog de Jonathan Oliver.
●● Diseño de servicios para resistencia. Si el sistema está diseñado para detectar y reiniciar instancias
de servicio fallidas, podría ser necesario implementar el procesamiento que realizan las instancias
de servicio como operaciones idempotentes para minimizar los efectos de que un único mensaje
se recupere y procese más de una vez.
●● Detección de mensajes dudosos. Un mensaje mal formado o una tarea que requiere acceso a
recursos que no están disponibles pueden causar el fallo de una instancia de servicio. El sistema
debería evitar que esos mensajes se devuelvan a la cola y, en su lugar, capturar y almacenar los
detalles de esos mensajes en otros lugares para poder analizarlos si es necesario.
●● Gestión de los resultados. La instancia de servicio que gestiona un mensaje se desacopla
completamente de la lógica de la aplicación que genera el mensaje y puede que no sea capaz de
comunicarse directamente. Si la instancia de servicio genera resultados que deben pasarse a la lógica
de la aplicación, esta información debe almacenarse en una ubicación que sea accesible a ambos. Para
evitar que la lógica de la aplicación recupere datos incompletos, el sistema debe indicar cuándo se ha
completado el procesamiento.
Si utiliza Azure, un proceso de trabajo puede pasar de nuevo los resultados a la lógica de la aplicación
mediante el uso de una cola de respuesta de mensajes dedicada. La lógica de la aplicación debe ser
capaz de correlacionar estos resultados con el mensaje original. Este escenario se describe con más
detalle en Introducción a la mensajería asincrónica.
●● Escalado del sistema de mensajería. En una solución a gran escala, una sola cola de mensajes podría
saturarse por la gran cantidad de mensajes y convertirse en un cuello de botella en el sistema. En
esta situación, piense en la posibilidad de particionar el sistema de mensajería para enviar mensajes
de productores específicos a una cola en particular o bien utilizar el equilibrio de carga para distribuir
mensajes entre varias colas de mensajes.
●● Garantía de la fiabilidad del sistema de mensajería. Se necesita un sistema de mensajería fiable
para garantizar que, después de que la aplicación ponga en cola un mensaje, este no se perderá.
Esto es esencial para garantizar que todos los mensajes se entreguen al menos una vez.
Ejemplo
Azure proporciona colas de almacenamiento y colas de Service Bus que pueden actuar como un
mecanismo para implementar este patrón. La lógica de la aplicación puede publicar mensajes en una
cola y los consumidores que se han implementado como tareas en uno o más roles pueden recuperar los
mensajes de esta cola y procesarlos. Para conseguir resistencia, una cola de Service Bus permite que un
consumidor utilice el modo PeekLock cuando recupera un mensaje de la cola. En realidad, este modo no
elimina el mensaje, sino que simplemente se lo oculta a otros consumidores. El consumidor original puede
eliminar el mensaje cuando haya terminado de procesarlo. Si el consumidor falla, el tiempo de espera de
PeekLock se agotará y el mensaje volverá a ser visible para que otro consumidor pueda recuperarlo.
Para obtener información detallada sobre el uso de colas de Azure Service Bus, consulte las colas,
los temas y las suscripciones de Service Bus. Para obtener información sobre el uso de colas de
almacenamiento de Azure, consulte Introducción a Azure Queue Storage con .NET.
// Set the maximum delivery count for messages in the queue. A message
// is automatically dead-lettered after this number of deliveries. The
// default value for dead letter count is 10.
queueDescription.MaxDeliveryCount = 3;
await manager.CreateQueueAsync(queueDescription);
}
...
El siguiente fragmento de código muestra cómo una aplicación puede crear y enviar un lote de mensajes
a la cola.
El código siguiente muestra cómo una instancia del servicio al consumidor puede recibir mensajes
de la cola utilizando un enfoque basado en eventos. El parámetro processMessageTask del método
ReceiveMessages es un delegado que hace referencia al código que se va a ejecutar cuando se recibe
un mensaje. Este código se ejecuta de forma asincrónica.
Contexto y problema
Una aplicación de cloud suele implementar una gran variedad de operaciones. En algunas soluciones, lo
mejor es seguir el principio de diseño de la separación inicial de los problemas y dividir estas operaciones
en unidades computacionales diferentes que se alojan e implementan individualmente (por ejemplo, como
aplicaciones web App Service, separadas, máquinas virtuales separadas o roles del servicio en el cloud
separados). Sin embargo, aunque esta estrategia puede ayudar a simplificar el diseño lógico de la solución,
al implementar un gran número de unidades computacionales como parte de la misma aplicación, pueden
aumentar los costes de hosting y la complejidad de la administración del sistema.
Cada unidad computacional consume recursos de pago, incluso cuando está inactiva o se utiliza muy
poco. Por lo tanto, esta no siempre es la solución más rentable.
En Azure, este problema se aplica a los roles de un servicio en el cloud, los servicios de aplicaciones y
las máquinas virtuales. Estos elementos se ejecutan en su propio entorno virtual. No se realiza un uso
eficiente de los recursos si se ejecuta una recopilación de roles, sitios web o máquinas virtuales separados
que están diseñados para realizar un conjunto de operaciones bien definidas, pero que tienen que
comunicarse y cooperar como parte de una única solución.
Solución
Para reducir los costes, aumentar la utilización, mejorar la velocidad de la comunicación y reducir la
administración, es posible consolidar varias tareas u operaciones en una sola unidad computacional.
Las tareas pueden agruparse según criterios basados en las características que proporcionan los entornos
y los costes asociados a estas características. Un enfoque común consiste en buscar tareas que tengan
un perfil similar en lo referente a su escalabilidad, duración y requisitos de procesamiento. Al agruparlos,
pueden escalarse como una unidad. La elasticidad que ofrecen muchos entornos de cloud permite iniciar y
detener instancias adicionales de una unidad computacional según la carga de trabajo. Por ejemplo, Azure
proporciona escalado automático que se puede aplicar a los roles de un servicio en el cloud, servicios de
aplicaciones y máquinas virtuales. Para obtener más información, consulte Guía de escalado automático.
Como ejemplo de contador, para demostrar cómo se puede utilizar la escalabilidad para determinar las
operaciones que no deberían agruparse, considere las siguientes dos tareas:
●● La Tarea 1 realiza un sondeo en busca de mensajes poco frecuentes independientes del tiempo que
se envían a una cola.
●● La Tarea 2 maneja ráfagas de alto volumen de tráfico de red.
La segunda tarea requiere elasticidad, lo que puede significar que hay que iniciar y detener un gran
número de instancias de la unidad computacional. Si se aplica el mismo escalado a la primera tarea,
la consecuencia sería simplemente que habría más tareas que recibirían mensajes infrecuentes en la misma
cola y eso sería un desperdicio de los recursos.
En muchos entornos de cloud, es posible especificar los recursos disponibles para una unidad
computacional en lo que se refiere al número de núcleos de CPU, memoria, espacio en disco, etc.
Si hay tareas que requieren una gran cantidad de potencia de CPU en ráfagas cortas, considere la
posibilidad de consolidarlas en una sola unidad computacional que proporcione la potencia necesaria. Sin
embargo, es importante equilibrar esta necesidad para mantener ocupados a los recursos más costosos
con respecto a la contención que se produciría si se sobrecargaran demasiado. Por ejemplo, las tareas de
larga duración y de alta intensidad informática no deben compartir la misma unidad computacional.
Problemas y consideraciones
Al implementar este patrón, tenga en cuenta los siguientes puntos:
Duración. La infraestructura de cloud recicla periódicamente el entorno virtual que aloja una unidad
computacional. Cuando hay muchas tareas de larga ejecución dentro de una unidad computacional,
puede que sea necesario configurar la unidad para evitar que se recicle hasta que estas tareas hayan
terminado. Como alternativa, diseñe las tareas utilizando un enfoque dirigido a las comprobaciones que
les permita detenerse limpiamente y continuar en el punto en que se interrumpieron cuando se reinicia
la unidad computacional.
Seguridad. Es posible que las tareas de la misma unidad computacional compartan el mismo contexto
de seguridad y puedan acceder a los mismos recursos. Debe existir un alto grado de confianza entre
las tareas y la seguridad de que una tarea no va a dañar o afectar negativamente a otra. Asimismo,
el creciente número de tareas que se ejecutan en una unidad computacional incrementa la superficie
de ataque de la unidad. La seguridad de cada tarea es la misma que la de la tarea que posee más
vulnerabilidades.
Tolerancia a fallos. Si una de las tareas de una unidad computacional falla o se comporta anormalmente,
eso puede afectar a las demás tareas que se ejecutan en de la misma unidad. Por ejemplo, si una tarea no
se inicia correctamente, puede provocar el fallo de toda la lógica de inicio de la unidad computacional
y evitar que se ejecuten otras tareas de la misma unidad.
Contención. Evite la introducción de contención entre las tareas que compiten por los recursos en la
misma unidad computacional. Lo ideal es que las tareas que comparten la misma unidad computacional
deben tener diferentes características de utilización de los recursos. Por ejemplo, es probable que dos
tareas de alta intensidad informática no deban residir en la misma unidad computacional y tampoco dos
tareas que consuman grandes cantidades de memoria. Sin embargo, mezclar una tarea de alta intensidad
informática con una tarea que requiere una gran cantidad de memoria es una combinación viable.
Complejidad. Combinar varias tareas en una sola unidad computacional aumenta la complejidad del
código de la unidad, lo que posiblemente dificulta las pruebas, la depuración y el mantenimiento.
Arquitectura lógica estable. Diseñe e implemente el código en cada tarea, para que no sea necesario
cambiarlo, incluso si cambia el entorno físico en el que se ejecuta la tarea.
Problemas y consideraciones
Utilice este patrón para tareas que no sean rentables si se ejecutan en sus propias unidades
computacionales. Si una tarea pasa gran parte del tiempo inactiva, puede resultar costoso ejecutar
esa tarea en una unidad dedicada.
Este patrón podría no ser adecuado para las tareas que realizan operaciones tolerantes a errores críticas o
tareas que procesan datos altamente sensibles o privados y que requieren su propio contexto de seguridad.
Estas tareas se deben ejecutar en su propio entorno aislado, en una unidad computacional distinta.
Ejemplo
Si crea un servicio de cloud en Azure, es posible consolidar el procesamiento realizado por varias tareas en
un solo rol. Normalmente, se trata de un rol de trabajador que realiza tareas de procesamiento asincrónico
o en segundo plano.
En algunos casos, es posible incluir tareas de procesamiento asincrónico o en segundo plano en el rol
de la web. Esta técnica ayuda a reducir costes y a simplificar la implementación, aunque puede afectar a
la escalabilidad y la capacidad de respuesta de la interfaz pública proporcionada por el rol de la web. En
el artículo Combinación de varios roles de trabajador de Azure en un rol de web de Azure, se ofrece una
descripción detallada de la implementación de tareas de procesamiento asincrónico o en segundo plano
en un rol de web.
El rol es responsable de iniciar y detener las tareas. Cuando el controlador del tejido de Azure carga un rol,
produce el evento Start del rol. Se puede anular el método OnStart de la clase WebRole o WorkerRole para
manejar este evento, tal vez para inicializar los datos y otros recursos de los que dependen las tareas de
este método.
Cuando se completa OnStartmethod, el rol puede empezar a responder a las solicitudes. Encontrará más
información y guías sobre el uso de los métodos OnStart y Run en un rol en la sección Procesos de inicio
de aplicaciones en la guía de patrones y prácticas Traslado de aplicaciones al cloud.
Mantenga el código del método OnStart lo más conciso que sea posible. Azure no impone ningún límite
en el tiempo que tarda en completarse este método, pero el rol no podrá empezar a responder a las
solicitudes de red que recibe hasta que este método termine.
Cuando haya terminado el método OnStart, el rol ejecuta el método Run. En este punto, el controlador
de tejido puede empezar a enviar solicitudes al rol.
Coloque el código que crea las tareas en el método Run. Tenga en cuenta que el método Run define la
duración de la instancia del rol. Cuando este método finaliza, el controlador de tejido se encarga de que
el rol se cierre.
Cuando un rol se cierra o se recicla, el controlador de tejido impide que se reciban más solicitudes del
equilibrador de carga y provoca el evento Stop. Para capturar este evento, sobrescriba el método OnStop
del rol y realice la limpieza necesaria antes de que el rol termine.
Los métodos MyWorkerTask1 y MyWorkerTask2 muestran cómo realizar diferentes tareas en el mismo rol
de trabajador. El siguiente código muestra MyWorkerTask1. Es una tarea simple que está inactiva durante
30 segundos y luego produce un mensaje de rastreo Repite este proceso hasta que se cancela la tarea.
El código de MyWorkerTask2 es similar.
try
{
while (!ct.IsCancellationRequested)
{
// Wake up and do some background processing if not canceled.
// TASK PROCESSING CODE HERE
Trace.TraceInformation(“Doing Worker Task 1 Work”);
El código de ejemplo muestra una implementación común de un proceso en segundo plano. En una
aplicación real, puede seguir esta misma estructura, excepto en que deberá colocar su propia lógica
de procesamiento en el cuerpo del bucle que espera a la solicitud de cancelación.
/// <summary>
/// The cancellation token source use to cooperatively cancel running tasks
/// </summary>
private readonly CancellationTokenSource cts = new CancellationTokenSource();
/// <summary>
/// List of running tasks on the role instance
/// </summary>
private readonly List<Task> tasks = new List<Task>();
// If there wasn’t a cancellation request, stop all tasks and return from Run()
// An alternative to canceling and returning when a task exits would be to
// restart the task.
if (!cts.IsCancellationRequested)
{
Trace.TraceInformation(“Task returned without cancellation request”);
Stop(TimeSpan.FromMinutes(5));
}
}
...
En este ejemplo, el método Run espera a que se completen las tareas. Si se cancela una tarea,
el método Run presupone que el rol se está cerrando y espera a que las tareas restantes se cancelen
antes de terminar (espera un máximo de cinco minutos antes de terminar). Si una tarea falla debido
a una excepción prevista, el método Run cancela la tarea.
Se llama al método Stop, que se muestra en el siguiente código, cuando el controlador de tejido cierra
la instancia de rol (se invoca desde el método OnStop). El código detiene cada tarea sin problemas
cancelándola. Si alguna tarea tarda más de cinco minutos en completarse, el procesamiento de la
cancelación del método Stop deja de esperar y el rol finaliza.
// Stop running tasks and wait for tasks to complete before returning
// unless the timeout expires.
private void Stop(TimeSpan timeout)
{
Trace.TraceInformation(“Stop called. Canceling tasks.”);
// Cancel running tasks.
cts.Cancel();
// Wait for all the tasks to complete before returning. Note that the
// emulator currently allows 30 seconds and Azure allows five
// minutes for processing to complete.
try
{
Task.WaitAll(tasks.ToArray(), timeout);
}
catch (AggregateException ex)
{
Trace.TraceError(ex.Message);
Contexto y problema
La mayoría de las aplicaciones trabajan con datos. El enfoque típico es que la aplicación mantenga el
estado actual de los datos actualizándolos mientras los usuarios trabajan con ellos. Por ejemplo, en el
modelo tradicional de creación, lectura, actualización y eliminación (CRUD), uno de los procesos de datos
típicos es la lectura de datos del almacén, la realización de algunas modificaciones en él y la actualización
del estado actual de los datos con los nuevos valores, a menudo mediante el uso de transacciones que
bloquean los datos.
Para conocer en mayor profundidad los límites del enfoque CRUD, consulte CRUD: solo cuando pueda
permitírselo.
Solución
El patrón de abastecimiento de eventos define un enfoque del manejo de operaciones en datos que está
basado en una secuencia de eventos, cada uno de los cuales se registra en un almacén solo de anexos. El
código de la aplicación envía una serie de eventos que obligatoriamente describen cada acción que se ha
producido en los datos al almacén de eventos donde se conservan. Cada evento representa un conjunto
de cambios en los datos (como AddedItemToOrder).
Los eventos se conservan en un almacén de eventos que actúa como sistema de registro (la fuente de
datos autorizada) sobre el estado actual de los datos. Normalmente, el almacén de eventos publica estos
eventos para poder notificar a los consumidores y puede manejarlos si es necesario. Los consumidores, por
ejemplo, podrían iniciar las tareas que se aplican a las operaciones de los eventos en otros sistemas o realizar
cualquier otra acción asociada que sea necesaria para completar la operación. Observe que el código de la
aplicación que genera los eventos está desacoplado de los sistemas que se suscriben a los eventos.
Los usos habituales de los eventos que publica el almacén de eventos son mantener vistas materializadas
de entidades como acciones si la aplicación las cambia y para la integración con sistemas externos. Por
ejemplo, un sistema puede mantener una vista materializada de todos los pedidos de clientes que se
utiliza para rellenar las partes de la interfaz de usuario. A medida que la aplicación añade nuevos pedidos,
añade o elimina artículos del pedido y añade información de envío, los eventos que describen estos
cambios se pueden manejar y utilizar para actualizar la vista materializada.
La figura muestra información general del patrón e incluye algunas de las opciones para usar el flujo
de eventos, como crear una vista materializada, integrar eventos con sistemas y aplicaciones externas
y reproducir eventos para crear proyecciones del estado actual de entidades específicas.
Los eventos son objetos simples que describen una acción que se ha producido junto con los datos
asociados necesarios para describir la acción que representa el evento. Los eventos no actualizan
directamente un almacén de datos. Simplemente se registran para gestionarlos en el momento adecuado.
Esto puede simplificar la implementación y la administración.
Normalmente, los eventos tienen significado para un experto en el dominio, mientras que la falta de
correspondencia de la impedancia objeto-relacional puede hacer que las tablas de bases de datos
complejas sean difíciles de entender. Las tablas son construcciones artificiales que representan el estado
actual del sistema, no los eventos que se han producido.
El abastecimiento de eventos puede ayudar a evitar que las actualizaciones simultáneas causen conflictos,
porque evita la necesidad de actualizar directamente los objetos en el almacén de datos. Sin embargo, aún
hay que diseñar el modelo de dominio para protegerse de las solicitudes que podrían producir un estado
incoherente.
El almacén de eventos genera eventos y las tareas realizan operaciones en respuesta a esos eventos. Este
desacoplamiento de las tareas de los eventos ofrece flexibilidad y capacidad de ampliación. Las tareas
conocen el tipo de evento y los datos del evento, pero no la operación que ha activado el evento. Además,
cada evento puede gestionarlo varias tareas. Esto permite una integración sencilla con otros servicios
y sistemas que solo reciben los eventos nuevos que produce el almacén de eventos. Sin embargo, los
eventos de abastecimiento de eventos suelen ser de muy bajo nivel y podría ser necesario generar en
su lugar eventos de integración específicos.
Normalmente, el abastecimiento de eventos se combina con el patrón CQRS realizando las tareas de
administración de datos en respuesta a los eventos y materializando vistas desde los eventos almacenados.
Problemas y consideraciones
Tenga en cuenta los puntos siguientes a la hora de decidir cómo implementar este patrón:
El sistema solo tendrá coherencia final si se crean vistas materializadas o se generan proyecciones de
datos mediante la reproducción de eventos. Hay cierto retardo entre el momento en que una aplicación
añade eventos al almacén de eventos como resultado de la gestión de una solicitud, la publicación de los
eventos y el manejo de estos por parte de los consumidores. Durante este período, es posible que hayan
llegado al almacén de eventos nuevos eventos que describen otros cambios en las entidades.
Notas:
Consulte la Introducción a la coherencia de datos para obtener información acerca de coherencia final.
El almacén de eventos es la fuente permanente de información y, por lo tanto, los datos de eventos
no se deberían actualizar nunca. La única manera de actualizar una entidad para deshacer un cambio es
añadir un evento de compensación al almacén de eventos. Si necesita cambiar el formato (en lugar de
los datos) de los eventos persistentes, quizá durante una migración, puede ser difícil combinar los eventos
existentes del almacén con la nueva versión. Puede ser necesario recorrer en iteración todos los eventos
realizando cambios para que sean compatibles con el nuevo formato o añadir nuevos eventos que usen
el nuevo formato. Considere la posibilidad de usar de una marca de versión en cada versión del esquema
de eventos para mantener los formatos de eventos nuevos y antiguos.
Las aplicaciones multiproceso y las diversas instancias de aplicaciones podrían estar almacenando eventos
en el almacén de eventos. La coherencia de los eventos en el almacén de eventos es esencial, al igual que
el orden de los eventos que afecta a una entidad específica (el orden en que se producen los cambios en una
entidad afecta a su estado actual). Para evitar problemas, añada una marca de tiempo a cada evento. Otra
práctica común es comentar cada evento que se derive de una solicitud con un identificador incremental.
Si dos acciones intentan añadir eventos para la misma entidad al mismo tiempo, el almacén de eventos puede
rechazar un evento que coincida con un identificador de entidad existente y el identificador de eventos.
No hay ningún enfoque estándar ni existe ningún mecanismo, como las consultas SQL, para leer los
eventos para obtener información. Los únicos datos que se pueden extraer son un flujo de eventos
utilizando un identificador de eventos como criterio. Normalmente, el ID de evento se asigna a entidades
individuales. El estado actual de una entidad se puede determinar solamente mediante la reproducción
de todos los eventos que están relacionados con él con respecto al estado original de esa entidad.
La publicación del evento se podría realizar "al menos una vez" y, por tanto, los consumidores de los
eventos deben ser idempotentes. No debe volver a aplicar la actualización que se describe en un evento
si el evento se gestiona más de una vez. Por ejemplo, si varias instancias de un consumidor mantienen
una suma de la propiedad de una entidad, como el número total de pedidos realizados, solo una debe
conseguir incrementar esa suma cuando se produce un evento de realización de un pedido. Aunque esto
no es una característica clave del abastecimiento de eventos, es la decisión de implementación habitual.
●● Cuando desee registrar los eventos que se producen y poder reproducirlos para restablecer el estado
de un sistema, revertir los cambios o mantener un historial y una auditoría. Por ejemplo, cuando una
tarea consta de varios pasos, puede que necesite ejecutar acciones para revertir las actualizaciones
y luego repetir algunos pasos para devolver los datos a un estado coherente.
●● Cuando el uso de eventos sea una característica natural del funcionamiento de la aplicación y requiera
poco desarrollo adicional o esfuerzo de implementación.
●● Cuando sea necesario desacoplar el proceso de introducción o actualización de los datos de las tareas
necesarias para aplicar estas acciones. Esto podría realizarse para mejorar el rendimiento de la interfaz
de usuario o para distribuir eventos a otros agentes de escucha que actúan cuando se producen
eventos. Por ejemplo, se podría integrar un sistema de pago de nóminas en un sitio web de envío de
gastos, para que los eventos que produce el almacén de eventos en respuesta a las actualizaciones
de datos que se realizan en el sitio web los consuma tanto el sitio web como el sistema de pago de
nóminas.
●● Cuando se desea flexibilidad para poder cambiar el formato de los modelos materializados y los datos
de la entidad si los requisitos cambian o, cuando se utiliza en conjunción con CQRS, es necesario
adaptar un modelo de lectura o las vistas que exponen los datos.
●● Cuando se utiliza junto con CQRS, y la coherencia final es aceptable mientras se actualiza un modelo
de lectura, o el impacto en el rendimiento de la rehidratación de entidades y datos de un flujo de
eventos sea aceptable.
●● Sistemas donde se requiere coherencia y actualizaciones en tiempo real de las vistas de los datos.
●● Sistemas donde la aparición de actualizaciones conflictivas de los datos subyacentes es muy limitada.
Por ejemplo, sistemas que predominantemente añaden datos en lugar de actualizarlos.
Ejemplo
Un sistema de administración de conferencias debe realizar un seguimiento del número de reservas que
se han realizado para una conferencia para comprobar si aún quedan asientos cuando un posible asistente
trata de hacer una reserva. El sistema podría almacenar el número total de reservas para una conferencia
al menos de dos formas diferentes:
● El sistema podría almacenar la información sobre el número total de reservas como una entidad
separada en una base de datos que contiene información de reservas. A medida que se realizan o
cancelan reservas, el sistema podría incrementar o disminuir este número según sea necesario. Este
enfoque es sencillo en teoría, pero puede causar problemas de escalabilidad si hay un gran número
de asistentes intentando realizar reservas durante un breve período de tiempo. Por ejemplo, el último
día antes de que se cierre el período de reserva.
● El sistema podría almacenar información sobre las reservas y cancelaciones como eventos que se
mantienen en el almacén de eventos. Luego, podría calcular el número de asientos disponibles
reproduciendo estos eventos. Este enfoque puede ser más escalable debido a la inmutabilidad de
los eventos. El sistema solo debe ser capaz de leer datos del almacén de eventos o anexar datos al
almacén de eventos. La información de los eventos sobre reservas y cancelaciones no se modifica
nunca.
El siguiente diagrama muestra cómo se podría implementar el subsistema de reservas de entradas del
sistema de administración de conferencias usando el abastecimiento de eventos.
2. Se construye una suma que contiene información sobre todas las reservas de la conferencia
consultando los eventos que describen las reservas y las cancelaciones. Esta suma se llama
SeatAvailability y está dentro de un modelo de dominio que expone métodos para consultar
y modificar los datos en la suma.
Algunas de las optimizaciones cuyo uso debe considerarse son el uso de instantáneas (para que no
sea necesario consultar y reproducir la lista completa de eventos para obtener el estado actual de la
suma) y el mantenimiento de una copia en caché de la suma en memoria.
3. El controlador de comandos invoca un método que expone el modelo de dominio para realizar las
reservas.
4. La suma SeatAvailability registra un evento que contiene el número de entradas que se han reservado.
La próxima vez que la suma aplique eventos, todas las reservas se utilizarán para calcular cuántas
entradas quedan.
Además de ampliar el ámbito para mejorar la escalabilidad, el uso de un almacén de eventos proporciona
también un historial completo, o una auditoría, de las reservas y cancelaciones de una conferencia. Los
eventos del almacén de eventos son el registro exacto. No hay necesidad de que las sumas se conserven
de otra manera porque el sistema puede reproducir fácilmente los eventos y restablecer el estado en
cualquier punto en el tiempo.
●● Guía de partición de datos. Con frecuencia, los datos se particionan cuando se utiliza el abastecimiento
de eventos para mejorar la escalabilidad, reducir la contención y optimizar el rendimiento. Describe
cómo dividir los datos en particiones discretas y los problemas que pueden surgir.
Contexto y problema
La mayoría de los entornos de tiempo de ejecución de las aplicaciones incluyen información de
configuración que está contenida en archivos implementados con la aplicación. En algunos casos, es posible
editar estos archivos para cambiar el comportamiento de la aplicación después de que se ha implementado.
Es difícil administrar los cambios en las configuraciones locales en varias instancias en ejecución de la
aplicación, especialmente si están alojadas en el cloud. La consecuencia puede ser que las instancias
utilicen diferentes ajustes de la configuración mientras se está implementando la actualización.
Además, las actualizaciones de las aplicaciones y los componentes pueden requerir cambios en los
esquemas de configuración. Muchos sistemas de configuración no admiten diferentes versiones de
la información de configuración.
Solución
Almacene la información de configuración en un almacenamiento externo y proporcione una interfaz
que pueda utilizarse de una forma rápida y eficaz para leer y actualizar los ajustes de la configuración.
El tipo de almacén externo depende del hosting y el entorno de tiempo de ejecución de la aplicación.
En un hosting de cloud, normalmente se trata de un servicio de almacenamiento basado en cloud, pero
podría ser una base de datos alojada u otro sistema.
El almacén de respaldo que elija para la información de configuración debe tener una interfaz que
proporcione un acceso constante y sencillo. Debe exponer la información en un formato estructurado
y escrito correctamente. Es posible que la implementación también tenga que autorizar el acceso de los
usuarios con el fin de proteger los datos de configuración y ser lo suficientemente flexible como para
permitir el almacenamiento de varias versiones de la configuración (por ejemplo, desarrollo, prueba o
producción, incluyendo las diversas versiones de cada una).
Muchos sistemas de configuración integrados leen los datos cuando se inicia la aplicación y almacenan en
caché los datos en memoria para proporcionar un acceso rápido y minimizar el impacto en el rendimiento
de la aplicación. Dependiendo del tipo de almacén de respaldo que se utilice y la latencia de este almacén,
podría ser útil implementar un mecanismo de almacenamiento en caché en el almacén de configuración
externo. Para obtener más información, consulte la Guía de almacenamiento en caché. La figura muestra
información general del patrón de almacén de configuración externa con una memoria caché local
opcional.
Tenga en cuenta los puntos siguientes a la hora de decidir cómo implementar este patrón:
Elija un almacén de respaldo que ofrezca un rendimiento aceptable, alta disponibilidad y robustez
y del que, además, se pueda realizar una copia de seguridad como parte del proceso de mantenimiento
y administración de las aplicaciones. En una aplicación alojada en cloud, una buena opción es utilizar
un mecanismo de almacenamiento en cloud para satisfacer estos requisitos.
Diseñe el esquema del almacén de respaldo para permitir flexibilidad en los tipos de información que
puede contener. Asegúrese de que permite cumplir todos los requisitos de configuración, tales como
datos con tipo, recopilaciones de ajustes, varias versiones de ajustes y cualquier otra característica que
necesiten las aplicaciones que los utilizan. El esquema debería ser fácil de extender para permitir ajustes
adicionales a medida que cambian los requisitos.
Piense en las capacidades físicas del almacén de respaldo, cómo se relaciona con la forma en que
se almacena la información de la configuración y los efectos sobre el rendimiento. Por ejemplo, para
guardar un documento XML que contiene información de configuración, será necesario que la interfaz
de configuración o la aplicación analicen el documento con el fin de leer los ajustes individuales. Hará
que sea más difícil actualizar un ajuste, aunque el almacenamiento en caché de los ajustes puede ayudar
a compensar el menor rendimiento de lectura.
Piense en cómo la interfaz de configuración permitirá controlar el ámbito y la herencia de los ajustes de la
configuración. Por ejemplo, podría ser un requisito determinar el ámbito de los ajustes de la configuración al
nivel de la organización, la aplicación y la máquina. Podría ser necesario permitir la delegación del control de
acceso a diferentes ámbitos e impedir o permitir que aplicaciones individuales anulen los ajustes.
Asegúrese de que la interfaz de configuración puede exponer los datos de configuración en los formatos
requeridos como valores con tipo, recopilaciones, pares clave/valor o bolsas de propiedades.
Piense en cómo se comportará la interfaz del almacén de configuración cuando los ajustes contengan
errores o no existan en el almacén de respaldo. Podría ser adecuado devolver los ajustes predeterminados
y registrar los errores. También debe pensar en otros aspectos, como la detección de mayúsculas y
minúsculas en las claves o nombres de la configuración, el almacenamiento y manejo de datos binarios
y las formas en que se manejan valores nulos o vacíos.
Piense en cómo proteger los datos de configuración para permitir el acceso solo a los usuarios y
las aplicaciones apropiados. Probablemente, esta es una característica de la interfaz del almacén de
configuración, pero también es necesario asegurarse de que no se pueda acceder directamente a los datos
del almacén de respaldo sin el permiso correspondiente. Asegúrese de que haya una separación estricta
entre los permisos necesarios para leer y escribir datos de configuración. Piense también si necesita cifrar
todos o algunos de los ajustes de la configuración y cómo se implementará esto en la interfaz del almacén
de configuración.
Si una aplicación almacena en caché la información de configuración, hay que avisar a la aplicación si
cambia la configuración. Podría ser posible implementar una política de caducidad en los datos de la
configuración almacenados en caché para que esta información se actualice automáticamente de manera
periódica y se recojan todos los cambios (además de realizar las acciones correspondientes).
●● Los ajustes de configuración que se comparten entre varias aplicaciones e instancias de aplicación
o si hay que aplicar una configuración estándar en varias aplicaciones e instancias de aplicación.
●● Un sistema de configuración estándar que no es compatible con todos los ajustes de la configuración
requeridos, como almacenar imágenes o tipos de datos complejos.
●● Como un almacén complementario para algunos ajustes de las aplicaciones, tal vez para permitir que
las aplicaciones anulen algunos o todos los ajustes almacenados centralmente.
Ejemplo
En una aplicación alojada de Microsoft Azure, una opción típica para almacenar información de
configuración de manera externa es utilizar el almacenamiento de Azure. Es resistente, ofrece alto
rendimiento y se replica tres veces con conmutación por error automático para ofrecer alta disponibilidad.
El almacenamiento de tablas de Azure proporciona un almacén de clave/valor con la capacidad de utilizar
un esquema flexible para los valores. El almacenamiento de blobs de Azure proporciona un almacén
jerárquico basado en contenedores que puede contener cualquier tipo de datos en blobs con nombres
individuales.
Esta interfaz define métodos para recuperar y actualizar los ajustes de configuración que se guardan en el
almacén de configuración e incluye un número de versión que se puede utilizar para detectar si los ajustes
de configuración se han modificado recientemente. La clase BlobSettingsStore utiliza la propiedad ETag
del blob para implementar el control de versiones. La propiedad de ETag se actualiza automáticamente
cada vez que se escribe el blob.
Por su diseño, esta sencilla solución expone todos los ajustes de configuración como valores de cadena
en lugar de valores con tipo.
El siguiente código de ejemplo muestra cómo se implementa el evento Changed, el método GetSettings
y el método CheckForConfigurationChanges:
string value;
try
{
this.settingsCacheLock.EnterReadLock();
return value;
}
...
private void CheckForConfigurationChanges()
{
try
{
// It is assumed that updates are infrequent.
// If the versions are the same, nothing has changed in the configuration.
if (this.currentVersion == latestVersion) return;
// Get the latest settings from the settings store and publish changes.
var latestSettings = await this.settings.FindAllAsync();
if (this.settingsCache != null)
{
//Notify settings changed
latestSettings.Except(this.settingsCache).ToList().ForEach(kv => this.changed.
OnNext(kv));
}
this.settingsCache = latestSettings;
}
finally
{
this.settingsCacheLock.ExitWriteLock();
}
/// <summary>
/// Start the background monitoring for configuration changes in the central store
/// </summary>
public void StartMonitor()
{
if (this.IsMonitoring)
return;
try
{
this.timerSemaphore.Wait();
/// <summary>
/// Loop that monitors for configuration changes
/// </summary>
/// <returns></returns>
public async Task ConfigChangeMonitor()
{
while (!cts.Token.IsCancellationRequested)
{
/// <summary>
/// Stop monitoring for configuration changes
/// </summary>
public void StopMonitor()
{
try
{
this.timerSemaphore.Wait();
this.monitoringTask = null;
}
finally
{
this.timerSemaphore.Release();
}
}
// Get a setting.
var setting = ExternalConfiguration.Instance.GetAppSetting(“setting1”);
Trace.TraceInformation(“Worker Role: Get setting1, value: “ + setting);
this.completeEvent.WaitOne();
}
El código siguiente, también de la clase WorkerRole, muestra cómo la aplicación se suscribe a los eventos
de configuración.
Contexto y problema
Normalmente, los usuarios necesitan trabajar con varias aplicaciones que proporcionan y alojan diferentes
organizaciones con las que tienen relaciones comerciales. Estos usuarios podrían tener que utilizar
credenciales específicas (y diferentes) para cada una. Esto puede:
●● Provocar una experiencia de usuario inconexa. Los usuarios suelen olvidarse de las credenciales
de inicio de sesión cuando tienen muchas diferentes.
Normalmente, los usuarios prefieren utilizar las mismas credenciales para todas estas aplicaciones.
La figura muestra el patrón de identidad federada que se utiliza cuando una aplicación cliente necesita
acceder a un servicio que requiere autenticación. La autenticación se realiza por medio de un IdP que
trabaja en colaboración con un STS. El IdP emite tokens de seguridad que proporcionan información sobre
el usuario autenticado. Esta información, denominada notificaciones, incluye la identidad del usuario y
también puede incluir otra información, como la pertenencia a roles y derechos de acceso más detallados.
Este modelo suele denominarse control de acceso basado en notificaciones. Las aplicaciones y los
servicios autorizan el acceso a características y funcionalidades basadas en las notificaciones contenidas
en el token. El servicio que requiere autenticación debe confiar en el IdP. La aplicación cliente entra en
contacto con el IdP que realiza la autenticación. Si la autenticación es correcta, el IdP devuelve un token
que contiene las notificaciones que identifican al usuario de STS (tenga en cuenta que el IdP y STS puede
ser el mismo servicio). El STS puede transformar y aumentar las notificaciones en el token en función de
reglas predefinidas antes de devolvérselo al cliente. Luego, la aplicación cliente puede pasar el token al
servicio como prueba de su identidad.
Puede haber STS adicionales en la cadena de confianza. Por ejemplo, en el escenario que se describe más
adelante, un STS local confía en otro STS que se encarga de acceder a un proveedor de identidades para
autenticar al usuario. Este enfoque es común en escenarios de empresa donde hay un directorio y STS local.
La identidad federada también tiene la gran ventaja de que la administración de la identidad y las
credenciales es responsabilidad del proveedor de identidades. La aplicación o el servicio no necesitan
proporcionar funciones de administración de identidades. Asimismo, en escenarios corporativos, el directorio
corporativo no tiene que conocer al usuario si confía en el proveedor de identidades. Esto elimina toda la
sobrecarga administrativa que supone tener que administrar la identidad del usuario en el directorio.
Problemas y consideraciones
Tenga en cuenta lo siguiente a la hora de diseñar aplicaciones que implementen la autenticación federada:
●● La autenticación puede ser un único punto de error. Si implementa la aplicación en varios centros de
datos, piense en la posibilidad de implementar su mecanismo de administración de identidades en los
mismos centros de datos para mantener la disponibilidad y la fiabilidad de la aplicación.
●● Las herramientas de autenticación hacen posible configurar el control de acceso en función de las
notificaciones de roles que contiene el token de autenticación. Esto suele denominarse control de
acceso basado en roles (RBAC) y puede permitir un nivel de control más detallado del acceso a
recursos y características.
●● Si hay configurado más de un proveedor de identidades para el STS, debe detectar a qué proveedor
de identidades se debería redirigir al usuario para la autenticación. Este proceso se denomina
detección del dominio de inicio. El STS podría ser capaz de hacer esto automáticamente basándose en
una dirección de correo electrónico o nombre de usuario que proporciona el usuario, un subdominio
de la aplicación al que está accediendo el usuario, el ámbito de la dirección IP del usuario o en el
contenido de una cookie almacenada en el navegador del usuario. Por ejemplo, si el usuario introduce
una dirección de correo electrónico en el dominio de Microsoft, como usuario@live.com, el STS
redirigirá al usuario a la página de inicio de sesión de la cuenta de Microsoft. En visitas posteriores, el
STS podría utilizar una cookie para indicar que el último inicio de sesión se realizó con una cuenta de
Microsoft. Si la detección automática no puede determinar el dominio de inicio, el STS mostrará una
página de detección del dominio de inicio que incluye a los proveedores de identidades de confianza
y el usuario debe seleccionar el que desea utilizar.
●● Identidad federada con múltiples socios. En este caso, es necesario autenticar a empleados
corporativos y socios de negocio que no tienen cuentas en el directorio corporativo. Esto es común
en aplicaciones de negocio a negocio, aplicaciones que se integran con servicios de terceros y donde
se han combinado empresas con diferentes sistemas de TI o recursos compartidos.
●● Identidad federada en aplicaciones SaaS. En este caso, los proveedores de software independientes
proporcionan un servicio listo para su uso para varios clientes o inquilinos. Cada inquilino se autentica
utilizando un proveedor de identidades adecuado. Por ejemplo, los usuarios de negocios usan
sus credenciales corporativas, mientras que los consumidores y clientes del inquilino utilizarán sus
credenciales de identidad social.
Ejemplo
Una organización aloja una aplicación multiempresa de software como servicio (SaaS) en Microsoft
Azure. La aplicación incluye un sitio web que los inquilinos pueden usar para administrar la aplicación
de sus propios usuarios. La aplicación permite a los inquilinos acceder al sitio web mediante el uso
de una identidad federada que generan los Servicios de federación de Active Directory (ADFS) cuando
el propio Active Directory de la organización autentica al usuario.
Los inquilinos no necesitan recordar credenciales distintas para acceder a la aplicación y un administrador
de la empresa del inquilino puede configurar la lista de usuarios que pueden acceder a la aplicación en su
propio ADFS.
Orientación relacionada
●● Microsoft Azure Active Directory
●● Servicios de dominio Active Directory
●● Servicios de federación de Active Directory
●● Administración de identidades para aplicaciones multiempresa en Microsoft Azure
●● Aplicaciones multiempresa en Azure
Patrón de gatekeeper
Protege las aplicaciones y servicios mediante el uso de una instancia de host dedicada que actúa
como intermediaria entre los clientes y la aplicación o el servicio, valida y verifica las solicitudes y envía
solicitudes y datos entre ellos. Puede proporcionar una capa adicional de seguridad y limitar la superficie
de ataque del sistema.
Contexto y problema
Las aplicaciones exponen su funcionalidad a los clientes aceptando y procesando solicitudes. En escenarios
alojados en cloud, las aplicaciones exponen los puntos de conexión a los que se conectan los clientes
y suelen incluir el código para manejar las solicitudes de los clientes. Este código realiza la autenticación
y la validación, parte del procesamiento las solicitudes, o incluso todo, y es probable que acceda al
almacenamiento y otros servicios en nombre del cliente.
Solución
Para minimizar el riesgo de que los clientes accedan a información sensible y servicios, desacople los hosts
o las tareas que expongan puntos de conexión públicos del código que procesa solicitudes y tiene acceso
al almacenamiento. Para ello, use una fachada o una tarea dedicada que interactúe con los clientes y luego
entregue la solicitud, quizás a través de una interfaz desacoplada, a los hosts o tareas que la gestionan.
La figura ofrece información general de este patrón.
●● Validación controlada. El gatekeeper valida todas las solicitudes y rechaza las que no cumplen los
requisitos de validación.
●● Exposición y riesgo limitados. El gatekeeper no tiene acceso a las credenciales o claves utilizadas por
el host de confianza para acceder al almacenamiento y los servicios. Si se compromete el gatekeeper,
el atacante no accede a estas credenciales o claves.
Este patrón actúa como un firewall en una topografía de red típica. Permite al gatekeeper examinar las
solicitudes y tomar una decisión sobre si pasar la solicitud al host de confianza (a veces denominado
maestro de claves) que realiza las tareas requeridas. Normalmente, esta decisión requiere que el
gatekeeper valide y sanee el contenido de la solicitud antes de pasarla al host de confianza.
Problemas y consideraciones
Tenga en cuenta los puntos siguientes a la hora de decidir cómo implementar este patrón:
●● Asegúrese de que los hosts de confianza que pasa el gatekeeper solicitan que solo se expongan
puntos de conexión internos o protegidos y se conectan solo con el gatekeeper. Los hosts de
confianza no deberían exponer interfaces ni puntos de conexión externos.
●● El gatekeeper debe ejecutarse en un modo de privilegios limitados. Normalmente, esto significa que
el gatekeeper y el host de confianza se ejecutan en servicios alojados o máquinas virtuales separados.
●● El gatekeeper no debe realizar ningún procesamiento relacionado con las aplicaciones o servicios ni
acceder a los datos. Su función es simplemente validar y sanear las solicitudes. Puede que los hosts de
confianza tengan que realizar una validación adicional de las solicitudes, pero la validación principal
debe realizarla el gatekeeper.
●● Utilice un canal de comunicación segura (HTTPS, SSL o TLS) entre el gatekeeper y los hosts de
confianza o las tareas donde esto es posible. Sin embargo, algunos entornos de hosting no admiten
HTTPS en puntos de conexión internos.
Es probable que la adición de una capa adicional a la aplicación para implementar el patrón
del gatekeeper tenga algún impacto en el rendimiento debido al procesamiento adicional y la
comunicación de red que requiere.
●● Aplicaciones distribuidas donde es necesario realizar la validación de solicitudes por separado de las
tareas principales o centralizar esta validación para simplificar la administración y el mantenimiento.
Ejemplo
En un escenario alojado en el cloud, este patrón se puede implementar desacoplando el gatekeeper o la
máquina virtual de los roles y servicios de confianza de una aplicación. Para ello, se utiliza un punto de
conexión interno, una cola o almacenamiento como un mecanismo de comunicación intermedio La figura
ilustra el uso de un punto de conexión interno.
Patrones relacionados
El patrón de clave auxiliar también podría ser importante al implementar el patrón de gatekeeper. Al
comunicarse entre el gatekeeper y los roles de confianza, es una buena práctica mejorar la seguridad
mediante el uso de claves o tokens que limitan los permisos para acceder a los recursos.
En el diagrama siguiente, el cliente envía solicitudes a cada servicio (1,2,3). Cada servicio procesa
la solicitud y envía la respuesta de nuevo a la aplicación (4,5,6). En una red móvil con una latencia
normalmente alta, es ineficaz utilizar las solicitudes individuales de esta manera y se podría interrumpir
la conectividad o derivarse en solicitudes incompletas. Aunque que es posible realizar cada solicitud en
paralelo, la aplicación debe enviar, esperar y procesar los datos para cada solicitud, y todo en conexiones
independientes, lo que aumenta la posibilidad de que falle.
Solución
Use una puerta de enlace para reducir la locuacidad entre el cliente y los servicios. La puerta de enlace
recibe solicitudes de los clientes, envía solicitudes a los diferentes sistemas de back-end y luego agrupa
los resultados y se los devuelve al cliente solicitante.
Este patrón puede reducir el número de solicitudes que realiza la aplicación a los servicios de back-end
y mejorar el rendimiento de la aplicación en redes de alta latencia.
En el siguiente diagrama, la aplicación envía una solicitud a la puerta de enlace (1). La solicitud contiene
un paquete de solicitudes adicionales. La puerta de enlace los descompone y procesa cada solicitud
enviándola al servicio correspondiente (2). Cada servicio devuelve una respuesta a la puerta de enlace (3).
La puerta de enlace combina las respuestas de cada servicio y envía la respuesta a la aplicación (4).
La aplicación realiza una sola solicitud y recibe una única respuesta de la puerta de enlace.
●● La puerta de enlace debe ubicarse cerca de los servicios de back-end para reducir la latencia todo
lo posible.
●● El servicio de puerta de enlace puede introducir un único punto de fallo. Asegúrese de que la puerta
de enlace está diseñada correctamente para satisfacer los requisitos de disponibilidad de la aplicación.
La puerta de enlace puede presentar un cuello de botella. Asegúrese de que la puerta de enlace tiene un
rendimiento suficiente para manejar la carga y puede escalarse para adaptarse al crecimiento esperado.
●● Realice pruebas de carga en la puerta de enlace para asegurarse de que no se introducen errores
en cascada de los servicios.
●● Si una o más llamadas al servicio tardan demasiado, puede ser aceptable que se agote el tiempo
de espera y se devuelva un conjunto parcial de datos. Piense cómo manejará esta situación la aplicación.
●● Utilice una E/S asincrónica para asegurarse de que un retardo en el back-end no causa problemas de
rendimiento en la aplicación.
●● Considere la posibilidad de devolver datos en caché como una estrategia de conmutación por error
para manejar errores.
●● Desea reducir el número de llamadas entre un cliente y un servicio único en varias operaciones.
En esa situación, sería mejor añadir una operación por lotes al servicio.
Ejemplo
En el ejemplo siguiente, se muestra cómo crear un servicio NGINX de agregación de puerta de enlace
sencillo con Lua.
worker_processes 4;
events {
worker_connections 1024;
}
http {
server {
listen 80;
location = /batch {
content_by_lua ‘
ngx.req.read_body()
ngx.say(cjson.encode({results = results}))
‘;
}
location = /service1 {
default_type application/json;
echo ‘{“attr1”:”val1”}’;
}
location = /service2 {
default_type application/json;
echo ‘{“attr2”:”val2”}’;
}
}
}
Contexto y problema
Algunas características suelen utilizarse en varios servicios y requieren configuración, administración
y mantenimiento. Un servicio compartido o especializado que se distribuye con cada implementación
de la aplicación aumenta la sobrecarga administrativa y la probabilidad de que se produzca un error
de implementación. Las actualizaciones de una característica compartida se deben implementar en todos
los servicios que comparten esa característica.
Para gestionar adecuadamente los problemas de seguridad (validación de tokens, cifrado, administración
de certificados SSL) y otras tareas complejas, es posible que los miembros del equipo deban tener
habilidades enormemente especializadas. Por ejemplo, un certificado que necesita una aplicación se debe
configurar e implementar en todas las instancias de la aplicación. Con cada nueva implementación, hay
que administrar el certificado para que no caduque. Cualquier certificado común que caduque se debe
actualizar, probar y verificar en cada implementación de la aplicación.
Solución
Descargue algunas de las características en una puerta de enlace API, particularmente las cuestiones de
transversalidad como la administración de certificados, la autenticación, la terminación SSL, la supervisión,
la conversión de protocolos o la limitación. Descargue algunas de las características en una puerta de
enlace API, particularmente las cuestiones de transversalidad como la administración de certificados,
la autenticación, la terminación SSL, la supervisión, la conversión de protocolos o la limitación.
El siguiente diagrama muestra una puerta de enlace API que termina las conexiones SSL entrantes.
Solicita datos en nombre del solicitante original desde cualquier servidor HTTP ascendente de la puerta
de enlace API.
Problemas y consideraciones
●● Asegúrese de que la puerta de enlace API es altamente disponible y resistente a los errores. Evite
puntos únicos de error ejecutando varias instancias de su puerta de enlace API.
●● Asegúrese de que la puerta de enlace está diseñada para los requisitos de capacidad y escalado de
su aplicación y puntos de conexión. Asegúrese de que la puerta de enlace no se convierte en un
cuello de botella para la aplicación y es lo suficientemente escalable.
●● Solo descargue las características que utiliza toda la aplicación, tales como la transferencia de datos
o la seguridad.
●● Haya una característica común en las implementaciones de aplicaciones que pueden tener diferentes
requisitos de recursos, como recursos de memoria, capacidad de almacenamiento o conexiones de red.
Ejemplo
La siguiente configuración, en la que se utiliza Nginx como dispositivo de descarga SSL, termina una
conexión SSL entrante y distribuye la conexión a uno de tres servidores HTTP ascendentes.
upstream iis {
server 10.3.0.10 max_fails=3 fail_timeout=15s;
server 10.3.0.20 max_fails=3 fail_timeout=15s;
server 10.3.0.30 max_fails=3 fail_timeout=15s;
}
server {
listen 443;
ssl on;
ssl_certificate /etc/nginx/ssl/domain.cer;
ssl_certificate_key /etc/nginx/ssl/domain.key;
location / {
set $targ iis;
proxy_pass http://$targ;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
}
}
Orientación relacionada
●● Patrón Back-ends for Front-ends
●● Patrón de agregación de puerta de enlace
●● Patrón de enrutamiento de puerta de enlace
Contexto y problema
Cuando un cliente necesita consumir varios servicios, puede ser difícil establecer un punto de conexión
separado para cada servicio y que el cliente administre cada punto de conexión. Por ejemplo, una
aplicación de comercio electrónico podría proporcionar servicios de búsqueda, comentarios, cesta de la
compra, pago e historial de pedidos. Cada servicio tiene una API diferente con la que debe interactuar el
cliente y el cliente debe conocer cada punto de conexión para conectarse a los servicios. Si se modifica o
actualiza, el cliente debe actualizarse también. Si refactoriza un servicio en dos o más servicios distintos,
debe cambiar el código en el servicio y el cliente.
Con este patrón, la aplicación cliente solo necesita conocer un solo punto de conexión y comunicarse
con él. Si un servicio está consolidado o descompuesto, el cliente no requiere necesariamente una
actualización. Puede seguir realizando solicitudes a la puerta de enlace y solo cambia el enrutamiento.
Una puerta de enlace también permite resumir los servicios de back-end de los clientes, lo que le permite
que las llamadas de cliente sean sencillas y, al mismo tiempo, permite cambios en los servicios de back-end
detrás de la puerta de enlace. Las llamadas de cliente se pueden enrutar a cualquier servicio o servicios
que se necesiten para manejar el comportamiento esperado del cliente, lo que le permite añadir, dividir
y reorganizar los servicios detrás de la puerta de enlace sin cambiar el cliente.
Este patrón también puede ayudar con la implementación, permitiéndole administrar la forma en que se
despliegan las actualizaciones para los usuarios. Cuando se implementa una nueva versión de su servicio,
puede hacerse en paralelo con la versión existente. El enrutamiento le permite controlar qué versión del
servicio se presenta a los clientes, lo que le da la flexibilidad de utilizar diversas estrategias de publicación,
ya sean incrementales, en paralelo o implementaciones completas de actualizaciones. Cualquier problema
que se descubra después de que se implemente el nuevo servicio se puede revertir rápidamente
realizando un cambio de configuración en la puerta de enlace, sin que eso afecte a los clientes.
Problemas y consideraciones
●● El servicio de puerta de enlace puede introducir un único punto de fallo. Asegúrese de que está
diseñado correctamente para satisfacer sus requisitos de disponibilidad. A la hora de realizar la
implementación, tenga en cuenta las capacidades de resistencia y tolerancia a fallos.
●● El servicio de puerta de enlace puede presentar un cuello de botella. Asegúrese de que la puerta de
enlace tenga un rendimiento suficiente para manejar la carga y pueda escalarse fácilmente conforme
a sus expectativas de crecimiento.
●● Necesita enrutar solicitudes desde puntos de conexión con direcciones externas a puntos de conexión
virtuales internos, como los puertos que se exponen en una máquina virtual para agrupar en un
clúster las direcciones IP virtuales.
Puede que este patrón no sea adecuado cuando se tiene una aplicación sencilla que utiliza solamente
uno o dos servicios.
Ejemplo
El siguiente archivo de configuración, en el que se utiliza Nginx como enrutador, es un ejemplo de un
archivo de configuración sencillo en el que un servidor enruta solicitudes para aplicaciones que residen
en diferentes directorios virtuales para diferentes máquinas en el back-end.
server {
listen 80;
server_name domain.com;
location /app1 {
proxy_pass http://10.0.3.10:80;
}
location /app2 {
proxy_pass http://10.0.3.20:80;
}
location /app3 {
proxy_pass http://10.0.3.30:80;
}
}
Orientación relacionada
●● Patrón Back-ends for Front-ends
●● Patrón de agregación de puerta de enlace
●● Patrón de descarga de puerta de enlace
Contexto y problema
Es una buena práctica y, a menudo, un requisito empresarial, supervisar las aplicaciones web y servicios de
back-end para asegurarse de que están disponibles y funcionan correctamente. Sin embargo, es más difícil
supervisar los servicios que se ejecutan en el cloud que supervisar los servicios locales. Por ejemplo, no se
tiene control completo del entorno de hosting y, normalmente, los servicios dependen de otros servicios
proporcionados por proveedores de plataformas y terceros.
Hay muchos factores que afectan a las aplicaciones alojadas en cloud, como la latencia de red, el rendimiento
y la disponibilidad de los sistemas informáticos y de almacenamiento subyacentes y el ancho de banda de
red entre ellos. El servicio puede fallar completa o parcialmente por cualquiera de estos factores. Por lo tanto,
se debe verificar a intervalos regulares que el servicio esté funcionando correctamente para garantizar el
necesario nivel de disponibilidad, que puede formar parte de su acuerdo de nivel de servicio (SLA).
Solución
Implemente la supervisión del estado mediante el envío de solicitudes a un punto de conexión en la
aplicación. La aplicación debe realizar las comprobaciones necesarias y devolver una indicación de su estado.
●● Las comprobaciones (si hay alguna) que realiza la aplicación o servicio en respuesta a la solicitud
al punto de conexión de la verificación de estado.
●● Comprobación de otros recursos o servicios situados en la aplicación o en otro lugar, pero que utiliza
la aplicación.
Hay disponibles servicios y herramientas que supervisan aplicaciones web enviando una solicitud a un
conjunto de puntos de conexión configurables y evaluando los resultados con respecto a un conjunto
de reglas configurables. Es relativamente sencillo crear un punto de conexión de servicio cuyo único
propósito sea llevar a cabo algunas pruebas funcionales en el sistema.
Comprobaciones típicas que se pueden realizar por medio de las herramientas de supervisión:
●● Validación del código de respuesta. Por ejemplo, una respuesta HTTP 200 (OK) indica que la aplicación
respondió sin errores. El sistema de supervisión también puede comprobar otros códigos de respuesta
para obtener resultados más completos.
●● Comprobación del contenido de la respuesta para detectar errores, incluso cuando se devuelve un
código de estado 200 (OK). De esta forma, se pueden detectar errores que solo afectan a una sección
de la página web devuelta o la respuesta al servicio. Por ejemplo, la comprobación del título de una
página o la búsqueda de una frase específica que indica que se ha devuelto la página correcta.
●● Medición del tiempo de respuesta, que indica una combinación de la latencia de red y el tiempo que
ha tardado la aplicación en ejecutar la solicitud. Un valor en aumento puede indicar un problema
emergente con la aplicación o la red.
●● Comprobación de recursos o servicios ubicados fuera de la aplicación, como una red de distribución
de contenido que utiliza la aplicación para entregar contenido desde cachés globales.
●● Medición del tiempo de respuesta de una búsqueda de DNS para la dirección URL de la aplicación
con el fin de medir la latencia de DNS y los fallos de DNS.
●● Validación de la dirección URL que devuelve la consulta DNS para garantizar entradas correctas. Esto
puede ayudar a evitar el redireccionamiento malintencionado de solicitudes por medio de un ataque
en el servidor DNS.
También es útil, siempre que sea posible, realizar estas comprobaciones desde diferentes ubicaciones
locales o alojadas para medir y comparar los tiempos de respuesta. Idealmente, debería supervisar
las aplicaciones desde ubicaciones que estén cerca de los clientes para obtener una visión precisa
del rendimiento de cada ubicación. Además de proporcionar un mecanismo de comprobación más
robusto, los resultados pueden ayudarle a decidir la ubicación de implementación de la aplicación
y si se implementa en más de un centro de datos.
También se deben realizar pruebas en todas las instancias de servicio que utilizan los clientes para
asegurarse de que la aplicación está funcionando correctamente para todos los clientes. Por ejemplo,
si el almacenamiento de cliente se extiende a más de una cuenta de almacenamiento, el proceso de
supervisión debería comprobar todo esto.
Problemas y consideraciones
Tenga en cuenta los puntos siguientes a la hora de decidir cómo implementar este patrón:
Cómo validar la respuesta. Por ejemplo, ¿un único código de estado 200 (OK) es suficiente para verificar
si la aplicación está funcionando correctamente? Aunque esto sirve de medida básica de la disponibilidad
de las aplicaciones y es la implementación mínima de este patrón, proporciona poca información sobre las
operaciones, tendencias y posibles problemas futuros en la aplicación.
El número de puntos de conexión que se van a exponer para una aplicación. Un enfoque consiste en
exponer al menos un punto de conexión para los servicios fundamentales usados por la aplicación y otro
para servicios de menor prioridad, permitiendo la asignación de distintos niveles de importancia a cada
resultado de supervisión. Considere también la posibilidad de exponer más puntos de conexión, por
ejemplo, uno para cada servicio fundamental, a fin de obtener granularidad de supervisión adicional. Por
ejemplo, una comprobación de verificación de estado podría analizar la base de datos, el almacenamiento
y un servicio de geocodificación externo que usa una aplicación, requiriendo todo ello un nivel distinto
de tiempo de actividad y de respuesta. La aplicación podría seguir en buen estado si el servicio de
geocodificación o alguna otra tarea en segundo plano no está disponible durante unos minutos.
Si se usa el mismo punto de conexión para la supervisión de la misma forma que para el acceso general,
pero en una ruta de acceso específica diseñada para las comprobaciones de verificación de estado,
por ejemplo, /HealthCheck/{GUID}/ en el punto de conexión de acceso general. Esto permite que las
herramientas de supervisión ejecuten algunas pruebas funcionales de la aplicación, como agregar un
registro de nuevo usuario, iniciar sesión y hacer un pedido de prueba, comprobando también que el punto
de conexión de acceso general está disponible.
Almacenamiento en caché del estado del punto de conexión. Podría resultar caro ejecutar la
comprobación de estado con demasiada frecuencia. Si se informa del estado de mantenimiento a través
de un panel, por ejemplo, no quiere que cada solicitud del panel desencadene una comprobación de
estado. En su lugar, compruebe de forma periódica el estado del sistema y almacénelo en caché. Exponga
un punto de conexión que devuelva el estado almacenado en caché.
Cómo configurar la seguridad para los puntos de conexión de supervisión a fin de protegerlos del acceso
público, que podría exponer la aplicación a los ataques malintencionados, dar lugar a la exposición de
información confidencial o atraer los ataques de denegación de servicio (DoS). Normalmente, esto debería
hacerse en la configuración de la aplicación, de modo que pueda actualizarse fácilmente sin reiniciar la
aplicación. Considere la posibilidad de usar una o más de las siguientes técnicas:
●● Proteja el punto de conexión exigiendo autenticación. Para ello, use una clave de seguridad de
autenticación en el encabezado de solicitud o pase credenciales con la solicitud, siempre que el
servicio o herramienta de supervisión admita la autenticación.
● Use un punto de conexión confuso u oculto. Por ejemplo, exponga el punto de conexión
de una dirección IP diferente a la usada por la dirección URL de la aplicación predeterminada,
configure el punto de conexión de un puerto HTTP estándar o use una ruta de acceso
compleja a la página de prueba. Normalmente, puede especificar puertos y direcciones
de punto de conexión adicionales en la configuración de la aplicación, así como agregar
entradas de estos puntos de conexión al servidor DNS si es necesario para evitar tener que
especificar la dirección IP directamente.
● Es probable que los ataques de DoS tengan menos impacto en un punto de conexión
independiente que realice pruebas funcionales básicas sin comprometer el funcionamiento
de la aplicación. Lo ideal es evitar el uso de una prueba que podría exponer información
confidencial. Si debe devolver información que podría ser útil para un atacante, tenga en
cuenta cómo protegerá el punto de conexión y los datos frente al acceso no autorizado. En
este caso, no es suficiente basarse simplemente en la confusión. También debería considerar
la posibilidad de usar una conexión HTTPS y cifrar los datos confidenciales, aunque esto
aumentará la carga del servidor.
●● Cómo obtener acceso a un punto de conexión protegido mediante autenticación. No todas las
herramientas y marcos se pueden configurar para incluir credenciales con la solicitud de verificación
de estado. Por ejemplo, las características de verificación de estado integradas de Microsoft Azure no
pueden proporcionar credenciales de autenticación. Algunas alternativas de terceros son Pingdom,
Panopta, NewRelic y Statuscake.
●● Cómo garantizar que el rendimiento del agente de supervisión sea correcto. Un enfoque consiste en
exponer un punto de conexión que solo devuelva un valor de la configuración de la aplicación o un
valor aleatorio que se pueda usar para realizar pruebas al agente.
Asimismo, garantice que el sistema de supervisión realice comprobaciones por su cuenta, como una
prueba automática y una prueba integrada, a fin de evitar que emita resultados falsos positivos.
●● Supervisión de servicios de nivel intermedio o compartidos para detectar y aislar un error que podría
alterar otras aplicaciones.
Ejemplo
En los siguientes ejemplos de código, tomados de la clase HealthCheckController (en GitHub hay
disponible una muestra que explica este patrón), se puede ver la exposición de un punto de conexión
para realizar diversas comprobaciones de estado.
El método CoreServices, mostrado a continuación en C#, realiza una serie de comprobaciones de los
servicios usados en la aplicación. Si todas las pruebas se ejecutan sin error, el método devuelve un código
de estado 200 (Correcto). Si cualquiera de las pruebas genera una excepción, el método devuelve un
código de estado 500 (Error interno). El método podría, de forma opcional, devolver información adicional
al producirse un error, si la herramienta o el marco de supervisión puede hacer uso de ella.
// This can optionally return different status codes based on the exception.
// Optionally it could return more details about the exception.
// The additional information could be used by administrators who access the
// endpoint with a browser, or using a ping utility that can display the
// additional information.
return new HttpStatusCodeResult((int)HttpStatusCode.InternalServerError);
}
return new HttpStatusCodeResult((int)HttpStatusCode.OK);
}
El método ObscurePath muestra cómo puede leer una ruta de acceso en la configuración de la aplicación
y usarla como punto de conexión para las pruebas. En este ejemplo, en C#, también se muestra cómo
puede aceptar un identificador como parámetro y usarlo para comprobar si hay solicitudes válidas.
// The obscure path can be set through configuration to hide the endpoint.
var hiddenPathKey = CloudConfigurationManager.GetSetting(“Test.ObscurePath”);
// If the value passed does not match that in configuration, return 404 (Not Found).
if (!string.Equals(id, hiddenPathKey))
{
return new HttpStatusCodeResult((int)HttpStatusCode.NotFound);
}
El método TestResponseFromConfig muestra cómo puede exponer un punto de conexión que compruebe
si hay un valor de parámetro de configuración especificado.
int returnStatusCode;
●● Use un servicio o marco de terceros como Microsoft System Center Operations Manager.
●● Cree una utilidad personalizada o un servicio que se ejecute por su cuenta o en un servidor
hospedado.
Las condiciones que puede supervisar varían dependiendo del mecanismo de hosting que elija para la
aplicación (como Web Sites, Cloud Services, Virtual Machines o Mobile Services), pero todas estas incluyen
la capacidad de crear una regla para alertas que usa un punto de conexión web que especifique en la
configuración del servicio. Este punto de conexión debe responder de forma oportuna de modo que
el sistema de alerta pueda detectar que la aplicación funciona correctamente.
Si hospeda la aplicación en roles web o de trabajo de Azure Cloud Services o Virtual Machines, puede
aprovechar uno de los servicios integrados de Azure llamado Traffic Manager. Traffic Manager es un
servicio de enrutamiento y equilibrio de carga que puede distribuir solicitudes a instancias específicas
de su aplicación hospedada de Cloud Services basada en una variedad de reglas y configuraciones.
Además de las solicitudes de enrutamiento, Traffic Manager hace ping a una dirección URL, un puerto
y una ruta de acceso relativa que especifique de forma periódica para determinar qué instancias de la
aplicación definida en sus reglas son activas y responden a solicitudes. Si detecta un código de estado
200 (Correcto), marca la aplicación como disponible. Cualquier otro código de estado hace que Traffic
Manager marque la aplicación como sin conexión. Puede ver el estado en la consola de Traffic Manager
y configurar la regla para recalcular solicitudes a otras instancias de la aplicación que respondan.
Sin embargo, Traffic Manager solo esperará diez segundos para recibir una respuesta de la dirección URL
de supervisión. Por lo tanto, debe garantizar que el código de verificación de estado se ejecute en este
momento, permitiendo la latencia de red para el viaje de ida y vuelta de Traffic Manager a la aplicación
y viceversa.
Lea más información sobre cómo usar Traffic Manager para supervisar las aplicaciones. También se
debate sobre Traffic Manager en la guía de implementación de varios centros de datos.
Contexto y problema
Muchos almacenes de datos organizan los datos para una recopilación de entidades mediante la clave
principal. Una aplicación puede usar esta clave para encontrar y recuperar datos. En la figura se muestra un
ejemplo de un almacén de datos que incluye información del cliente. La clave principal es el Id. de cliente.
En la figura se muestra información del cliente organizada por la clave principal (Id. de cliente).
Aunque la clave principal es valiosa para las consultas que capturan datos en función del valor de esta
clave, una aplicación podría no poder usar la clave principal si necesita recuperar datos en función de
algún otro campo. En el ejemplo de los clientes, una aplicación no puede usar la clave principal Id.
de cliente para recuperar clientes si consulta datos únicamente haciendo referencia al valor de algún
otro atributo, como la ciudad en la que se encuentra el cliente. Para realizar una consulta como esta,
la aplicación podría tener que capturar y examinar todos los registros de cliente, lo que podría ser un
proceso lento.
Puede crear tantos índices secundarios como necesite para respaldar las diferentes consultas realizadas
por la aplicación. Por ejemplo, en una tabla Clientes de una base de datos relacional donde el Id. de cliente
es la clave principal, es beneficioso agregar un índice secundario sobre el campo de ciudad si la aplicación
busca con frecuencia clientes según su ciudad de residencia.
Sin embargo, aunque los índices secundarios son habituales en los sistemas relacionales, la mayoría de
los almacenes de datos NoSQL usados por las aplicaciones en el cloud no proporcionan una característica
equivalente.
Solución
Si el almacén de datos no admite los índices secundarios, puede emularlos manualmente creando sus
propias tablas de índice. Una tabla de índice organiza los datos según una clave especificada. Se suelen
usar tres estrategias para estructurar una tabla de índice, dependiendo del número de índices secundarios
necesarios y la naturaleza de las consultas realizadas por una aplicación.
La primera estrategia es duplicar los datos de cada tabla de índice, pero organizarlos según diferentes
claves (desnormalización completa). En la siguiente figura se muestran las tablas de índice que organizan
la misma información de cliente por Ciudad y Apellido.
Esta estrategia es adecuada si los datos son relativamente estáticos en comparación con el número de
veces que se consultan con cada clave. Si los datos son más dinámicos, la sobrecarga de procesamiento
de mantenimiento de cada tabla de índice resulta demasiado grande para que este enfoque sea útil.
Asimismo, si el volumen de datos es muy grande, la cantidad de espacio necesaria para almacenar los
datos duplicados es significativa.
La segunda estrategia es crear tablas de índice normalizadas organizadas por diferentes claves y hacer
referencia a los datos originales mediante la clave principal en lugar de duplicarlos, como se muestra
en la siguiente figura. Los datos originales se llaman tabla de hechos.
La tercera estrategia es crear tablas de índice normalizadas parcialmente organizadas por claves diferentes
que duplican campos recuperados con frecuencia. Haga referencia a la tabla de hechos para tener acceso
a campos a los que se tiene acceso de forma menos habitual. En la siguiente figura se muestra cómo
se duplican los datos a los que se tiene acceso de forma menos habitual en cada tabla de índice.
Con esta estrategia, puede lograr un equilibrio entre los primeros dos enfoques. Los datos de las consultas
habituales se pueden recuperar rápidamente mediante una sola búsqueda, mientras la sobrecarga de
espacio y mantenimiento no sea tan significativa como la duplicación de todo el conjunto de datos.
Si una aplicación consulta datos con frecuencia especificando una combinación de valores (por ejemplo,
"Busque todos los clientes que viven en Redmond y cuyo apellido es Smith"), podría implementar las
claves en los elementos de la tabla de índice como una concatenación del atributo Ciudad y el atributo
Apellido. En la siguiente figura se muestra una tabla de índice basada en claves compuestas. Las claves
se ordenan por Ciudad y, a continuación, por Apellido para los registros con el mismo valor de Ciudad.
Problemas y consideraciones
Tenga en cuenta los puntos siguientes a la hora de decidir cómo implementar este patrón:
●● La sobrecarga de mantenimiento de los índices secundarios puede ser significativa. Debe analizar
y comprender las consultas que usa su aplicación. Cree solo tablas de índice cuando sea posible su
uso regular. No cree tablas de índice especulativas para respaldar las consultas no realizadas por una
aplicación o realizadas solo de forma ocasional.
●● La implementación de una tabla de índice como estructura normalizada que hace referencia a los
datos originales requiere que una aplicación realice dos operaciones de búsqueda para encontrar
datos. La primera operación busca la tabla de índice para recuperar la clave principal y la segunda
usa la clave principal para capturar los datos.
●● Si un sistema incorpora un número de tablas de índice sobre conjuntos de datos muy grandes, puede
resultar difícil mantener la coherencia entre las tablas de índice y los datos originales. Puede que sea
posible diseñar la aplicación en torno al modelo de coherencia al cabo del tiempo. Por ejemplo, para
insertar, actualizar o eliminar datos, una aplicación podría enviar un mensaje a una cola y permitir a
una tarea independiente realizar la operación y mantener las tablas de índice que hacen referencia
a estos datos de forma asincrónica. Para obtener más información sobre cómo implementar la
coherencia a lo largo del tiempo, consulte la Introducción a la coherencia de datos.
●● Las tablas de almacenamiento de Microsoft Azure admiten las actualizaciones transaccionales para los
cambios realizados en los datos albergados en la misma partición, que se denomina transacciones de
grupos de entidades. Si puede almacenar los datos de una tabla de hechos y una o varias tablas de
índice en la misma partición, puede usar esta característica para ayudar a garantizar la coherencia.
●● Un campo seleccionado como clave secundaria de una tabla de índice es imparcial y solo puede tener
un conjunto pequeño de valores (por ejemplo, género).
●● El equilibrio de los valores de los datos de un campo seleccionado como la clave secundaria de una tabla
de índice es altamente sesgado. Por ejemplo, si el 90 % de los registros contienen el mismo valor en
un campo, la creación y el mantenimiento de una tabla de índice para buscar datos en función de este
campo podría crear una mayor sobrecarga que la detección secuencial a través de los datos. Sin embargo,
si las consultas se dirigen con frecuencia a los valores situados en el 10 % restante, este índice puede
resultar útil. Debe entender las consultas realizadas por su aplicación y la frecuencia con que lo hace.
Ejemplo
Las tablas de almacenamiento de Azure proporcionan un almacén de datos de pares clave-valor altamente
escalable para las aplicaciones que se ejecutan en el cloud. Las aplicaciones almacenan y recuperan los
valores de los datos especificando una clave. Los valores de los datos pueden contener varios campos,
pero la estructura de un elemento de datos es opaca para el almacenamiento de tablas, que se limita
a controlar un elemento de datos como una matriz de bytes.
Por ejemplo, piense en una aplicación que almacena información sobre películas. La aplicación suele
consultar las películas por género (acción, documental, histórica, comedia, drama, etc.). Podría crear una
tabla de Azure con particiones para cada género usando este como clave de partición y especificando el
nombre de la película como clave de fila, como se muestra en la siguiente figura.
Este enfoque es menos eficaz si también es necesario que la aplicación consulte las películas por actor
protagonista. En este caso, puede crear una tabla de Azure independiente que actúe como tabla de índice.
La clave de partición es el actor y la clave de fila es el nombre de la película. Los datos de cada actor se
almacenarán en particiones independientes. Si una película tiene más de un actor protagonista, la misma
película aparecerá en varias particiones.
Puede duplicar los datos de la película en los valores albergados por cada partición adoptando el
primer enfoque descrito en la sección Solución anterior. Sin embargo, es probable que cada película se
replique varias veces (una por cada actor), por lo que podría resultar más eficaz desnormalizar de forma
parcial los datos para respaldar las consultas (como los nombres de los otros actores) y permitir a una
aplicación recuperar cualquier detalle restante incluyendo la clave de partición necesaria para encontrar la
información completa en las particiones de género. En la tercera opción de la sección Solución se describe
este enfoque. En la siguiente figura se muestra este enfoque.
●● Patrón de particionamiento. El patrón de tabla de índice suele usarse junto con datos particionados
mediante particiones. El patrón de particionamiento proporciona más información sobre cómo dividir
un almacén de datos en un conjunto de particiones.
●● Patrón de vistas materializadas. En lugar de indexar datos para respaldar las consultas que resumen
los datos, podría ser más adecuado crear una vista materializada de los datos. Describe cómo
respaldar consultas de resumen eficaces generando vistas previamente completadas sobre los datos.
Contexto y problema
Una aplicación en el cloud típica tiene muchas tareas que actúan de forma coordinada. Todas estas tareas
podrían ser instancias que ejecutan el mismo código y requieren acceso a los mismos recursos, o bien
podrían funcionar conjuntamente en paralelo para realizar las partes individuales de un cálculo complejo.
Por ejemplo:
●● En un sistema basado en el cloud que implementa escalado horizontal, varias instancias de la misma
tarea podrían ejecutarse al mismo tiempo con cada instancia que presta servicio a un usuario
diferente. Si estas instancias se escriben en un recurso compartido, es necesario coordinar sus
acciones para evitar que cada instancia sobrescriba los cambios realizados por el resto.
●● Si las tareas realizan elementos individuales de un cálculo complejo en paralelo, los resultados deben
agregarse al completarse en su totalidad.
Todas las instancias de tarea son compañeras, por lo que no hay un líder natural que pueda actuar como
coordinador o acumulador.
Solución
Debe elegirse una sola instancia de tarea para actuar como líder y esta debe coordinar las acciones de las
otras instancias de tarea subordinadas. Si todas las instancias de tarea ejecutan el mismo código, cada una
podrá actuar como líder. Por lo tanto, el proceso de elección debe administrarse con cuidado para evitar
que dos o más instancias asuman el rol de líder al mismo tiempo.
El sistema debe proporcionar un mecanismo sólido para seleccionar el líder. Este método debe hacer
frente a eventos como interrupciones de red o errores de proceso. En muchas soluciones, las instancias de
tarea subordinadas supervisan el líder a través de algún tipo de método de latido o por sondeo. Si el líder
designado termina de forma inesperada o un error de red hace que el líder no se encuentre disponible
para las instancias de tarea subordinadas, es necesario la elección de un nuevo líder.
Existen varias estrategias para elegir un líder entre un conjunto de tareas en un entorno distribuido,
incluyéndose las siguientes:
●● Selección de la instancia de tarea con el Id. de proceso o la instancia de menor rango.
●● Adquisición rápida de una exclusión mutua compartida y distribuida. La primera instancia de tarea
que adquiere la exclusión mutua es el líder. Sin embargo, el sistema debe asegurarse de que, si el
líder termina o se desconecta del resto del sistema, la exclusión mutua se libera para permitir a otra
instancia de tarea convertirse en el líder.
●● Implementación de uno de los algoritmos de elección de líder habituales como Bully Algorithm o Ring
Algorithm. Estos algoritmos suponen que cada candidato de la elección tiene un identificador único
y que puede comunicarse con los otros candidatos de forma fiable.
Problemas y consideraciones
Tenga en cuenta los puntos siguientes a la hora de decidir cómo implementar este patrón:
●● El proceso de elección de un líder debe ser resistente a los errores transitorios y persistentes.
●● Debe ser posible detectar si el líder ha fracasado o, de lo contrario, ha dejado de estar disponible
(por ejemplo, debido a un error de comunicaciones). Con qué rapidez depende del sistema la
●● En un sistema que implementa escalado automático horizontal, el líder podría terminarse si la escala
del sistema se reduce de nuevo y cierra algunos de los recursos informáticos.
●● El uso de una exclusión mutua compartida y distribuida presenta una dependencia del servicio
externo que proporciona la exclusión mutua. El servicio constituye un único punto de error. Si deja
de estar disponible por alguna razón, el sistema no podrá elegir un líder.
●● El uso de un solo proceso dedicado como líder es un enfoque muy sencillo. Sin embargo, si el proceso
no se realiza correctamente, podría producirse un retraso significativo mientras se reinicia. La latencia
resultante puede afectar al rendimiento y los tiempos de respuesta de otros procesos si esperan a que
el líder coordine una operación.
Evite hacer del líder un cuello de botella en el sistema. El propósito del líder es coordinar el trabajo de
las tareas subordinadas y no tiene que participar necesariamente en este trabajo (aunque debería poder
hacerlo si la tarea no se elige como líder).
●● La coordinación entre las tareas puede lograrse mediante un método más ligero. Por ejemplo, si varias
instancias de tarea solo necesitan acceso coordinado a un recurso compartido, una mejor solución
consiste en usar un bloqueo optimista o pesimista para controlar el acceso.
●● Una solución de terceros es más adecuada. Por ejemplo, el servicio de Microsoft Azure HDInsight
(basado en Apache Hadoop) usa los servicios proporcionados por Apache Zookeeper para coordinar
el mapa y reducir las tareas que recopilan y resumen datos.
Ejemplo
El proyecto DistributedMutex de la solución LeaderElection (en GitHub hay disponible una muestra que
explica este patrón) muestra cómo usar una concesión en Azure Storage Blob para proporcionar un
mecanismo para implementar una exclusión mutua compartida y distribuida. Esta exclusión mutua puede
usarse para elegir un líder entre un grupo de instancias de rol en un servicio de cloud de Azure. La primera
instancia de rol en adquirir la concesión se elige como líder y permanece como tal hasta que libera la
concesión o no puede renovar esta. Otras instancias de rol pueden seguir supervisando la concesión de
blobs en caso de que el líder deje de estar disponible.
Para evitar una instancia de rol con errores que retenga la concesión de forma indefinida, especifique un
ciclo de vida para la concesión. Cuando este caduca, la concesión pasa a estar disponible. Sin embargo,
aunque una instancia de rol tiene la concesión, puede solicitar que esta se renueve y se le concederá la
concesión durante un período adicional. La instancia de rol puede repetir este proceso continuamente
si desea retener la concesión. Para obtener más información sobre cómo conceder un blob, consulte el
artículo relativo al blob de concesión (API de REST).
if (!string.IsNullOrEmpty(leaseId))
{
// Create a new linked cancellation token source so that if either the
// original token is canceled or the lease can’t be renewed, the
// leader task can be canceled.
using (var leaseCts =
CancellationTokenSource.CreateLinkedTokenSource(new[] { token }))
{
// Run the leader task.
var leaderTask = this.taskToRunWhenLeaseAquired.Invoke(leaseCts.Token);
...
}
}
}
...
}
La tarea iniciada por el líder también se ejecuta de forma asincrónica. Mientras se ejecuta esta tarea,
el método RunTaskWhenBlobLeaseAquired mostrado en el siguiente ejemplo de código intenta renovar
la concesión de forma periódica. Esto ayuda a garantizar que la instancia de rol permanezca como líder.
En la solución de ejemplo, el retraso entre las solicitudes de renovación es inferior al tiempo especificado
para la duración de la concesión a fin de impedir que otra instancia de rol se elija como líder. Si la
renovación no se realiza correctamente por alguna razón, se cancela la tarea.
// When any task completes (either the leader task itself or when it
// couldn’t renew the lease) then cancel the other task.
await CancelAllWhenAnyCompletes(leaderTask, renewLeaseTask, leaseCts);
}
}
}
}
...
}
●● Si la tarea realizada por el líder se detiene, el líder podría continuar renovando la concesión,
impidiendo a cualquier otra instancia de rol adquirir la concesión y asumir el rol de líder para
coordinar las tareas. En el mundo real, el estado del líder debe comprobarse con frecuencia.
●● El proceso de elección no es determinista. No puede realizar ninguna suposición sobre qué instancia
de rol adquirirá la concesión de blobs y se convertirá en el líder.
●● El blob usado como destino de la concesión de blobs no debe utilizarse con cualquier otro propósito.
Si una instancia de rol intenta almacenar datos en este blob, no se podrá obtener acceso a estos datos
a menos que la instancia de rol sea el líder y cuente con la concesión de blobs.
●● Guía de partición de recursos informáticos. En esta guía se describe cómo asignar tareas a hosts en
un servicio de cloud de una manera que ayude a minimizar los costes manteniendo la escalabilidad, el
rendimiento, la disponibilidad y la seguridad del servicio.
Contexto y problema
Al almacenar datos, la prioridad para los desarrolladores y los administradores de datos se suele centrar en
cómo se almacenan los datos, a diferencia de cómo se leen. El formato de almacenamiento elegido suele
estar estrechamente relacionado con el formato de los datos, los requisitos para administrar el tamaño de
los datos, la integridad de los datos y el tipo de almacenamiento en uso. Por ejemplo, al usar el almacén
de documentos NoSQL, los datos suelen representarse como una serie de agregados, cada uno de los
cuales contiene toda la información de esa entidad.
Sin embargo, esto puede tener un efecto negativo en las consultas. Si una consulta solo necesita un
subconjunto de los datos de algunas entidades, como un resumen de los pedidos de varios clientes sin
todos los detalles de pedido, debe extraer todos los datos de las entidades pertinentes para obtener la
información requerida.
Solución
Para respaldar la realización de consultas adecuadas, una solución habitual es generar, de antemano, una
vista que materialice los datos en un formato adaptado al conjunto de resultados requeridos. El patrón
de vistas materializadas describe la generación de vistas previamente completadas de datos en entornos
donde los datos de origen no tienen un formato compatible con la realización de consultas, donde la
generación de una consulta adecuada es difícil o donde la realización de consultas es escasa debido
a la naturaleza de los datos o el almacén de datos.
Estas vistas materializadas, que solo contienen los datos requeridos por una consulta, permiten a las
aplicaciones obtener de forma rápida la información que necesitan. Además de unir tablas o combinar
entidades de datos, las vistas materializadas pueden incluir los valores actuales de las columnas o
elementos de datos calculados, los resultados de combinar valores o ejecutar transformaciones en los
elementos de datos y los valores especificados como parte de la consulta. Una vista materializada incluso
puede optimizarse para solo una consulta única.
Un punto clave es que una vista materializada y los datos que contiene son totalmente descartables
porque se pueden crear de nuevo por completo con los almacenes de datos de origen. Una aplicación
nunca actualiza directamente una vista materializada, de manera que se trata de una memoria caché
especializada.
Cuando los datos de origen de la vista cambian, esta debe actualizarse para incluir la nueva información.
Puede programar esto para que se produzca de forma automática o si el sistema detecta un cambio en
los datos originales. En algunos casos podría ser necesario regenerar la vista manualmente. En la figura
se muestra un ejemplo de cómo puede usarse el patrón de vistas materializadas.
En algunos sistemas, por ejemplo, al usar el patrón de abastecimiento de eventos para mantener un
almacén con solo los eventos que han modificado los datos, las vistas materializadas son necesarias.
Completar vistas de forma previa examinando todos los eventos para determinar el estado actual
podría ser la única manera de obtener información del almacén de eventos. Si no usa el abastecimiento
de eventos, debe considerar si una vista materializada es útil o no. Las vistas materializadas tienden
a adaptarse de forma específica a una consulta o a un número pequeño de ellas. Si se usan muchas
consultas, las vistas materializadas pueden dar lugar a unos requisitos de capacidad de almacenamiento
inaceptables y al coste de almacenamiento.
Considere el impacto en la coherencia de los datos al generar la vista y al actualizarla si esto ocurre según
una programación establecida. Si los datos de origen cambian al generarse la vista, la copia de los datos
en la vista no será totalmente coherente con los datos originales.
Tenga en cuenta dónde almacenará la vista. La vista no debe estar en el mismo almacén o partición que
los datos originales. Puede ser un subconjunto de varias particiones diferentes combinadas.
Una vista se puede crear de nuevo en caso de pérdida. Por ello, si la vista es transitoria y se usa solo para
mejorar el rendimiento de las consultas reflejando el estado actual de los datos, o bien para mejorar la
escalabilidad, puede almacenarse en una memoria caché o en una ubicación menos fiable.
Al definir una vista materializada, maximice su valor agregándole columnas o elementos de datos en
función del cálculo o la transformación de elementos de datos existentes, de los valores pasados en la
consulta o de las combinaciones de estos valores cuando sea apropiado.
●● Crear vistas temporales que puedan mejorar drásticamente el rendimiento de las consultas o puedan
actuar directamente como vistas de origen u objetos de transferencia de datos para la IU, para los
informes o para las presentaciones.
●● Respaldar de forma ocasional escenarios con conexión o sin conexión en los cuales la conexión al
almacén de datos no siempre se encuentra disponible. En este caso, la vista puede almacenarse en
caché de forma local.
●● Simplificar consultas y exponer datos para la experimentación de modo que no sea necesario conocer
el formato de datos de origen. Por ejemplo, al unir diferentes tablas en una o varias bases de datos,
o bien uno o varios dominios en almacenes NoSQL y, a continuación, formatear los datos para
adaptarse a su uso final.
●● Proporcionar acceso a subconjuntos específicos de los datos de origen a los que, por motivos de
seguridad o privacidad, no debería tenerse acceso en general. Dichos datos tampoco deberían quedar
expuestos a su modificación ni de forma total a los usuarios.
●● Abarcar diferentes almacenes de datos para aprovechar sus funcionalidades individuales. Por ejemplo,
el uso de un almacén en el cloud que sea eficaz a la hora de escribir como almacén de datos de
referencia y una base de datos relacional que ofrezca un buen rendimiento de lectura y consulta para
guardar las vistas materializadas.
●● Los datos de origen cambian muy rápido o bien se puede tener acceso a ellos sin usar una vista.
En estos casos, debe evitar la sobrecarga de procesamiento de creación de vistas.
●● La prioridad de la coherencia es alta. Las vistas podrían no ser siempre totalmente coherentes con
los datos originales.
La creación de esta vista materializada requiere consultas complejas. Sin embargo, al exponer el resultado
de la consulta como vista materializada, los usuarios pueden obtener fácilmente los resultados y usarlos
directamente o incorporarlos en otra consulta. Es probable que la vista se use en un panel o sistema de
informes y se puede actualizar periódicamente (por ejemplo, semanalmente).
Aunque en este ejemplo se usa Almacenamiento de tablas de Azure, muchos sistemas de administración
de bases de datos relacionales también proporcionan soporte nativo para las vistas materializadas.
●● Patrón CQRS (Command and Query Responsibility Segregation). Úselo para actualizar la
información de una vista materializada respondiendo a eventos que se producen cuando cambian
los valores de datos subyacentes.
●● Patrón de abastecimiento de eventos. Úselo junto con el patrón CQRS para mantener la información
de una vista materializada. Cuando cambian los valores de datos en los que se basa una vista
materializada, el sistema puede generar eventos que describan estos cambios y guardarlos en un
almacén de eventos.
Contexto y problema
Es necesaria una aplicación para realizar una variedad de tareas de complejidad diversa sobre la
información que procesa. Un enfoque sencillo pero inflexible para implementar una aplicación consiste
en realizar este procesamiento como un módulo monolítico. Sin embargo, es probable que este enfoque
disminuya las oportunidades de refactorizar el código, optimizarlo o reutilizarlo si se requieren partes del
mismo procesamiento en cualquier otro lugar de la aplicación.
En la figura se ilustran los problemas con el procesamiento de datos mediante el enfoque monolítico. Una
aplicación recibe y procesa datos de dos fuentes. Un módulo independiente procesa los datos de cada
fuente. Este realiza una serie de tareas para transformar estos datos, antes de pasar el resultado a la lógica
empresarial de la aplicación.
Sin embargo, las tareas de procesamiento realizadas por cada módulo o los requisitos de implementación
de cada tarea podrían cambian a medida que se actualizan los requisitos empresariales. Algunas tareas
podrían consumir muchos recursos informáticos y podrían beneficiarse de su ejecución en hardware eficaz,
mientras que otras podrían no requerir unos recursos tan caros. Además, podría requerirse procesamiento
adicional en el futuro o podría cambiar el orden en que el procesamiento realizó las tareas. Es necesaria
una solución que resuelva estos problemas y aumente las posibilidades de reutilización del código.
Solución
Derribe el procesamiento requerido para cada flujo en un conjunto de componentes (o filtros)
independientes, cada uno de los cuales realiza una sola tarea. Al estandarizar el formato de los datos que
cada componente recibe y envía, estos filtros se pueden combinar juntos en una canalización. Esto ayuda
a evitar la duplicación del código y facilita la eliminación, la sustitución o la integración de componentes
adicionales si cambian los requisitos de procesamiento. En la siguiente figura se muestra una solución
implementada mediante canalizaciones y filtros.
El tiempo que tarda en procesarse una sola solicitud depende de la velocidad del filtro más lento de
la canalización. Uno o varios filtros podrían ser un cuello de botella, especialmente si aparece un gran
número de solicitudes en un flujo de un determinado origen de datos. Una ventaja clave de la estructura
de la canalización es que ofrece oportunidades para ejecutar instancias paralelas de filtros lentos, lo que
permite al sistema repartir la carga y mejorar el rendimiento.
Los filtros que constituyen una canalización pueden ejecutarse en diferentes máquinas, lo que les permite
escalarse de forma independiente y aprovechar la elasticidad proporcionada por muchos entornos
de cloud. Un filtro que hace un uso intensivo de computación puede ejecutarse en hardware de alto
rendimiento, mientras que otros filtros menos exigentes se pueden hospedar en hardware básico menos
caro. Incluso no es necesario que los filtros estén en el mismo centro de datos o ubicación geográfica,
lo que permite a cada uno de los elementos de una canalización ejecutarse en un entorno cercano a los
recursos que requieren. En la siguiente figura se muestra un ejemplo aplicado a la canalización de los
datos de la primera fuente.
Otra ventaja es la resiliencia que este modelo puede proporcionar. Si se produce un error en un filtro o
la máquina en la que se ejecuta este ya no está disponible, la canalización puede volver a programar el
trabajo realizado por el filtro y dirigir este trabajo a otra instancia del componente. Si se produce un error
en un solo filtro, esto no significa necesariamente que se vaya a producir otro error en toda la canalización.
Problemas y consideraciones
Debe considerar los puntos siguientes a la hora de decidir cómo implementar este patrón:
●● Complejidad. La mayor flexibilidad que proporciona este patrón también puede presentar
complejidad, especialmente si los filtros de una canalización se distribuyen en diversos servidores.
●● Fiabilidad. Use una infraestructura que garantice que los datos que fluyen entre los filtros de una
canalización no se perderán.
●● Idempotencia. Si se produce un error en un filtro de una canalización tras recibir un mensaje y el trabajo
se vuelve a programar para otra instancia del filtro, parte del trabajo podría haberse completado ya. Si
este trabajo actualiza algún aspecto del estado global (como la información almacenada en una base de
datos), la misma actualización podría repetirse. Un problema similar podría producirse si se produce un
error en un filtro después de publicar sus resultados en el siguiente filtro de la canalización, pero antes
de indicar que su trabajo se ha completado correctamente. En estos casos, otra instancia del filtro podría
repetir el mismo trabajo, dando lugar a la doble publicación de los mismos resultados. Esto podría
ocasionar el doble procesamiento de los mismos datos por parte de filtros posteriores de la canalización.
Por lo tanto, los filtros de una canalización deben diseñarse para ser idempotentes. Para obtener más
información, consulte los patrones de idempotencia en el blog de Jonathan Oliver.
●● Contexto y estado. En una canalización, cada filtro se ejecuta esencialmente de forma aislada
y no debe realizar ninguna suposición sobre su invocación. Esto significa que cada filtro debe
proporcionarse con contexto suficiente para realizar su trabajo. Este contexto podría incluir gran
cantidad de información de estado.
●● Los pasos de procesamiento realizados por una aplicación tienen diferentes requisitos de
escalabilidad. Los filtros que deben aplicarse en el mismo proceso pueden agruparse. Para obtener
más información, consulte el patrón de consolidación de recursos de proceso.
●● Se requiere flexibilidad para permitir la reordenación de los pasos de procesamiento realizados por
una aplicación o la posibilidad de agregar y quitar pasos.
●● El sistema puede beneficiarse de la distribución del procesamiento para los pasos correspondientes
a los distintos servidores.
●● Es necesaria una solución fiable que minimice los efectos del error en un paso mientras se procesan
los datos.
●● La cantidad de información de contexto o estado requerida por un paso hace que este enfoque
resulte ineficaz. Podría ser posible la persistencia de información de estado en una base de datos
en su lugar, pero no use esta estrategia si la carga adicional de la base de datos da lugar a una
contención excesiva.
Ejemplo
Puede usar una secuencia de colas de mensajes para proporcionar la infraestructura requerida para
implementar una canalización. Una cola de mensajes inicial recibe mensajes sin procesar. Un componente
implementado como una tarea de filtro atiende un mensaje de esta cola, realiza su trabajo y,
a continuación, publica el mensaje transformado en la siguiente cola de la secuencia. Otra tarea de filtro
puede atender los mensajes de esta cola, procesarlos, publicar los resultados en otra cola, etc., hasta que
los datos completamente transformados aparezcan en el mensaje final de la cola. En la siguiente figura se
ilustra la implementación de una canalización mediante las colas de mensajes.
...
// Create the inbound and outbound queue clients.
this.inQueue = QueueClient.CreateFromConnectionString(...);
}
this.inQueue.OnMessageAsync(
async (msg) =>
{
...
// Process the filter and send the output to the
// next queue in the pipeline.
var outMessage = await asyncFilterTask(msg);
// Note: There’s a chance that the same message could be sent twice
// or that a message gets processed by an upstream or downstream
// filter at the same time.
// This would happen in a situation where processing of a message was
// completed, it was sent to the next pipe/queue, and then failed
// to complete when using the PeekLock method.
// Idempotent message processing and concurrency should be considered
// in a real-world implementation.
},
options);
}
this.inQueue.Close();
...
}
La solución de ejemplo implementa filtros en un conjunto de roles de trabajo. Cada rol de trabajo se
puede escalar de forma independiente, dependiendo de la complejidad del procesamiento empresarial
que realice o los recursos requeridos para el procesamiento. Además, varias instancias de cada rol de
trabajo se pueden ejecutar en paralelo para mejorar el rendimiento.
this.pipeFilterA.Start();
...
}
newMsg.Properties.Add(Constants.FilterAMessageKey, “Complete”);
return newMsg;
});
...
}
...
}
Este rol contiene un objeto ServiceBusPipeFilter. El método OnStart del rol se conecta a las colas para
recibir mensajes de entrada y publicar mensajes de salida (los nombres de las colas se definen en la clase
Constants). El método Run invoca el método OnPipeFilterMessagesAsync para procesar cada mensaje
recibido (en este ejemplo, el procesamiento se simula esperando durante un breve período de tiempo).
Al completarse el procesamiento, se crea un nuevo mensaje con los resultados (en este caso, el mensaje
de entrada tiene una propiedad personalizada agregada), el cual se publica en la cola de salida.
La cola de entrada del rol FinalReceiveRoleEntry es la cola de salida del rol PipeFilterBRoleEntry. El método
Run del rol FinalReceiveRoleEntry, mostrado a continuación, recibe el mensaje y realiza una parte del
procesamiento final. A continuación, escribe los valores de las propiedades personalizadas agregadas por
los filtros de la canalización a la salida de seguimiento.
return null;
});
...
}
...
}
●● Patrón de consumidores competitivos. Una canalización puede contener varias instancias de uno
o varios filtros. Este enfoque resulta útil para ejecutar instancias paralelas de filtros lentos, lo que
permite al sistema repartir la carga y mejorar el rendimiento. Cada instancia de un filtro competirá por
encontrar información con las otras instancias. Dos instancias de un filtro no deben poder procesar los
mismos datos. Proporciona una explicación de este enfoque.
Contexto y problema
Las aplicaciones pueden delegar tareas específicas a otros servicios como, por ejemplo, procesar en
segundo plano o integrarse en otras aplicaciones o servicios. En el cloud, suele usarse una cola de
mensajes para delegar las tareas al procesamiento en segundo plano. En muchos casos, el orden en que
un servicio recibe las solicitudes no es importante. Sin embargo, en otros, es necesario priorizar solicitudes
concretas que deben procesarse antes que otras con prioridad más baja, enviadas previamente por la
aplicación.
Solución
Una cola suele ser una estructura de tipo "primero en entrar, primero en salir" (FIFO) y los consumidores
reciben los mensajes en el mismo orden en el que se enviaron a esta. Sin embargo, algunas colas admiten
el envío de mensajes con prioridad. La aplicación que envía el mensaje puede asignar una prioridad y
los mensajes de la cola se reordenan automáticamente, de forma que aquellos con prioridad más alta
se reciban antes que los de prioridad más baja. En la ilustración se muestra una cola de mensajes con
prioridad.
Una solución alternativa para los sistemas que no admiten las colas de mensajes basadas en prioridad
es contar con una cola independiente para cada prioridad. La aplicación es responsable de enviar los
mensajes a la cola adecuada y cada cola puede tener un grupo de consumidores distinto. Las colas de
mayor prioridad pueden tener un grupo de consumidores más grande y ejecutarse en un hardware más
rápido que las de prioridad más baja. En la ilustración siguiente se muestra el uso de colas de mensajes
independientes para cada prioridad.
Una variación de esta estrategia es tener un único grupo de consumidores que compruebe primero los
mensajes de las colas de prioridad alta y que, solo después de haberlo hecho, comience a recuperar los
mensajes de las colas de menor prioridad. Existen algunas diferencias semánticas entre una solución
que usa un único grupo de procesos de consumidor (ya sea con una cola única que admite mensajes
con distintas prioridades o con varias colas que administran por separado los mensajes de prioridades
diferentes) y una solución que usa varias colas con un grupo independiente para cada una.
En el enfoque de un solo grupo, los mensajes de prioridad más alta siempre se reciben y se procesan
antes que los de menor prioridad. En teoría, los mensajes con una prioridad muy baja podrían relevarse
continuamente y no llegar a procesarse jamás. En el enfoque de varios grupos, los mensajes de prioridad
más baja siempre se procesarán, solo que no tan rápido como los de mayor prioridad (dependiendo del
tamaño relativo de los grupos y de los recursos que tienen disponibles).
El uso de un mecanismo de puesta en cola por prioridad puede proporcionar las ventajas siguientes:
Problemas y consideraciones
Tenga en cuenta los puntos siguientes a la hora de decidir cómo implementar este patrón:
Defina las prioridades en el contexto de la solución. Por ejemplo, una prioridad alta puede significar que
los mensajes deben procesarse en un plazo de diez segundos. Identifique los requisitos para administrar
los elementos con una prioridad alta, así como el resto de recursos que debe asignarse para satisfacer
estos criterios.
Decida si todos los elementos de prioridad alta deben procesarse antes que cualquier otro de prioridad
más baja. Si del procesamiento de los mensajes se encarga un único grupo de consumidores, debe
proporcionarse un mecanismo que pueda anticiparse y suspender una tarea encargada de un mensaje
de prioridad baja si un mensaje de mayor prioridad pasa a estar disponible.
En el enfoque de varias colas, cuando se usa un grupo de procesos de consumidor único que escucha
en todas las colas en lugar de un grupo de consumidores dedicado para cada cola, el consumidor debe
aplicar un algoritmo que garantice que siempre se atienden los mensajes de las colas de mayor prioridad
antes que los de las de prioridad más baja.
Supervise la velocidad de procesamiento en las colas de prioridad alta y baja para asegurarse de que los
mensajes que contienen se procesan a la velocidad esperada.
Si debe garantizar el procesamiento de los mensajes de prioridad baja, es necesario aplicar el enfoque
de varias colas de mensajes con varios grupos de consumidores. Igualmente, en una cola que admite la
priorización de los mensajes, se puede incrementar dinámicamente la prioridad de un mensaje puesto
en cola a medida que pasa el tiempo. Sin embargo, este enfoque depende de la cola de mensajes que
proporcione esta característica.
El uso de una cola independiente para cada prioridad de mensaje funciona mejor para los sistemas que
tienen un número reducido de prioridades bien definidas.
El sistema puede determinar las prioridades de los mensajes de forma lógica. Por ejemplo, en lugar de
tener mensajes explícitos de prioridad alta y baja, podrían designarse como "cliente que paga tarifas"
o "cliente que no paga tarifas". En función de modelo de negocio, el sistema puede asignar más recursos
al procesamiento de los mensajes de clientes que pagan tarifas frente a los de aquellos que no pagan.
Ejemplo
Microsoft Azure no ofrece un mecanismo de puesta en cola que admita de forma nativa la priorización
automática de los mensajes a través de su clasificación. Sin embargo, proporciona suscripciones y temas
de Azure Service Bus que admiten un mecanismo de puesta en cola con filtrado de mensajes, junto con
una amplia gama de funciones de gran flexibilidad que lo convierten en ideal para su uso en la mayoría
de las implementaciones de colas de prioridad.
Una solución de Azure puede implementar un tema de Service Bus al que una aplicación puede enviar
mensajes, de la misma forma que una cola. Los mensajes pueden contener metadatos en forma de
propiedades personalizadas definidas por la aplicación. Las suscripciones a Service Bus se pueden asociar
al tema y filtrar los mensajes en función de sus propiedades. Cuando una aplicación envía un mensaje a un
tema, dicho mensaje se dirige a la suscripción adecuada donde pueda leerlo un consumidor. Los procesos
de consumidor pueden recuperar mensajes de una suscripción con la misma semántica que una cola de
mensajes (una suscripción es una cola lógica). En la ilustración siguiente se muestra la implementación de
una cola de prioridades con suscripciones y temas de Azure Service Bus.
Tenga en cuenta que no hay nada especial en la designación de los mensajes de prioridad alta y baja en
este ejemplo. Son simples etiquetas que se especifican como propiedades en cada mensaje y se usan para
dirigir los mensajes a una suscripción concreta. Si se requieren prioridades adicionales, es relativamente
fácil crear más suscripciones y grupos de procesos de consumidor para administrarlas.
La solución PriorityQueue disponible en GitHub contiene una implementación de este enfoque. Esta
solución contiene dos proyectos de roles de trabajo llamados PriorityQueue.High y PriorityQueue.
Low. Dichos roles heredan de la clase PriorityWorkerRole, que contiene la funcionalidad necesaria para
conectarse a una suscripción especificada en el método OnStart.
Los roles de trabajo PriorityQueue.High y PriorityQueue.Low se conectan a suscripciones distintas,
definidas en las opciones de configuración. Un administrador puede configurar que se ejecute un número
distinto de instancias de cada rol. Normalmente habrá más instancias del rol de trabajo PriorityQueue.High
que de PriorityQueue.Low.
El método Run de la clase PriorityWorkerRole establece que el método ProcessMessage virtual (también
definido en la clase PriorityWorkerRole) debe ejecutarse para cada mensaje que se reciba en la cola.
El código siguiente muestra los métodos Run y ProcessMessage. La clase QueueManager, que se define
en el proyecto PriorityQueue.Shared, proporciona métodos auxiliares para usar colas de Azure Service Bus.
Cuando una aplicación envía mensajes al tema asociado a las suscripciones que usan los roles de trabajo
PriorityQueue.High y PriorityQueue.Low, especifica la prioridad mediante la propiedad personalizada
Priority, como se muestra en el ejemplo de código siguiente. Este código (que se implementa en la clase
WorkerRole en el proyecto PriorityQueue.Sender) usa el método auxiliar SendBatchAsync de la clase
QueueManager para enviar mensajes a un tema por lotes.
this.queueManager.SendBatchAsync(lowMessages).Wait();
...
this.queueManager.SendBatchAsync(highMessages).Wait();
●● Introducción a la mensajería asincrónica. Es posible que un servicio de consumidor que procesa una
solicitud necesite enviar una respuesta a la instancia de la aplicación que envió la solicitud. Proporciona
información sobre las estrategias que se pueden usar para implementar mensajes de solicitud o respuesta.
●● Patrón de limitación. Puede implementar la limitación mediante el uso de colas. Se pueden usar
mensajes con prioridad para asegurarse de que se da prioridad a las solicitudes de aplicaciones
●● Guía de escalado automático. Se puede escalar el tamaño del grupo de procesos de consumidor que
administra una cola en función de la longitud de dicha cola. Esta estrategia puede ayudar a mejorar el
rendimiento, sobre todo en el caso de los grupos que administran mensajes de prioridad alta.
Contexto y problema
Muchas soluciones en el cloud implican la ejecución de tareas que invocan servicios. En este entorno,
si un servicio se somete a cargas elevadas intermitentes, puede causar problemas de rendimiento o de
fiabilidad.
Un servicio puede formar parte de la misma solución que las tareas que lo usan o bien ser un servicio de
terceros que proporciona acceso a recursos de uso frecuente, como una memoria caché o un servicio de
almacenamiento. Si varias tareas simultáneas usan el mismo servicio, puede ser difícil predecir el volumen
de solicitudes para el servicio en cualquier momento.
Un servicio puede experimentar picos de demanda que hacen que se sobrecargue y no pueda responder a
las solicitudes de manera puntual. Asimismo, si un servicio se desborda con un número elevado de solicitudes
simultáneas, puede generar un error al no poder administrar la contención causada por las solicitudes.
Solución
Refactorice la solución e inserte una cola entre la tarea y el servicio. La tarea y el servicio se ejecutan
de forma asincrónica. La tarea envía un mensaje con los datos requeridos por el servicio a una cola. La
cola actúa como búfer y almacena el mensaje hasta que el servicio lo recupera. El servicio recupera los
mensajes de la cola y los procesa. Las solicitudes de diversas tareas, que pueden generarse a un ritmo muy
variable, pueden pasarse al servicio a través de la misma cola de mensajes. En esta ilustración se muestra
el uso de una cola para nivelar la carga en un servicio.
●● Ayuda a maximizar la disponibilidad, ya que los posibles retrasos de los servicios no tienen un efecto
inmediato y directo en la aplicación, que puede seguir enviando mensajes a la cola incluso cuando el
servicio no está disponible o no procesa los mensajes.
●● Ayuda a maximizar la escalabilidad, ya que se puede modificar tanto el número de colas como de
servicios para satisfacer la demanda.
●● Ayuda a controlar los costes, ya que el número de instancias del servicio implementadas tiene que ser
suficiente para satisfacer únicamente la carga media, no la carga máxima.
Algunos servicios implementan la limitación cuando la demanda alcanza un umbral que, en caso de
traspasarse, podría generar un error del sistema. La limitación puede reducir la funcionalidad disponible.
Para asegurarse de no alcanzar dicho umbral, puede implementar la nivelación de carga con estos servicios.
Problemas y consideraciones
Tenga en cuenta los puntos siguientes a la hora de decidir cómo implementar este patrón:
●● Debe implementarse lógica de aplicación que controle el ritmo al que los servicios administran
los mensajes, para evitar el desbordamiento del recurso de destino. Evite pasar picos de demanda
inesperados a la etapa siguiente del sistema. Pruebe el sistema en carga para asegurarse de que
proporciona la nivelación necesaria y, para ello, ajuste el número de colas y de instancias del servicio
que administran los mensajes.
●● Las colas de mensajes son un mecanismo de comunicación unidireccional. Si una tarea espera
respuesta de un servicio, puede que sea necesario implementar un mecanismo que el servicio pueda
usar para este fin. Para obtener más información, consulte Introducción a la mensajería asincrónica.
●● Tenga cuidado si aplica el escalado automático a los servicios que reciben las solicitudes en la cola.
Esto puede causar una mayor contención de los recursos compartidos por estos servicios y reducir
la eficacia del uso de la cola para nivelar la carga.
Sin embargo, no lo es si la aplicación espera una respuesta del servicio con una latencia mínima.
Ejemplo
Un rol web de Microsoft Azure almacena datos mediante un servicio de almacenamiento independiente.
Si se ejecuta un gran número de instancias del rol web de forma simultánea, es posible que el servicio de
almacenamiento no pueda responder a las solicitudes con la rapidez suficiente para evitar que se agote el
tiempo de espera o se genere un error. En esta ilustración se resalta un servicio que se satura debido a un
número elevado de solicitudes simultáneas de instancias de un rol web.
Patrón de reintento
Permita que una aplicación pueda controlar los errores transitorios cuando intenta conectarse a un servicio
o un recurso de red mediante un reintento transparente de las operaciones con errores. Esto puede
mejorar la estabilidad de la aplicación.
Contexto y problema
Una aplicación que se comunica con elementos que se ejecutan en el cloud tiene que ser sensible a los errores
transitorios que pueden ocurrir en este entorno. Entre estos errores se incluyen la pérdida momentánea de la
conectividad de red con los componentes y los servicios, la falta temporal de disponibilidad de un servicio o el
agotamiento del tiempo de espera que se produce cuando un servicio está ocupado.
Estos errores suelen corregirse automáticamente y, si la acción que desencadenó el error se repite tras
cierto tiempo, es posible que se realice correctamente. Por ejemplo, un servicio de base de datos que
procesa un gran número de solicitudes simultáneas puede implementar una estrategia de limitación
que rechace temporalmente cualquier otra solicitud hasta que la carga de trabajo disminuya. Quizás
una aplicación que intenta acceder a la base de datos no pueda conectarse pero, si lo vuelve a intentar
transcurrido cierto tiempo, es posible que lo consiga.
Solución
En el cloud son frecuentes los errores transitorios y una aplicación debe diseñarse para administrarlos
con elegancia y transparencia. Esto minimiza los efectos que los errores pueden tener en las tareas de
negocios que la aplicación realiza.
Si una aplicación detecta un error cuando intenta enviar una solicitud a un servicio remoto, puede
administrar el error mediante las estrategias siguientes:
●● Cancelar. Si se observa que el error no es transitorio o es poco probable que la acción se realice
correctamente en caso de repetirse, la aplicación debe cancelar la operación y notificar una excepción.
Por ejemplo, un error de autenticación debido a que se proporcionaron credenciales no válidas no se
va a solucionar, independientemente del número de veces que se repita.
●● Reintentar después de un retraso. Si el error se produce debido a un error común relacionado con la
conectividad o la falta de disponibilidad, puede que la red o el servicio necesiten un breve período de
tiempo mientras se corrigen los problemas de conectividad o se elimina el trabajo pendiente.
La aplicación debe esperar un tiempo adecuado antes de reintentar la solicitud.
Para los errores transitorios más habituales, el período entre reintentos debe elegirse de forma que
abarque las solicitudes de varias instancias de la aplicación con la mayor uniformidad posible. Esto reduce
la posibilidad de que un servicio ocupado se siga sobrecargando. Si varias instancias de una aplicación
saturan continuamente un servicio con solicitudes de reintento, el servicio tardará más tiempo en
recuperarse.
Si la solicitud sigue generando errores, la aplicación puede esperar y realizar otro intento. Si es necesario,
el proceso puede repetirse con retrasos incrementales entre los reintentos, hasta haber probado con
un número máximo de solicitudes. El retraso puede incrementarse de forma progresiva o exponencial,
en función del tipo de error y de la probabilidad de que se corrija durante ese tiempo.
La aplicación debe encapsular todos los intentos de acceso a un servicio remoto en el código
que implementa una política de reintentos que coincide con una de las estrategias mencionadas
anteriormente. Las solicitudes enviadas a servicios diferentes pueden estar sujetas a políticas distintas.
Algunos proveedores proporcionan bibliotecas que implementan políticas de reintentos, donde la
aplicación puede especificar el número máximo de reintentos, el tiempo entre ellos y otros parámetros.
Una aplicación debe registrar los detalles de los errores y de las operaciones erróneas. Esta información
es útil para los operadores. Si un servicio está ocupado o no disponible con frecuencia, suele deberse
a que el servicio ha agotado sus recursos. Para reducir la frecuencia de estos errores, escale el servicio
Microsoft Entity Framework ofrece servicios para reintentar las operaciones de base de datos. Además,
la mayoría de los SDK de cliente y los servicios de Azure incluyen un mecanismo de reintento. Para
obtener más información, consulte la guía de reintentos para servicios específicos.
Problemas y consideraciones
Debe considerar los puntos siguientes a la hora de decidir cómo implementar este patrón.
Una política de reintentos agresiva con un retraso mínimo entre los intentos y gran cantidad de reintentos,
puede degradar aún más un servicio ocupado que se ejecuta al límite de su capacidad, o casi. Esta política
de reintentos también puede afectar a la capacidad de respuesta de la aplicación si se intenta realizar una
operación con errores continuamente.
Si una solicitud sigue generando errores después de un número de reintentos significativo, es mejor que
la aplicación evite que se dirijan más solicitudes al mismo recurso y que simplemente notifique el error
de forma inmediata. Cuando el período expire, la aplicación puede dejar pasar una o más solicitudes
provisionalmente para ver si se procesan correctamente. Para obtener más detalles de esta estrategia,
consulte el patrón de interruptor de circuito.
Una solicitud a un servicio puede generar errores por diversas razones y producir distintas excepciones
en función de la naturaleza del error. Algunas excepciones indican un error que puede resolverse
rápidamente, mientras que otras indican un error más permanente. Es útil para la política de reintentos
ajustar el tiempo entre reintentos en función del tipo de excepción.
Piense en la forma en que reintentar una operación que forma parte de una transacción afectará a la
coherencia global de esta última. Ajuste la política de reintentos para las operaciones transaccionales a fin
de maximizar las posibilidades de éxito y reducir la necesidad de deshacer todos los pasos de la transacción.
Implemente lógica de reintento solo allí donde se entienda todo el contexto de una operación de error.
Por ejemplo, si una tarea que contiene una política de reintentos invoca a otra que también contiene
una política de este tipo, el procesamiento puede sufrir largos retrasos debido a este nivel adicional de
reintentos. Puede ser preferible configurar la tarea de nivel inferior para el error inmediato y notificar del
motivo del error a la tarea que la invoca. A continuación, la tarea de nivel superior puede administrar el
error en función de su propia política.
Es importante registrar todos los errores de conectividad que causan un reintento para poder identificar
los problemas subyacentes con la aplicación, los servicios o los recursos.
Patrón de Programador-Agente-Supervisor
Coordine un conjunto de acciones distribuidas como una operación única. Si cualquiera de las acciones
genera errores, intente administrarlos de forma transparente o deshaga el trabajo realizado para que la
operación al completo se realice correctamente o no, como un todo. Esto puede agregar resistencia a un
sistema distribuido, ya que le permite recuperar y reintentar acciones que no se pudieron realizar debido
a excepciones transitorias y errores permanentes o de proceso.
Contexto y problema
Una aplicación realiza tareas que incluyen una serie de pasos, algunos de los cuales pueden invocar
servicios remotos o acceder a recursos remotos. Los pasos individuales pueden ser independientes entre
sí, si bien se organizan mediante la lógica de aplicación que implementa la tarea.
Siempre que sea posible, la aplicación debe asegurarse de que la tarea se ejecuta hasta el final
y de resolver cualquier error que pueda ocurrir al acceder a los servicios o recursos remotos. Los
errores pueden producirse por muchas razones. Por ejemplo, puede que la red esté inactiva, que las
comunicaciones se hayan interrumpido, que un servicio remoto no responda o tenga un estado inestable,
o incluso que un recurso remoto esté temporalmente inaccesible debido a posibles restricciones de
los recursos. En muchos casos, los errores serán transitorios y pueden abordarse mediante el patrón de
reintento.
Si la aplicación detecta un error más persistente del que no puede recuperarse con facilidad, debe ser
capaz de restaurar el sistema a un estado coherente y de garantizar la integridad de toda la operación.
Solución
El patrón de Programador-Agente-Supervisor define los actores siguientes, que coordinan los pasos que
deben realizarse como parte de la tarea global.
●● El Programador organiza los pasos que componen la tarea que se va a ejecutar y coordina su
funcionamiento. Los pasos pueden combinarse en una canalización o en un flujo de trabajo. El
Programador es el responsable de garantizar que los pasos del flujo de trabajo se realicen en el orden
correcto. Al realizarse cada uno de los pasos, el Programador registra el estado del flujo de trabajo,
como "paso no iniciado aún", "paso en ejecución" o "paso completado". La información de estado
también debe incluir el límite de tiempo máximo permitido para la finalización del paso, llamado
tiempo de finalización. Si un paso requiere acceso a un recurso o servicio remoto, el Programador
invoca al Agente adecuado y le pasa los detalles del trabajo que debe realizarse. El Programador suele
comunicarse con un Agente mediante mensajes asincrónicos de solicitud/respuesta, que pueden
implementarse mediante colas, aunque también se pueden usar otras tecnologías de mensajes
distribuidos.
●● El Supervisor controla el estado de los pasos en la tarea que realiza el Programador. Se ejecuta
periódicamente (la frecuencia es específica del sistema) y examina el estado de los pasos que
mantiene el Programador. Si detecta que el tiempo de espera se ha agotado o se ha producido algún
error, organiza el Agente adecuado para recuperar el paso o ejecutar la acción correctiva adecuada
(que puede incluir la modificación del estado de un paso). Tenga en cuenta que el Programador y los
Agentes son los encargados de implementar las acciones de recuperación o correctivas. El Supervisor
solo tiene que solicitar que se realicen estas acciones.
Cuando la aplicación está lista para ejecutar una tarea, envía una solicitud al Programador. El Programador
registra la información de estado inicial sobre la tarea y sus pasos (por ejemplo, paso no iniciado aún)
en el almacén de estado y, después, comienza a realizar las operaciones que define el flujo de trabajo.
Al iniciar cada paso, el Programador actualiza la información de estado del paso concreto en dicho
almacén (por ejemplo, paso en ejecución).
Si un paso hace referencia a un recurso o servicio remoto, el Programador envía un mensaje al Agente
adecuado. El mensaje contiene la información que el Agente necesita para pasar al servicio o acceder
al recurso, además del tiempo de finalización para la operación. Si el Agente completa la operación
correctamente, devuelve una respuesta al Programador. Entonces, el Programador puede actualizar
la información de estado en el almacén de estado (por ejemplo, paso completado) y realizar el paso
siguiente. Este proceso continúa hasta que se completa toda la tarea.
Un Agente puede implementar cualquier lógica de reintento necesaria para realizar su trabajo.
Sin embargo, si el Agente no completa su trabajo antes de que expire el tiempo de finalización, el
Programador da por hecho que la operación es errónea. En ese caso, el Agente debe detener su trabajo
e intentar no devolver nada al Programador (ni siquiera un mensaje de error) ni probar cualquier tipo de
recuperación. El motivo de esta restricción es que puede que haya otra instancia del Agente programada
para ejecutar el paso incorrecto, después de haberse agotado el tiempo de espera de este o de generar
un error (este proceso se describe más adelante).
Si se produce un error del Agente, el Programador no recibirá ninguna respuesta. El patrón no distingue
entre un paso para el que se ha agotado el tiempo de espera y otro con errores en sí.
Si se agota el tiempo de espera de un paso o este genera errores, el almacén de estado contendrá un
registro que indica que el paso se está ejecutando, pero el tiempo de finalización habrá transcurrido.
El Supervisor busca pasos como este e intenta recuperarlos. Una estrategia posible es que el Supervisor
actualice el valor de finalización para ampliar el tiempo disponible para completar el paso y que,
a continuación, envíe un mensaje al Programador donde se identifique el paso en el que se ha agotado
el tiempo de espera. Después, el Programador puede intentar repetir el paso. Sin embargo, este diseño
requiere que las tareas sean idempotentes.
Puede darse el caso de que el Supervisor tenga que evitar el reintento de un mismo paso si este genera
errores o expira continuamente. Para ello, puede conservar un recuento de reintentos para cada paso,
junto con la información de estado, en el almacén de estado. Si el recuento supera un umbral predefinido,
el Supervisor puede adoptar la estrategia de esperar durante un período de tiempo prolongado antes
de notificar al Programador que debe reintentar el paso, con la expectativa de que el error se resuelva
durante este tiempo. Como alternativa, el Supervisor puede enviar un mensaje al Programador para
solicitar que se deshaga la tarea entera mediante la implementación de un patrón de transacciones
de compensación. Este enfoque dependerá de que el Programador y los Agentes proporcionen la
información necesaria para implementar las operaciones de compensación para cada paso completado
correctamente.
La ventaja clave de este patrón es que el sistema es resistente en caso de errores temporales o
irrecuperables inesperados y puede construirse de forma que se recupere automáticamente. Por ejemplo,
si se produce un error de un Agente o del Programador, puede iniciarse uno nuevo y el Supervisor
puede organizar que se reanude una tarea. Si el Supervisor falla, puede iniciarse otra instancia que
asuma el control a partir del punto donde se produjo el error. Si el Supervisor está programado para
ejecutarse periódicamente, puede iniciarse una nueva instancia automáticamente después de un intervalo
predefinido. El almacén de estado puede replicarse para alcanzar un grado de resistencia aún mayor.
Problemas y consideraciones
Debe considerar los puntos siguientes a la hora de decidir cómo implementar este patrón:
●● Este patrón puede ser difícil de implementar y requiere pruebas exhaustivas de cada modo de error
posible del sistema.
●● La frecuencia con la que se ejecuta el Supervisor es importante. Debe ejecutarse con una frecuencia
suficiente para impedir que los pasos con errores bloqueen una aplicación durante un período
prolongado y, a la vez, no tan a menudo como para convertirse en una sobrecarga.
●● Los pasos que realiza un Agente pueden ejecutarse más de una vez. La lógica que implementa estos
pasos debe ser idempotente.
Puede que este patrón no sea adecuado para las tareas que no invocan servicios remotos ni acceden
a recursos remotos.
Ejemplo
Se ha implementado en Microsoft Azure una aplicación web que implementa un sistema de comercio
electrónico. Los usuarios pueden ejecutarla para buscar los productos disponibles y realizar pedidos. La
interfaz de usuario se ejecuta como rol web y los elementos de procesamiento de pedidos de la aplicación
se implementan como un conjunto de roles de trabajo. Parte de la lógica de procesamiento de pedidos
implica acceder a un servicio remoto. Este aspecto del sistema puede ser propenso a errores duraderos
o transitorios. Por este motivo, los diseñadores usan el patrón de Programador-Agente-Supervisor a fin de
implementar los elementos de procesamiento de pedidos del sistema.
●● LockedBy. El identificador de instancia del rol de trabajo que administra el pedido. Puede haber varias
instancias del rol de trabajo que ejecuten el Programador, pero cada pedido debe administrarse en
una sola instancia.
●● ProcessState. Estado actual de la tarea que administra el pedido. Los estados posibles son:
● Pendiente. El pedido ya se ha creado pero aún no ha se iniciado el procesamiento.
● En procesamiento. El pedido se está procesando.
● Procesado. El pedido se ha procesado correctamente.
● Error. No se pudo realizar el procesamiento del pedido.
En esta información de estado, el campo OrderID se copia del identificador correspondiente del nuevo
pedido. Los campos LockedBy y CompleteBy se establecen como nulos, el campo ProcessState se
establece en Pendiente y el campo FailureCount se establece en 0.
En este ejemplo, la lógica de administración de pedidos es relativamente simple y tiene un único paso que
invoca un servicio remoto. En un escenario más complejo con múltiples pasos, el proceso de envío puede
implicar a varios de ellos, por lo que se crearían diversos registros en el almacén de estado y cada uno de
ellos describiría el estado de un paso individual.
El Programador también se ejecuta como parte de un rol de trabajo e implementa la lógica de negocios
que administra el pedido. Una instancia del Programador que sondea nuevos pedidos examina el almacén
de estado para encontrar registros en los que el campo LockedBy sea nulo y ProcessState esté pendiente.
Cuando el Programador encuentra un pedido nuevo, rellena inmediatamente el campo LockedBy con
su identificador de instancia propio, establece un valor adecuado en el campo CompleteBy y define
ProcessState como En procesamiento. El código está diseñado para ser exclusivo e individual, a fin de
garantizar que dos instancias simultáneas del Programador no intenten administrar un mismo pedido
al mismo tiempo.
A continuación, el Programador ejecuta el flujo de trabajo empresarial para procesar el pedido de forma
asincrónica y pasa el valor del campo OrderID del almacén de estado. El flujo de trabajo encargado del
pedido recupera los detalles de este de la base de datos de pedidos y realiza su trabajo. Cuando en un
paso del flujo de trabajo de procesamiento de pedidos debe invocarse al servicio remoto, se usa un
Agente. El paso del flujo de trabajo se comunica con el Agente mediante un par de colas de mensajes
de Azure Service Bus que actúan como canal de solicitud/respuesta. En la ilustración se muestra una vista
de alto nivel de la solución.
Si el tiempo de finalización expira antes de que el Agente reciba una respuesta del servicio remoto,
el Agente detiene su procesamiento y termina de administrar el pedido. Del mismo modo, si el flujo de
trabajo que administra el pedido sobrepasa el tiempo de finalización, también se termina. En ambos casos,
el estado del pedido en el almacén de estado permanece como En procesamiento, pero el tiempo de
finalización indica que el tiempo para procesar el pedido ha pasado y se considera que el proceso no se
ha realizado correctamente. Tenga en cuenta que, si el Agente que accede al servicio remoto o el flujo de
trabajo que administra el pedido (o ambos) terminan de forma inesperada, la información del almacén de
estado quedará también establecida como En procesamiento y tendrá un valor de tiempo de finalización
expirado.
El Supervisor examina periódicamente el almacén de estado para buscar pedidos cuyo valor de tiempo
de finalización haya expirado. Si encuentra un registro, incrementa el valor del campo FailureCount. Si el
valor de número de errores está por debajo de un umbral especificado, el Supervisor restablece el campo
LockedBy como nulo, actualiza el campo CompleteBy con un nuevo tiempo de caducidad y establece
el valor del campo ProcessState en Pendiente. Una instancia del Programador puede elegir este pedido
y realizar su procesamiento como se ha indicado. Si el valor de número de errores supera un umbral
especificado, se da por hecho que el motivo del error no es transitorio. El Supervisor establece el estado
del pedido como Error y genera un evento que alerta a un operador.
En este ejemplo, el Supervisor se implementa en un rol de trabajo independiente. Se pueden usar diversas
estrategias para organizar la ejecución de la tarea del Supervisor, incluido el uso del servicio Scheduler
de Azure (no debe confundirse con el componente Programador de este patrón). Para obtener más
información sobre el servicio Scheduler de Azure, visite la página de Scheduler.
Aunque no se muestra en este ejemplo, puede que el Programador tenga que mantener informada a la
aplicación que envió el pedido acerca del progreso y del estado del mismo. La aplicación y el Programador
están aislados entre sí para eliminar cualquier dependencia entre ellos. La aplicación no sabe qué instancia del
Programador administra el pedido y este a su vez desconoce qué instancia específica de la aplicación lo envió.
Para poder notificar el estado del pedido, la aplicación puede usar su propia cola de respuestas privada.
Los detalles de esta cola de respuestas se incluirían como parte de la solicitud dirigida al proceso de envío,
que incluiría esta información en el almacén de estado. A continuación, el Programador enviaría mensajes
a esta cola en los que se indicaría el estado del pedido (solicitud recibida, pedido completado, pedido con
errores, etc.) Además, debe incluir el identificador del pedido en los mensajes para que la aplicación pueda
correlacionarlos con la solicitud original.
●● Patrón de interruptor de circuito. Un Agente puede usar este patrón para administrar los errores que
tardan un plazo de tiempo variable en corregirse al conectarse a un recurso o servicio remoto.
●● Patrón de elección del líder. Puede ser necesario para coordinar las acciones de varias instancias
●● Referencia 6: Una saga de sagas. Ejemplo que muestra cómo el patrón CQRS usa un administrador
de procesos (parte de la guía de CQRS Journey).
Patrón de particionamiento
Divide un almacén de datos en un conjunto de particiones horizontales. Esto puede mejorar la
escalabilidad al almacenar grandes volúmenes de datos y al acceder a ellos.
Contexto y problema
Un almacén de datos hospedado por un solo servidor puede estar sujeto a las limitaciones siguientes:
●● Espacio de almacenamiento. Se espera que un almacén de datos para una aplicación en el cloud
a gran escala contenga un volumen de datos elevado que puede aumentar significativamente con
el tiempo. Normalmente, un servidor proporciona una cantidad finita de almacenamiento en disco,
pero pueden reemplazarse los discos existentes por otros más grandes o agregar más discos a una
máquina a medida que aumenta el volumen de datos. Sin embargo, el sistema llegará a alcanzar un
límite en el que no será posible incrementar la capacidad de almacenamiento de forma fácil en un
servidor dado.
●● Recursos informáticos. Una aplicación en el cloud debe admitir un gran número de usuarios
simultáneos, cada uno de los cuales ejecuta consultas que recuperan información del almacén
de datos. Es posible que un servidor único que hospede el almacén de datos no pueda ofrecer la
potencia de procesamiento necesaria para admitir esta carga. Los usuarios obtendrían tiempos de
respuesta más largos y se producirían errores frecuentes al agotarse el tiempo de espera cuando
las aplicaciones intentaran almacenar y recuperar datos. Podría agregarse memoria o actualizar los
procesadores, pero el sistema llegaría a un límite en el que no sería posible seguir aumentando los
recursos informáticos.
●● Ancho de banda de red. El rendimiento de un almacén de datos que se ejecuta en un único servidor
se rige, en última instancia, por la velocidad a la que el servidor puede recibir solicitudes y enviar
respuestas. El volumen del tráfico de red puede sobrepasar la capacidad de la red que se usa para
conectarse al servidor, lo que daría lugar a solicitudes erróneas.
●● Geografía. Puede que sea necesario almacenar los datos generados por usuarios específicos en la
misma región en la que se encuentran debido a motivos legales, de cumplimiento o de rendimiento,
o reducir la latencia de acceso a los datos. Si los usuarios están dispersos en distintos países o regiones,
puede que no sea posible almacenar todos los datos de la aplicación en un almacén de datos único.
Agregar capacidad de disco, potencia de procesamiento, memoria y conexiones de red para escalar
verticalmente puede posponer los efectos de algunas de estas limitaciones, pero seguramente solo se
trate de una solución temporal. Una aplicación comercial en el cloud capaz de admitir un gran número
de usuarios y volúmenes de datos elevados debe ser capaz de escalar de forma prácticamente indefinida,
por lo que el escalado vertical no es necesariamente la mejor solución.
●● Un sistema puede utilizar hardware listo para usar en lugar de equipos caros y especializados para
cada nodo de almacenamiento.
●● Puede reducir la contención y mejorar el rendimiento al equilibrar la carga de trabajo entre las
distintas particiones.
●● En el cloud, las particiones pueden ubicarse físicamente cerca de los usuarios que van a acceder
a los datos.
Al dividir un almacén de datos en particiones, decida qué datos deben colocarse en cada una de ellas.
Normalmente, una partición contiene elementos que se engloban dentro de un rango determinado por
uno o más atributos de los datos. Estos atributos forman la clave de partición, que debe ser estática y no
estar basada en datos que pueden cambiar.
El particionamiento organiza los datos físicamente. Cuando una aplicación almacena y recupera datos, la
lógica de particionamiento dirige la aplicación a la partición adecuada. Dicha lógica puede implementarse
como parte del código de acceso a datos en la aplicación. También puede implementarla el sistema de
almacenamiento de datos, si admite el particionamiento de forma transparente.
Para garantizar un rendimiento y una escalabilidad óptimos, es importante dividir los datos de forma
adecuada para los tipos de consultas que la aplicación realiza. En muchos casos, es poco probable que el
esquema de particionamiento coincida exactamente con los requisitos de cada consulta. Por ejemplo, en
un sistema multiinquilino, puede que una aplicación tenga que recuperar datos de inquilino mediante el
identificador correspondiente, pero también puede que tenga que buscar estos datos basándose en otros
atributos, como el nombre o la ubicación del inquilino. Para afrontar estas situaciones, implemente una
estrategia de particionamiento con una clave de partición que admita las consultas que se realizan con
más frecuencia.
Si las consultas recuperan datos de forma periódica mediante una combinación de valores de atributos,
seguramente podrá enlazar atributos entre sí para definir una clave de partición compuesta. Como
alternativa, use un patrón como el de tabla de índices para proporcionar una búsqueda rápida de los
datos basada en atributos que la clave de partición no cubre.
La asignación entre la clave de partición y el almacenamiento físico puede basarse en particiones físicas
en las que cada clave de partición se asigna a una partición física. Una alternativa más flexible para
reequilibrar las particiones es el particionamiento virtual, donde las claves de partición se asignan al
mismo número de particiones virtuales que, a su vez, se asignan a un número menor de particiones
físicas. En este enfoque, una aplicación localiza los datos con una clave de partición que hace referencia
a una partición virtual y, a su vez, el sistema asigna las particiones virtuales a particiones físicas de forma
transparente. La asignación entre una partición virtual y una física puede cambiar sin necesidad de
modificar el código de la aplicación para que use un conjunto distinto de claves de partición.
La estrategia de rango. Esta estrategia agrupa los elementos relacionados en la misma partición y los
ordena por clave de partición: las claves de partición son secuenciales. Es útil para las aplicaciones que
suelen recuperar conjuntos de elementos mediante consultas por rango (consultas que devuelven un
conjunto de elementos de datos para una clave de partición que se engloba en un rango determinado).
Por ejemplo, si una aplicación necesita buscar de forma periódica todos los pedidos realizados en un
mes determinado, estos datos pueden recuperarse de forma más rápida si todos los pedidos de un mes
se almacenan por orden de fecha y hora en la misma partición. Si cada uno de los pedidos se almacena
en una partición distinta, tendrán que realizarse un gran número de consultas puntuales (consultas que
devuelven un solo elemento de datos) para recuperarlos individualmente. En la ilustración siguiente se
muestra el almacenamiento de conjuntos secuenciales (rangos) de datos en una partición.
La estrategia de hash. El objetivo de esta estrategia es reducir las posibilidades de puntos calientes
(particiones que reciben una cantidad desproporcionada de la carga). Distribuye los datos entre las
particiones de forma que logra un equilibrio entre el tamaño de cada partición y la carga media de cada
una de ellas. La lógica de particionamiento calcula la partición en la que se va a almacenar un elemento en
función de un hash de uno o más atributos de los datos. La función de uso de hash elegida debe distribuir
los datos de manera uniforme entre las particiones, para lo que posiblemente inserte algún elemento
aleatorio en el proceso. En la ilustración siguiente se muestran datos de inquilinos de particionamiento
que se basan en un hash de identificadores de inquilino.
●● Búsqueda. Ofrece un mayor control sobre la forma en que se configuran y se usan las particiones.
El uso de particiones virtuales reduce el impacto al reequilibrar los datos, ya que pueden agregarse
nuevas particiones físicas para homogeneizar la carga de trabajo. La asignación entre una partición
virtual y las particiones físicas que la implementan puede modificarse sin afectar al código de
aplicación que usa una clave de partición para almacenar y recuperar datos. La búsqueda de
ubicaciones de partición puede imponer una sobrecarga adicional.
●● Rango. Es fácil de implementar y funciona bien con consultas por rango, ya que suelen capturar
varios elementos de datos de una sola partición en una operación única. Esta estrategia ofrece una
administración más fácil de los datos. Por ejemplo, si los usuarios de una misma región están en la
misma partición, se pueden programar las actualizaciones por zona horaria en función del patrón
de demanda y carga local. Sin embargo, esta estrategia no proporciona un equilibrio óptimo entre
las particiones, ya que reequilibrarlas es difícil y puede que no resuelva el problema de las cargas
desiguales si la mayoría de la actividad es para las claves de partición adyacentes.
●● Hash. Esta estrategia es más adecuada para llevar a cabo una distribución más uniforme de la carga y
los datos. El enrutamiento de solicitudes puede realizarse directamente mediante la función hash. No
es necesario mantener un mapa. Tenga en cuenta que el procesamiento del hash puede implicar una
sobrecarga adicional. Además, reequilibrar las particiones resulta difícil.
Los sistemas de particionamiento más habituales implementan uno de los enfoques descritos
anteriormente, pero también debe tener en cuenta los requisitos empresariales de sus aplicaciones
y sus patrones de uso de datos. Por ejemplo, en una aplicación multiinquilino:
●● Puede particionar los datos en función de la carga de trabajo. Puede separar los datos de inquilinos
muy volátiles en particiones independientes. Como resultado, puede incrementarse la velocidad de
acceso a datos de otros inquilinos.
●● Puede particionar los datos en función de la ubicación de los inquilinos. Se pueden tomar los datos
de los inquilinos de una región geográfica específica sin conexión para realizar la copia de seguridad
y el mantenimiento durante las horas de menos tráfico en esa región, mientras que los datos de los
inquilinos de otras regiones se mantienen online y están accesibles en su horario laboral.
●● A los inquilinos de alto valor se les pueden asignar sus propias particiones privadas, de alto
rendimiento y carga ligera, mientras que los de valor más bajo se puede esperar que compartan
particiones más ocupadas y densas.
Los datos de inquilinos que necesitan un alto grado de privacidad y aislamiento pueden almacenarse
en un servidor totalmente independiente.
●● Los datos de inquilinos que necesitan un alto grado de privacidad y aislamiento pueden almacenarse
en un servidor totalmente independiente.
Problemas y consideraciones
Tenga en cuenta los puntos siguientes a la hora de decidir cómo implementar este patrón:
●● La fragmentación es complementaria a otras formas de partición, como la partición vertical y la
partición funcional. Por ejemplo, una sola fragmentación puede incluir entidades que se han dividido
en sentido vertical y una partición funcional puede implementarse como diversas fragmentaciones.
Para obtener más información sobre la fragmentación, consulte Guía de partición de datos.
●● Mantenga las fragmentaciones equilibradas para que todas ellas se ocupen de un volumen similar
de E/S. Dado que los datos se insertan y se eliminan, es necesario reequilibrar periódicamente las
fragmentaciones para garantizar una distribución uniforme y reducir las posibilidades de conflictos.
Las operaciones de reequilibrio pueden consumir muchos recursos. Para reducir la necesidad de
efectuar operaciones de reequilibrio, debe estar preparado para crecer y, para ello, deberá asegurarse
de que cada fragmentación disponga del suficiente espacio libre para ocuparse del volumen de
cambios esperado. También debe desarrollar estrategias y secuencias de comandos que pueda utilizar
para equilibrar rápidamente las fragmentaciones si esto fuera necesario.
●● Utilice datos estables para las claves de fragmentación. Si cambia la clave de fragmentación,
es posible que el elemento de datos correspondiente tenga que transferirse entre las fragmentaciones,
lo cual incrementaría la cantidad de trabajo que deben realizar las operaciones de actualización. Por
este motivo, se recomienda evitar basar la clave de fragmentación en información que pueda ser
volátil. En su lugar, busque atributos que no varíen o que de forma natural formen una clave.
●● Asegúrese de que las claves de fragmentación sean únicas. Por ejemplo, evite utilizar campos que
se incrementen automáticamente como la clave de fragmentación. En algunos sistemas, los campos
de incrementación automática no se pueden coordinar entre las distintas fragmentaciones, lo que
podría traducirse en que los elementos de las diferentes fragmentaciones tengan la misma clave de
fragmentación.
●● Las fragmentaciones se puede localizar geográficamente para que los datos que contienen estén cerca
de las instancias de una aplicación que las utilice. Este enfoque puede mejorar considerablemente
el rendimiento, pero requiere una reflexión adicional para las tareas que deben acceder a múltiples
fragmentaciones en diferentes lugares.
Ejemplo
El siguiente ejemplo en C# se sirve de un conjunto de bases de datos SQL Server que hacen las veces de
fragmentaciones. Cada base de datos contiene un subconjunto de los datos que utiliza una aplicación.
La aplicación recupera los datos que se distribuyeron a través de las fragmentaciones mediante su propia
lógica de fragmentación (este es un ejemplo de una consulta de divergencia). Los detalles de los datos
que se encuentra en cada fragmentación se devuelven a través de un método llamado GetShards. Este
método devuelve una lista enumerable de objetos ShardInformation, donde el tipo ShardInformation
contiene un identificador para cada fragmentación y la cadena de conexión de SQL Server que deben
utilizar las aplicaciones para conectarse a la fragmentación (las cadenas de conexión no aparecen en el
ejemplo de código).
El código siguiente muestra cómo utiliza la aplicación la lista de objetos ShardInformation para realizar
una consulta que recupera datos desde cada fragmentación en paralelo. No se presentan los detalles de
la consulta, sin embargo, en este ejemplo los datos que se recuperan contienen una cadena que podría
contener información como el nombre de un cliente si las fragmentaciones incluyen los detalles de los
clientes. Los resultados se agregan a una colección ConcurrentBag para que la aplicación los procese.
Este patrón se denomina sidecar porque se asemeja a los sidecares que están unidos a las motocicletas.
En el patrón, el sidecar se vincula a una aplicación principal y ofrece funciones complementarias para la
aplicación. El patrón sidecar también comparte el mismo ciclo de vida que la aplicación principal, además,
se crea y quita con ella. El patrón sidecar se denomina en ocasiones patrón compañero y es un patrón de
descomposición.
Contexto y problema
En muchas ocasiones las aplicaciones y los servicios requieren funcionalidad relacionada, como
servicios de supervisión, registro, configuración y conectividad a red. Estas tareas periféricas se pueden
implementar a modo de componentes o servicios independientes.
Si la aplicación se divide en servicios, cada uno de ellos se puede generar en diferentes idiomas y con
diversas tecnologías. Aunque esto favorezca la flexibilidad, también conlleva que cada componente
deba tener sus propias dependencias y bibliotecas de idioma específicas para acceder a la plataforma
subyacente y a cualquier recurso que se comparta con la aplicación principal. Además, la implementación
de estas características como diferentes servicios puede añadir latencia a la aplicación. La gestión del
código y las dependencias de estas interfaces de idioma específicas también pueden incrementar
considerablemente la complejidad, en particular para el hosting, la implementación y la administración.
Solución
Coubique un conjunto coherente de tareas junto con la aplicación principal, pero colóquelo dentro de su
propio proceso o contenedor. Esto crea una interfaz homogénea para los servicios de la plataforma en los
diversos idiomas.
●● El sidecar puede tener acceso a los mismos recursos que la aplicación principal. Por ejemplo, un
sidecar puede supervisar los recursos del sistema que utiliza el mismo sidecar y la aplicación principal.
●● Dada su proximidad con la aplicación principal, no hay una latencia significativa al comunicarse entre sí.
El patrón de sidecar se utiliza por lo general con contenedores y se denomina contenedor de sidecar
o contenedor compañero.
Problemas y consideraciones
●● Piense en la implementación y formato de embalaje que va a utilizar para implementar servicios,
procesos o contenedores. Los contenedores funcionan bastante bien con el patrón de sidecar.
●● Antes de agregar funcionalidad a un sidecar, piense si funcionaría mejor como servicio independiente
o como un daemon más tradicional.
●● Es preciso que los componentes o las características estén coubicados en el mismo host que la aplicación.
●● Se necesita un servicio que comparta la totalidad del ciclo de vida de la aplicación principal, pero que
pueda actualizarse de forma independiente.
Ejemplo
El patrón de sidecar se puede aplicar a muchas situaciones. Estos son algunos ejemplos comunes:
●● API de la infraestructura. El equipo de desarrollo de infraestructuras crea un servicio que se
implementa junto con cada aplicación, en lugar de una biblioteca cliente específica de idioma para
acceder a la infraestructura. El servicio se carga como un sidecar y proporciona una capa común
de servicios de infraestructura, que incluye servicios de registro, datos de entorno, almacén de
configuración, detección, comprobaciones de estado y vigilancia. El sidecar también supervisa el
entorno del host de la aplicación principal, además procesa (o usa un contenedor) y registra la
información en un servicio centralizado.
●● Administrar NGINX/HAProxy. Implemente NGINX con un servicio de sidecar que supervise el estado
del entorno, después actualice el archivo de configuración de NGINX y recicle el proceso cuando se
necesite un cambio de estado.
●● Sidecar embajador. Implemente un servicio embajador a modo de sidecar. La aplicación realiza las
llamadas a través del embajador. El embajador se encarga del registro de solicitudes, el enrutamiento,
la interrupción de circuitos y otras características relativas a la conectividad.
●● Proxy de descarga. Coloque un proxy de NGINX frente a una instancia de servicio node.js para
gestionar la entrega de contenido de archivos estáticos para el servicio.
Orientación relacionada
• Patrón embajador
Contexto y problema
Las aplicaciones web suelen incluir algunos elementos de contenido estático. Es posible que este contenido
estático incluya páginas HTML y otros recursos como imágenes y documentos que están disponibles para
clientes, bien porque forman parte de una página HTML (por ejemplo, imágenes online, hojas de estilo
y archivos de JavaScript en el cliente) o a modo descarga independiente (como documentos PDF).
Pese a que los servidores web están bien definidos para optimizar las solicitudes a través de la ejecución
eficiente de código de páginas dinámicas y el almacenamiento de resultados en la memoria caché, tienen
que gestionar peticiones para descargar contenido estático. Esto consume ciclos de procesamiento que en
la mayoría de los casos podrían utilizarse de forma más eficaz.
Solución
En la mayoría de los entornos de hosting en el cloud es posible reducir al mínimo la necesidad de utilizar
instancias de cálculo (por ejemplo, utilice una instancia más pequeña o menos instancias); para ello,
coloque algunos de los recursos de la aplicación y las páginas estáticas en un servicio de almacenamiento.
El consumo de recursos para el almacenamiento hospedado en el cloud es, por lo general, muy inferior
que para las instancias de cálculo.
Problemas y consideraciones
Tenga en cuenta los puntos siguientes a la hora de decidir cómo implementar este patrón:
●● El servicio de almacenamiento hospedado debe exponer un extremo HTTP al que puedan obtener acceso
los usuarios para descargar recursos estáticos. Algunos servicios de almacenamiento admiten también
HTTPS, por lo que es posible hospedar recursos en servicios de almacenamiento que requieran SSL.
●● Para obtener un rendimiento y disponibilidad óptimos, piense en utilizar una red de distribución
de contenidos (CDN) para almacenar en memoria caché los contenidos del contenedor de
almacenamiento en múltiples centros de datos a lo largo y ancho del planeta. Sin embargo,
lo más probable es que los servicios de la CDN sean de pago.
Lo más habitual es que de forma predeterminada las cuentas de almacenamiento sean de replicación
geográfica con el fin de aportar resiliencia respecto a eventos que puedan afectar a los centros de
datos. Esto indica que la dirección IP puede cambiar, pero la dirección URL seguirá siendo la misma.
●● Cuando algunos de los contenidos están en una cuenta de almacenamiento y otros se hospedan en
una instancia de proceso, implementar y actualizar una aplicación se hace más complejo. Es posible
que tenga que efectuar implementaciones separadas y generar una versión de la aplicación y el
contenido para administrarla con mayor facilidad, especialmente cuando el contenido estático incluye
archivos de script o componentes de interfaz de usuario. Sin embargo, si solamente hay que actualizar
los recursos estáticos, bastaría con cargarlos en la cuenta de almacenamiento sin necesidad de volver
a desplegar el paquete de la aplicación.
Ejemplo
Un explorador web puede obtener acceso directamente al contenido estático en Azure Blob Storage.
Azure ofrece una interfaz basada en HTTP sobre almacenamiento que puede exponerse públicamente
a los clientes. Por ejemplo, los contenidos en un contendor del almacenamiento Azure Blob se exponen
mediante una dirección URL con el siguiente formato:
http://[ nombre-cuenta-almacenamiento ].blob.core.windows.net/[ nombre-contenedor ]/[ nombre-archivo ]
Cuando se carga contenido es necesario crear uno o más contendores de blobs para conservar los
archivos y los documentos. Tenga en cuenta que los permisos predeterminados para los contenedores
nuevos son privados y deben cambiarse a públicos para que los clientes puedan tener acceso a los
contenidos. Si es necesario proteger el contenido de accesos anónimos, podrá implementar el Patrón de
llave de valet, por tanto, los usuarios deberán presentar un token válido para descargar los recursos.
En Conceptos de Blob service, se ofrece información acerca del almacenamiento de blob y las formas
de obtener acceso al mismo y utilizarlo.
Los enlaces en las páginas que se entregan al cliente deben especificar la dirección URL completa del
contenedor de blob y el recurso. Por ejemplo, una página que contenga un enlace a una imagen en un
contenedor público puede contener el siguiente código HTML.
<img src=”http://mystorageaccount.blob.core.windows.net/myresources/image1.png”
alt=”My image” />
Si los recursos están protegidos mediante una llave de valet, como una firma de acceso compartido de
Azure, esta firma se debe incluir en las direcciones URL de los enlaces.
En GitHub se encuentra disponible una solución llamada StaticContentHosting que utiliza almacenamiento
externo para recursos estáticos. El proyecto StaticContentHosting.Cloud contiene archivos de
configuración que especifican la cuenta de almacenamiento y el contendor que conserva el contenido
estático.
<Setting name=”StaticContent.StorageConnectionString”
value=”UseDevelopmentStorage=true” />
<Setting name=”StaticContent.Container” value=”static-content” />
La clase Settings del archivo Settings.cs del proyecto StaticContentHosting.Web contiene métodos para
extraer estos valores y generar un valor de cadena que contiene la dirección URL del contenedor de la
cuenta de almacenamiento en el cloud.
return url.Content(contentPath);
}
}
El archivo Index.cshtml de la carpeta Views\Home contiene un elemento de imagen que utiliza el método
StaticContentUrl para crear la dirección URL para su atributo src.
●● Patrón de llave de valet. Si se parte de la base de que los recursos de destino no están disponibles
para los usuarios anónimos es necesario implementar una seguridad en el almacén que conserve el
contenido estático. Describe cómo utilizar un token o una llave que ofrezca a los clientes un acceso
restringido a un recurso o servicio específicos como los servicios de almacenamiento hospedados en
el cloud.
Patrón de estrangulador
Migra progresivamente un sistema heredado reemplazando gradualmente las partes específicas
de funcionalidades con nuevas aplicaciones y servicios. Como se están sustituyendo las características
de los sistemas heredados, el nuevo sistema terminará por sustituir las características del sistema anterior,
de forma que quede estrangulando y pueda retirarlo.
Contexto y problema
Según los sistemas van envejeciendo, las herramientas de desarrollo, las tecnologías de hosting e
incluso las arquitecturas del sistema donde estas se generaron caen en desuso. A medida que se van
sumando características y funcionalidades nuevas, la complejidad de estas aplicaciones puede aumentar
drásticamente, por lo que será más complicado mantener o añadir nuevas características.
Sustituir completamente a un sistema complejo puede ser una gran empresa. Lo habitual es realizar
una migración gradual a un nuevo sistema, a la vez que se mantiene el antiguo para gestionar las
características que no se migraron aún. Sin embargo, cuando se ejecutan dos versiones diferentes
de una aplicación, los clientes deben saber dónde se encuentran características particulares. Cada vez
que se migra una función o servicio, los clientes deben actualizarse para apuntar a la nueva ubicación.
Solución
Sustituir gradualmente porciones específicas de funcionalidad con las aplicaciones y los servicios nuevos.
Crear un muro que intercepte las peticiones dirigidas al sistema back-end heredado. Este muro dirigirá las
peticiones a la aplicación heredada o a los nuevos servicios. Las características existentes se pueden migrar
gradualmente al sistema nuevo y los consumidores podrán seguir utilizando la misma interfaz, sin saber
que se está llevando a cabo algún tipo de migración.
Problemas y consideraciones
●● Piense cómo gestionar los servicios y almacenes de datos que potencialmente puedan utilizar sistemas
nuevos y heredados. Asegúrese de que ambos pueden tener acceso a estos recursos en paralelo.
●● Asegúrese de que el muro no se convierta en un punto único de fallos o un cuello de botella para
el rendimiento.
Utilice este patrón cuando vaya a migrar gradualmente una aplicación back-end a una arquitectura nueva.
●● Para sistemas más pequeños donde la complejidad de una sustitución integral es poca.
Patrón de limitación
Controla el consumo de recursos que utiliza una instancia de una aplicación, un inquilino individual o un
servicio completo. De esta forma, el sistema sigue funcionando y cumple los acuerdos de nivel de servicio,
incluso cuando los aumentos de la demanda imponen una carga extrema en los recursos.
Contexto y problema
La carga en una aplicación en el cloud normalmente varía con el tiempo en función del número de
usuarios activos o los tipos de actividades que realizan. Por ejemplo, habrá más usuarios activos durante
las horas laborables o es posible que el sistema deba efectuar análisis de cálculo que consumen muchos
recursos al final de cada mes. También es posible que se produzca un aumento súbito e inesperado
en la actividad. Si los requisitos de procesamiento del sistema sobrepasan la capacidad de los recursos
disponibles, el rendimiento será insuficiente e incluso podría interrumpirse. Si el sistema tiene que cumplir
con un determinado nivel de servicio, una interrupción de tal naturaleza sería inaceptable.
Hay muchas estrategias disponibles para gestionar las diversas cargas en el cloud, en función de los
objetivos de negocio de la aplicación. Una estrategia es utilizar el escalado automático para hacer
corresponder los recursos aprovisionados con las necesidades del usuario en un momento determinado.
Con esto se puede satisfacer sistemáticamente la demanda del usuario, al mismo tiempo que se optimizan
los recursos invertidos en la ejecución. Sin embargo, aunque el escalado automático pueda desencadenar
el aprovisionamiento de recursos adicionales, este no será inmediato. Si la demanda crece rápidamente,
puede haber una ventana de tiempo donde se produzca un déficit de recursos.
Solución
Una estrategia alternativa al escalado automático es permitir que las aplicaciones utilicen los recursos
hasta un límite y restringirlos cuando se alcance este límite. El sistema debe supervisar cómo está
utilizando los recursos para que, cuando el uso exceda el umbral, pueda limitar las peticiones de uno o
más usuarios. Esto permitirá al sistema seguir funcionando y cumplir cualquier tipo de acuerdo de nivel de
servicio (SLA) en vigor. Para obtener más información sobre el control de uso de recursos, consulte la Guía
de telemetría e instrumentación.
El sistema podría implementar varias estrategias de limitación, entre las que se incluyen:
●● Rechazar solicitudes de un usuario individual que ya haya obtenido acceso a las API del sistema más
de un número definido de veces por segundo durante un período de tiempo determinado. Para esto
es necesario que el sistema mida el uso de los recursos de cada inquilino o usuario que ejecute una
aplicación. Para obtener más información, consulte la Guía de medición de servicios.
●● Deshabilitar o reducir la funcionalidad de determinados servicios que no son esenciales para que los
servicios esenciales puedan ejecutarse sin trabas con recursos suficientes. Por ejemplo, si la aplicación
está transmitiendo vídeo, puede cambiar a una resolución menor.
●● Aplazar las operaciones que se realizan en nombre de aplicaciones o inquilinos de menor prioridad.
Estas operaciones se pueden suspender o limitar y generar una excepción para informar al inquilino
de que el sistema está ocupado y que la operación se retomará más adelante.
La figura muestra un gráfico de área relativo al uso de los recursos (una combinación de memoria,
CPU, ancho de banda y otros factores) con respecto al tiempo dedicado a las aplicaciones que hacen
uso de tres características. Una característica es un área de funcionalidad, como un componente que
realiza un conjunto específico de tareas, una fragmentación de código que efectúa un cálculo complejo
o un elemento que ofrece un servicio como una memoria caché in-memory. Estas características están
etiquetadas como A, B y C.
La zona inmediatamente por debajo de la línea de una característica identifica los recursos que utilizan
las aplicaciones cuando invocan esta característica. Por ejemplo, el área por debajo de la línea de la
característica A muestra los recursos que consumen las aplicaciones que utilizan esta característica A, y el
área entre las líneas de las características A y B indica los recursos que utilizan las aplicaciones que invocan
la característica B. Al agregar áreas para cada característica, se muestra el uso total de recursos del sistema.
La figura anterior ilustra las consecuencias de aplazar operaciones. Justo antes del tiempo T1, el total de
recursos asignados a todas las aplicaciones que utilizan estas características alcanza un umbral (el límite
de uso de los recursos). Llegados a este punto, las aplicaciones corren el peligro de agotar los recursos
disponibles. En este sistema, la característica B no es tan crucial como las características A o C, por tanto se
deshabilita provisionalmente y se liberan los recursos que se estaban usando. Entre los tiempos T1
Los métodos de escalado automático y limitación también se pueden combinar para que las aplicaciones
conserven su capacidad de respuesta y cumplan los SLA. Si se espera que la demanda siga siendo alta,
el método de limitación ofrece una solución provisional mientras que el sistema se escala horizontalmente.
En este momento, se puede restablecer la funcionalidad completa del sistema.
La siguiente figura muestra un gráfico de área sobre el uso global de los recursos por parte de las
aplicaciones que se ejecutan en un sistema con respecto al tiempo e ilustra cómo se pueden combinar
los métodos de limitación y escalado automático.
En tiempo T1, se alcanza el umbral que especifica el límite suave de uso de los recursos. En estos
momentos, el sistema puede iniciar el escalado horizontal. Sin embargo, si los recursos nuevos no se
encuentran disponibles con la suficiente rapidez, es posible que se agoten los recursos existentes y se
produzcan errores en el sistema. Para evitar que esto ocurra, el sistema se limita provisionalmente según
se ha descrito anteriormente. Cuando se completa el escalado automático y los recursos adicionales se
encuentren disponibles, la limitación se puede moderar.
●● La limitación de una aplicación, y la estrategia a utilizar, es una decisión arquitectónica que repercute
en la totalidad del diseño del sistema. El método de limitación debe plantearse en una fase temprana
del proceso de diseño de la aplicación porque una vez que se implementa el sistema no es fácil de
añadirlo.
●● El método de limitación se debe realizar rápidamente. Es preciso que el sistema sea capaz de detectar
un aumento en la actividad y reaccionar en consecuencia. El sistema también debe ser capaz de volver
a su estado original rápidamente después de que la carga haya disminuido. Esto requiere que los
datos de rendimiento apropiados se capturen y supervisen de forma continuada.
●● El método de limitación se puede utilizar como una medida provisional mientras que un sistema
realiza un escalado automático. En algunos casos es mejor simplemente aplicar la limitación antes
que escalar cuando haya una explosión en la actividad repentina y no se espera que dure demasiado,
porque un escalado puede incrementar considerablemente los costes de ejecución.
●● Si la limitación se utiliza como medida provisional mientras que un sistema se escala automáticamente
y si las demandas de recursos aumentan muy rápidamente, es posible que el sistema no pueda seguir
funcionando, incluso cuando opera en modo de limitación. Si esto no resulta aceptable, plantéese
conservar reservas mayores de capacidad y configurar un escalado automático más agresivo.
●● Para evitar que un inquilino monopolice los recursos que proporciona una aplicación.
●● Para ayudar a optimizar los costes de un sistema mediante la limitación de los niveles máximos
de recursos necesarios con el fin de que siga funcionando.
Ejemplo
La cifra final ilustra cómo se puede implementar el método de limitación en un sistema multiempresa.
Los usuarios de cada una de las organizaciones inquilinas tienen acceso a una aplicación hospedada en el
cloud donde se completaron y enviaron encuestas. La aplicación contiene la instrumentación que controla
la tasa a la que estos usuarios presentan peticiones a la aplicación.
●● Guía de medición de servicios. Describe cómo medir los servicios con el fin de comprender cómo
se utilizan. Esta información puede ser útil para determinar cómo limitar los servicios.
●● Guía de escalado automático. El método de limitación se puede utilizar como medida provisional
mientras que un sistema se escala automáticamente o bien, para eliminar la necesidad de que un
sistema se escale automáticamente. Contiene información sobre estrategias de escalado automático.
●● Patrón de colas de prioridad. Un sistema puede utilizar las colas de prioridad como parte
de su estrategia de limitación, con el fin de mantener el rendimiento en aplicaciones fundamentales
o de más valor, mientras reduce el rendimiento de aplicaciones menos importantes.
Solución
Necesita resolver el problema del control del acceso a los almacenes de datos en los que el almacén no
puede gestionar la autenticación y la autorización de clientes. Una solución típica consiste en restringir el
acceso a la conexión pública del almacén de datos y proporcionar al cliente una clave o token que pueda
validar el almacén de datos.
Esta clave o token se denomina por lo general llave de valet. Proporciona un acceso de tiempo limitado
a recursos específicos y solo permite realizar operaciones predefinidas tales como la lectura y la escritura
en el almacenamiento o las colas o bien, hacer cargas y descargas en un explorador web. Las aplicaciones
pueden crear y emitir llaves de valet a dispositivos de clientes y exploradores web de forma rápida y
sencilla, lo que permite a los clientes realizar las operaciones necesarias sin que la aplicación gestione
directamente la transferencia de datos. Esto elimina de la aplicación y el servidor la sobrecarga de
procesamiento, así como sus consecuencias en el rendimiento y el escalado.
El cliente utiliza este token para obtener acceso a recursos específicos en el almacén de datos durante solo
un período de tiempo específico y para aplicar restricciones en los permisos de acceso, tal como se muestra
en la figura. Después del período especificado, la llave quedará anulada y no permitirá el acceso al recurso.
La aplicación también puede invalidar claves. Se trata de un método muy práctico si el cliente notifica al
servidor que la operación de transferencia de datos se ha completado. Posteriormente, el servidor puede
invalidar esa clave para evitar otras operaciones.
Si se utiliza este patrón, se simplifica la gestión del acceso a los recursos porque no es preciso crear y
autenticar a usuarios, conceder permisos y, después, volver a quitar al usuario. Asimismo, también es fácil
limitar la ubicación, el permiso y el periodo de validez, basta con generar una clave en tiempo de ejecución.
Los factores importantes son limitar el período de validez y, en particular, la ubicación del recurso en la
mayor medida de lo posible para que el receptor solo pueda utilizarlo para el propósito previsto.
Problemas y consideraciones
Tenga en cuenta los puntos siguientes a la hora de decidir cómo implementar este patrón:
Administrar el estado de validez y el período de la clave. Si se filtra o corre peligro, la clave
puede desbloquear eficazmente el elemento de destino y hace que pase a estar disponible para usos
malintencionados durante el periodo de validez. Normalmente, las claves se pueden revocar o deshabilitar,
en función de cómo se hayan emitido. Se pueden modificar las políticas del servidor o se puede invalidar
la clave del servidor con la que se firmó. Especifique un período de validez corto para reducir al mínimo
el riesgo de permitir que se produzcan operaciones no autorizadas en el almacén de datos. Sin embargo,
si el periodo de validez es demasiado corto, es posible que el cliente no pueda completar la operación
antes de que caduque la clave. Permita a los usuarios autorizados renovar la clave antes de que caduque
el periodo de validez si es necesario un acceso repetido a los recursos protegidos.
Controlar el nivel de acceso que proporcionará la clave. Por lo general, la clave debe permitir que
el usuario solamente pueda efectuar las acciones necesarias para completar la operación, tales como
un acceso de solo lectura si el cliente no va a poder cargar datos en el almacén de datos. Para la carga
de archivos, es habitual especificar una clave que proporcione permisos de solo escritura, así como la
ubicación y el periodo de validez. Es fundamental para especificar con precisión el recurso o el conjunto
de recursos a los que se aplica la clave.
Plantear cómo controlar el comportamiento de los usuarios. Al implementar este patrón se pierde
cierto control sobre los recursos a los que tienen acceso los usuarios. El nivel de control queda limitado
por las posibilidades de las políticas y permisos disponibles para el servicio o el almacén de datos de
destino. Por ejemplo, generalmente no es posible crear una clave que limite el tamaño de los datos que se
van a escribir en el almacenamiento o el número de veces que se puede utilizar la clave para tener acceso
a un archivo. Esto puede traducirse en costes inesperados muy elevados por la transferencia de datos,
incluso cuando el uso es por parte del cliente previsto, y es posible que lo haya provocado un error en el
código que desencadena operaciones repetidas de carga o descarga. Para limitar el número de veces que
se puede cargar un archivo, siempre que sea posible, fuerce que el cliente notifique a la aplicación cuándo
se ha completado una operación. Por ejemplo, algunos almacenes de datos generan eventos que puede
utilizar el código de la aplicación para supervisar las operaciones y controlar el comportamiento de los
usuarios. Sin embargo, es difícil hacer cumplir las cuotas para usuarios individuales en una situación de
multiempresa donde todos los usuarios en un inquilino utilizan la misma clave.
Valide y, opcionalmente, sanee todos los datos subidos. Los usuarios maliciosos que logren tener acceso
a la clave podrían cargar datos diseñados para poner en peligro el sistema. Asimismo, los usuarios autorizados
pueden cargar datos que no sean válidos y, cuando se procesen, podrían provocar errores o fallos en el
sistema. Al objeto de implementar una protección frente a estas situaciones, asegúrese de que todos los datos
cargados se validaron y que se haya comprado que no hubiera contenido malicioso antes de utilizarlos.
Otras cuestiones que se deben tener en cuenta al implementar este patrón son:
●● Si el cliente no notifica o no puede notificar al servidor la finalización de la operación y el único límite
es el período de vencimiento de la clave, la aplicación no podrá realizar operaciones de auditoría
como contar el número de cargas o descargas o la prevención de múltiples cargas o descargas.
●● Es posible que se vea limitada la flexibilidad de las políticas de claves que se pueden generar. Por
ejemplo, algunos mecanismos solo permiten el uso de un período de vencimiento programado. Otros
no tienen capacidad para especificar permisos de lectura y escritura con los detalles suficientes.
●● Si se especifica la hora de inicio del periodo de validez de la clave o el token, asegúrese de que sea
ligeramente anterior a la hora en la que el servidor que se utiliza haya establecido como margen
para aquellos clientes que no estén sincronizados con precisión. El valor predeterminado, si no se
especifica, es normalmente la hora del servidor.
●● La dirección URL que contiene la clave se registrará en los archivos de registro del servidor. Aunque la
clave venza por lo general antes de que los archivos de registro se utilicen para su análisis, asegúrese
de limitar el acceso a los mismos. Si se transmiten datos de registro a un sistema de supervisión o se
almacenan en otra ubicación, plantéese aplicar un retardo para evitar fugas de claves hasta que haya
pasado su período de validez.
●● Si el código de cliente se ejecuta en un navegador web, es posible que el navegador tenga que ser
compatible con el uso compartido de recursos entre orígenes (CORS) para habilitar el código que se
ejecuta dentro en el explorador web, al objeto de tener acceso a datos en dominios diferentes al que
se utilizó para aprovisionar la página. Algunos exploradores antiguos y ciertos almacenes de datos
no admiten CORS, y es posible que el código que se ejecuta en estos exploradores pueda utilizar
una llave de valet para proporcionar acceso a datos en dominios diferentes, como una cuenta de
almacenamiento en el cloud.
●● Cuando los datos se almacenan en un almacén de datos remoto o un centro de datos diferente. Si la
aplicación tiene que actuar a modo de gatekeeper, podrían generarse cargos por el ancho de banda
adicional de la transferencia de datos entre centros de datos o bien, a través de redes públicas o
privadas entre el cliente y la aplicación y, posteriormente, entre la aplicación y el almacén de datos.
●● Si es preciso que la aplicación realice algún tipo de tarea en los datos antes de almacenarlos o antes
de enviarlos al cliente. Por ejemplo, si la aplicación necesita realizar la validación, obtener acceso a
los registros o ejecutar una transformación de los datos. Sin embargo, algunos clientes y almacenes
de datos pueden negociar y llevar a cabo transformaciones sencillas, como la compresión y la
descompresión (por ejemplo, un explorador web puede por lo general gestionar formatos GZip).
●● Si el diseño de una aplicación existente hace difícil incorporar el patrón. Al utilizar este patrón
normalmente es preciso utilizar un método arquitectónico diferente para la entrega y recepción de datos.
Ejemplo
Azure admite firmas de acceso compartidas en Azure Storage para controlar de forma pormenorizada el
acceso a datos en blobs, tablas y colas, y para temas y colas de Service Bus. Los tokens de firma de acceso
compartido se pueden configurar para proporcionar derechos de acceso específicos tales como lectura,
escritura, actualización y eliminación en tablas específicas, un intervalo de claves en una tabla, una cola, un
blob o un contenedor de blobs. La validez puede ser un período de tiempo determinado o no tener límite.
Las firmas para el acceso compartido de Azure también admiten políticas de acceso almacenadas en el
servidor que pueden estar asociadas a un recurso específico como una tabla o blob. Esta característica
ofrece un control adicional, así como flexibilidad en comparación con los tokens de firma de acceso
compartido generados por aplicaciones y debe utilizarse siempre que sea posible. Se puede cambiar la
configuración que se define en una política almacenada en el servidor y esto se refleja en el token sin
necesidad de emitir uno nuevo, pero las opciones definidas en el token no se pueden cambiar sin emitir
uno nuevo. Con este enfoque también se puede revocar un token de firma de acceso compartido válido
antes de que venza.
Para obtener más información, consulte Introducción a SAS (Shared Access Signature, firma de acceso
compartido) de tabla, SAS de cola y actualizar a SAS de blob y Usar firmas de acceso compartido en
MSDN.
El código siguiente muestra cómo crear un token de firma de acceso compartido que sea válido durante
cinco minutos. El método "GetSharedAccessReferenceForUpload" devuelve un token de firmas de acceso
compartido que se puede utilizar para cargar un archivo en Azure Blob Storage.
// Specify a start time five minutes earlier to allow for client clock skew.
SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-5),
●● Patrón de gatekeeper. Este patrón puede utilizarse junto con la llave de valet para proteger
aplicaciones y servicios mediante el uso de una instancia de host dedicada que actúa como
intermediaria entre clientes y la aplicación o el servicio. El gatekeeper valida y desinfecta las
solicitudes; además, pasa las peticiones y los datos entre el cliente y la aplicación. Esto puede
proporcionar una capa adicional de seguridad y reducir la superficie de ataque del sistema.
●● Introducción a SAS (Shared Access Signature, firma de acceso compartido) de tabla, SAS de cola
y actualizar a SAS de blob
Listas de
comprobación de
revisión del diseño
Utilice esta lista de comprobación como punto de partida para evaluar su cultura y procesos de DevOps.
Cultura
Garantizar la alineación del negocio en todas las organizaciones y equipos
●● Garantice que los equipos de negocio, desarrollo y operaciones estén todos alineados.
Planificación proactiva.
●● Planifique de forma proactiva los posibles errores.
●● Implante procesos para identificar rápidamente los problemas cuando se produzcan.
●● Remítase a los miembros del equipo correctos para fijar y confirmar la solución.
Documentar operaciones
●● Documente todas las herramientas, los procesos y las tareas automatizadas con el mismo nivel
de calidad que su código de producto.
●● Documente el diseño actual y la arquitectura de los sistemas que admite, junto con los procesos
de recuperación y otros procedimientos de mantenimiento.
●● Céntrese en los pasos que emprende en la práctica y no en los procesos que teóricamente son
los mejores.
Revise y actualice periódicamente la documentación.
●● Respecto al código, asegúrese de que se incluyen comentarios significativos, especialmente
en las API públicas y utilice herramientas para generar automáticamente el código de la
documentación.
Compartir conocimiento
●● Asegúrese de que la documentación está organizada y se identifica con facilidad.
●● Utilice presentaciones informales, vídeos o boletines de noticias para compartir conocimientos.
Desarrollo
Ofrecer a los desarrolladores entornos similares a los de producción
●● Tenga los entornos de desarrollo y pruebas lo más cerca posible del entorno de producción.
●● Asegúrese de que los datos de las pruebas son coherentes con los datos que se utilizan en
producción, aunque se trate de datos de ejemplo y no de datos reales de producción (por
razones de privacidad o cumplimiento).
●● Planee generar y pasar a estado de anónimo los datos de pruebas de ejemplo.
Asegurarse de que todos los miembros del equipo autorizados pueden proporcionar una
infraestructura y desplegar la aplicación
●● Cualquier persona con los permisos adecuados tiene que poder crear o implementar recursos
similares a los de producción sin ir al equipo de operaciones.
Pruebas en producción
●● Realice pruebas para garantizar que el código implementado funciona como se había previsto.
●● Para las implementaciones que no se actualicen con frecuencia, programe pruebas de
producción de forma periódica como parte del mantenimiento.
Versión
Automatizar implementaciones
●● Automatice la implementación de la aplicación para probar los entornos de ensayo y de producción.
Supervisión
Haga que los sistemas se puedan observar
●● Establezca puntos de conexión de estado externos para supervisar el estado y garantizar que las
aplicaciones se codifiquen para instrumentar la métrica de las operaciones.
●● Utilice un esquema común y coherente que le permita correlacionar los eventos en varios sistemas.
Administración
Automatice las tareas de operaciones
●● Automatice los procesos de operaciones repetitivas siempre que sea posible para garantizar
la uniformidad de calidad y ejecución.
●● Al código que implementa la automatización se le debe aplicar la versión en el control de
código fuente.
Como con cualquier otro código, las herramientas de automatización deben probarse.
Documente los procedimientos de remisión a una instancia superior para las dependencias
externas
●● Disponga de un plan para abordar las interrupciones si utiliza los servicios externos.
●● Cree documentación para los procesos de minimización planificados.
●● Incluya los contactos de soporte técnico y las vías de remisión a una instancia superior.
Siga los principios de privilegio mínimo cuando otorgue acceso a los recursos.
●● Administre con prudencia el acceso a los recursos.
●● Solo conceda un acceso de usuario a lo que necesiten para completar sus tareas.
●● Implemente todos los componentes, servicios y recursos, y calcule las instancias como varias
instancias.
●● Diseñe la aplicación de modo que se pueda configurar para utilizar varias instancias.
●● Diseñe la aplicación para que, de forma automática, detecte errores y redirija las solicitudes
a instancias sin error.
Diseñe tareas y mensajes para que sean idempotentes (que se puedan repetir con seguridad)
●● Haga idempotentes a los consumidores de mensajes y las operaciones que llevan a cabo.
●● Detecte mensajes duplicados o bien utilice un enfoque optimista para gestionar conflictos.
●● Utilice mensajería asincrónica que no bloquee al remitente mientras espera una respuesta.
●● Utilice un sistema de mensajería que proporcione alta disponibilidad y garantice semántica
por lo menos una vez.
●● Haga importante el procesamiento de mensajes (véase el punto anterior).
●● Diseñe aplicaciones que gestionen cargas de trabajo variables, como los picos de primera hora
de la mañana o cuando se lanza un producto nuevo en un sitio de comercio electrónico.
●● Utilice el ajuste de escala automático siempre que sea posible.
●● Ponga en la cola las solicitudes de servicios y degrádelas correctamente cuando las colas casi
hayan completado su capacidad.
●● Asegúrese de que haya suficiente capacidad y rendimiento en condiciones no de ráfaga para
vaciar las colas y gestionar las solicitudes pendientes. Para obtener más información, consulte
Patrón de nivelación de carga basada en cola.
Implementación y mantenimiento
●● Implemente por lo menos dos instancias de cada rol en el servicio. Esto permite que un rol no
esté disponible mientras el otro permanece activo.
●● Aloje aplicaciones esenciales para el negocio en más de una región para ofrecer máxima
disponibilidad.
●● Azure App Service admite intercambiar entre los entornos de almacenamiento provisional
y producción sin que suponga tiempo de inactividad para las aplicaciones.
●● Si prefiere almacenar provisionalmente de forma local o bien implementar versiones diferentes
de la aplicación al mismo tiempo y migrar gradualmente los usuarios, es posible que no pueda
utilizar una operación de VIP Swap.
●● Los ajustes de configuración de una aplicación o un servicio Azure se pueden cambiar sin
necesidad de reiniciar el rol.
●● Diseñe una aplicación para que acepte cambios en los ajustes de configuración sin necesidad
de reiniciar toda la aplicación.
Utilice dominios de actualización para evitar tiempos de inactividad durante las actualizaciones
●● Especifique cuántos dominios de actualización deben crearse para un servicio cuando este
se implementa.
Nota
Los roles también se distribuyen entre dominios de error, cada uno de los cuales es bastante
independiente de otros dominios de error en cuanto a bastidor de servidor, alimentación y
suministro de refrigeración, a fin de reducir al mínimo la posibilidad de que un error afecte a todas
las instancias de rol. Esta distribución se produce automáticamente y no se puede controlar.
●● Coloque dos o más máquinas virtuales en el mismo conjunto de disponibilidad para garantizar
que no se implementen en el mismo dominio de error.
●● Para potenciar al máximo la disponibilidad, cree varias instancias de cada máquina virtual crítica
utilizada por el sistema y colóquelas en el mismo conjunto de disponibilidad.
●● Si está ejecutando varias máquinas virtuales que atienden propósitos diferentes, cree un
conjunto de disponibilidad para cada máquina virtual.
●● Agregue las instancias de cada máquina virtual a cada conjunto de disponibilidad.
Administración de datos
●● Utilice el almacenamiento con redundancia geográfica (RA-GRS, por sus siglas en inglés) con
acceso de lectura para mayor disponibilidad.
●● Utilice Azure SQL Database y Cosmos DB para obtener compatibilidad de réplica geográfica.
●● Configure réplicas de bases de datos secundarias en otras regiones.
●● Si hay una interrupción regional o no es posible conectarse a la base de datos principal,
conmute por error a la réplica secundaria.
Para obtener más información, consulte Cómo distribuir los datos globalmente con Azure
Cosmos DB.
●● Utilice la partición para reducir al mínimo las posibilidades de que se produzcan actualizaciones
contradictorias.
Habilite la opción de alta disponibilidad para conservar una copia secundaria de una caché
de Azure Redis
●● Cuando utilice Azure Redis Cache, seleccione el nivel estándar o superior para conservar una
copia secundaria del contenido. Para obtener más información, consulte Crear una caché en
Azure Redis Cache.
Errores y fallos
●● Asegúrese de que los tiempos de espera que aplica sean adecuados para cada servicio o recurso
así como el cliente que está accediendo a ellos.
●● Quizás sea conveniente permitir un tiempo de espera más largo para una instancia determinada
de un cliente, en función del contexto y de otras acciones que esté realizando el cliente.
●● Diseñe una estrategia de reintento para acceder a todos los servicios y recursos que no admitan
de forma inherente el reintento de conexión automático.
●● Utilice una estrategia que incluya un retraso creciente entre reintentos a medida que aumente el
número de errores.
●● En lugar de seguir reintentando una operación con pocas probabilidades de éxito, la aplicación
debe aceptar rápidamente que la operación ha fallado y gestionar correctamente este error.
●● Puede utilizar el modelo de interruptor de circuito para rechazar solicitudes de operaciones
específicas durante períodos definidos. Para obtener más información, consulte Patrón de
interruptor de circuito.
●● Diseñe aplicaciones para que aprovechen varias instancias sin que ello afecte el funcionamiento
y las conexiones existentes en la medida de lo posible.
●● Utilice varias instancias y distribuya las solicitudes entre ellas, y detecte y evite enviar solicitudes
a las instancias con error, a fin de potenciar al máximo la disponibilidad.
●● Proporcione un medio para reproducir las operaciones de escritura del almacenamiento de blobs
en SQL Database cuando el servicio esté disponible.
●● Detecte los errores y redirija las solicitudes a otros servicios que puedan ofrecer funciones
alternativas, o bien a instancias de copia de seguridad que puedan mantener las operaciones
fundamentales mientras el servicio principal esté desconectado.
●● Para los errores posibles pero que aún no hayan ocurrido, proporcione los datos suficientes para
permitir que el personal de operaciones determinen la causa, subsanen la situación y garanticen
que el sistema permanezca disponible.
●● En el caso de errores que ya se hayan producido, la aplicación debe ofrecer un mensaje de error
al usuario pero intentar seguir operativa con funciones reducidas.
●● En todos los casos, el sistema de supervisión debe capturar datos completos para permitir una
recuperación rápida y modificar el sistema para evitar que la situación se repita.
Con regularidad, pruebe todos los sistemas de conmutación por error y de reserva
●● Pruebe los sistemas de conmutación por error y de reserva antes de que se necesiten para
compensar un problema real durante el tiempo de ejecución.
●● Cree un plan aceptado, probado por completo de recuperación ante cualquier tipo de error que
pueda afectar la disponibilidad del sistema.
●● Elija una arquitectura de recuperación ante desastres multisitio para las aplicaciones críticas para
una misión.
●● Identifique un dueño específico del plan de recuperación ante desastres, incluidas la
automatización y las pruebas.
●● Asegúrese de que el plan esté documentado adecuadamente y automatice el proceso tanto
como sea posible.
●● Cree una estrategia de copia de seguridad para todos los datos de referencia y transaccionales,
y pruebe con regularidad la restauración de estas copias de seguridad.
●● Imparta cursos al personal de operaciones para que pongan en práctica el plan y realicen
simulaciones de desastres de forma periódica con el fin de validarlo y mejorarlo.
Diseñe algunas partes del proceso para que sean discretas y se puedan descomponer.
Reduzca al mínimo el tamaño de cada pieza, siguiendo las normas habituales de separación
de asuntos y el principio de responsabilidad única.
Diseñe aplicaciones para que reaccionen a cargas variables aumentando y disminuyendo el número
de instancias de roles, colas y otros servicios que utilicen.
Implemente la configuración o la autodetección de instancias conforme se agreguen y quiten, para que
el código de la aplicación pueda realizar el enrutamiento necesario.
Opte por una capacidad de autoescalado, como Azure Autoscale, para mecanismos personalizados
o externos, a menos que el mecanismo incorporado no atienda sus requisitos.
Utilice reglas de escalado programado siempre que sea posible para garantizar la disponibilidad de
recursos sin demora del arranque, pero utilice las reglas de autoescalado reactivo cuando sea necesario,
para hacer frente a cambios inesperados en la demanda.
Si está previsto que una solicitud a un servicio tarde mucho en ejecutarse o absorba una cantidad
considerable de recursos, descargue el procesamiento de esta solicitud en una tarea separada.
Utilice roles de trabajadores o trabajos en segundo plano (dependiendo de la plataforma de hosting)
para ejecutar estas tareas.
Cuando haya muchas tareas en segundo plano, o las tareas exijan una cantidad considerable de
tiempo o recursos, distribuya el trabajo entre varias unidades de proceso (como roles de trabajador
o trabajos en segundo plano).
Requisitos
Defina los requisitos de disponibilidad de su cliente
●● Obtenga el acuerdo de su cliente para los objetivos de disponibilidad de cada pieza de sus
aplicaciones. Para obtener más información, consulte Definición de los requisitos de resistencia.
Diseño de aplicaciones
Realice un análisis en modo de error (FMA) de su aplicación
●● Configure la aplicación para que se amplíe automáticamente a medida que aumente la carga.
●● Disponga de más de una instancia mediana o de mayor tamaño de Application Gateway para
garantizar la disponibilidad del servicio en virtud de los términos del SLA.
●● Utilice un patrón activo-activo (que distribuya solicitudes entre varias instancias activas) o un
patrón activo-pasivo (que mantenga una instancia en reserva, en caso de error de la instancia
principal).
●● Implemente varias instancias de los servicios de la aplicación en pares regionales.
Utilice Azure Traffic Manager para enrutar el tráfico de la aplicación a regiones diferentes
●● Asegúrese de que la lógica de estado compruebe las partes críticas del sistema y responda
adecuadamente a los sondeos de mantenimiento.
●● Para un sondeo de Traffic Manager, el punto de conexión de estado debe comprobar las
dependencias críticas que se implementen en la misma región y cuyo fallo debería dar lugar
una conmutación por error a otra región.
●● Para un equilibrador de carga, el punto de conexión de estado debe notificar el estado de la
máquina virtual.
●● No incluya otras capas o servicios externos. · Para obtener orientación sobre la implementación
de un seguimiento de estado en la aplicación, consulte Patrón de supervisión de puntos de
conexión de mantenimiento.
●● Si su aplicación tiene dependencias con servicios externos, identifique dónde y cómo puede
producir errores, y el efecto que estos tienen en su aplicación.
●● Registre sus invocaciones de supervisión y diagnóstico, y correlaciónelas con el registro de
estado y diagnóstico de la aplicación mediante un identificador exclusivo.
●● Diseñe cada parte de la aplicación para permitir operaciones asincrónicas, siempre que sea posible.
Administración de datos
●● Evalúe los métodos de réplica de cada tipo de almacenamiento en Azure, incluyendo Azure
Storage Replication y SQL Database Active Geo-Replication para garantizar que la aplicación
atienda los requisitos de datos.
Asegúrese de que ninguna cuenta de usuario tenga acceso a los datos de producción y de
copia de seguridad
●● Diseñe la aplicación para limitar los permisos de cuenta de usuario, de manera que solamente
los usuarios que requieran acceso de escritura lo tengan únicamente para producción o para
copia de seguridad, y no para ambos.
Documente y pruebe los procesos de conmutación por error y conmutación por recuperación
●● De forma regular, pruebe los pasos documentados para verificar si un operador que los esté
siguiendo puede conmutar correctamente el origen de datos tanto por error como
por recuperación.
●● De forma regular, verifique si los datos de copia de seguridad son los previstos mediante
la ejecución de un script para validar la integridad de los datos, el esquema y las consultas.
●● Registre y notifique las incoherencias para se pueda reparar el servicio de copia de seguridad.
Seguridad
●● El valor predeterminado de acceso a los recursos de la aplicación debe ser lo más restrictivo
posible.
●● Conceda permisos de nivel superior previa aprobación.
●● Compruebe los permisos de privilegio mínimo de otros recursos que tengan sus propios
sistemas de permisos, como SQL Server.
Pruebas
●● Asegúrese de que los servicios dependientes de la aplicación se conmuten por error y por
recuperación en el orden correcto.
Realice pruebas en producción con datos tanto sintéticos como de usuarios reales
●● Implemente una estrategia de registro sólida para capturar tanta información específica de una
versión como sea posible.
●● Diseñe un proceso de reversión para volver a la última versión buena conocida y reducir
al mínimo el tiempo de inactividad.
Operaciones
Mida las estadísticas de llamada remota y ponga la información a disposición del equipo
de la aplicación
●● Resuma la métrica, como latencia, rendimiento y errores, de las llamadas remotas en los
percentiles 95 y 99.
●● Realice un análisis estadístico de la métrica para revelar los errores que se producen dentro
de cada percentil.
●● Identifique los indicadores de rendimiento clave del estado de la aplicación, como excepciones
transitorias y latencia de llamadas remotas, y establezca valores de umbral adecuados para cada
uno de ellos.
●● Envíe una alerta a las operaciones cuando se alcance el valor de umbral.
●● Establezca estos umbrales en niveles que permitan identificar problemas antes de que
se vuelvan críticos y exijan una respuesta de recuperación.
Asegúrese de que el equipo cuente con más de una persona capacitada para supervisar
la aplicación y realizar los pasos de recuperación manual
●● Si los requisitos de la aplicación superan los límites de suscripción de Azure, cree otra suscripción
de Azure y dótela de recursos suficientes.
●● Escale verticalmente (eligiendo, por ejemplo, otro plan de tarifa) o escale horizontalmente
(agregando instancias nuevas) para evitar los límites por servicio.
Diseñe los requisitos de almacenamiento de la aplicación para que se encuentren dentro de los
objetivos de capacidad de ampliación y rendimiento de Azure
●● Si la carga de trabajo fluctúa en el tiempo, utilice los conjuntos de escalado de Azure VM para
establecer automáticamente el número de instancias de las VM.
●● Si la aplicación utiliza Azure SQL Database, asegúrese de que haya seleccionado el nivel
de servicio adecuado.
●● Si la aplicación exige más de 200 cuentas de almacenamiento, deberá crear una suscripción y,
a su vez, crear cuentas de almacenamiento adicionales en ella.
●● Si la aplicación excede los objetivos de capacidad de ampliación de los discos de la máquina virtual,
aprovisione cuentas de almacenamiento adicionales y cree allí los discos de la máquina virtual.
Telemetría
●● Asegúrese de que el sistema de registro correlacione las llamadas entre los límites de servicio,
para que pueda seguir la solicitud en toda la aplicación.
Recursos de Azure
●● Cuando implemente en dos regiones, elija regiones del mismo par regional.
●● Cree grupos de recursos diferentes para los entornos de producción, desarrollo y prueba.
●● En una implementación de varias regiones, coloque los recursos de cada región en grupos de
recursos diferentes. Esto facilita volver a implementar una región sin que ello afecte a las demás.
App Service
●● Seleccione un tamaño de nivel e instancia que cumpla los requisitos de rendimiento para una carga
normal y, a continuación, amplíe las instancias para gestionar los cambios de volumen de tráfico.
Cree planes de App Service diferentes para los entornos de producción y de pruebas
●● Si la solución tiene un front-end web y una API web, considere la posibilidad de descomponerlas
en aplicaciones de App Service diferentes.
●● Si inicialmente no necesita ese nivel de capacidad de ampliación, puede implementar las
aplicaciones en el mismo plan y moverlas a planes diferentes más adelante.
Evite utilizar la característica de copia de seguridad de App Service para hacer copias
de seguridad de bases de datos de Azure SQL
Cree una ranura de implementación para retener la última implementación buena conocida (LKG,
por sus siglas en inglés)
●● No utilice la misma cuenta de almacenamiento para los registros y los datos de aplicaciones.
Supervise el rendimiento
●● Utilice un servicio de supervisión del rendimiento como New Relic o Application Insights para
supervisar el rendimiento y el comportamiento de una aplicación bajo carga.
Application Gateway
●● Implemente Application Gateway con dos instancias por lo menos. Para poder optar al SLA,
debe proporcionar dos o más instancias medianas o grandes.
Búsqueda de Azure
●● Utilice por lo menos dos réplicas para una alta disponibilidad de lectura, o tres para una alta
disponibilidad de lectura y escritura.
Para Queue Storage, cree una cola de copia de seguridad en otra región
●● Cree una cola de copia de seguridad en una cuenta de almacenamiento de otra región.
Cosmos DB
SQL Database
Utilice particionamiento
●● Utilice los grupos de disponibilidad Always On de SQL Server para replicar la base de datos.
●● Si ya utiliza Azure Backup para las copias de seguridad de las VM, considere el uso de
Azure Backup para las cargas de trabajo de SQL Server con DPM.
●● De lo contrario, utilice Copia de seguridad administrada de SQL Server en Microsoft Azure.
●● Después de una conmutación por error de Traffic Manager, haga una conmutación por
recuperación manual, en lugar de conmutar por recuperación de forma automática.
●● Antes conmutar por recuperación, asegúrese de que todos los subsistemas de aplicación
estén en buen estado.
●● Cree un punto de conexión personalizado que informe sobre el estado general de la aplicación.
●● Sin embargo, no informe acerca de errores de servicios que no sean críticos.
Máquinas virtuales
Evite una carga de trabajo de producción en una sola máquina virtual
●● Al mover una carga de trabajo existente a Azure, comience por el tamaño de VM más
parecido al de los servidores locales.
●● A continuación, mida el rendimiento de la carga de trabajo real con respecto a la CPU,
la memoria y los IOPS del disco, y ajuste el tamaño si es necesario.
●● Si necesita varios NIC, tenga en cuenta el límite de NIC por cada tamaño.
Para incluir direcciones IP públicas en la lista blanca o bien bloquearlas, agregue un NSG
a la subred
●● Bloquee el acceso de usuarios malintencionados o bien permita el acceso solo a usuarios con
privilegio para acceder a la aplicación.
●● Para un sondeo de HTTP, utilice un punto de conexión personalizado que informe acerca del
estado general de la aplicación, incluyendo todas las dependencias críticas.
●● No bloquee el tráfico hacia o desde esta IP en ninguna política de firewall o regla de grupo
de seguridad de red (NSG, por sus siglas en inglés).
Resumen
En esta guía ha aprendido cómo elegir el estilo de arquitectura adecuado
para la aplicación y las tecnologías de cálculo y almacenamiento de datos
más adecuadas, y a aplicar los principios y los pilares de diseño a la hora
de desarrollar sus aplicaciones.
En el futuro, las nuevas tendencias, demandas de usuarios y capacidades seguirán creando incluso más
oportunidades de mejorar las arquitecturas. Para jugar con ventaja, le animamos a mantenerse al tanto
de los recursos y la orientación siguientes:
291
9
Arquitecturas de
referencia de Azure
Nuestras arquitecturas de referencia se organizan por escenario, con
arquitecturas relacionadas agrupadas. Cada arquitectura incluye prácticas
recomendadas, junto con consideraciones de capacidad de ampliación,
disponibilidad, facilidad de gestión y seguridad. Además, casi todas
incluyen una solución implementable.
294
• If you are likely to synchronize more than 100,000 objects from your local directory, use a production version of SQL Server, and use SQL clustering to achieve high
availability.
• Protect on-premises applications that can be accessed externally. Use the Azure AD Application Proxy to provide controlled access to on-premises web applications for
external users.
• Actively monitor Azure AD for signs of suspicious activity.
• Use conditional access control to deny authentication requests from unexpected sources.
Azure
Extend Active Directory Domain Services (AD DS) to Azure Architecture Components
This architecture extends an on-premises Active Directory environment to Azure using Active Directory Domain Services (AD DS). This architecture can reduce the latency caused by sending
authentication and local authorization requests from the cloud back to AD DS running on-premises. Consider this option if you need to use AD DS features that are not currently On-premises network
implemented by Azure AD.
The on-premises network includes local Active Directory
servers that can perform authentication and authorization
for components located on-premises.
On-premises nework Virtual network
Active Directory servers
These are domain controllers implementing directory
GATEWAY SUBNET services (AD DS) running as VMs in the cloud. These servers
UDR PRIVATE DMZ IN AVAILABLITY PRIVATE DMZ OUT can provide authentication of components running in your
SET Azure virtual network.
AD Server AD Server
NIC
NIC
contoso�com contoso�com
NSG NVA Active Directory subnet
The AD DS servers are hosted in a separate subnet. Network
NSG security group (NSG) rules protect the AD DS servers and
NIC
NIC
NIC
NSG
NVA
routes (UDRs) handle routing for on-premises traffic that
VM passes to Azure. Traffic to and from the Active Directory
NSG NSG VM servers does not pass through the network virtual appliances
(NVAs) used in this scenario.
NSG
NIC
NIC
VM
NVA
VM VM
PIP
Recommendations
• Deploy at least two VMs running AD DS as domain controllers and add them to an availability set.
• For VM size, use the on-premises AD DS machines as a starting point, and pick the closest Azure VM sizes.
• Create a separate virtual data disk for storing the database, logs, and SYSVOL for Active Directory.
• Configure the VM network interface (NIC) for each AD DS server with a static private IP address for full domain name service (DNS) support.
• Monitor the resources of the domain controller VMs as well as the AD DS Services and create a plan to quickly correct any problems.
295
• Perform regular AD DS backups. Don't simply copy the VHD files of domain controllers, because the AD DS database file on the VHD may not be in a consistent state
when it's copied.
• Do not shut down a domain controller VM using Azure portal. Instead, shut down and restart from the guest operating system.
• Use either BitLocker or Azure disk encryption to encrypt the disk hosting the AD DS database.
• Azure disk encryption to encrypt the disk hosting the AD DS database.
Azure
Create an Active Directory Domain Services (AD DS) resource forest in Azure Architecture Components
This architecture shows an AD DS forest in Azure with a one-way trust relationship with an on-premises AD domain. The forest in Azure contains a domain that does not exist on-premises.
This architecture maintains security separation for objects and identities held in the cloud, while allowing on-premises identities to access your applications running in Azure. On-premises network
The on-premises network contains its own Active Directory
forest and domains.
Active Directory servers
These are domain controllers implementing domain services
running as VMs in the cloud. These servers host a forest
containing one or more domains, separate from those
located on-premises.
On-premises nework Virtual network One-way trust relationship
The example in the diagram shows a one-way trust from the
domain in Azure to the on-premises domain. This
GATEWAY SUBNET
relationship enables on-premises users to access resources
UDR PRIVATE DMZ IN AVAILABLITY PRIVATE DMZ OUT in the domain in Azure, but not the other way around. It is
SET
possible to create a two-way trust if cloud users also require
AD Server AD Server access to on-premises resources.
NIC
NIC
contoso�com contoso�com
NSG NVA
Active Directory subnet
The AD DS servers are hosted in a separate subnet. Network
NSG
security group (NSG) rules protect the AD DS servers and
NIC
NIC
MANAGEMENT SUBNET
Gateway NVA provide a firewall against traffic from unexpected sources.
NSG Internal Load
Balancer Azure gateway
Jump Box
The Azure gateway provides a connection between the
on-premises network and the Azure VNet. This can be a VPN
Web app request connection or Azure ExpressRoute. For more information,
WEB TIER
AVAILABLITY PUBLIC DMZ IN AVAILABLITY PUBLIC DMZ OUT AD DS SUBNET see Implementing a secure hybrid network architecture in
Authentication request SET (CONTOSO�COM)
AVAILABLITY
SET SET Azure.
ADDS trust relationship
NIC
NIC
NSG
NVA
VM
NSG NSG VM
NSG
NIC
NIC
VM
NVA
VM VM
PIP
296
Recommendations
• Provision at least two domain controllers for each domain. This enables automatic replication between servers.
• Create an availability set for the VMs acting as Active Directory servers handling each domain. Put at least two servers in this availability set.
• Consider designating one or more servers in each domain as standby operations masters in case connectivity to a server acting as a flexible single master operation
(FSMO) role fails.
Azure
Active Directory Federation Services (AD FS) Architecture Components
This architecture extends an on-premises network to Azure and uses Active Directory Federation Services (AD FS) to perform federated authentication and authorization. AD FS can be hosted on-premises,
but for applications running in Azure, it may be more efficient to replicate AD FS in the cloud.
Use this architecture to authenticate users from partner organizations, allow users to authenticate from outside of the organizational firewall, or allow users to connect from authorized mobile devices.
AD DS subnet
The AD DS servers are contained in their own subnet with network
security group (NSG) rules acting as a firewall.
On-premises nework Virtual network
AD DS servers
Domain controllers running as VMs in Azure. These servers provide
GATEWAY SUBNET PRIVATE DMZ IN AVAILABLITY PRIVATE DMZ OUT authentication of local identities within the domain.
MANAGEMENT SUBNET SET
UDR
Gateway AD FS subnet
NIC
NIC
Web app request NVA AD FS servers
Authentication request Internal Load The AD FS servers provide federated authorization and authentication.
Balancer In this architecture, they perform the following tasks:
Federated authentication
request Receiving security tokens containing claims made by a partner
Partner network
federation server on behalf of a partner user. AD FS verifies that
WEB TIER
AVAILABLITY the tokens are valid before passing the claims to the web applica-
SET tion running in Azure to authorize requests.
The web application running in Azure is the relying party. The
NSG partner federation server must issue claims that are understood
Federation
VM by the web application. The partner federation servers are
server
referred to as account partners, because they submit access
requests on behalf of authenticated accounts in the partner
VM organization. The AD FS servers are called resource partners
because they provide access to resources (the web application).
VM
Authenticating and authorizing incoming requests from external
users running a web browser or device that needs access to web
applications, by using AD DS and the Active Directory Device
Registration Service.
PUBLIC DMZ IN AVAILABLITY PUBLIC DMZ OUT
PIP
SET The AD FS servers are configured as a farm accessed through an Azure
load balancer. This implementation improves availability and scalabili -
ty. The AD FS servers are not exposed directly to the Internet. All
NIC
NIC
NSG
NVA Internet traffic is filtered through AD FS web application proxy servers
NSG and a DMZ (also referred to as a perimeter network).
NIC
NIC
NVA AD FS proxy subnet
The AD FS proxy servers can be contained within their own subnet,
PIP with NSG rules providing protection. The servers in this subnet are
exposed to the Internet through a set of network virtual appliances
that provide a firewall between your Azure virtual network and the
Internet.
Recommendations
WEB TIER
AVAILABLITY
SET AD FS web application proxy (WAP) servers
• For VM size, use the on-premises AD FS machines as a starting point, and These VMs act as AD FS servers for incoming requests from partner
pick the closest Azure VM sizes. organizations and external devices. The WAP servers act as a filter,
NSG
shielding the AD FS servers from direct access from the Internet. As
VM with the AD FS servers, deploying the WAP servers in a farm with load
• Create separate Azure availability sets for the AD FS and WAP VMs, with at balancing gives you greater availability and scalability than deploying
least two update domains and two fault domains. a collection of stand-alone servers.
VM
297
• Place AD FS servers and WAP servers in separate subnets with their own
firewalls. Use NSG rules to define firewall rules.
VM Partner organization
A partner organization running a web application that requests access
to a web application running in Azure. The federation server at the
• Configure the network interface for each of the VMs hosting AD FS and
partner organization authenticates requests locally, and submits secu-
WAP servers with static private IP addresses. rity tokens containing claims to AD FS running in Azure. AD FS in
Azure validates the security tokens, and if valid can pass the claims to
• Prevent direct exposure of the AD FS servers to the Internet. the web application running in Azure to authorize them.
• Do not join the WAP servers to the domain.
Red híbrida
Estas arquitecturas de referencia muestran prácticas probadas de creación
de conexiones sólidas entre una red local y Azure.
299
• If you need to ensure that the on-premises network remains available to the Azure VPN gateway, implement a failover cluster for the on-premises VPN gateway. balancers. For more information about the application
infrastructure, see Running Windows VM workloads and
• If your organization has multiple on-premises sites, create multi-site connections to one or more Azure VNets. This approach requires dynamic (route-based) routing, so Running Linux VM workloads.
make sure that the on-premises VPN gateway supports this feature.
Internal load balancer
• Generate a different shared key for each VPN gateway. Use a strong shared key to help resist brute-force attacks. Network traffic from the VPN gateway is routed to the cloud
application through an internal load balancer. The load
• If you need higher bandwidth than a VPN connection supports, consider using an Azure ExpressRoute connection instead. balancer is located in the front-end subnet of the
application.
Azure
Connect an on-premises network to Azure using ExpressRoute Architecture Components
This architecture extends an on-premises network to Azure, using Azure ExpressRoute. ExpressRoute connections use a private, dedicated connection through a third-party connectivity
provider. The private connection extends your on-premises network into Azure. On-premises network
A private local-area network running within an organization.
Azure public services
ExpressRoute circuit
A layer 2 or layer 3 circuit supplied by the connectivity
provider that joins the on-premises network with Azure
Public peering through the edge routers. The circuit uses the hardware
infrastructure managed by the connectivity provider.
Local edge routers
Routers that connect the on-premises network to the circuit
On-premises nework
managed by the provider. Depending on how your
corporate network
connection is provisioned, you may need to provide the
public IP addresses used by the routers.
Azure Virtual networks
Local Microsoft
edge edge Microsoft edge routers
routers routers
Two routers in an active-active highly available configuration.
Private peering These routers enable a connectivity provider to connect their
ExpressRoute circuit circuits directly to their datacenter. Depending on how your
connection is provisioned, you may need to provide the
public IP addresses used by the routers.
Azure virtual networks (VNets)
Each VNet resides in a single Azure region, and can host
multiple application tiers. Application tiers can be
segmented using subnets in each VNet.
Azure public services
Office 365 services
Azure services that can be used within a hybrid application.
Microsoft peering These services are also available over the Internet, but
accessing them using an ExpressRoute circuit provides low
latency and more predictable performance, because traffic
does not go through the Internet. Connections are
performed using public peering, with addresses that are
either owned by your organization or supplied by your
connectivity provider.
Recommendations
Office 365 services
• Ensure that your organization has met the ExpressRoute prerequisite requirements for connecting to Azure. See ExpressRoute prerequisites & checklist.
The publicly available Office 365 applications and services
• Create an Azure VNet with an address space large enough for all of your required resources, with room for growth in case more VMs are needed in the future. The provided by Microsoft. Connections are performed using
address space of the VNet must not overlap with the on-premises network. Microsoft peering, with addresses that are either owned by
your organization or supplied by your connectivity provider.
• The virtual network gateway requires a subnet named GatewaySubnet. Do not deploy any VMs to the gateway subnet. Also, do not assign an NSG to this subnet, as it will You can also connect directly to Microsoft CRM Online
cause the gateway to stop functioning. through Microsoft peering.
• Although some providers allow you to change your bandwidth, make sure you pick an initial bandwidth that surpasses your needs and provides room for growth. Connectivity providers (not shown)
300
• Consider the following options for high availability: Companies that provide a connection either using layer 2 or
layer 3 connectivity between your datacenter and an Azure
datacenter.
If you're using a layer 2 connection, deploy redundant routers in your on-premises network in an active-active configuration. Connect the primary circuit to one router, and the secondary
circuit to the other.
If you're using a layer 3 connection, verify that it provides redundant BGP sessions that handle availability for you.
Connect the VNet to multiple ExpressRoute circuits, supplied by different service providers. This strategy provides additional high-availability and disaster recovery capabilities.
Configure a site-to-site VPN as a failover path for ExpressRoute. This option only applies to private peering. For Azure and Office 365 services, the Internet is the only failover path.
Azure
Connect an on-premises network to Azure using ExpressRoute with VPN failover Architecture Components
This architecture extends an on-premises network to Azure by using ExpressRoute, with a site-to-site virtual private network (VPN) as a failover connection. Traffic flows between the
on-premises network and the Azure VNet through an ExpressRoute connection. If there is a loss of connectivity in the ExpressRoute circuit, traffic is routed through an IPSec VPN tunnel. On-premises network
A private local-area network running within an organization.
VPN appliance
A device or service that provides external connectivity to the
On-premises nework on-premises network. The VPN appliance may be a hardware
device, or it can be a software solution such as the Routing
and Remote Access Service (RRAS) in Windows Server 2012.
Local Microsoft
For a list of supported VPN appliances and information on
Edge edge
Routers routers configuring selected VPN appliances for connecting to
Azure, see About VPN devices for Site-to-Site VPN Gateway
connections.
ExpressRoute circuit ExpressRoute circuit
A layer 2 or layer 3 circuit supplied by the connectivity
Gateway provider that joins the on-premises network with Azure
through the edge routers. The circuit uses the hardware
infrastructure managed by the connectivity provider.
Virtual network
ExpressRoute virtual network gateway
The ExpressRoute virtual network gateway enables the VNet
GATEWAY WEB TIER
AVAILABLITY
BUSINESS TIER
AVAILABLITY
DATA TIER
AVAILABLITY to connect to the ExpressRoute circuit used for connectivity
SUBNET
SET SET SET with your on-premises network.
VPN virtual network gateway
NSG VM NSG VM NSG VM
The VPN virtual network gateway enables the VNet to
connect to the VPN appliance in the on-premises network.
The VPN virtual network gateway is configured to accept
VM VM VM requests from the on-premises network only through the
ExpressRoute
VPN appliance. For more information, see Connect an
Gateway on-premises network to a Microsoft Azure virtual network.
VM VM VM
VPN connection
The connection has properties that specify the connection
MANAGEMENT SUBNET type (IPSec) and the key shared with the on-premises VPN
appliance to encrypt traffic.
NSG
Azure Virtual Network (VNet)
VM
VPN Gateway Each VNet resides in a single Azure region, and can host
Jumpbox
multiple application tiers. Application tiers can be
segmented using subnets in each VNet.
Gateway subnet
The virtual network gateways are held in the same subnet.
301
Recommendations Cloud application
• The recommendations from the previous two architectures apply to this architecture. The application hosted in Azure. It might include multiple
tiers, with multiple subnets connected through Azure load
balancers. For more information about the application
• After you establish the virtual network gateway connections, test the environment. First make sure you can connect from your on-premises network to your Azure VNet.
infrastructure, see Running Windows VM workloads and
This connection will use ExpressRoute. Then contact your provider to stop ExpressRoute connectivity for testing, and verify that you can still connect using the VPN
Running Linux VM workloads.
connection.
Azure
Implement a hub-spoke network topology in Azure Architecture Components
In this architecture, the hub is an Azure virtual network (VNet) that acts as a central point of connectivity to your on-premises network. The spokes are VNets that peer with the hub, and can
be used to isolate workloads. On-premises network
Reasons to consider this architecture : A private local-area network running within an organization.
Reduce costs by centralizing services shared services such as network virtual appliances (NVAs) and DNS servers.
Overcome subscriptions limits by peering VNets from different subscriptions to the central hub.
Separate concerns between central IT (SecOps, InfraOps) and workloads (DevOps). VPN Device
A device or service that provides external connectivity to the
Spoke1 Virtual Network on-premises network. The VPN device may be a hardware device, or
a software solution such as the Routing and Remote Access Service
(RRAS) in Windows Server 2012. For a list of supported VPN applianc-
es and information on configuring selected VPN appliances for con-
WEB TIER necting to Azure, see About VPN devices for Site-to-Site VPN Gate-
AVAILABLITY
way connections.
SET
On-premise network Hub Virtual Network VPN virtual network gateway
NSG VM
or ExpressRoute gateway
The virtual network gateway enables the VNet to connect to the VPN
PERIMETER CLOUD ACCESS GATEWAY SUBNET SHARED SERVICES
device, or ExpressRoute circuit, used for connectivity with your
SERVICES POINT
VM on-premises network. For more information, see Connect an
NSG
on-premises network to a Microsoft Azure virtual network.
AVAILABLITY
SET VM Note:
The deployment scripts for this reference architecture use a VPN
gateway for connectivity, and a VNet in Azure to simulate your
Peering
on-premises network.
VM Peering Spoke2 Virtual Network
Backend Systems DNS Services VPN Device ExpressRoute Hub Vnet
Gateway
Azure VNet used as the hub in the hub-spoke topology. The hub is
the central point of connectivity to your on-premises network, and a
VM WEB TIER
AVAILABLITY place to host services that can be consumed by the different work-
SET loads hosted in the spoke VNets.
DNS
Gateway subnet
NSG VM
The virtual network gateways are held in the same subnet.
VM Shared services subnet
A subnet in the hub VNet used to host services that can be shared
among all spokes, such as DNS or AD DS.
VM
Spoke Vnets
One or more Azure VNets that are used as spokes in the hub-spoke
Recommendations topology. Spokes can be used to isolate workloads in their own
VNets, managed separately from other spokes. Each workload might
• The hub VNet, and each spoke VNet, can be implemented in different resource groups, and even different subscriptions, as long as they belong to the same Azure Active include multiple tiers, with multiple subnets connected through
Directory (Azure AD) tenant in the same Azure region. This allows for a decentralized management of each workload, while sharing services maintained in the hub VNet. Azure load balancers. For more information about the application
infrastructure, see Running Windows VM workloads and Running
Linux VM workloads.
302
• A hub-spoke topology can be used without a gateway, if you don't need connectivity with your on-premises network.
• If you require connectivity between spokes, consider implementing an NVA for routing in the hub, and using user defined routes (UDRs) in the spoke to forward traffic to
the hub. Vnet peering
Two VNets in the same Azure region can be connected using a peer-
• Make sure to consider the limitation on the number of VNet peerings per VNet in Azure. If you need more spokes than this limit, consider creating a ing connection. Peering connections are non-transitive, low latency
hub-spoke-hub-spoke topology, where the first level of spokes also act as hubs. connections between VNets. Once peered, the VNets exchange traffic
by using the Azure backbone, without the need for a router. In a
• Consider what services are shared in the hub, to ensure the hub scales to the number of spokes. hub-spoke network topology, you use VNet peering to connect the
hub to each spoke.
Red DMZ
Estas arquitecturas de referencia muestran prácticas probadas de creación
de redes DMZ que protejan el límite entre una red virtual Azure y una red
local o Internet.
NIC
NIC
MANAGEMENT SUBNET
10�0�0�128/25 NVA such as allowing or denying access as a firewall, optimizing
wide area network (WAN) operations (including network
Internal Load
NSG Balancer
compression), custom routing, or other network
functionality.
Jump Box
Web Tier, Business Tier, and Data Tier Subnets
Subnets hosting the VMs and services that implement an
example 3-tier application running in the cloud. See Running
WEB TIER
AVAILABLITY
BUSINESS TIER DATA TIER Windows VMs for an N-tier architecture on Azure for more
10�0�1�0/24 AVAILABLITY AVAILABLITY
SET
10�0�2�0/24
SET
10�0�3�0/24
SET information.
User Defined Routes
NSG VM NSG VM NSG VM User defined routes define the flow of IP traffic within Azure
VNets.
NOTE: Depending on the requirements of your VPN
VM VM VM connection, you can configure Border Gateway Protocol
(BGP) routes instead of using UDRs to implement the
forwarding rules that direct traffic back through the
on-premises network.
VM VM VM
Management Subnet
This subnet contains VMs that implement management and
monitoring capabilities for the components running in the
Recommendations VNet.
• Use Role-Based Access Control (RBAC) to manage the resources in your application.
• On-premises traffic passes to the VNet through a virtual network gateway. We recommend an Azure VPN gateway or an Azure ExpressRoute gateway.
• Create a network security group (NSG) for the inbound NVA subnet, and only allow traffic originating from the on-premises network.
304
• Create NSGs for each subnet to provide a second level of protection in case of an incorrectly configured or disabled NVA.
• Force-tunnel all outbound Internet traffic through your on-premises network using the site-to-site VPN tunnel, and route to the Internet using network address
translation (NAT).
• Don't completely block Internet traffic from the application tiers, as this will prevent these tiers from using Azure PaaS services that rely on public IP addresses, such as VM
diagnostics logging.
• Perform all application and resource monitoring through the jumpbox in the management subnet.
Azure
DMZ between Azure and the Internet Architecture Components
This architecture implements a DMZ (also called a perimeter network) that accepts Internet traffic to an Azure virtual network. It also includes a DMZ that handles traffic from an on-premises
network. Network virtual appliances (NVAs) implement security functionality such as firewalls and packet inspection. Public IP Address (PIP)
The IP address of the public endpoint. External users
connected to the Internet can access the system through this
On-premises nework Virtual network address.
GATEWAY SUBNET
Network Virtual Appliance (NVA)
10�0�255�224/27
PRIVATE DMZ IN AVAILABLITY PRIVATE DMZ OUT This architecture includes a separate pool of NVAs for traffic
UDR 10�0�0�0/27 SET 10�0�0�32/27 originating on the Internet.
Azure Load Balancer
NIC
NIC
NVA
NSG All incoming requests from the Internet pass through the
Gateway NSG
load balancer and are distributed to the NVAs in the public
DMZ.
MANAGEMENT SUBNET
NIC
NIC
10�0�0�128/25 NVA
Public DMZ Inbound Subnet
Internal Load This subnet accepts requests from the Azure load balancer.
NSG
Balancer
Incoming requests are passed to one of the NVAs in the
Jump Box public DMZ.
Web app request
Public DMZ Outbound Subnet
WEB TIER BUSINESS TIER DATA TIER
AVAILABLITY AVAILABLITY AVAILABLITY
10�0�1�0/24
SET
10�0�2�0/24
SET
10�0�3�0/24
SET
Requests that are approved by the NVA pass through this
subnet to the internal load balancer for the web tier.
NSG NSG NSG
VM VM VM
VM VM VM
VM VM VM
PUBLIC DMZ IN AVAILABLITY PUBLIC DMZ OUT
10�0�0�0/27 SET 10�0�0�32/27
Azure Load
NIC
NIC
Balancer NVA
PIP NSG NSG
Recommendations
NIC
NIC
NVA
• Use one set of NVAs for traffic originating on the Internet, and another for
traffic originating on-premises.
• Include a layer-7 NVA to terminate application connections at the NVA level
and maintain compatibility with the backend tiers.
305
• For scalability and availability, deploy the public DMZ NVAs in an availability
set with a load balancer to distribute requests across the NVAs.
• Even if your architecture initially requires a single NVA, we recommend
putting a load balancer in front of the public DMZ from the beginning. That
makes it easier to scale to multiple NVAs in the future.
• Log all incoming requests on all ports. Regularly audit the logs.
Aplicación web
administrada
Estas arquitecturas de referencia muestran prácticas probadas de
aplicaciones web que utilizan Azure App Service y otros servicios
administrados en Azure.
307
deployments into a separate App Service plan to isolate them from the production version.
• Store configuration settings as app settings. Define the app settings in your Resource Manager templates, or using PowerShell. Never check passwords, access keys, or
connection strings into source control. Instead, pass these as parameters to a deployment script that stores these values as app settings.
• Consider using App Service authentication to implement authentication with an identity provider such as Azure Active Directory, Facebook, Google, or Twitter.
• Use SQL Database point-in-time restore to recover from human error by returning the database to an earlier point in time. Use geo-restore to recover from a service
outage by restoring a database from a geo-redundant backup.
Azure
Improved scalability in a web application Architecture Components
This architecture builds on the one shown in “Basic web application” and adds elements to improve scalability and performance.
Resource Group
A resource group is a logical container for Azure resources.
Web App and API App
A typical modern application might include both a website
Web Front End and one or more RESTful web APIs. A web API might be
consumed by browser clients through AJAX, by native client
App Service App Service Plan Data Storage applications, or by server-side applications. For
Authentication Plan considerations on designing web APIs, see API design
guidance.
{}
Azure Active SQL Database Document DB WebJob
Directory Web App API App WebJob Redis Cache Use Azure WebJobs to run long-running tasks in the
background. WebJobs can run on a schedule, continously, or
in response to a trigger, such as putting a message on a
queue. A WebJob runs as a background process in the
context of an App Service app.
Queue
Logs Queue Static Azure Search In the architecture shown here, the application queues
Content background tasks by putting a message onto an Azure
Queue storage queue. The message triggers a function in the
WebJob. Alternatively, you can use Service Bus queues. For a
Blob comparison, see Azure Queues and Service Bus queues -
compared and contrasted.
Storage Storage Storage Content Delivery
Account Account Account Network
Cache
Store semi-static data in Azure Redis Cache.
Resource
Group CDN
Use Azure Content Delivery Network (CDN) to cache publicly
Email/SMS available content for lower latency and faster delivery of
Service content.
Edge Servers
Data Storage
Use Azure SQL Database for relational data. For
Recommendations non-relational data, consider a NoSQL store, such as Cosmos
DB.
• Use Azure WebJobs to run long-running tasks in the background. WebJobs can run on a schedule, continuously, or in response to a trigger, such as putting a message
on a queue.
Azure Search
• Consider deploying resource intensive WebJobs to a separate App Service plan. This provides dedicated instances for the WebJob.
Use Azure Search to add search functionality such as search
• Use Azure Redis Cache to cache semi-static transaction data, session state, and HTML output. suggestions, fuzzy search, and language-specific search.
Azure Search is typically used in conjunction with another
• Use Azure CDN to cache static content. The main benefit of a CDN is to reduce latency for users, because content is cached at an edge server that is geographically close data store, especially if the primary data store requires strict
consistency. In this approach, store authoritative data in the
to the user. CDN can also reduce load on the application, because that traffic is not being handled by the application.
308
other data store and the search index in Azure Search. Azure
Search can also be used to consolidate a single search index
• Choose a data store based on application requirements. Depending on the scenario, you might use multiple stores. For more guidance, see Choose the right data store.
from multiple data stores.
• If you are using Azure SQL Database, consider using elastic pools. Elastic pools enable you to manage and scale multiple databases that have varying and unpredictable
usage demands. Email/SMS
Use a third-party service such as SendGrid or Twilio to send
• Also consider using Elastic Database tools to shard the database. Sharding allows you to scale out the database horizontally. email or SMS messages instead of building this functionality
directly into the application.
• Use Transparent Data Encryption to encrypt data at rest in Azure SQL Database.
Azure
Run a web application in multiple regions Architecture Components
This architecture shows a web application running on Azure App Service in two regions to achieve high availability. If an outage occurs in the primary region, the application can fail over to the secondary region.
Primary and Secondary Regions
Region 1 (Active)
This architecture uses two regions to achieve higher
availability. The application is deployed to each region.
App Service App Service Plan Data Storage During normal operations, network traffic is routed to the
Plan primary region. If the primary region becomes unavailable,
{} traffic is routed to the secondary region.
SQL Database Document DB
Web App API App WebJob Redis Cache Azure Traffice Manager
Traffic Manager routes incoming requests to the primary
region. If the application running that region becomes
Internet
unavailable, Traffic Manager fails over to the secondary
region.
Logs Queue Static
Content Azure Search
Geo-replication
of SQL Database and Cosmos DB.
Storage Storage Storage Content Delivery
Account Account Account Network (CDN)
should content below be included?
Region 2 (Standby) Read-only
replica Geo-replication A multi-region architecture can provide higher availability
than deploying to a single region. If a regional outage affects
the primary region, you can use Traffic Manager to fail over
to the secondary region. This architecture can also help if an
App Service App Service Plan Data Storage individual subsystem of the application fails.
Plan
{} There are several general approaches to achieving high
availability across regions:
SQL Database Document DB
Web App API App WebJob Redis Cache Active/passive with hot standby. Traffic goes to one region,
while the other waits on hot standby. Hot standby means the
VMs in the secondary region are allocated and running at all
times.
Logs Queue Active/passive with cold standby. Traffic goes to one region,
Azure Search while the other waits on cold standby. Cold standby means
the VMs in the secondary region are not allocated until
needed for failover. This approach costs less to run, but will
generally take longer to come online during a failure.
Storage Storage
Account Account Active/active. Both regions are active, and requests are load
balanced between them. If one region becomes unavailable,
Recommendations it is taken out of rotation.
• Each Azure region is paired with another region within the same geography. In general, choose regions from the same regional pair. If there is a broad outage, recovery of at least one region out of every This reference architecture focuses on active/passive with hot
pair is prioritized. standby, using Traffic Manager for failover.
• Configure Traffic Manager to use priority routing, which routes all requests to the primary region. If the primary region becomes unreachable, Traffic Manager automatically fails over to the secondary
region.
• Traffic Manager uses an HTTP (or HTTPS) probe to monitor the availability of each region. Create a health probe endpoint that reports the overall health of the application.
309
• Traffic Manager is a possible failure point in the system. Review the Traffic Manager SLA, and determine whether using Traffic Manager alone meets your business requirements for high availability. If not,
consider adding another traffic management solution as a failback.
• For Azure SQL Database, use Active Geo-Replication to create a readable secondary replica in a different region. Fail over to a secondary database if your primary database fails or needs to be taken offline.
• Cosmos DB also supports geo-replication across regions. One region is designated as writable and the others are read-only replicas. If there is a regional outage, you can fail over by selecting another
region to be the write region.
• For Azure Storage, use read-access geo-redundant storage (RA-GRS).
Ejecución de cargas
de trabajo en máquina
virtual de Linux
Estas arquitecturas de referencia muestran prácticas probadas
de ejecución de máquinas virtuales de Linux en Azure.
311
• Reserve a static IP address if you need a fixed IP address that won't change — for example, if you need to create an A record in DNS, or need the IP address to be added
to a safe list.
Diagnostics
• For higher availability, deploy multiple VMs behind a load balancer. See [Load balanced VMs reference architecture] Diagnostic logging is crucial for managing and
troubleshooting the VM.
• Use Azure Security Center to get a central view of the security state of your Azure resources. Security Center monitors potential security issues and provides a
comprehensive picture of the security health of your deployment.
• Consider Azure Disk Encryption if you need to encrypt the OS and data disks.
Azure
Run load-balanced VMs for scalability and availability Architecture Components
This architecture shows running several Linux virtual machines (VMs) running behind a load balancer, to improve availability and scalability. This architecture can be used for any stateless
workload, such as a web server, and is a building block for deploying n-tier applications. Availability Set
The availability set contains the VMs, making the VMs
eligible for the availability service level agreement (SLA) for
Azure VMs. For the SLA to apply, the availability set must
include a minimum of two VMs. Availability sets are implicit
in scale sets. If you create VMs outside a scale set, you need
to create the availability set independently.
Virtual Network (VNet) and Subnet
Every VM in Azure is deployed into a VNet that is further
divided into subnets.
Azure Load Balancer
Virtual network
The load balancer distributes incoming Internet requests to
the VM instances. The load balancer includes some related
SUBNET
resources:
VM 1 Storage VHDs
Account
Public IP Address
AVAILABLITY
SET A public IP address is needed for the load balancer to
receive Internet traffic.
Front-end Configuration
Public IP
VM 2 Storage VHDs Associates the public IP address with the load balancer.
Account
Azure Load Back-end Address Pool
Internet Balancer Contains the network interfaces (NICs) for the VMs that
Diagnostics will receive the incoming traffic.
VM Scaleset
Logs
Logs Storage
Load Balancer Rules
Account Used to distribute network traffic among all the VMs in the
back-end address pool.
Network Address Translation (NAT) Rules
Used to route traffic to a specific VM. For example, to enable
remote desktop protocol (RDP) to the VMs, create a separate
NAT rule for each VM.
Storage
If you are not using managed disks, storage accounts hold
the VM images and other file-related resources, such as VM
Recommendations diagnostic data captured by Azure.
• Consider using a VM scale set if you need to quickly scale out VMs, or need to autoscale. If you don’t use a scale set, place the VMs in an availability set. VM Scale set
A VM scale set is a set of identical VMs used to host a
• Use Managed disks, which do not require a storage account. You simply specify the size and type of disk and it is deployed in a highly available way. workload. Scale sets allow the number of VMs to be scaled in
or out manually, or based on predefined rules.
• Place the VMs within the same subnet. Do not expose the VMs directly to the Internet, but instead give each VM a private IP address. Clients connect using the public IP
312
address of the load balancer.
• For incoming Internet traffic, the load balancer rules define which traffic can reach the back end. However, load balancer rules don't support IP whitelisting, so if you want
to add certain public IP addresses to a whitelist, add an NSG to the subnet.
• The load balancer uses health probes to monitor the availability of VM instances. If your VMs run an HTTP server, create an HTTP probe. Otherwise create a TCP probe.
• Virtual networks are a traffic isolation boundary in Azure. VMs in one VNet cannot communicate directly to VMs in a different VNet. VMs within the same VNet can
communicate, unless you create network security groups (NSGs) to restrict traffic.
Azure
Run Linux VMs for an N-tier Application Architecture Components
This architecture shows how to deploy Linux virtual machines (VMs) to run an N-tier application in Azure. For the data tier, this architecture shows Apache Cassandra, which provides
replication and failover. However you could easily replace Cassandra in this architecture with another database, such as SQL Server. Availability Sets
Create an availability set for each tier, and provision at least
two VMs in each tier. This makes the VMs eligible for a
higher service level agreement (SLA) for VMs.
Subnets
VIRTUAL NETWORK Create a separate subnet for each tier. Specify the address
range and subnet mask using CIDR notation.
WEB TIER BUSINESS TIER DATA TIER
SUBNET
AVAILABLITY SUBNET
AVAILABLITY SUBNET
AVAILABLITY
SET SET SET Load Balancers
Use an Internet-facing load balancer to distribute incoming
VM
Internet traffic to the web tier, and an internal load balancer
NSG VM NSG VM to distribute network traffic from the web tier to the business
VM VM
tier.
Cassandra
NSG
Cluster
VM VM
Jumpbox
Azure Load Also called a bastion host. A secure VM on the network that
VM VM administrators use to connect to the other VMs. The
Internet Balancer
jumpbox has an NSG that allows remote traffic only from
VM VM VM public IP addresses on a safe list. The NSG should permit
secure shell (SSH) traffic.
Monitoring
MANAGEMENT SUBNET
Monitoring software such as Nagios, Zabbix, or Icinga can
give you insight into response time, VM uptime, and the
overall health of your system. Install the monitoring software
on a VM that's placed in a separate management subnet.
NSG
VM
NSGs
DevOps Jumpbox Use network security groups (NSGs) to restrict network
traffic within the VNet. For example, in the 3-tier architecture
shown here, the database tier does not accept traffic from
the web front end, only from the business tier and the
management subnet.
Apache Cassandra Database
Provides high availability at the data tier, by enabling
replication and failover.
Recommendations
• When you create the VNet, determine how many IP addresses your resources in each subnet require.
• Choose an address range that does not overlap with your on-premises network, in case you need to set up a gateway between the VNet and your on-premises network later.
• Design subnets with functionality and security requirements in mind. All VMs within the same tier or role should go into the same subnet, which can be a security boundary.
313
• Use NSG rules to restrict traffic between tiers. For example, in the 3-tier architecture shown above, the web tier should not communicate directly with the database tier.
• Do not allow SSH access from the public Internet to the VMs that run the application workload. Instead, all SSH access to these VMs must come through the jumpbox.
• The load balancers distribute network traffic to the web and business tiers. Scale horizontally by adding new VM instances. Note that you can scale the web and business
tiers independently, based on load.
• At the database tier, having multiple VMs does not automatically translate into a highly available database. For a relational database, you will typically need to use replication
and failover to achieve high availability.
Azure
Run Linux VMs in multiple regions for high availability Architecture Components
This architecture shows an N-tier application deployed in two Azure regions. This architecture can provide higher availability than a single region. If an outage occurs in the primary region,
the application can fail over to the secondary region. However, you must consider issues such as data replication and managing failover. Primary and Secondary Regions
Use two regions to achieve higher availability. One is the
primary region.The other region is for failover.
WEB TIER BUSINESS TIER CASSANDRA
Azure Traffic Manager
Traffic Manager routes incoming requests to one of the
VM
VM regions. During normal operations, it routes requests to the
VM primary region. If that region becomes unavailable, Traffic
VM VM
Manager fails over to the secondary region. For more
VM information, see the section Traffic Manager configuration.
VM
VM Resource Group
VM VM
Create separate resource groups for the primary region, the
VM
VM secondary region, and for Traffic Manager. This gives you the
flexibility to manage each region as a single collection of
resources. For example, you could redeploy one region,
VM Jumpbox without taking down the other one. Link the resource
groups, so that you can run a query to list all the resources
for the application.
VNets
WEB TIER BUSINESS TIER CASSANDRA
Create a separate VNet for each region. Make sure the
address spaces do not overlap.
VM
VM
VM
VM VM Apache Cassandra
VM Deploy Cassandra in data centers across Azure regions for
VM high availability. Within each region, nodes are configured in
rack-aware mode with fault and upgrade domains, for
VM
VM VM resiliency inside the region.
VM
VM
VM Jumpbox
Recommendations
• Each Azure region is paired with another region within the same geography. In general, choose regions from the same regional pair. If there is a broad outage, recovery of at
least one region out of every pair is prioritized.
• Configure Traffic Manager to use priority routing, which routes all requests to the primary region. If the primary region becomes unreachable, Traffic Manager automatically
fails over to the secondary region.
• If Traffic Manager fails over, we recommend performing a manual failback rather than implementing an automatic failback. Verify that all application subsystems are healthy
before failing back.
• Traffic Manager uses an HTTP (or HTTPS) probe to monitor the availability of each region. Create a health probe endpoint that reports the overall health of the application.
314
• Traffic Manager is a possible failure point in the system. Review the Traffic Manager SLA, and determine whether using Traffic Manager alone meets your business
requirements for high availability. If not, consider adding another traffic management solution as a failback.
• For the data tier, this architecture shows Apache Cassandra for data replication and failover. Other database systems have similar functionality.
• When you update your deployment, update one region at a time to reduce the chance of a global failure from an incorrect configuration or an error in the application.
• Test the resiliency of the system to failures. Measure the recovery times and verify they meet your business requirements.
Ejecución de cargas
de trabajo en máquina
virtual de Windows
Estas arquitecturas de referencia muestran prácticas probadas
de ejecución de máquinas virtuales de Windows en Azure.
Public IP Address deleted during reboots and other VM lifecycle events. Use
VHD this disk only for temporary data, such as page or swap files.
VM
Internet
Data Disk
Data 2 A data disk is a persistent VHD used for application data.
Data disks are stored in Azure Storage, like the OS disk.
Temp
Diagnostics
Virtual Network (VNet) and Subnet
Logs Every VM in Azure is deployed into a VNet that is further
divided into subnets.
Logs Storage
Physical SSD
Account
on Host Public IP Address
A public IP address is needed to communicate with the
VM—for example over remote desktop (RDP).
Recommendations Network interface (NIC)
• For best disk I/O performance, we recommend Premium Storage, which stores data on solid-state drives (SSDs). The NIC enables the VM to communicate with the virtual
network.
• Use Managed disks, which do not require a storage account. You simply specify the size and type of disk and it is deployed in a highly available way.
• Attach a data disk for persistent storage of application data. Network security group (NSG)
The NSG is used to allow/deny network traffic to the subnet.
• Enable monitoring and diagnostics, including health metrics, diagnostics infrastructure logs, and boot diagnostics.
You can associate an NSG with an individual NIC or with a
subnet. If you associate it with a subnet, the NSG rules apply
• Add an NSG to the subnet to allow/deny network traffic to the subnet. To enable remote desktop (RDP), add a rule to the NSG that allows inbound traffic to TCP port 3389. to all VMs in that subnet.
316
• Reserve a static IP address if you need a fixed IP address that won't change — for example, if you need to create an A record in DNS, or need the IP address to be added to
a safe list. Diagnostics
Diagnostic logging is crucial for managing and
• For higher availability, deploy multiple VMs behind a load balancer. See [Load balanced VMs reference architecture] troubleshooting the VM.
• Use Azure Security Center to get a central view of the security state of your Azure resources. Security Center monitors potential security issues and provides a
comprehensive picture of the security health of your deployment.
• Consider Azure Disk Encryption if you need to encrypt the OS and data disks.
Azure
Run load-balanced VMs for scalability and availability Architecture Components
This architecture shows running several Windows virtual machines (VMs) running behind a load balancer, to improve availability and scalability. This architecture can be used for any stateless
workload, such as a web server, and is a building block for deploying n-tier applications. Resource group
Resource groups are used to group resources so they can be
managed by lifetime, owner, and other criteria.
Virtual Network (VNet) and Subnet
Every VM in Azure is deployed into a VNet that is further
divided into subnets.
Azure Load Balancer
The load balancer distributes incoming Internet requests to
the VM instances. The load balancer includes some related
resources:
Virtual network
Public IP Address
A public IP address is needed for the load balancer to
SUBNET VM 1 Storage VHDs receive Internet traffic.
Account
AVAILABLITY
SET Front-end Configuration
Associates the public IP address with the load balancer.
Back-end Address Pool
Public IP
VM 2 Storage VHDs
Contains the network interfaces (NICs) for the VMs that
Account
will receive the incoming traffic.
Azure Load
Internet Balancer Load Balancer Rules
VM Scaleset
Diagnostics Used to distribute network traffic among all the VMs in the
Logs back-end address pool.
Logs Storage
Account VM Scale set
A VM scale set is a set of identical VMs used to host a
workload. Scale sets allow the number of VMs to be scaled in
or out manually, or based on predefined rules.
Availability Set
The availability set contains the VMs, making the VMs
eligible for the availability service level agreement (SLA) for
Azure VMs. In order for the SLA to apply, the availability set
must include a minimum of two VMs. Availability sets are
implicit in scale sets. If you create VMs outside a scale set,
Recommendations you need to create the availability set independently.
• Consider using a VM scale set if you need to quickly scale out VMs, or need to autoscale. If you don’t use a scale set, place the VMs in an availability set.
Storage
If you are not using managed disks, storage accounts hold
• Use Managed disks, which do not require a storage account. You simply specify the size and type of disk and it is deployed in a highly available way.
the VM images and other file-related resources, such as VM
diagnostic data captured by Azure.
• Place the VMs within the same subnet. Do not expose the VMs directly to the Internet, but instead give each VM a private IP address. Clients connect using the public IP
address of the load balancer.
317
• For incoming Internet traffic, the load balancer rules define which traffic can reach the back end. However, load balancer rules don't support IP whitelisting, so if you want
to add certain public IP addresses to a whitelist, add an NSG to the subnet.
• The load balancer uses health probes to monitor the availability of VM instances. If your VMs run an HTTP server, create an HTTP probe. Otherwise create a TCP probe.
• Virtual networks are a traffic isolation boundary in Azure. VMs in one VNet cannot communicate directly to VMs in a different VNet. VMs within the same VNet can
communicate, unless you create network security groups (NSGs) to restrict traffic.
Azure
Run Windows VMs for an N-tier application Architecture Components
This architecture shows how to deploy Windows virtual machines (VMs) to run an N-tier application in Azure. For the data tier, this architecture uses SQL Server Always On Availability
Groups, which provide replication and failover. Availability Sets
Create an availability set for each tier, and provision at least
two VMs in each tier. This makes the VMs eligible for a
higher service level agreement (SLA) for VMs.
Subnets
VIRTUAL NETWORK
Create a separate subnet for each tier. Specify the address
range and subnet mask using CIDR notation.
WEB TIER BUSINESS TIER BUSINESS TIER
SUBNET
AVAILABLITY SUBNET
AVAILABLITY SUBNET
AVAILABLITY
SET SET SET
Load Balancers
Use an Internet-facing load balancer to distribute incoming
Internet traffic to the web tier, and an internal load balancer
NSG VM NSG VM NSG to distribute network traffic from the web tier to the
business tier.
SQL Server
(Primary)
Jumpbox
VM VM
Also called a bastion host. A secure VM on the network that
Azure Load
administrators use to connect to the other VMs. The
Internet Balancer
jumpbox has an NSG that allows remote traffic only from
public IP addresses on a safe list. The NSG should permit
VM VM
remote desktop (RDP) traffic.
SQL Server Monitoring
(Secondary)
Monitoring software such as Nagios, Zabbix, or Icinga can
MANAGEMENT SUBNET ACTIVE DIRECTORY SUBNET
give you insight into response time, VM uptime, and the
overall health of your system. Install the monitoring software
on a VM that's placed in a separate management subnet.
NSG NSG
VM VM NSGs
Use network security groups (NSGs) to restrict network
DevOps Jumpbox AD DS AD DS File share
Server Server witness traffic within the VNet. For example, in the 3-tier architecture
shown here, the database tier does not accept traffic from
the web front end, only from the business tier and the
management subnet.
SQL Server Always On Availability Group
Provides high availability at the data tier, by enabling
replication and failover.
Recommendations
Active Directory Domain Services
• When you create the VNet, determine how many IP addresses your resources in each subnet require. (AD DS) Servers
• Choose an address range that does not overlap with your on-premises network, in case you need to set up a gateway between the VNet and your on-premises network later. Prior to Windows Server 2016, SQL Server Always On
Availability Groups must be joined to a domain. This is
because Availability Groups depend on Windows Server
• Design subnets with functionality and security requirements in mind. All VMs within the same tier or role should go into the same subnet, which can be a security boundary.
Failover Cluster (WSFC) technology. Windows Server 2016
introduces the ability to create a Failover Cluster without
• Use NSG rules to restrict traffic between tiers. For example, in the 3-tier architecture shown above, the web tier should not communicate directly with the database tier. Active Directory, in which case the AD DS servers are not
318
required for this architecture. For more information, see
• Do not allow remote desktop (RDP) access from the public Internet to the VMs that run the application workload. Instead, all RDP access to these VMs must come through What's new in Failover Clustering in Windows Server 2016.
the jumpbox.
• The load balancers distribute network traffic to the web and business tiers. Scale horizontally by adding new VM instances. Note that you can scale the web and business
tiers independently, based on load.
• We recommend Always On Availability Groups for SQL Server high availability. When a SQL client tries to connect, the load balancer routes the connection request to the
primary replica. If there is a failover to another replica, the load balancer automatically starts routing requests to the new primary replica.
Azure
Run Windows VMs in multiple regions for high availability Architecture Components
This architecture shows an N-tier application deployed in two Azure regions. This architecture can provide higher availability than a single region. If an outage occurs in the primary region,
the application can fail over to the secondary region. However, you must consider issues such as data replication and managing failover. Primary and Secondary Regions
Use two regions to achieve higher availability. One is the
WEB TIER
primary region. The other region is for failover.
BUSINESS TIER SQL SERVER ALWAYS ON
AVAILABILITY GROUP
VM
Azure Traffic Manager
VM Traffic Manager routes incoming requests to one of the
VM regions. During normal operations, it routes requests to the
VM primary region. If that region becomes unavailable, Traffic
Manager fails over to the secondary region. For more
VM
VM VM information, see the section Traffic Manager configuration.
ACTIVE DIRECTORY
Resource Groups
JUMPBOX GATEWAY SUBNET
Create separate resource groups for the primary region, the
secondary region, and for Traffic Manager. This gives you the
flexibility to manage each region as a single collection of
VM resources. For example, you could redeploy one region,
VPN Gateway
without taking down the other one. Link the resource
groups, so that you can run a query to list all the resources
for the application.
JUMPBOX ACTIVE DIRECTORY GATEWAY SUBNET VNets
Create a separate VNet for each region. Make sure the
address spaces do not overlap.
VM
VPN Gateway
SQL Server Always On Availability Group
WEB TIER BUSINESS TIER SQL SERVER ALWAYS ON
AVAILABILITY GROUP If you are using SQL Server, we recommend SQL Always On
Availability Groups for high availability. Create a single
VM availability group that includes the SQL Server instances in
VM both regions.
VM
Note
VM
VM Also consider Azure SQL Database, which provides a
VM relational database as a cloud service. With SQL Database,
VM you don't need to configure an availability group or manage
failover.
Recommendations
• Each Azure region is paired with another region within the same geography. In general, choose regions from the same regional pair. If there is a broad outage, recovery of at least one region out of every VPN Gateways
pair is prioritized. Create a VPN gateway in each VNet, and configure a
VNet-to-VNet connection, to enable network traffic between
• Configure Traffic Manager to use priority routing, which routes all requests to the primary region. If the primary region becomes unreachable, Traffic Manager automatically fails over to the secondary
the two VNets. This is required for the SQL Always On
region.
Availability Group.
• If Traffic Manager fails over, we recommend performing a manual failback rather than implementing an automatic failback. Verify that all application subsystems are healthy before failing back.
• Traffic Manager uses an HTTP (or HTTPS) probe to monitor the availability of each region. Create a health probe endpoint that reports the overall health of the application.
• Traffic Manager is a possible failure point in the system. Review the Traffic Manager SLA, and determine whether using Traffic Manager alone meets your business requirements for high availability. If not,
319
consider adding another traffic management solution as a failback.
• Create a SQL Server Always On Availability Group that includes the SQL Server instances in both the primary and secondary regions. Configure the replicas in the secondary region to use asynchronous
commit, for performance reasons.
• If all of the SQL Server database replicas in the primary region fail, you can manually fail over the availability group. With forced failover, there is a risk of data loss. Once the primary region is back online,
take a snapshot of the database and use tablediff to find the differences.
• When you update your deployment, update one region at a time to reduce the chance of a global failure from an incorrect configuration or an error in the application.
• Test the resiliency of the system to failures. Measure the recovery times and verify they meet your business requirements.