VENTAS: 1-800-867-1389

Prácticas recomendadas para el diseño de servicios a gran escala en los Servicios en la nube de Azure

Actualizado: enero de 2014

Autores: Mark Simms y Michael Thomassy

Colaboradores: Jason Roth y Ralph Squillace

Revisores: Brad Calder, Dennis Mulder, Mark Ozur, Nina Sarawgi, Marc Mercuri, Conor Cunningham, Peter Carlin, Stuart Ozer, Lara Rubbelke y Nicholas Dritsas.

La informática en nube es informática distribuida, que requiere un planeamiento y entrega meditados, independientemente de la plataforma elegida. El propósito de este documento es proporcionar una orientación razonada, basada en escenarios de clientes reales del para generar aplicaciones escalables en Azure y en la Base de datos SQL, aprovechando el método de plataforma como servicio (PaaS); las aplicaciones de este tipo se compilan como Servicios en la nube de Azure mediante los roles web y de trabajo.

ImportantImportante
NOTA: Todos los consejos sobre prácticas recomendadas de este documento son el resultado del compromiso adquirido con los clientes que ejecutan código de producción en Azure. En este documento se describe la plataforma de Servicios en la nube (PaaS) de Azure basada en la versión v1.6 del SDK; no se tratan características como Sitios web de Azure o Máquinas virtuales de Azure (IaaS).

En este documento se explican los conceptos de diseño subyacentes para la compilación de aplicaciones de Azure, las capacidades clave de la plataforma Azure, los límites y funciones, así como los procedimientos recomendados para trabajar con los servicios esenciales de Azure. El foco está en las aplicaciones responsables de un almacén de datos distribuidos con coherencia flexible (en contraposición a los modelos de datos multiempresa de alta densidad o estrictamente coherentes).

Los aspectos de desplazamiento de las aplicaciones y servicios de Azure pueden ser atractivos por muchas razones, por ejemplo:

  • Conservar o consolidar los gastos de capital en gastos operativos (convertir el capital en operaciones).

  • Reducir los costos (y mejorar la eficiencia) mediante una coincidencia más estrecha de la demanda y la capacidad.

  • Mejorar la agilidad y el tiempo de comercialización al reducir o quitar las barreras de la infraestructura.

  • Aumentar el alcance de la audiencia a nuevos mercados como los dispositivos móviles.

  • Beneficiarse de la escala masiva de la informática en nube al generar nuevas aplicaciones que pueden admitir un público global en los centros de datos distribuidos geográficamente.

Hay muchas razones técnicas excelentes para desarrollar nuevas aplicaciones o para trasladar todas o algunas de las aplicaciones existentes a Azure. Cuando el entorno está enriquecido con alternativas de implementación, se debe evaluar cuidadosamente el modelo específico de la aplicación para seleccionar el enfoque de implementación correcto. Algunas aplicaciones están indicadas para los Servicios en la nube de Azure (que es un enfoque de plataforma como servicio o PaaS), mientras que otras pueden beneficiarse de un enfoque parcial o completo de infraestructura como servicio (o IaaS), por ejemplo, las Máquinas virtuales de Azure. Finalmente, algunos requisitos de aplicación pueden atenderse mejor usando ambos juntos.

La aplicación debe tener uno o varios de los tres aspectos clave siguientes para maximizar las ventajas de los Servicios en la nube de Azure. (No todos ellos deben estar presentes en la aplicación; una aplicación bien puede producir un rendimiento seguro de la inversión si se usa Azure de la forma adecuada con solo uno de los siguientes aspectos. Sin embargo, una carga de trabajo que no presente ninguna de estas características probablemente no es lo más conveniente para los Servicios en la nube de Azure).

Los aspectos importantes que deben evaluarse en una aplicación son:

  • Demanda elástica. Una de las ventajas clave que tiene pasarse a Azure es el escalado flexible: la posibilidad de agregar o quitar capacidades a la aplicación (escalarla y reducirla horizontalmente) para que se ajuste mejor a la dinámica demanda de los usuarios. Si la carga de trabajo tiene una demanda estática y constante (por ejemplo, un número estático de usuarios, transacciones, etc.) esta ventaja de los Servicios en la nube de Azure no se maximiza.

  • Usuarios y dispositivos distribuidos. La ejecución en Azure proporciona acceso inmediato a la implementación global de aplicaciones. Si la carga de trabajo tiene una base de usuarios capturada que se ejecuta en una sola ubicación (por ejemplo, una sola oficina), la implementación de la nube no puede proporcionar una rentabilidad óptima de la inversión.

  • Cargas de trabajo en particiones. Las aplicaciones de la nube se escalan al ampliarlas, con lo que se agrega más capacidad en fragmentos menores. Si la aplicación depende de la ampliación (por ejemplo, bases de datos y almacenamientos de datos grandes) o es una carga de trabajo especializada y dedicada (por ejemplo, un almacenamiento de alta velocidad grande, unificado), debe descomponerse (con particiones) para ejecutarla en servicios ampliados con el fin de que sea viable en la nube. Dependiendo de la carga de trabajo, esto puede ser un ejercicio nada trivial.

Cabe reiterar que Al evaluar la aplicación, bien se puede lograr un alto retorno de la inversión de pasar a los Servicios en la nube de Azure o compilar para ellos si la carga de trabajo tiene solo uno de los tres aspectos anteriores que destacan en un entorno de plataforma como servicio, tal como los Servicios en la nube de Azure. Las aplicaciones que tienen las tres características probablemente obtendrán un rendimiento seguro de la inversión.

Mientras muchos aspectos del diseño de aplicaciones para Azure son muy conocidos en el desarrollo local, hay varias diferencias clave sobre cómo se comportan la plataforma y los servicios subyacentes. Conocer estas diferencias y, en consecuencia, saber cómo diseñar para la plataforma - no con ella – es fundamental en la entrega de aplicaciones que cumplen la promesa de escalarse elásticamente en la nube.

En esta sección se describen cinco conceptos clave que son los elementos fundamentales de diseño para compilar aplicaciones de ampliación extensamente distribuida a gran escala para los entornos de plataforma como servicio (PaaS), por ejemplo, los Servicios en la nube de Azure. Conocer estos conceptos le ayudará a diseñar y compilar aplicaciones que no solo funcionan en los Servicios en la nube de Azure, sino que prosperan ahí y devuelven tantos beneficios de la inversión como es posible. Todas las consideraciones y opciones de diseño que se describen más adelante en este documento se ligarán a uno de estos cinco conceptos.

Además, merece la pena observar que, mientras muchas de estas consideraciones y procedimientos recomendados se ven a través de la lente de una aplicación .NET, los conceptos y enfoques subyacentes son independientes en gran parte del lenguaje o de la plataforma.

El cambio principal al pasar de una aplicación local a los Servicios en la nube de Azure está relacionado con la manera en que se escalan las aplicaciones. El método tradicional para compilar aplicaciones grandes se basa en una combinación de escala horizontal (servidores web y de aplicaciones si estado) y escala vertical (comprar un sistema de memoria mayor o de varios núcleos, instalar un servidor de base de datos, construir un centro de datos mayor, etc.). En la nube la escala vertical no es una opción realista; la única manera de lograr aplicaciones verdaderamente escalables es el diseño explícito para la escala horizontal.

Dado que muchos de los elementos de una aplicación local ya están preparados para la escala horizontal (servidores web, servidores de aplicaciones), el desafío consiste en identificar los aspectos de la aplicación que tengan una dependencia en un servicio de escala vertical y convertirlos (o asignarlos) a una implementación de escala horizontal. El principal candidato para una dependencia de escala vertical suele ser la base de datos relacionales (SQL Server o Base de datos SQL de Azure).

Los diseños relacionales tradicionales se han centrado en torno a un modelo de datos global coherente (escala vertical de un solo servidor) con coherencia sólida y comportamiento transaccional. El método tradicional para proporcionar la escala en este almacén de copia de seguridad consistía en “hacer todo sin estado” con el fin de diferir la responsabilidad de administrar el estado al servidor SQL de escala vertical.

Sin embargo, la increíble escalabilidad de SQL Server aporta una carencia distintiva de escala verdaderamente elástica. Es decir, en lugar de una disponibilidad de recursos con gran capacidad de respuesta, se debe comprar un gran servidor con una fase de migración costosa, con la capacidad de supera con mucho la demanda, cada vez que se expanda la escala vertical. Además, hay una curva exponencial de gastos al escalar el hardware superior a la gama media.

Dado que la escala horizontal forma la base arquitectónica de los Servicios en la nube de Azure, las aplicaciones deben diseñarse para trabajar con los almacenes de datos de escala horizontal. Esto significa que los desafíos de diseño como crear explícitamente particiones de los datos en fragmentos menores (que pueden caber en una partición de datos o en una unidad de escala horizontal) y administrar la coherencia entre los elementos de datos distribuidos. De esta forma se alcanza la escala con las particiones de forma que se evitan muchas de las desventajas del diseño de la escala vertical.

Cambiar de técnicas conocidas de escala vertical a escalar horizontalmente la administración de los datos y del estado suele ser uno de los mayores obstáculos del diseño para la nube; solucionar estos desafíos y diseñar aplicaciones que puedan aprovechar las capacidades escalables y elásticas de los Servicios en la nube de Azure y de la Base de datos SQL de Azure para administrar los datos duraderos constituyen el foco de gran parte de este documento.

En un mundo donde ejecuta su propio centro de datos, tiene un grado casi infinito de control, yuxtapuesto con un número casi infinito de opciones. Todo, desde la planta física (aire acondicionado, suministro eléctrico, espacio) hasta la infraestructura (racks, servidores, almacenamiento, red, etc.) a la configuración (topología de enrutamiento, instalación del sistema operativo), está bajo control.

Pero este grado de control tiene un costo de capital, operativo, humano y de tiempo. El costo de administrar todos los detalles de un entorno ágil y cambiante está en el núcleo del impulso de la virtualización y es un aspecto clave del avance a la nube. A cambio de abandonar una medida de control, estas plataformas reducen el costo de la implementación y administración, y mejoran la agilidad. La restricción que imponen consiste en que el tamaño (capacidad, rendimiento, etc.) de los componentes y los servicios disponibles está restringido a un conjunto fijo de ofertas.

Para usar una analogía, loa envíos comerciales masivos se basan principalmente en los contenedores de transporte. Estos contenedores pueden servir para varios tipos de transporte (marítimo, ferroviario y por carretera) y están disponibles en diversos tamaños estándar (de hasta 16 metros de longitud). Si la cantidad de carga que desea enviar supera la capacidad del camión más grande, necesitará usar:

  • Varios camiones. Esto implica dividir la carga (o crear particiones) para que quepa en varios contenedores y coordinar la entrega de los camiones.

  • Un método de transporte especial. Para la carga que no se puede distribuir en contenedores estándar (por ser demasiado grande, voluminosa, etc.), es necesario usar métodos sumamente especializados, como barcazas. Estos métodos son normalmente mucho más costosos que el envío de carga estándar.

Si llevamos esta analogía a Azure (y la informática en nube en general), cada recurso tiene un límite. Ya sea una instancia de un rol individual, una cuenta de almacenamiento, un servicio en la nube o incluso un centro de datos, cada recurso disponible en Azure tiene un límite finito. Pueden ser límites de gran tamaño, como la cantidad de almacenamiento disponible en un centro de datos (del mismo modo en que los grandes buques de carga pueden transportar 10 000 contenedores), pero son finitos.

Teniendo esto en mente, el escalado consiste en: crear particiones de la carga y componerla en varias unidades de escalado, ya sean máquinas virtuales, bases de datos, cuentas de almacenamiento, servicios en la nube o centros de datos.

En este documento usamos el término unidad de escala para hacer referencia a un grupo de recursos que pueden (a) controlar un grado definido de carga y (b) combinarse para administrar la carga adicional. Por ejemplo, una cuenta de Almacenamiento de Azure tiene un tamaño máximo de 100 TB. Si necesita almacenar más de 100 TB de datos, deberá usar varias cuentas de almacenamiento (es decir, al menos dos unidades de escala de almacenamiento).

Las directrices generales de diseño para la capacidad de cada servicio principal o componente de Azure se describe en secciones posteriores, junto con los enfoques recomendados para combinar estos servicios para la escala adicional.

Se han invertido cantidades enormes de tiempo, energía y capital intelectual en la compilación de aplicaciones locales muy resistentes. Esto se reduce normalmente a separar la aplicación en componentes de estado bajo (servidores de aplicaciones, conexión de red) y los componentes de estado alto (bases de datos, redes SAN), y hacer que cada uno sea resistente a los modos de error.

En este contexto, un modo de error hace referencia a una combinación de (a) observar el sistema en un estado de error, (b) como resultado del motivo del error. Por ejemplo, una base de datos que es inaccesible debido a una actualización de la contraseña mal configurada es un modo de error; el estado del error es la incapacidad para conectarse (conexión rechazada, credenciales no aceptadas), y la causa del error es una actualización de contraseña que no se comunicó correctamente al código de la aplicación.

Los componentes de estado bajo proporcionan resistencia mediante una redundancia con acoplamiento flexible, con la “integración” en el sistema administrado por sistemas externos. Por ejemplo, si se colocan servidores web adicionales detrás de un equilibrador de carga, cada servidor web es idéntico a los otros (por lo que agregar nueva capacidad se convierte en una cuestión de clonar una imagen del servidor web), con la integración en la aplicación total administrada por el equilibrador de carga.

Los componentes de estado alto proporcionan resistencia mediante una redundancia de acoplamiento estricto, con la “integración” administrada estrechamente entre los componentes. Algunos ejemplos son:

  • SQL Server. Al agregar una instancia de SQL Server redundante como parte de un clúster activo/pasivo se requiere una selección cuidadosa (es decir, idéntica) de hardware compatible y de almacenamiento compartido (como una red SAN) para entregar conmutación por error coherente de transacciones entre varios nodos.

  • Suministro eléctrico. El suministro eléctrico redundante constituye un ejemplo muy sofisticado, ya que requiere varios sistemas que actúan en concierto para mitigar problemas locales (varias fuentes de alimentación para un servidor, con hardware a bordo para cambiar entre las fuentes de alimentación primaria y secundaria) y centrales (generadores de reserva para la pérdida de alimentación).

Las soluciones de resistencia basadas en enfoques de acoplamiento estricto son intrínsecamente más costosas que los enfoques de acoplamiento más flexible que “agregan más elementos clonados”, ya que requieren personal muy experto, hardware especializado, así como una configuración y comprobación cuidadosas. No solo es difícil hacerlo bien, si no que cuesta dinero hacerlo correctamente.

Este enfoque de centrarse en asegurarse de que las plataformas de hardware sean muy resistentes se puede entender como una “cáscara de huevo de titanio”. Para proteger el contenido del huevo, lo cubrimos con una capa de duro (y costoso) titanio.

La experiencia en la ejecución de sistemas de escala (vea http://www.mvdirona.com/jrh/TalksAndPapers/JamesRH_Lisa.pdf para obtener una explicación adicional) ha demostrado que, en cualquier sistema suficientemente grande (como los sistemas de datos en la escala de Azure), el simple número de partes físicas móviles lleva a algunas partes del sistema a interrumpirse constantemente. La plataforma Azure se diseñó de forma tal que pudiera trabajar con esta limitación, en lugar de contra ella, confiando en la recuperación automatizada de los eventos de error del nivel de nodo. Esta intención del diseño recorre todos los servicios esenciales de Azure y es clave para diseñar una aplicación que funcione con el modelo de disponibilidad de Azure.

El paso a Azure cambia el asunto de la resistencia de un desafío de la redundancia de infraestructura a un desafío de la redundancia de los servicios. Muchos de los servicios principales que dominan el planeamiento local de la disponibilidad “simplemente siguen trabajando” en Azure:

  • La Base de datos SQL mantiene automáticamente coherentes en cuando a las transacciones varias réplicas de los datos. Los errores de nivel de nodo de una base de datos conmutan por error automáticamente al elemento secundario coherente; compare la facilidad de esta experiencia con el tiempo y el gasto necesarios para proporcionar resistencia local.

  • El Almacenamiento de Azure mantiene automáticamente coherentes varias copias de los datos (si desea lectura adicional, vea http://sigops.org/sosp/sosp11/current/2011-Cascais/11-calder-online.pdf). Los errores de nivel de nodo de un volumen de almacenamiento conmutan por error automáticamente a un elemento secundario coherente. Al igual que ocurre con la Base de datos SQL, esta experiencia totalmente administrada se puede comparar con la administración directa del almacenamiento resistente en un clúster o SAN local.

Sin embargo, el título de esta sección es disponibilidad, no resistencia. La resistencia es solo una parte del caso global de entregar continuamente valor a los usuarios dentro de los límites de un SLA. Si todos los componentes de la infraestructura de un servicio son correctos, pero el servicio no puede hacer frente al volumen esperado de usuarios, no está disponible ni ofrece valor.

Las cargas de trabajo centradas en la movilidad o en las redes sociales (como las aplicaciones web públicas con aplicaciones de dispositivo móvil) tienden a ser mucho más dinámicas que las que apuntan a audiencias cautivas y solo requieren un enfoque más sofisticado para controlar los eventos de ráfaga y la carga máxima. Los conceptos clave que se deben tener en cuenta para diseñar la disponibilidad en las aplicaciones de Azure se describen detalladamente en este documento, en función de estos ejes centrales:

  • Cada servicio o componente de Azure proporciona un contrato de nivel de servicio (SLA); este SLA no se puede correlacionar directamente con la métrica de disponibilidad necesaria para ejecutar la aplicación. Comprender todos los componentes del sistema, su SLA de disponibilidad y cómo interactúan es importante para saber la disponibilidad global que se puede entregar a los usuarios.

    • Evite los puntos de error únicos que puedan degradar el SLA, como los roles de una sola instancia.

    • Componga o recurra a varios componentes para mitigar el impacto de que un servicio específico se quede sin conexión o no esté disponible.

  • Cada servicio o componente de Azure puede experimentar un error, ya sea un evento transitorio y efímero o un evento duradero. La aplicación debe escribirse de tal forma que controle el error correctamente.

    • Para los errores transitorios, proporcione los mecanismos de reintento apropiados para volver a conectar o reenviar el trabajo.

    • Para otros eventos de error, proporcione una instrumentación enriquecida del evento de error (que informa del error en las operaciones) y un mensaje de error adecuado para el usuario.

    • Siempre que sea posible, recurra a otro servicio o flujo de trabajo. Por ejemplo, si una solicitud para insertar datos en la Base de datos SQL produce un error (por cualquier motivo no transitorio, como un esquema no válido), escriba los datos en el almacenamiento de blob en un formato serializado. Esto permitiría que los datos se capturen de forma duradera y se envíen a la base de datos una vez resuelto el problema de esquema.

  • Todos los servicios tienen una capacidad máxima, ya sea explícita (mediante una directiva de limitación o asíntota de carga máxima) o implícita (cuando se alcanza un límite de recursos del sistema).

    • Diseñe la aplicación de forma que se degrade correctamente en el caso de alcanzar los límites de recursos, y realice la acción adecuada para suavizar el impacto para el usuario.

    • Implemente la lógica de retroceso y reintento adecuada para evitar un efecto de “convoy” en los servicios. Sin un mecanismo de retroceso adecuado, los servicios de nivel inferiores no tendrán nunca la probabilidad de ponerse al día después de experimentar un evento de tráfico máximo (por ejemplo, que la aplicación intente insertar más carga en el servicio, lo que activa la directiva de limitación o el agotamiento de los recursos).

  • Los servicios que pueden experimentar eventos rápidos de ráfaga deben tratar de superar correctamente la carga de diseño máxima, normalmente a través de la funcionalidad de pérdida.

    • De forma parecida a como el cuerpo humano limita el flujo de sangre a las extremidades al enfrentarse a frío extremo, debe diseñar los servicios para perder los servicios menos importantes en eventos de carga extrema.

    • El corolario aquí no consiste en que no todos los servicios suministrados por la aplicación tienen una importancia empresarial equivalente y pueden estar sujetos a unos SLA diferentes.

Estos conceptos de alto nivel se aplicarán con más detalle en cada una de las secciones que describen los servicios esenciales de Azure, junto con los objetivos de disponibilidad para cada servicio o componente, y recomendaciones sobre cómo diseñar la disponibilidad. Tenga presente que el centro de datos sigue siendo un punto de error en las aplicaciones grandes; ya se trate de suministros eléctricos (vea un ejemplo aquí) o de un error de los sistemas (vea un ejemplo aquí), la infraestructura y los problemas de las aplicaciones han desactivado centros de datos. Aunque son relativamente poco habituales, las aplicaciones que requieren los mayores niveles de tiempo de actividad deben implementarse en varios centros de datos redundantes.

La implementación de aplicaciones en varios centros de datos requiere diversas capacidades de infraestructura y de las aplicaciones:

  • Lógica de la aplicación para enrutar a los usuarios de los servicios al centro de datos adecuado (basado en la localización geográfica, el particionamiento del usuario u otra lógica de afinidad).

  • Sincronización y replicación del estado de la aplicación entre los centros de datos, con la latencia y los niveles de coherencia adecuados.

  • La implementación autónoma de aplicaciones, de forma que las dependencias entre los centros de datos se minimice (es decir, que impida la situación donde un error en el centro de datos A desencadena un error en el centro de datos B).

Al igual que ocurre con la disponibilidad, proporcionar soluciones de recuperación ante desastres (en caso de pérdida del centro de datos) ha requerido un tiempo, energía y capital enormes. Esta sección se centrará en enfoques y consideraciones para proporcionar continuidad empresarial en el caso de un error del sistema y pérdida de datos (ya sean activados por el sistema o por el usuario), ya que el término “recuperación ante desastres” ha adquirido connotaciones específicas en los enfoques de implementación de la comunidad de bases de datos.

La entrega de la continuidad empresarial se desglosa en:

  • Mantener el acceso y disponibilidad de los sistemas empresariales fundamentales (aplicaciones que funcionan en un estado duradero) en el caso de error grave de la infraestructura.

  • Mantener el acceso y disponibilidad de los datos empresariales fundamentales (estado duradero) en el caso de error grave de la infraestructura.

  • Mantener la disponibilidad de los datos empresariales fundamentales (estado durable) en el caso de error del operador o eliminación accidental, modificación o daños.

Los dos primeros elementos se han solucionado tradicionalmente en el contexto de la recuperación geográfica de desastres (geo-DR); la tercera corresponde al dominio de la copia de seguridad y la restauración de los datos.

Azure cambia la ecuación significativamente a favor de la disponibilidad de los sistemas empresariales fundamentales y habilita la implementación rápida, geográficamente distribuida de las aplicaciones clave en centros de datos de todo el mundo. De hecho, el proceso de desarrollo de una aplicación geográficamente distribuida no es diferente del desarrollo de un único servicio en la nube.

Queda el desafío clave de administrar el acceso al estado duradero; tener acceso a los servicios de estado duradero (como el Almacenamiento de Azure y la Base de datos SQL) a través de centros de datos normalmente produce unos resultados óptimos debido a la latencia alta o variable, y no cumple el requisito de la continuidad empresarial en caso de error del centro de datos.

Al igual que ocurre con la resistencia, muchos servicios de Azure ofrecen (o tienen en su mapa de ruta) replicación geográfica automática. Por ejemplo, a menos que se haya configurado específicamente lo contrario, todas las operaciones de escritura en el Almacenamiento de Azure (blob, cola o tabla) se replican en otro dentro de datos (cada centro de datos tiene un destino específico de “reflejo” en la misma región geográfica). Esto reduce enormemente el tiempo y el esfuerzo necesarios para proporcionar soluciones tradicionales de recuperación ante desastres sobre Azure. En secciones posteriores se aporta información general sobre las capacidades de replicación geográfica de los servicios esenciales de Azure que administran el estado duradero.

Para mantener la continuidad empresarial en caso de error del usuario o del operador, hay varias consideraciones adicionales a las que debe responder el diseño de aplicaciones. Aunque el Almacenamiento de Azure proporciona una capacidad de auditoría limitada a través de la característica de análisis de almacenamiento (descrita en una sección posterior), no proporciona ninguna funcionalidad de restauración a un momento dado. Los servicios que requieren resistencia en el caso de eliminación o modificación accidental necesitarán buscar enfoques centrados en la aplicación, como, por ejemplo, la copia periódica de blobs en una cuenta de almacenamiento diferente.

La Base de datos SQL proporciona la funcionalidad básica para mantener las instantáneas históricas de datos, incluida la copia y la importación o exportación de la base de datos a través de bacpac. Estas opciones se tratan detalladamente más adelante en este documento.

Con la escala elástica proporcionada por la plataforma Azure, la curva de oferta puede asemejarse mucho a la curva de demanda (en lugar de tener una gran cantidad de capacidad adicional para responder a la carga máxima).

Con la escala elástica, el costo de bienes se controla mediante:

  • El número de unidades de escala empleadas en una solución; máquinas virtuales, cuentas de almacenamiento, etc. (composición para la escala)

  • La eficiencia del trabajo se logra eficazmente con estas unidades de escala.

Nos referimos al volumen de trabajo que se puede realizar para una determinada cantidad de capacidad como, por ejemplo, la densidad de la aplicación. Los servicios y marcos de trabajo más densos permiten que se realice un mayor volumen de trabajo para una determinada implementación de los recursos; es decir, la mejora de la densidad habilita la reducción de la capacidad implementada (y del costo), o la capacidad de absorber la carga adicional con la misma capacidad implementada. La densidad se controla mediante dos factores clave:

  • La eficiencia con la que se realiza el trabajo dentro de una unidad de escala. Esta es la forma tradicional de optimización del rendimiento: administrar la contención y los bloqueos de subprocesos, optimizar los algoritmos, ajustar las consultas SQL.

  • La eficiencia con la que se coordina el trabajo entre las unidades de escala. En una situación donde los sistemas se componen de grandes números de unidades menores, la capacidad de combinarlas eficazmente es esencial para proporcionar eficiencia. Esto implica los marcos de trabajo y las herramientas que se comunican a través de los componentes, como las pilas de mensajes SOAP (por ejemplo, WCF), las ORM (como Entity Framework), las llamadas TDS (código de cliente de SQL) y la serialización de objetos (por ejemplo, los contratos de datos o JSON).

Además de las técnicas de optimización tradicionales usadas en un único equipo (o base de datos), la optimización de la comunicación y de las operaciones distribuidas es crítico para la entrega de un servicio escalable y eficaz de Azure. Estas optimizaciones clave se tratan detalladamente en secciones posteriores:

  • Llamadas en bloque, no locuaces. Para cada operación distribuida (es decir, una que tiene como resultado una llamada de red) hay cierta sobrecarga de la trama, serialización, procesamiento, etc. del paquete. Para minimizar la cantidad de sobrecarga, intente procesar los lotes en un número menor de operaciones “en bloque”, en lugar de usar un gran número de operaciones “locuaces”. Tenga presente que el proceso por lotes de operaciones pormenorizadas aumenta la latencia y la exposición a la pérdida potencial de datos. Los ejemplos de comportamiento correcto del procesamiento por lotes son:

    • SQL. Ejecute varias operaciones en un único lote.

    • Servicios REST y SOAP (como WCF). Aproveche las interfaces de operaciones centradas en mensajes, en lugar de usar un estilo RPC locuaz, y considere un enfoque basado en REST si es posible.

    • Almacenamiento de Azure (blobs, tablas, colas). Publique varias actualizaciones en un lote, no individualmente.

  • Impacto de la serialización. Mover datos entre equipos (así como dentro y fuera del almacenamiento duradero) requiere normalmente que los datos se serialicen en un formato de conexión. La eficacia (es decir, el tiempo que se tarda y el espacio usado) de esta operación domina rápidamente el rendimiento global de la aplicación en los sistemas grandes.

    • Aproveche los marcos de trabajo de serialización, que son muy eficaces.

    • Utilice JSON para la comunicación con los dispositivos o para aplicaciones interoperables (legibles).

    • Utilice la serialización binaria eficaz (por ejemplo, protobuf o Avro) para la comunicación entre servicios cuando pueda controlar ambos extremos.

  • Utilice marcos de trabajo eficaces. Hay muchos marcos de trabajo enriquecidos disponibles para el desarrollo, con grandes conjuntos sofisticados de características. El inconveniente de muchos de estos marcos de trabajo consiste en que a menudo se incurre en un costo de rendimiento por características que se usan.

    • Aísle los servicios y las API de cliente detrás de interfaces genéricas para permitir el reemplazo o la evaluación en paralelo (ya sea a través de generadores estáticos o de una inversión del contenedor del control). Por ejemplo, proporcione una capa de almacenamiento en caché acoplable trabajando con una interfaz genérica, en lugar de usar una implementación concreta (como Caching de Azure).

En la sección anterior introdujimos los conceptos de diseño clave y las perspectivas de la compilación de aplicaciones que se aprovechan del entramado de la nube suministrado por Azure. En esta sección se explorarán los servicios y las características principales de la plataforma, y se mostrarán sus capacidades, los límites de la escala y los modelos de disponibilidad.

Puesto que cada componente del servicio o de la infraestructura de Azure proporciona una capacidad finita con un SLA de disponibilidad, es importante comprender estos límites y comportamientos a la hora de elegir las opciones de diseño adecuadas para los objetivos de escalabilidad de destino y para el SLA del usuario final. Cada uno de los servicios principales de Azure se presenta en el contexto de cuatro ejes clave: las características y su intención, la densidad, la escalabilidad y la disponibilidad.

Una suscripción a Azure es la unidad básica de administración, facturación y cuotas de servicio. Cada suscripción a Azure tiene un valor predeterminado establecido de cuotas que se pueden aumentar poniéndose en contacto con el servicio de soporte técnico y está pensada para evitar los superávits accidentales y el consumo de recursos.

Cada suscripción tiene un propietario y un conjunto de coadministradores, autorizados a través de las cuentas de Microsoft (antes id. activos), que tienen un control total sobre los recursos de la suscripción a través del portal de administración. Pueden crear cuentas de almacenamiento, implementar los servicios en la nube, cambiar la configuración y agregar o quitar coadministradores.

Las API de administración de Azure (servicios web basados en REST) proporcionan una interfaz de automatización para crear, configurar e implementar los servicios de Azure (usados por el portal de administración en segundo plano). El acceso a estas API se limita mediante certificados de administración.

 

Servicio Límite predeterminado

Servicios en la nube

20

Cuentas de almacenamiento

20

Cores

20

Servidores lógicos de Base de datos SQL

5

TipSugerencia
Para más información sobre lo último en subscripciones y límites de servicio de Azure, consulta Subscripciones y límites de servicio, presupuestos y restricciones de Azure

Un servicio en la nube de Azure (antes servicio hospedado) es la unidad básica de implementación y escala. Cada servicio en la nube consta de dos implementaciones (producción y ensayo), cada una con un conjunto de roles. El servicio en la nube tiene una entrada DNS pública (en forma de nombreServicio.cloudapp.net) para la implementación de producción y una entrada DNS de implementación de ensayo (en forma de algúnGuid.cloudapp.net).

Cada implementación contiene uno o más roles, ya sea un rol web o un rol de trabajo, que a su vez contiene una o más instancias (máquinas virtuales no duraderas). Cada instancia contiene una instantánea idéntica, inmutable y no duradera de un paquete de software para ese rol (es decir, en todas las instancias de un rol determinado se implementa una versión idéntica). Estas instancias se ejecutan en una versión de Windows Server especializada en Azure (con muchos servicios deshabilitados de forma predeterminada por seguridad adicional, configurados para funcionar bien con la conexión de red y el entramado de servicios de Azure, etc.) y el entramado de Azure les aplica automáticamente las revisiones de forma predeterminada. La incorporación de revisiones en directo se controla con un esquema de actualización gradual, que se describe a continuación.

Los servicios en la nube se pueden implementar en cualquier centro de datos de Azure, ya sea directamente (eligiendo la región de destino al crear el servicio) o a través de un grupo de afinidad. Un grupo de afinidad es una referencia indirecta a un destino de implementación que se puede usar para simplificar la implementación de todos los componentes de una aplicación en el mismo centro de datos.

Los roles web se preconfiguran con una instancia de IIS, que hospeda el código de aplicación. El código de aplicación hospedado en los roles de trabajo se ejecuta en el host de aplicación de ejecución prolongada preconfigurado. Cada servicio en la nube puede tener hasta 25 roles. La configuración predeterminada de los roles consiste en ejecutar el código .NET, pero un rol puede estar configurado para ejecutar cualquier código compatible con Windows Server: Java, Python, Ruby, node.js, etc. Todas las características de la plataforma mencionadas en este documento están disponibles en cualquier plataforma, pero pueden requerir el desarrollo adicional de proxy de cliente como destino de las API basadas en REST.

En un servicio en la nube, todas las instancias tienen asignadas direcciones IP privadas (en el bloque 10.x); todas las conexiones salientes parecen proceder de una sola dirección IP virtual, o VIP (que es la VIP de implementación del servicio en la nube), mediante la traducción de direcciones de red. Todas las conexiones entrantes deben pasar a través de extremos configurados; estos extremos proporcionan acceso con equilibrio de carga para los roles y los puertos internos. Por ejemplo, de forma predeterminada las conexiones entrantes de HTTP/HTTPS (puertos 80 y 443) a la implementación del servicio en la nube tienen equilibrio de carga en todas las instancias disponibles del rol web primario.

Observe que la latencia de servicios cruzados (es decir, recorrer NAT fuera de un servicio en la nube y a través del equilibrador de carga hasta llegar a otro servicio) es mucho más variable que el equivalente local y es una de las razones de que se recomienden las conexiones de servicios cruzados por lotes o “en bloque” para obtener escalabilidad.

El entramado de Azure también proporciona un servicio de configuración disponible para todas las instancias de la implementación del servicio en la nube. En la definición del servicio (como parte del ciclo de desarrollo) se proporciona un conjunto estático de claves de configuración esperadas, además del conjunto inicial de valores de configuración implementados con el servicio cuando se publica en Azure. Este conjunto de valores de configuración está disponible como búsqueda de tiempo de ejecución para todas las instancias de la implementación del servicio y se puede modificar en tiempo de ejecución mediante una interfaz REST, el portal de Azure o un script de PowerShell.

Cuando se cambia la configuración de tiempo de ejecución, todas las instancias pueden elegir (en el código de aplicación) enlazar la notificación del cambio de configuración y administrar las actualizaciones de configuración internamente. Si el código de aplicación no se escribe para capturar el evento de cambio de configuración, todas las instancias del rol experimentarán un reinicio gradual para actualizar la configuración.

El estado de cada instancia no es duradero; cualquier configuración sobre la imagen base de Azure (una Máquina virtual de Windows Server especializada) requiere una configuración de inicio para crear los contadores de rendimiento, ajustar la configuración de IIS, instalar software dependiente, etc. Estos scripts de configuración se ejecutan normalmente como tarea de inicio especificada por la configuración del servicio en la nube.

En un servicio en la nube, el entramado de Azure proporciona información sobre la configuración, las direcciones IP internas, la configuración del servicio, etc., a través de RoleEnvironment. Todos los procesos que se ejecutan en una instancia de Azure pueden tener acceso a la información de RoleEnvironment para recuperar la configuración, detectar la topología de red, etc. También se pueden usar las API de administración de Azure para tener acceso a esta información externamente.

El entramado de Azure expone dos conceptos básicos para administrar un error en un componente, la reconfiguración y la actualización o revisión: los dominios de actualización y los dominios de error.

Los dominios de actualización son agrupaciones lógicas de un servicio de Azure; de forma predeterminada cada servicio tiene cinco (5) dominios de actualización (este valor se puede modificar en la definición del servicio en la nube). Cualquier cambio o actualización del servicio afecta únicamente a un solo dominio de actualización a la vez. Los ejemplos de estos cambios incluyen aplicar revisiones al sistema operativo, cambiar el tamaño de la máquina virtual, agregar una o varias instancias de un rol o roles o a un servicio en ejecución, o modificar la configuración del extremo.

Esto permite la reconfiguración en directo de un servicio en la nube en ejecución mientras se mantiene la disponibilidad. Para los roles que contienen una sola instancia, el entramado de Azure no puede proporcionar disponibilidad durante las operaciones de actualización, que es el motivo por el que la ejecución de roles de una sola instancia no cumple el SLA de Azure.

Los dominios de error son agrupaciones lógicas basadas en el hardware subyacente. Mientras no se garantiza que se asigne directamente a una configuración de hardware específica, piense en la agrupación lógica como la forma del entramado de Azure de separar automáticamente las instancias de recursos subyacentes que representa un solo punto de error (como un único servidor físico, bastidor, etc. subyacente). Para hacer frente al SLA de servicio, Azure necesita implementar las instancias al menos en dos dominios de error. Este es el otro del motivo por el que las implementaciones de rol de una sola instancia no cumplen el SLA de Azure.

En resumen:

  • Las unidad básica de implementación y escala en Azure es el servicio en la nube, que se compone de un conjunto de roles. Cada rol contiene un conjunto de instancias de rolidénticas, cada una de las cuales ejecuta una versión de Windows Server especializada, configurada para la nube.

  • Además de la topología física (roles e instancias) y el código de aplicación, los servicios en la nube definen una configuración de todo el servicio. Esta configuración se puede actualizar en tiempo de ejecución.

  • Cada instancia de rol no es duradera (no se garantiza que los cambios, archivos, etc., sean persistentes en caso de reinicio, revisiones o eventos de error).

  • Cada servicio en la nube expone una sola IP virtual para el tráfico entrante y saliente. El servicio en la nube expone los extremos, que proporcionan una asignación con equilibrio de carga (Round Robin) a un rol y un puerto internos.

  • Azure usa los dominios de actualización para separar lógicamente los grupos de instancias y proporcionar actualizaciones o modificaciones graduales (a la vez que conserva la disponibilidad).

  • Azure usa los dominios de error para agrupar físicamente las instancias lejos de los puntos de error únicos (por ejemplo, la ejecución de todas las instancias en el mismo equipo físico subyacente).

  • Aproveche varias suscripciones para aislar los entornos de desarrollo, prueba, ensayo y producción.

Cada rol contiene un conjunto de una o varias instancias. Cada una de estas instancias es una máquina virtual que ejecuta una versión especializada de Windows Server. Las instancias (o máquinas virtuales) están actualmente disponibles en cinco tamaños, de muy pequeño a muy grande. Cada uno de estos tamaños tiene asignada cierta cantidad de CPU, memoria, almacenamiento y ancho de banda.

 

Tamaño de la máquina virtual Núcleos de CPU Memoria Espacio en disco para los recursos de almacenamiento local en los roles web y de trabajo Espacio en disco para los recursos de almacenamiento local en un rol de máquina virtual Ancho banda asignado (Mbps)

ExtraSmall

Compartidos

768 MB

19.480 MB

(6.144 MB se reservan para los archivos del sistema)

20 GB

5

Pequeña

1

1,75 GB

229.400 MB

(6.144 MB se reservan para los archivos del sistema)

165 GB

100

Mediana

2

3,5 GB

500.760 MB

(6.144 MB se reservan para los archivos del sistema)

340 GB

200

Grande

4

7 GB

1.023.000 MB

(6.144 MB se reservan para los archivos del sistema)

850 GB

400

ExtraLarge

8

14 GB

2.087.960 MB

(6.144 MB se reservan para los archivos del sistema)

1.890 GB

800

TipSugerencia
Para más información sobre lo último en subscripciones y límites de servicio de Azure, consulta Subscripciones y límites de servicio, presupuestos y restricciones de Azure

Siempre que se implementan dos o más instancias en dominios diferentes de error y actualización, Azure proporciona los siguientes SLA para los servicios en la nube:

  • 99,95 % de conectividad externa para los roles con conexión a Internet (los que tienen extremos externos)

  • Un 99,9 % detecta problemas de la instancia de rol antes de que pasen dos minutos e inicia acciones correctoras

Tanto los tamaños como el número de instancias de rol se pueden cambiar dinámicamente en una aplicación en ejecución (nota: el cambio de los tamaños de las instancias de rol desencadenará una reimplementación gradual). Debido al enfoque de escala horizontal de la compilación de aplicaciones de Azure, lo mayor no es necesariamente mejor cuando se trata de seleccionar tamaños de instancias. Esto se aplica tanto al costo (por qué pagar por lo que no se usa) como al rendimiento (en función de si la carga de trabajo está enlazada a la CPU, enlazada a E/S, etc.). Los enfoques para seleccionar el número de instancias y de tamaños de instancia se revisan con más detalle en la sección sobre los procedimientos recomendados de este documento.

El Almacenamiento de Azure es el servicio de datos duradero de línea base para Azure, y proporciona almacenamiento de blob (archivo), de cola y de tabla (clave para valores). La cuenta de almacenamiento es la unidad básica de escala y disponibilidad, y proporciona las siguientes capacidades. Toda la comunicación con el servicio de almacenamiento se basa en una interfaz REST sobre HTTP.

TipSugerencia
Para más información sobre lo último en subscripciones y límites de servicio de Azure, consulta Subscripciones y límites de servicio, presupuestos y restricciones de Azure

El SLA de disponibilidad de Almacenamiento de Azure garantiza que, al menos un 99,9 % del tiempo, las solicitudes con formato correcto para agregar, actualizar, leer y eliminar datos se realizarán y se procesarán correctamente y que, además, las cuentas de almacenamiento tendrán conectividad a la puerta de enlace de Internet.

Estos límites se comparten entre todos los usos de la cuenta de almacenamiento individual; es decir el número de operaciones por segundo y el ancho de banda completo se comparten entre las tablas, los blobs y las colas. Si una aplicación supera el número total de operaciones por segundo, el servicio puede devolver un código HTTP 503 Servidor ocupado. Las operaciones son específicas de cada aspecto del almacenamiento (tablas, colas o blobs), y se describen en las subsecciones siguientes.

En términos de la metáfora del contenedor de transporte usada anteriormente, cada cuenta de almacenamiento es un contenedor que proporciona cierta cantidad de capacidad. Si se supera el límite de una sola cuenta (o contenedor de transporte), se deben aprovechar varias cuentas en la misma aplicación.

El Almacenamiento de Azure proporciona disponibilidad y resistencia de forma predeterminada; todas las operaciones de escritura o actualizaciones del Almacenamiento de Azure se replican de forma transparente y coherente en los tres nodos de almacenamiento (que residen en diferentes dominios de actualización y error). El acceso al Almacenamiento de Azure se controla mediante la autenticación de factor único en forma de claves de acceso. Cada cuenta de almacenamiento tiene una clave principal y secundaria, que permiten la disponibilidad continua cuando se gira la clave principal. Los datos de Almacenamiento de Azure se replican geográficamente de forma automática en un centro de datos de “reflejo” (a menos que esta función se haya deshabilitado específicamente en el portal). La replicación geográfica es opaca y aprovecha la redirección DNS para conmutar por error los clientes a la ubicación secundaria en caso de error en el centro de datos principal.

Tenga en cuenta que mientras el Almacenamiento de Azure proporciona resistencia de los datos a través de las réplicas automatizadas, esto no impide que el código de aplicación (o los programadores y usuarios) dañe los datos por una eliminación accidental, una actualización, etc. Mantener la fidelidad de los datos en caso de un error de la aplicación o del usuario requiere técnicas más avanzadas, como copiar los datos en una ubicación de almacenamiento secundaria con un registro de auditoría. El almacenamiento de blob proporciona una capacidad de instantáneas que puede crear instantáneas de solo lectura en un momento dado del contenido de los blobs, que se pueden usar como base de una solución de fidelidad de los datos de blobs.

El Almacenamiento de Azure proporciona telemetría a través de la característica de análisis de almacenamiento, que recopila y expone los datos de uso acerca de las llamadas individuales de almacenamiento a las tablas, las colas y los blobs. El análisis de almacenamiento debe estar habilitado para cada cuenta de almacenamiento con una directiva de recopilación (recopilar para todos, solo para las tablas, etc.) y una directiva de retención (cuánto tiempo se mantienen los datos).

El almacenamiento de blob proporciona el servicio de administración de archivos de Azure y ofrece un método de alta disponibilidad y rentable para almacenar datos no estructurados masivos. El servicio proporciona dos tipos de blobs:

  • Blobs en bloques. Los blobs en bloques se han diseñado para administrar eficazmente los blobs grandes de datos. Cada blob en bloques consta de hasta 50 000 bloques, cada uno de un tamaño máximo de 4 MB (con un máximo total de tamaño de blob en bloques de 200 GB). Los blobs en bloques admiten la carga en paralelo para mover de forma eficaz y simultánea los archivos grandes a través de las redes. Los bloqueos individuales se pueden insertar, reemplazar o eliminar, pero no pueden modificarse in situ.

  • Blobs de página. Los blobs de página se han diseñado para ofrecer eficazmente operaciones de lectura/escritura aleatorias (por ejemplo, el acceso a un VHD). Cada blob de página tiene un tamaño máximo de 1 TB, que consta de 512 páginas de bytes. Las páginas individuales o los grupos de páginas pueden agregarse o actualizarse con una operación de sobrescritura en contexto.

Los límites de diseño para el almacenamiento de blob se muestran en la siguiente tabla. Recuerde que todas estas operaciones se restan de los límites generales de la cuenta de almacenamiento.

 

Servicio de blob Límite

Tamaño máximo de blob (bloque)

200 GB (bloques de 50 K)

Tamaño máximo del bloque

4 MB

Tamaño máximo de blob (página)

1 TB

Tamaño de página

512 bytes

Máximo de ancho banda o blob

480 Mbps

Al superar los límites de tamaño o de ancho banda de un solo blob, las aplicaciones pueden escribir en varios archivos de blob simultáneos (o secuenciales). Si la aplicación supera los límites de una única cuenta de almacenamiento, aproveche varias cuentas de almacenamiento para disponer de capacidad adicional.

Las colas de Azure proporcionan un servicio intermedio (desacoplado) de mensajería entre los publicadores y los suscriptores. Las colas admiten varios publicadores y suscriptores simultáneos, pero no exponen de forma nativa los primitivos de mensajería de orden superior como pub/sub o el enrutamiento basado en temas. Se usan normalmente para distribuir los elementos de trabajo (como mensajes, documentos, tareas, etc.) a un conjunto de instancias de rol de trabajo (o entre varios servicios hospedados, etc.).

Los mensajes de la cola se eliminan después de 7 días si no los recupera y elimina una aplicación. Proporcionan el desemparejamiento entre los publicadores y los consumidores de la información; mientras ambos tengan la clave de la cuenta de almacenamiento y el nombre de la cola, pueden comunicarse.

 

Servicio de cola Límite

Número máximo de mensajes en cola

N/D (hasta el límite de la cuenta de almacenamiento)

Duración máxima de un mensaje

1 semana (se purga automáticamente)

Tamaño máximo de mensaje

64 kB

Rendimiento máximo

~ 500 mensajes/segundo

Las colas se han diseñado para pasar los mensajes de control, no datos sin procesar. Si los mensajes son demasiado grandes para caber en una cola, refactorice los mensajes en datos y comandos independientes. Almacene los datos en el almacenamiento de blob, con una referencia (URI) a los datos y la intención (es decir, qué se debe hacer con los datos en el almacenamiento de blob) almacenados en un mensaje de la cola.

Para aumentar el rendimiento de una misma cola, procese varios mensajes por lotes en un único mensaje, después aproveche el comando de mensaje de actualización para el seguimiento del progreso de la encapsulación de las tareas del mensaje. Otra técnica es colocar varios mensajes en un blob con un puntero al blob en el mensaje de la cola.

Si la aplicación requiere más rendimiento del que proporciona una sola cola, use varias colas simultáneas. En este contexto, la aplicación debe implementar la lógica adecuada de particiones y de enrutamiento.

El almacenamiento de tabla de Azure proporciona un almacén coherente, muy duradero y escalable para los datos en columnas (bidimensionales). Proporciona una semántica de { clave de partición, clave de fila } -> { datos[] } para almacenar los datos y tener acceso a ellos, como se muestra en el diagrama siguiente. Cada tabla se divide en particiones, que a su vez contienen entidades. Cada entidad puede tener su propio esquema (plano) o su propia lista de propiedades (columnas).

Cada partición admite hasta 500 operaciones por segundo; a su vez, cada tabla admite hasta el máximo de operaciones disponibles en la cuenta de almacenamiento. Debido a que cada entidad contiene no solo los datos reales, sino también los metadatos en columnas (ya que cada entidad puede tener un esquema diferente), no se recomienda usar nombres de columna largos, especialmente para un enfoque grande.

 

Servicio de tabla Límite

Número máximo de operaciones por segundo por partición

500

Tamaño máximo de la entidad (nombres de columna + datos)

1 MB

Tamaño máximo de columna (byte[] o cadena)

64 kB

Número máximo de filas

N/D (hasta el límite de la cuenta de almacenamiento)

Tipos de datos admitidos

byte[], Boolean, datetime, double, Guid, int32, int64, string

Las entidades individuales (que se pueden considerar filas) tienen un tamaño máximo de 1 MB y las columnas individuales están limitadas a un máximo de 64 kB. Los tipos de datos admitidos se muestran en la tabla anterior; para los tipos no admitidos (como DateTimeOffset) se requiere un proxy de serialización en el código de aplicación (por ejemplo, DateTimeOffset se puede almacenar en un formato de cadena estándar).

El almacenamiento de tabla proporciona acceso a los datos almacenados mediante claves asociadas a las particiones y entidades, recorrido de particiones o recorrido de entidades. Admite la proyección de filtro, ya que una expresión de filtro puede insertarse en el almacenamiento de tabla como parte de la consulta y ejecutarse en almacenamiento de tabla. El almacenamiento de tabla no proporciona índices secundarios, de modo que una búsqueda no basada en la clave de partición o en la clave de entidad requiere un recorrido de tabla o de partición. Para las particiones que contienen un número no trivial de entidades, esto suele tener un impacto significativo en el rendimiento.

Cualquier procesamiento de consultas que lleve más de 5 segundos devuelve un token de continuación que la aplicación puede usar para seguir recibiendo los resultados de la consulta. Las consultas que recuperan más de 1000 entidades pueden aprovechar un modelo de paginación para devolver los datos en fragmentos de 1000 entidades (lo que es compatible de forma nativa con la API de almacenamiento de tabla).

Las únicas expresiones de consulta compatibles actualmente en el almacenamiento de tabla son el filtrado y la selección (con propiedades específicas); el almacenamiento de tabla no proporciona ninguna semántica de agregación ni de agrupación en el servidor. Para compilar aplicaciones que requieran agregación enriquecida o funciones analíticas, suele ser una opción mejor almacenar los datos en forma agregada o usar un motor relacional, por ejemplo, una Base de datos SQL de Azure. Algunas aplicaciones emplean un enfoque híbrido, en el que los datos se agregan desde el almacenamiento de tabla a una Base de datos SQL auxiliar que se usa para fines de consulta y de informe.

Elegir una función de particionamiento adecuada es crítico para el uso eficiente del almacenamiento de tabla. Hay dos opciones principales para el tipo de función de partición:

  • Hora. Las funciones de particionamiento basadas en la hora, que se usan normalmente para almacenar los datos de serie temporal, como los contadores de rendimiento de Diagnósticos de Azure (un uso que se trata en la sección sobre telemetría en este documento), convierten la hora actual en un valor que representa una ventana de tiempo (el minuto y la hora actuales, etc.).

    Permiten una búsqueda y ubicación eficaz de una partición determinada (ya que la cláusula de filtro del almacenamiento de tabla admite >=, <=, etc.), pero pueden ser propensas a limitaciones si la ventana de tiempo elegida es demasiado estrecha y se produce un evento de pico. Por ejemplo, si la función de partición elegida es el minuto actual y se produce un evento de pico, demasiados clientes pueden estar intentando escribir en la misma partición simultáneamente. Esto no solo afecta al rendimiento de la inserción, sino también al rendimiento de la consulta.

  • Datos. Las funciones de particionamiento centradas en los datos calculan el valor de la partición basándose en una o varias propiedades de los datos que se van a almacenar (o recuperar). Elegir una función de particionamiento controlada por datos adecuada depende de varios factores: los modelos de consulta, la densidad de claves de partición (el número de entidades que terminarán en una partición) y el crecimiento imprevisible (puede ser desafiante reequilibrar tablas muy grandes). Entre los modelos comunes se incluyen:

    • Un solo campo. La clave de partición es un único campo de los datos de origen (por ejemplo, un id. de cliente para la información de pedidos).

    • Varios campos.. La partición o la clave de fila es un compuesto (normalmente una concatenación) de varios campos en los datos de origen. Al seleccionar las claves de partición, observe que las operaciones por lotes requieren que todas las entidades estén en la misma partición (es decir, que tengan la misma clave de partición).

    • Campo calculado. La clave de partición se calcula a partir de uno o varios campos, basándose en una función determinista. Un ejemplo común de esto sería distribuir los perfiles de usuario en varias particiones. Se aplicará un algoritmo hash al id. de usuario mediante una función de hash diseñada para la distribución relativamente uniforme, después el módulo se realizará con el número de particiones deseadas.

Cualquier aplicación no trivial requerirá el uso de varias particiones. Incluso para las tablas con un número pequeño de entidades totales (por ejemplo, doscientas), si la aplicación tiene varios miles de solicitudes por segundo, se necesitan varias particiones para lograr rendimiento:

  • Una sola tabla y una sola partición. Es la opción más sencilla (un valor de clave de partición constante), adecuada para las cargas de trabajo de pequeña escala con cantidades limitadas de requisitos de rendimiento de los datos y las solicitudes (< 500 entidades/seg.).

  • Una sola tabla y varias particiones. La opción típica para la mayoría de las implementaciones; elija cuidadosamente las claves de partición para adaptarlas a los modelos de consulta de destino.

  • Varias cuentas de almacenamiento y varias particiones. Si se prevé que la carga va a superar las 5000 operaciones por segundo, es necesario el uso de tablas repartidas entre varias cuentas de almacenamiento.

Una vez elegida esta opción, el reequilibrio (reparticionamiento) de los datos puede ser un ejercicio costoso, que implica leer y copiar todas las entidades con las nuevas claves de partición y, a continuación, eliminar los datos antiguos. Observe que no hay ninguna restricción de tamaño mínimo de una partición; las particiones pueden estar formadas por una sola entidad (es decir, una fila).

Si la aplicación requiere más rendimiento del que proporciona una única tabla (después de una cuidadosa selección de particiones), utilice varias tablas simultáneas en diferentes cuentas de almacenamiento. En este contexto, la aplicación necesitará implementar la lógica de enrutamiento adecuada para seleccionar la cuenta de almacenamiento correcta.

La Red de entrega de contenido (CDN) de Azure proporciona una manera eficaz de almacenar en caché el contenido estático (de blobs o de salida de la aplicación) en una red de Caching global y distribuida. Esto alivia la presión en la aplicación para entregar el contenido estático y mejora la experiencia global del usuario final.

El SLA de disponibilidad de la red de entrega de contenido garantiza que los objetos almacenados en caché se entregarán con una disponibilidad del 99,9 % mensual.

El uso de CDN requiere que la función se active para la suscripción. A partir de ese momento, el contenido de blobs (de los contenedores públicamente disponibles y de acceso anónimo) y el contenido anónimo de salida de la aplicación (por ejemplo http://www.miapp.com/cdn/algunaPágina.aspx) puede almacenarse en memoria caché.

En general, para cualquier aplicación de gran escala, todo el contenido estático al que se tiene acceso normalmente (imágenes, CSS, etc.) debe entregarse a través de CDN con las directivas de caducidad de la memoria caché adecuadas.

Por ejemplo, considere un almacén de libros electrónicos en línea con 1 millón de títulos. Incluir el contenido (imágenes, etc.) de todos los títulos en CDN sería muy costoso (ya que el no se tendrá acceso al contenido con frecuencia y este estaría expirando constantemente), mientras que incluir solo el contenido principal (por ejemplo, los 50 primeros títulos) proporcionaría la mezcla correcta de almacenamiento en caché en comparación con el precio.

Uno de los elementos básicos de la entrega correcta de un servicio de gran escala es la telemetría (una visión general del funcionamiento, el rendimiento y la experiencia del usuario final de la aplicación). Los enfoque de telemetría para las aplicaciones de Azure deben tener en cuenta la escala horizontal y la naturaleza distribuida de la plataforma, así como los servicios de la plataforma disponibles para recopilar, analizar y usar la telemetría.

El componente de tecnología de línea base para recopilar y entender la telemetría de Azure es Diagnósticos de Azure (WAD). WAD consta de un agente que recopila datos de las instancias individuales y los reenvía a un punto central de recopilación (cuenta de almacenamiento), así como de un conjunto de estructuras y convenciones estándar para almacenar los datos y tener acceso a ellos. El agente admite varios enfoques de configuración, incluido el código (.NET), un archivo de configuración incrustado en el código del proyecto implementado o un archivo de configuración centralizado implementado en el almacenamiento de blob. La configuración es parcialmente dinámica en este último caso, lo que permite insertar los archivos de diagnóstico actualizados en el almacenamiento de blob y, a continuación, desplegarlos en los agentes de destino.

La configuración de WAD proporciona varios orígenes de datos; cada uno de estos orígenes de datos se recopila periódicamente, se procesa por lotes mediante una sesión de seguimiento de eventos para Windows (ETW) y se publica en la cuenta de almacenamiento de destino. El agente se ocupa de los problemas transitorios de conexión, los intentos, etc. Los orígenes de datos disponibles son:

  • Contadores de rendimiento. Un subconjunto de valores de los contadores de rendimiento (CPU, memoria, etc.) capturados en una sesión ETW local y colocados de forma periódica y como etapa intermedia en el almacenamiento de tabla.

  • Registros de eventos de Windows. Un subconjunto de registros de eventos de Windows (aplicación, sistema, etc.) capturados en una sesión ETW local y colocados de forma periódica y como etapa intermedia en el almacenamiento de tabla.

  • Registros de Azure. Registros de aplicación (mensajes de seguimiento) publicados por el código de aplicación (mediante System.Diagnostics.Trace) y capturados por un agente de escucha de seguimiento DiagnosticMonitorTraceListener. Se publican en la tabla de contadores de rendimiento de WAD en la cuenta de almacenamiento de destino.

  • Registros de IIS 7.0. Información de registro de IIS estándar sobre las solicitudes registradas por IIS (solo roles web). Los registros se recopilan en archivos locales y se colocan de forma periódica y como etapa intermedia en el almacenamiento de blob.

  • Registros de solicitudes con error de IIS. Información de IIS sobre las solicitudes con error, recopilada en archivos locales y colocada de forma periódica y como etapa intermedia en el almacenamiento de blob.

  • Volcados de memoria. En caso de bloqueo del sistema, los registros sobre el estado del sistema operativo se capturan y se publican en el almacenamiento de blob.

  • Origen de datos. WAD puede supervisar directorios locales adicionales (por ejemplo, los directorios de registro del almacenamiento local) y copiar periódicamente los datos en un contenedor personalizado en el almacenamiento de blob.

Cada uno de estos orígenes de datos se configura con el subconjunto de datos que se va a recopilar (por ejemplo, la lista de contadores de rendimiento) y con el intervalo de recopilación y publicación. También hay varios scripts de PowerShell disponibles para cambiar la configuración de tiempo de ejecución o forzar una publicación inmediata de los datos de los agentes en la cuenta de almacenamiento de destino.

ImportantImportante
Registrar la telemetría en una cuenta de almacenamiento independiente. Registrar la telemetría y los datos de aplicación en la misma cuenta de almacenamiento produciría problemas graves de contención en la escala.

La Base de datos SQL de Azure proporciona una base de datos como servicio, lo que permite que las aplicaciones aprovisionen e inserten los datos en las bases de datos relacionales, y las consulten rápidamente. Ofrece muchas de las características y la funcionalidad conocidas de SQL Server, a la vez que resume la carga de hardware, configuración, incorporación de revisiones y resistencia.

noteNota
La Base de datos SQL no proporciona una paridad 1:1 de características con SQL Server y está pensada para satisfacer un conjunto diferente de requisitos adecuados exclusivamente a las aplicaciones en la nube (escala elástica, base de datos como servicio para reducir los costos de mantenimiento, etc.). Para obtener más información, vea http://blogs.msdn.com/b/windowsazure/archive/2012/06/26/data-series-sql-server-in-windows-azure-virtual-machine-vs-sql-database.aspx.

El servicio se ejecuta en un entorno multiempresa compartido, con bases de datos y suscripciones de varios usuarios en ejecución en la infraestructura basada en hardware estándar (escala horizontal, no vertical).

Las bases de datos se proporcionan dentro de servidores lógicos; cada servidor lógico contiene de forma predeterminada hasta 150 bases de datos (incluida la base de datos maestra). De forma predeterminada, cada suscripción puede aprovisionar cinco (5) servidores lógicos, con la posibilidad de aumentar esta cuota, así como el número máximo de bases de datos por cada servidor lógico, mediante una llamada al servicio de soporte técnico.

A cada servidor lógico se le asigna un nombre DNS público, único, generado (con el formato [nombreDeServidor].baseDeDatos.windows.net) y cada uno cuenta con una suscripción que comparte la misma dirección IP pública. Se obtiene acceso a los servidores lógicos (y a las bases de datos) a través del puerto estándar de SQL (TCP/1433), con la API de administración basada en REST, que tiene acceso en el puerto TCP/833.

De forma predeterminada, el acceso al servidor lógico (y a todas sus bases de datos) está limitado mediante reglas de firewall basadas en IP del portal de administración de Azure (las reglas se pueden establecer en el servidor lógico o en bases de datos individuales). Para habilitar el acceso a las aplicaciones de Azure y la conectividad directa de la aplicación desde fuera de Azure (por ejemplo, para conectarse a SQL Server Management Studio) es necesario configurar las reglas de firewall. Estas reglas se pueden configurar a través del portal de administración de Azure con una llamada API del servicio de administración.

La Base de datos SQL proporciona compatibilidad con la mayoría de las características clave presentes en SQL Server, con algunas excepciones principales, entre las que se incluyen:

  • Todas las tablas deben contener un ÍNDICE CLÚSTER; los datos no se pueden INSERTAR en una tabla en la Base de datos SQL hasta que se haya definido un ÍNDICE CLÚSTER.

  • No se admite Common Language Runtime (CLR) incrustado, creación de reflejo de la base de datos, Service Broker, compresión de datos ni particiones de tabla.

  • No se admiten índices XML ni el tipo de datos XML.

  • No se admite el cifrado de datos transparente (TDE) ni la auditoría de datos

  • No se admite la búsqueda de texto completo

Cada base de datos, cuando se crea, se configura con un límite superior de tamaño. Los tamaños disponibles actualmente son 1 GB, 5 GB, 10 GB, 20 GB, 30 GB, 40 GB, 50 GB, 100 GB y 150 GB (el tamaño máximo actualmente disponible). Cuando una base de datos llega al límite superior de tamaño rechaza comandos adicionales INSERT o UPDATE (la consulta y eliminación de datos siguen siendo posibles). El tamaño de una base de datos también se puede crear (aumentar o disminuir) emitiendo el comando ALTER DATABASE.

A medida que las bases de datos se facturan en función del tamaño promedio usado por día, las aplicaciones que prevén un crecimiento rápido o imprevisible pueden elegir establecer inicialmente el tamaño máximo de la base de datos en 150 GB. Escalar una base de datos más allá de 150 GB requiere el uso de un enfoque de escala horizontal, que se describe con más detalle en la sección siguiente.

La Base de datos SQL proporciona resistencia a los errores de nivel de nodo. Todas las operaciones de escritura en una base de datos se replican automáticamente en dos o más nodos en segundo plano mediante una técnica de confirmación de quórum (el servidor principal y al menos uno secundario deben confirmar que la actividad se escribió en el registro de transacciones para que la transacción se considere correcta y vuelva). En el caso de error de nodo, la base de datos automáticamente conmuta por error a una de las réplicas secundarias. Esto produce una interrupción transitoria para las aplicaciones cliente – una de las principales razones por las que todos los clientes de la Base de datos SQL deben implementar alguna forma de control de conexión transitorio (vea a continuación los detalles de la implementación del control de conexión transitorio).

El SLA de disponibilidad mensual es de 99,9 % de tiempo de actividad, definido como la capacidad de conectar con la Base de datos SQL antes de 30 segundos en un intervalo de 5 minutos. Los eventos de conmutación por error descritos en el párrafo anterior aparecen normalmente en menos de 30 segundos, lo que refuerza la necesidad de que la aplicación controle errores transitorios de conexión.

La Base de datos SQL proporciona una visión general del estado y del rendimiento a través de las vistas de administración dinámica (DMV); estas DMV contienen información sobre aspectos clave del sistema, como rendimiento de las consultas, tamaño de la base de datos y de las tablas, etc. Las aplicaciones son responsables de recopilar y analizar la información de las DMV clave de forma periódica, y de integrarlas en el marco más amplio de la telemetría y de la visión general.

Hay varias opciones de continuidad empresarial (copia de seguridad, restauración) disponibles para la Base de datos SQL. Las bases de datos se pueden copiar mediante la funcionalidad de copia de base de datos o el servicio para importar y exportar una DAC. Una copia de base de datos proporciona resultados transaccionales coherentes, mientras que un bacpac (a través del servicio para importar y exportar) no los proporciona. Ambas opciones se ejecutan como servicios basados en cola en el centro de datos y no proporcionan actualmente un SLA de tiempo de finalización.

Observe que el servicio de copia de base de datos y de importación y exportación suponen un grado de carga significativo en la base de datos de origen, y pueden desencadenar contención de recursos o eventos de limitación (descritos en la sección de recursos compartidos y limitación a continuación). Aunque ninguno de estos enfoques proporciona el mismo grado de copia de seguridad incremental que admite SQL Server, actualmente se prevé que una nueva característica habilite la capacidad de restauración a un momento dado. La característica de restauración a un momento dado permite a los usuarios restaurar la base de datos a un momento arbitrario de las últimas 2 semanas.

La única técnica de autenticación admitida actualmente es la autenticación SQL: inicios de sesión con nombre de usuario y contraseña de factor único basados en los usuarios registrados en la base de datos. Las capacidades de autenticación de Active Directory o de dos factores no están aún disponibles. Se recomienda encarecidamente el cifrado de la conexión a la Base de datos SQL, con la compatibilidad de cifrado integrada de ADO.NET, ODBC, etc. Los permisos de nivel de base de datos son coherentes con los de SQL Server. Vea el artículo acerca de cómo administrar bases de datos e inicios de sesión en la Base de datos SQL de Azure para obtener una explicación detallada sobre la configuración de la seguridad de la Base de datos SQL de Azure.

La Base de datos SQL proporciona un conjunto enriquecido de vistas de administración dinámicas para observar el rendimiento de las consultas y el estado de la base de datos. Sin embargo, no se proporciona ninguna infraestructura automatizada para recopilar y analizar estos datos (y herramientas conocidas como el generador de perfiles de conexión directa y los contadores de rendimiento del sistema operativo no están disponibles). Los enfoques para la recopilación y el análisis se describen en la sección acerca de la telemetría de este documento.

Como se ha descrito anteriormente, la Base de datos SQL es un servicio multiempresa que se ejecuta en una infraestructura compartida. Las bases de datos de varios inquilinos comparten los nodos físicos subyacentes, que se crean encima de hardware estándar. Otros usuarios del sistema pueden utilizar los recursos clave (los subprocesos de trabajo, el registro de transacciones, E/S, etc.) en la misma infraestructura subyacente. El uso de recursos se rige y toma forma para mantener las bases de datos en los límites de recursos establecidos. Cuando estos límites se superan, ya sea en un inquilino o en un nivel físico de nodo, la Base de datos SQL responde limitando el uso o quitando conexiones. Estos límites se enumeran en la tabla siguiente.

 

Recurso Valor máximo por transacción y sesión Valor máximo por nodo físico Límite de limitación de software Límite de limitación de hardware

Subprocesos de trabajo

N/D

512

305

410

Tamaño de base de datos

Tamaño máximo configurado hasta 150 GB por base de datos

N/D

Ninguno

100 %; no se aceptan inserciones ni actualizaciones una vez alcanzado el límite

Crecimiento del registro de transacciones

2 GB por transacción

500 GB

N/D

N/D

Longitud del registro de transacciones

20 % del espacio de registro total (100 GB)

500 GB

N/D

N/D

Recuento de bloqueos

1 millón por transacción

N/D

N/D

N/D

Bloqueo de tareas del sistema

20 segundos

N/D

N/D

N/D

Espacio de base de datos temporal

5 GB

N/D

N/D

5 GB

Memoria

N/D

N/D

N/D

16 MB durante 20 segundos

Máximo de solicitudes simultáneas

400 por base de datos

N/D

N/D

N/D

Cuando se alcanza el límite de una transacción, el sistema cancela la transacción como respuesta. Cuando una base de datos alcanza el límite de limitación de software, se retrasan o se anulan las transacciones y las conexiones. Alcanzar un límite de limitación de hardware afecta a todas las bases de datos (y a todos los usuarios) en el nodo físico subyacente, hace que las operaciones existentes se terminen y evita nuevas operaciones o conexiones hasta que el recurso vuelva a estar otra vez por debajo del umbral de limitación.

Algunas de estas limitaciones tienen como resultado límites potencialmente no intuitivos del diseño y del rendimiento de una aplicación. Por ejemplo, limitar el crecimiento del registro de transacciones hasta un máximo de 2 GB por transacción impide que se cree un índice en una tabla grande (donde crear el índice generaría más de 2 GB de registro de transacciones). Las técnicas para realizar estas operaciones se describen en la sección de procedimientos recomendados de este documento.

Administrar estos tipos de condiciones de limitación y de errores transitorios requiere un cuidadoso diseño e implementación del código de cliente; solucionarlos requiere escalar el nivel de base de datos para utilizar simultáneamente varias bases de datos (la escala horizontal se describe en la sección siguiente).

El código de la aplicación cliente de SQL debe:

  • Implementar código de reintento que reconozca los códigos de error de SQL relacionados con la limitación y que proporcione la lógica de interrupción adecuada. Sin alguna forma de lógica de interrupción en la aplicación, la base de datos puede quedar bloqueada en un estado continuado de limitación e insertar constantemente la carga máxima en la base de datos.

  • Registre los errores de limitación mediante el código de reintento para distinguir entre un error de la conexión transitorio, de limitación y de hardware (sintaxis, sprocs que faltan y así sucesivamente). Esto ayudará en el seguimiento y en la solución de problemas de disponibilidad de la aplicación.

  • Implemente un modelo de interruptor. Cuando haya expirado una directiva de reintento correctamente elegida (equilibrio de la latencia y la respuesta del sistema con la frecuencia de reintento de la aplicación), invoque una ruta de acceso del código para controlar el error no transitorio (es decir, recorra el interruptor). Entonces el código de aplicación podrá:

    • Retroceder a otro servicio o enfoque. Si la aplicación no pudo insertar nuevos datos en la Base de datos SQL (y los datos no tenían que estar inmediatamente disponibles), los datos se podrían serializar en un valor DataTable (u otro formato XML o JSON), y escribirse en un archivo en el almacenamiento de blob. La aplicación podría devolver un código correcto al usuario (o a la llamada API) e insertar los datos en la base de datos en un momento posterior.

    • Generar un error silencioso que devuelva un valor NULL si los datos o el flujo de trabajo eran opcionales (no afectarán a la experiencia del usuario final).

    • Generar un error rápido que devuelva un código de error si no hay disponible ningún mecanismo de retroceso útil o adecuado.

La Base de datos SQL puede entregar un gran número de unidades de escala (bases de datos) relativamente pequeñas con facilidad. Implementar aplicaciones muy escalables en Azure aprovechando la Base de datos SQL requiere un enfoque de escala horizontal y componer los recursos de varias bases de datos para satisfacer la demanda variable. Dado que las aplicaciones se dirigían tradicionalmente a la “cáscara de huevo de titanio” de un único servidor de base de datos de escala vertical muy resistente, se requiere un diseño concienzudo para cambiar las aplicaciones de forma que hagan un uso eficaz de un servicio de base de datos de escala horizontal.

Con la Base de datos SQL, al igual que con otros servicios básicos de Azure, la escala horizontal y la composición son clave para la escala adicional (tamaño de base de datos, rendimiento) y los recursos (subprocesos de trabajo, etc.). Hay dos enfoques básicos para implementar el particionamiento o sharding (y, por consiguiente, la escala horizontal) en la Base de datos SQL; estos enfoques no se excluyen mutuamente en una aplicación:

  • Particionamiento horizontal. En un enfoque de particionamiento horizontal, las tablas o conjuntos de datos intactos se separan en bases de datos individuales. Por ejemplo, en una aplicación multiempresa que sirve a diferentes conjuntos de clientes, la aplicación puede crear una base de datos por cliente. En una aplicación mayor de una sola empresa, la tabla de clientes puede residir en una base de datos diferente de la tabla de pedidos. La clave de partición es normalmente el id. de inquilino (por ejemplo, el id. de cliente). En el diagrama siguiente, el conjunto de datos se divide horizontalmente en tres bases de datos diferentes mediante un hash del correo electrónico como valor de partición (es decir, la clave de partición es el correo electrónico; la función de partición usa un hash de la clave para asignar a una base de datos de destino).

  • Particionamiento vertical. En un enfoque de particionamiento vertical, un conjunto de datos se expanda entre varias tablas o bases de datos físicas, en función de particionamiento de esquema. Por ejemplo, los datos de cliente y los datos de pedido pueden estar repartidos entre diferentes bases de datos físicas. En el diagrama siguiente, se crean particiones del conjunto de datos verticalmente en dos bases de datos distintas. La información de usuario básica (nombre, correo electrónico) se almacena en DB1, con la información de perfil de usuario (como el URI de la imagen de avatar) almacenada en DB2.

Muchas aplicaciones usarán una mezcla de particionamiento horizontal y vertical (particionamiento híbrido), además de incorporar servicios de almacenamiento adicionales. Por ejemplo, las imágenes de avatar de los usuarios del ejemplo anterior se almacenaron como id. de base de datos, que la aplicación expandiría a una dirección URL completa. Esta dirección URL se asignaría a una imagen almacenada en un blob.

Al trabajar con un almacén de datos relacional de escala horizontal, la disponibilidad de cálculo es muy diferente. Los sistemas con grandes números de particiones tienen una probabilidad mayor de que un segmento de datos individual esté sin conexión y una probabilidad mucho menor de que la aplicación completa no esté disponible. Las aplicaciones deben tener en cuenta la disponibilidad parcial de los almacenes de datos back-end. Con un modelo de datos de escala horizontal, la disponibilidad de los datos ya no es una situación de todo o nada.

Volver a particionar los datos puede ser desafiante, especialmente si el modelo de uso o la distribución de los datos cambian con el tiempo. Las claves de partición basadas en intervalos, ya estén basadas en un número fijo (con un módulo hash de los valores de partición) o la distribución de los valores de partición, requiere el reequilibrio de datos entre las particiones individuales. Los esquemas de partición basados en intervalos utilizan a menudo divisiones o combinaciones binarias para simplificar las operaciones de reequilibrio.

Por ejemplo, los métodos de creación de particiones por rangos fijos (por ejemplo, la primera letra del apellido) pueden comenzar como una distribución equilibrada, pero cambiar rápidamente a estar muy desequilibrados a medida que aparecen nuevos usuarios (cada uno aporta su propio apellido, que puede o no estar distribuido de manera uniforme por el alfabeto). Tenga en cuenta la posible necesidad de ajustar con el tiempo el mecanismo de particionamiento y el costo de reequilibrar los datos.

Los esquemas de partición basados en búsquedas son más difíciles de implementar y requieren un mecanismo de búsqueda de alto rendimiento para cada inquilino o partición de datos, pero son más favorables al reequilibrio pormenorizado, ya que permiten que un único inquilino se reequilibre individualmente en una nueva partición. También permiten que se agregue capacidad adicional (nuevas bases de datos, etc.) al sistema sin tener que copiar los datos.

Independientemente de la mezcla de enfoques de particionamiento, pasar a una escala horizontal de las bases de datos relacionales con particiones implica ciertas restricciones que requieren un enfoque diferente para la administración y consulta de los datos:

  • El “buen” almacenamiento de datos SQL tradicional y los diseños de consulta se han optimizado para el almacenamiento y la coherencia aprovechando los modelos de datos normalizados. En este enfoque se supone la existencia de un espacio de datos global coherente, que usa referencias cruzadas e instrucciones JOIN entre las tablas. Con los datos repartidos en nodos físicamente distribuidos, las instrucciones JOIN y las referencias cruzadas solo son posibles en una sola partición. La Base de datos SQL no admite las consultas distribuidas a través de varias bases de datos; la combinación de datos tiene que controlarse en el nivel de cliente, y la desnormalización y replicación de datos, entre particiones.

  • Los datos y los metadatos de referencia se centralizan normalmente en tablas de referencia. En un enfoque de escala horizontal, estas tablas de referencia, así como los datos que no pueden separarse mediante la clave de partición común, deben replicarse entre varias particiones y mantenerse coherentes.

  • No hay ninguna forma práctica de entregar las transacciones distribuidas escalables de mayor rendimiento entre las particiones; los datos (y las actualizaciones de esquema) no serán coherentes transaccional entre las particiones. El código de aplicación necesita suponer, y explicar, cierto grado de coherencia flexible entre las particiones.

  • El código de aplicación necesita conocer el mecanismo de particionamiento (horizontal, vertical, tipo de partición) para poder conectarse a la partición o a las particiones adecuadas.

  • Las ORM comunes (como Entity Framework) no entienden de forma nativa los modelos de datos de escala horizontal; las aplicaciones que hacen un uso extenso de grandes ORM pueden requerir un rediseño significativo para ser compatibles con el particionamiento horizontal. Los diseños que aíslan a los inquilinos (conjuntos de clientes) de un enfoque de partición vertical en una única base de datos requieren generalmente menos rediseño en la capa de acceso a datos. El inconveniente del modelo de partición vertical puro consiste en que cada partición individual está limitada por la capacidad de una sola base de datos.

  • Las consultas que necesitan tocar (leer o escribir) varias particiones deben implementarse con un modelo de dispersión y recopilación, donde las consultas individuales se ejecutan en las particiones de destino y el conjunto de resultados se agregado en la capa de acceso a datos del cliente.

Para realizar el escalado horizontal con Base de datos SQL, se realiza el particionamiento de datos manual entre varias Bases de datos SQL. Este enfoque de escala horizontal proporciona la posibilidad de llegar a un crecimiento del costo casi lineal con la escala. El crecimiento o la capacidad elástico a petición puede crecer con los costos incrementales según sea necesario. No todas las aplicaciones pueden admitir este modelo de escala horizontal sin un rediseño significativo.

  • No se garantiza que las actualizaciones de esquema sean coherentes entre transacciones, especialmente al actualizar un gran número de particiones. Las aplicaciones deben aceptar los períodos de inactividad planeados o responder a varias versiones simultáneas del esquema implementado.

  • Los procesos de continuidad empresarial (copia de seguridad y restauración, etc.) necesitan tener en cuenta varias particiones de datos.

Las recomendaciones y los procedimientos recomendados de diseño para solucionar estos desafíos se tratan en la sección de procedimientos recomendados de este documento.

El resto de este documento se centra en ilustrar los procedimientos recomendados para entregar aplicaciones muy escalables con Azure y la Base de datos SQL, basadas en experiencias del mundo real y en el aprendizaje que proporcionan. En cada procedimiento recomendado se describe la optimización y los componentes de destino, el enfoque de implementación y los inconvenientes inherentes. Como ocurre con cualquier procedimiento recomendado, estas recomendaciones dependen en gran medida del contexto en el que se aplican. Evalúe la adecuación de cada procedimiento recomendado según las capacidades de la plataforma descritas en la sección anterior.

noteNota
Estas experiencias se han extraído de varios compromisos de cliente que no siguen el modelo OLTP (procesamiento de transacciones en línea) clásico. Es importante comprender que algunos de estos procedimientos recomendados pueden no ser directamente aplicables a las aplicaciones que requieren coherencia de datos segura o estricta; solo se conocen los requisitos empresariales exactos de la aplicación y su entorno.

Cada práctica recomendada se relacionará con uno o varios aspectos de la optimización:

  • Rendimiento. Cómo aumentar el número de operaciones (transacciones, llamadas de servicio, etc.) a través del sistema y reducir la contención.

  • Latencia. Cómo reducir la latencia en operaciones de agregado e individuales.

  • Densidad. Cómo reducir los puntos de contención al crear servicios en los contextos directos (por ejemplo, código de aplicación para la Base de datos SQL) y los contextos de agregado (el uso de varias cuentas de almacenamiento para mayor escala).

  • Facilidad de uso. Diagnósticos, telemetría y visión general: cómo entender el estado y el rendimiento de los servicios implementados en la escala.

  • Disponibilidad. Cómo aumentar la disponibilidad global de la aplicación y reducir el impacto de los puntos y modos de error (la disponibilidad bajo carga se trata en las secciones rendimiento, latencia y densidad).

Como unidad de línea base de escala en Azure, el diseño y la implementación cuidadosos de los servicios hospedados es crítico para proporcionar servicios disponibles muy escalables.

  • El número de instancias y dominios de actualización en un servicio hospedado puede tener un impacto significativo en el tiempo necesario para implementar, configurar y actualizar el servicio hospedado. Equilibrar el rendimiento y la escalabilidad se beneficia de la mayor complejidad necesaria para lograr esos beneficios. Mejorar la escalabilidad y flexibilidad aumenta normalmente los costos de implementación y administración de una solución.

  • Evite los roles de una sola instancia; esta configuración no cumple los requisitos del SLA de Azure. Durante un evento de error o de actualización de nodo, un rol de una sola instancia se desconecta. Limite su uso a tareas de “mantenimiento” de baja prioridad.

  • Cada centro de datos tiene una capacidad finita (aunque grande), y puede servir como punto de error único en raras circunstancias. Los servicios que requieren el nivel superior de escala y disponibilidad deben implementar una topología de varios centros de datos con varios servicios hospedados. Sin embargo:

  • Cuando no se necesita el nivel superior de disponibilidad (vea el elemento anterior), asegúrese de que las aplicaciones y los servicios dependientes están totalmente incluidos en un solo centro de datos. En las situaciones donde la solución debe usar varios centros de datos, utilice las siguientes instrucciones:

    • Evite las llamadas de red entre centros de datos para la operaciones en directo (a parte de la sincronización entre sitios deliberada). La latencia de largo alcance entre los centros de datos puede ser muy variable y generar características de rendimiento de la aplicación no esperadas o indeseables.

    • Utilice solo la funcionalidad mínima requerida que tenga acceso a los servicios en otro centro de datos. Normalmente, estas actividades están relacionadas con la continuidad de negocio y la replicación de datos.

Para las aplicaciones distribuidas de gran escala, el acceso a los datos de aplicación con estado es crítico. El rendimiento global de la aplicación y la latencia están limitados normalmente por la rapidez con la que se pueden recuperar, compartir y actualizar los datos y el contexto necesarios. Los servicios distribuidos de almacenamiento en memoria caché, como Caching de Azure y memcached, han evolucionado en respuesta a esta necesidad. Las aplicaciones deben utilizar una plataforma de memoria caché distribuida. Tenga en cuenta las directrices siguientes:

  • Utilice una plataforma de almacenamiento en memoria caché distribuida como rol de trabajo dentro del servicio hospedado. Esta gran proximidad a los clientes de la memoria caché reduce las barreras de latencia y rendimiento producidas por el recorrido del equilibrador de carga. Caché en rol de Caché de Azure hospeda el almacenamiento en caché en roles de trabajo dentro del servicio en la nube.

  • Use la plataforma de almacenamiento en memoria caché distribuida como repositorio principal para tener acceso a los datos y objetos comunes de la aplicación (por ejemplo, el perfil de usuario y el estado de la sesión), respaldado por la Base de datos SQL u otro almacén duradero en el enfoque de lectura completa o de cache-aside.

  • Los objetos de la memoria caché tienen un período de vida que afecta al tiempo que están activos en la memoria caché distribuida. Las aplicaciones establecen explícitamente el período de vida en los objetos almacenados en memoria caché o configuran un período de vida predeterminado para el contenedor de la memoria caché. Equilibre la opción de período de vida entre la disponibilidad (aciertos de caché) y la presión en la memoria y la obsolescencia de los datos.

  • Las memorias caché muestran una semántica de clave-byte>[]; tenga en cuenta el potencial de que las operaciones de escritura superpuestas creen datos incoherentes en la memoria caché. Las memorias caché distribuidas no proporcionan normalmente una API para las actualizaciones atómicas en los datos almacenados, ya que no son conscientes de la estructura de los datos almacenados.

    • Para las aplicaciones que requieren una coherencia estricta de las operaciones de escritura simultáneas, use una distribución de plataforma de almacenamiento en memoria caché que proporcione un mecanismo de bloqueo para actualizar las entidades. En el caso del almacenamiento en memoria caché de Azure, esto se puede implementar mediante GetAndLock o PutAndUnlock. Nota: esto tendrá un efecto negativo en el rendimiento.

  • El rendimiento de la memoria caché está limitado en la capa de aplicación por el tiempo necesario para serializar y deserializar objetos. Para optimizar este proceso, utilice un serializador binario relativamente simétrico (que requiera el mismo tiempo para codificar y descodificar datos) y muy eficaz, por ejemplo, protobuf.

    • Para usar la serialización personalizada correctamente, diseñe objetos de transferencia de datos (DTO) para la serialización en memoria caché, use la anotación adecuada para la serialización, impida las dependencias cíclicas y utilice pruebas unitarias para el seguimiento de la serialización eficaz.

De forma predeterminada, las conexiones entre las capas de servicio (que incluyen conexiones entrantes a través del equilibrador de carga) están sujetas a un esquema de asignación round-robin, con anclaje limitado de la conexión. En los diagramas siguientes se muestra la malla típica de conexión que es el resultado de las capas y los servicios externos (en el lado izquierdo se muestra una aplicación típica de solo capa web). Aunque esta malla no muestra ningún problema de rendimiento sustancial para los protocolos de conexión ligeros (como HTTP), algunas conexiones son costosas de conectar o inicializar o son un recurso regido (limitado). Por ejemplo, las conexiones de Base de datos SQL pertenecen a esta categoría. Para optimizar el uso de estos servicios y componentes externos, se recomienda encarecidamente establecer la afinidad de las llamadas de recursos con instancias concretas.

En el diagrama anterior, la topología de la derecha tiene capas de web y trabajo independientes (roles) dentro del mismo servicio hospedado. Esta topología también ha implementado la afinidad entre las capas web y de aplicación para anclar las llamadas de instancias de aplicación específicas a bases de datos concretas. Por ejemplo, para solicitar datos de la base de datos uno (DB1), las instancias web deben solicitar los datos a través de las instancias de aplicación uno o dos. Como el equilibrador de carga de Azure solo implementa actualmente una técnica round-robin, la entrega de afinidad en la aplicación requiere un diseño y una implementación cuidadosos.

  • Diseñe la aplicación con capas web y de aplicación independientes, y entregue la afinidad preparada para particiones o para recursos entre la capa web y de aplicación.

  • Implemente una lógica de enrutamiento que enrute de forma transparente las llamadas dentro de un mismo servicio a una instancia de la aplicación de destino. Use el conocimiento del mecanismo de partición usado por los recursos externos o de nivel inferior (como la Base de datos SQL).

La implementación práctica de esta arquitectura de varios niveles requiere una comunicación de servicios muy eficaz entre las capas web y de aplicación mediante protocolos ligeros y eficientes.

Las técnicas de desarrollo de una aplicación de Azure no se diferencian en lo fundamental de las técnicas de desarrollo para Windows Server. Sin embargo, el entramado elástico resalta la necesidad y las ventajas de emplear un código eficaz que use los recursos informáticos de la forma más eficaz posible.

  • Suponga que todos los servicios, llamadas de red y recursos dependientes son potencialmente no confiables y susceptibles de modos de error transitorios y continuados (por ejemplo, cómo implementar la lógica de reintento para la Base de datos SQL se trata más adelante en este tema):

    • Implemente las directivas de reintento adecuadas en las llamadas de servicio (Base de datos SQL, almacenamiento, etc.) para controlar las condiciones de error transitorias y la pérdida de conectividad.

    • Implemente directivas de interrupción en la lógica de reintento para evitar los efectos de “convoy” (reintentos que se apilan en el servicio y prolongan las interrupciones del sistema).

    • Implemente la telemetría de cliente enriquecida para registrar los mensajes de error y los eventos de error con la información contextual (servicio de destino, contexto de usuario o de cuenta, actividad, etc.).

  • No cree directamente subprocesos para programar el trabajo; en su lugar utilice un marco de programación y de simultaneidad como la TPL de .NET. Los subprocesos son objetos relativamente pesados, y su creación y eliminación no son triviales. Los programadores que trabajan con un grupo de subprocesos compartido pueden programar y ejecutar el trabajo de manera más eficaz. Esta arquitectura también proporciona una semántica de alto nivel para describir la continuación y el control de errores.

  • Optimice los objetos de transferencia de datos (DTO) para la serialización y la transmisión de red. Dada la naturaleza muy distribuida de las aplicaciones de Azure, la escalabilidad está limitada por la eficiencia con que los componentes individuales del sistema pueden comunicarse a través de la red. Los datos pasados a través de la red para la comunicación o el almacenamiento deben implementar la serialización de texto de JSON o un formato binario más eficaz con las sugerencias adecuadas para minimizar la cantidad de metadatos transferidos a través de la red (por ejemplo, nombres de campo más cortos “en la conexión").

    • Si la interoperación es importante, use un formato de texto eficaz, como JSON, para la interoperabilidad y los metadatos en la banda.

    • Si es importante un mayor rendimiento, por ejemplo, la comunicación entre servicios en la que se controlan ambos extremos, considere la posibilidad de usar un formato binario empaquetado muy eficaz, como bson o protobuf.

      • Evite la transferencia de datos locuaz (frecuente) de objetos pequeños. La comunicación locuaz entre servicios desperdicia recursos del sistema importantes en las tareas de sobrecarga y es susceptible a las respuestas de latencia variable.

      • Las pruebas para serializar y deserializar objetos deben ser un componente básico del marco de prueba automatizado. Las pruebas de funcionalidad garantizan que las clases de datos sean serializables y que no haya dependencias cíclicas. Las pruebas de rendimiento comprueban los tiempos de latencia y los tamaños de codificación necesarios.

  • Donde sea posible, utilice marcos de trabajo ligeros para la comunicación entre los componentes y los servicios. Muchas tecnologías tradicionales de la pila de .NET proporcionan un conjunto de características enriquecidas que podrían no estar alineadas con la naturaleza distribuida de Azure. Los componentes que proporcionan un mayor grado de abstracción entre el intento y la ejecución suelen implicar un alto costo de rendimiento.

    • Donde no se requiera la interoperación de protocolos ni la compatibilidad con protocolos avanzados, investigue el uso de la API web de ASP.NET en lugar de WCF para implementar los servicios web.

    • Si no necesita las características enriquecidas de Entity Framework, investigue el uso de un micro-ORM como Dapper para implementar el nivel de cliente de SQL.

  • Reduzca la cantidad de datos entregados fuera del centro de datos habilitando la compresión HTTP en IIS para los datos salientes.

  • Establezca la afinidad de las conexiones entre las capas para reducir la locuacidad y el cambio de contexto de las conexiones.

  • Para reducir la carga de la aplicación, use el almacenamiento de blob para servir el contenido estático grande (> 100 kB).

  • Para reducir la carga de la aplicación, use la red de entrega de contenido (CDN) a través del almacenamiento de blob para servir el contenido estático, como imágenes o CSS.

  • Evite usar la Base de datos SQL para los datos de sesión. En su lugar, use la memoria caché distribuida o cookies.

El Almacenamiento de Azure es la red troncal duradera de datos en una aplicación de Azure. Aunque proporciona una experiencia muy confiable y escalable “lista para utilizar”, las aplicaciones de gran tamaño requieren unas directrices de diseño y uso adecuadas.

  • Utilice varias cuentas de almacenamiento para una mayor escalabilidad, ya sea para un tamaño mayor (> 100 TB) o para más rendimiento (> 5000 operaciones por segundo). Asegúrese de que el código de aplicación se puede configurar para usar varias cuentas de almacenamiento, con las funciones de partición adecuadas que enruten el trabajo a las cuentas de almacenamiento. Diseñe la capacidad para agregar cuentas de almacenamiento adicionales como un cambio de configuración, no un cambio de código.

  • Seleccione cuidadosamente las funciones de partición para el almacenamiento de tabla con el fin de habilitar la escala deseada en términos de rendimiento de la inserción y de las consultas. Busque un enfoque de particionamiento basado en el tiempo para los datos de telemetría, con claves compuestas basadas en los datos de fila para los datos no temporales. Mantenga las particiones de un intervalo adecuado para un rendimiento óptimo; las particiones muy pequeñas restringen la capacidad de realizar operaciones por lotes (incluidas las consultas), mientras que las particiones muy grandes son costosas de consultar (y pueden crear cuellos de botella en las inserciones simultáneas de grandes volúmenes).

    • La selección de la función de particiones también tendrá un efecto fundamental en el rendimiento de las consultas; el almacenamiento de tabla proporciona una búsqueda eficaz por {clave de partición, clave de fila}, con un procesamiento menos eficiente de {clave de partición, filtro de coincidencias de fila} y {filtro de coincidencias de clave de partición, filtro de coincidencias de clave de fila}. Las consultas que requieren una tabla global examinan ({filtro de coincidencias de clave de fila}).

    • Las particiones pueden ser tan pequeñas como una sola entidad; esto proporciona un rendimiento muy optimizado para las cargas de trabajo de búsqueda pura como, por ejemplo, la administración del carro de la compra.

  • Cuando sea posible, procese por lotes las operaciones en el almacenamiento. Las operaciones de escritura de tabla deben procesarse por lotes, normalmente mediante el uso del método SaveChanges en la API de cliente .NET. Inserte una serie de filas en una tabla y, a continuación, confirme los cambios en un único lote con el método SaveChanges. Las actualizaciones del almacenamiento de blob también deben confirmarse en lotes, mediante el método PutBlockList. Al igual que ocurre con la API de almacenamiento de tabla, llame a PutBlockList en un intervalo de bloques, no en bloques individuales.ReplaceThisText

  • Elija nombres de columna cortos para las propiedades de la tabla, ya que los metadatos (nombres de propiedad) se almacenan en la banda. Los nombres de columna también cuentan para el tamaño máximo de fila de 1 MB. Los nombres de propiedad excesivamente largos desperdician recursos del sistema.

Tal como se explicó en la sección de exploración de Azure, la Base de datos SQL proporciona una base de datos relacional llave en mano como capacidad de servicio, que habilita el acceso escalable al almacenamiento de datos en un modo de escala horizontal. El uso correcto de la Base de datos SQL en las aplicaciones a gran escala requiere la selección cuidadosa de varias opciones de diseño e implementación; los puntos clave del diseño y los procedimientos recomendados se tratan en esta sección.

Muchas aplicaciones requieren una tabla de metadatos para almacenar detalles como la información de enrutamiento, de particiones y del inquilino. Almacenar estos metadatos en una sola base de datos crea un punto de error único, así como un cuello de escalabilidad. Los almacenes de metadatos centrales deben ampliarse de forma horizontal mediante una combinación de:

  • Almacenamiento dinámico en memoria caché. La información de la base de datos de configuración se debe almacenar dinámicamente en una memoria caché distribuida (como memcached o Servicio de caché de Azure).

    • Tenga cuidado del efecto de intentar cargar previamente la memoria caché de forma dinámica desde varios subprocesos de trabajo en el inicio de la aplicación, lo que conduce normalmente a una carga excesiva y a la limitación de la base de datos. Si la aplicación requiere una memoria caché carga previamente, delegue la responsabilidad de cargar los datos en un rol de trabajo dedicado (o una tarea programada) con una velocidad de carga configurable.

    • Si el rendimiento o la confiabilidad de la aplicación dependen de tener cierto segmento de datos disponible en la memoria caché, la aplicación debe rechazar las solicitudes entrantes hasta que la memoria caché se haya llenado previamente. Hasta que se rellenen los datos, la aplicación debe devolver un mensaje o un código de error adecuado.

  • Escala horizontal. Cree particiones de los datos en vertical (por tabla) o en horizontal (segmente la tabla entre varias particiones) para repartir la carga entre varias bases de datos.

La escalabilidad total de una Base de datos SQL con particiones está limitada por la escala de una base de datos individual (partición) y por la eficacia y eficiencia con la que están combinadas esas particiones para lograr una escala mayor:

  • Dado que los límites del registro de transacciones restringen las transacciones grandes, como, por ejemplo, la regeneración de índices, las tablas individuales no deben superar aproximadamente los 10 GB (tenga en cuenta que este límite práctico depende del tamaño de los índices de la tabla de destino, por lo que puede ser más o menos de 10 GB para la base de datos). Para las tablas individuales grandes, divida la tabla en tablas individuales menores y use una vista con particiones para proporcionar una superposición uniforme.

    • Mantener pequeños los tamaños de tabla individuales reduce el impacto del cambio de esquema o una regeneración del índice durante una actualización por fases. Los cambios en las tablas menores minimizan el tiempo de inactividad y la latencias debidos al bloqueo de las operaciones.

    • Este particionamiento complica las técnicas de administración. Las operaciones como volver a generar el índice se deben ejecutar en modo iterativo en todas las tablas del componente.

  • Mantenga las bases de datos individuales (particiones) razonablemente pequeñas. Las operaciones de continuidad como DB Copy o las exportaciones a bases de datos mayores de 50 GB pueden tardar horas en completarse (el servicio cancela las operaciones que se ejecutan durante más de 24 horas).

En un mundo de suministro de servicios continuo, administrar las actualizaciones o las modificaciones de esquema de la base de datos distribuida requiere el debido cuidado y atención para suavizar la ruta de acceso de actualización. Todos los procedimientos recomendados tradicionales para el control de las operaciones de esquema y metadatos en un almacén de datos de producción son más importantes que nunca. Por ejemplo, es una tarea mucho más compleja depurar y resolver un procedimiento almacenado que se ha eliminado accidentalmente en 1 de 100 bases de datos.

Dado que las actualizaciones de esquemas y las modificaciones de datos no son coherentes entre las particiones, las actualizaciones de una aplicación deben ser compatibles con los esquemas nuevos y antiguos durante el período de transición. Este requisito normalmente significa que cada versión de la aplicación debe ser al menos compatible con la versión actual y la versión anterior de esquema.

El cambio a una colección de bases de datos de escala horizontal crea desafíos en la administración de las conexiones. Cada conexión de Base de datos SQL es un recurso relativamente costoso, lo que se evidencia por el uso extenso de la agrupación de conexiones en las API de cliente (ADO.NET, ODBC, PHP, etc.). En lugar de que cada instancia de aplicación mantenga varias conexiones a un servidor SQL Server central, cada instancia de aplicación debe mantener potencialmente conexiones a varios servidores de base de datos.

Ya que las conexiones son un recurso costoso y potencialmente insuficiente, las aplicaciones deben devolver las conexiones agrupadas de forma puntual para administrarlas correctamente. El código de aplicación debe usar la cancelación automática de la conexión; en .NET el procedimiento recomendado consiste en ajustar todo el uso de SqlConnection en una instrucción using, por ejemplo:

using (var conn = new SqlConnection(connStr))
{
    // SQL client calls here
}

Como se describió anteriormente, las conexiones en una Base de datos SQL están sujetas a errores transitorios de conexión. La lógica de reintentos debe usarse en todas las conexiones y comandos para protegerse frente a estos errores transitorios (vea los detalles adicionales a continuación).

La Base de datos SQL solo admite las conexiones de TCP (no las canalizaciones con nombre) y se recomienda encarecidamente cifrar la conexión entre el código de aplicación y la Base de datos SQL. Para evitar intentos de conexión no deseados (por ejemplo, un intento de usar canalizaciones con nombre), las aplicaciones deben dar formato a sus cadenas de conexión SQL como sigue:

Server=tcp:{servername}.database.windows.net,1433;Database={database};User ID={userid}@{database};Password={password};Trusted_Connection=False;Encrypt=True;Connection Timeout=30;

Para las implementaciones de aplicaciones a gran escala, el número predeterminado de conexiones posibles puede aumentar exponencialmente entre una implementación de servicio hospedado y los servidores lógicos de Base de datos SQL en un clúster de Base de datos SQL (cada uno con una única dirección IP externa). Tomemos, por ejemplo, un servicio hospedado con 100 instancias, 50 bases de datos y el número predeterminado de conexiones, que es de 100 conexiones de forma predeterminada en ADO.NET.

MaxConnections=DatabaseCount*Instance Count*MaxConnectionPoolSize

Consulte la topología de red de un servicio hospedado; cada lado de conexión (el servicio hospedado y los servidores lógicos de Base de datos SQL) reside detrás de un equilibrador de carga de Azure. . Cada equilibrador de carga de Azure tiene un límite superior de conexiones de 64 K entre dos direcciones IPv4 cualesquiera. La combinación de esta topología de red con el número predeterminado de conexiones disponibles da lugar a errores de red graves en aplicaciones grandes.

  • Implemente las aplicaciones grandes entre varios servicios hospedados.

  • Implemente las bases de datos en varias suscripciones (no solo varios servidores lógicos de la misma suscripción) para obtener más direcciones IP únicas.

  • Implemente las aplicaciones de varios niveles para establecer la afinidad de las operaciones salientes con una instancia de la aplicación de destino (vea la sección anterior sobre servicios hospedados).

  • Recuerde que los grupos de conexiones se mantienen por cada cadena de conexión única y corresponden a cada combinación única de servidor de base de datos, base de datos e inicio de sesión. Use la agrupación de conexiones de cliente de SQL y limite explícitamente el tamaño máximo del grupo de conexiones de SQL. Las bibliotecas de cliente de SQL reutilizan las conexiones cuando es necesario; el impacto de un grupo de conexiones pequeño es la posibilidad del aumento de latencia mientras las aplicaciones esperan a que las conexiones estén disponibles.

En la siguiente lista se proporcionan recomendaciones para reducir el número de conexiones activas necesarias:

El cambio a un modelo de datos distribuido puede requerir modificaciones en el diseño del esquema de la base de datos, así como en ciertos tipos de consultas. Las aplicaciones que requieren el uso de transacciones distribuidas entre varias bases de datos tienen posiblemente un modelo de datos o una implementación inadecuados (por ejemplo, al intentar aplicar la coherencia global). Los diseños deben refactorizarse.

El uso de una instalación central de generación de secuencias se debe evitar para cualquier aspecto no trivial de la aplicación, debido a las restricciones de disponibilidad y escalabilidad. Muchas aplicaciones aprovechan las secuencias para proporcionar identificadores únicos globales, mediante un mecanismo central de seguimiento para aumentar la secuencia a petición. Esta arquitectura crea un punto de contención global y un cuello de botella con los que cada componente del sistema tendría que interactuar. Este cuello de botella es especialmente problemático para las aplicaciones móviles potencialmente desconectadas.

En su lugar, las aplicaciones deben aprovechar las funciones que pueden generar identificadores únicos globales, por ejemplo, los GUID, en un sistema distribuido. Por diseño, los GUID no son secuenciales, por lo que pueden provocar fragmentación cuando se usan como CLUSTERED INDEX en una tabla grande. Para reducir el efecto de la fragmentación de los GUID en un modelo de datos grande, cree particiones en la base de datos y mantenga las particiones individuales relativamente pequeñas. Esto permite que la Base de datos SQL desfragmente las bases de datos automáticamente durante la conmutación por error de réplica.

El código de la aplicación cliente debe tener en cuenta varios aspectos de la entrega de un modelo de datos distribuido:

  • Claves de partición. Las claves de partición deben formar parte de cada clase o modelo de datos y, potencialmente, decorarse con un atributo para permitir la detección de las claves de partición.

  • Telemetría. La capa de acceso a datos debe registrar automáticamente la información sobre cada llamada de SQL, incluido el destino, la partición, el contexto, la latencia y los códigos de error o reintentos.

  • Consultas distribuidas. Ejecutar consultas entre particiones introduce varios desafíos nuevos, incluidos el enrutamiento, la selección de la partición y el concepto de éxito parcial (algunas particiones individuales devuelven los datos correctamente, mientras que otras no). La capa de acceso a datos debe proporcionar delegados para ejecutar las consultas distribuidas en un modo asincrónico (paralelo) de dispersión y recopilación que devuelve un resultado compuesto. Las consultas distribuidas también necesitan tener en cuenta la limitación de los recursos subyacentes:

    • El grado máximo de paralelismo (para evitar la presión excesiva de los subprocesos y de la conexión).

    • El tiempo máximo de consulta (para reducir los aciertos totales de latencia de una consulta de ejecución prolongada o de una partición lenta).

También hay varias tareas de administración continuada que se deben realizar:

  • Tablas de referencia. Sin un espacio de consulta globalmente coherente, los datos de referencia de las instrucciones JOIN de las consultas se deben copiar en cada partición individual. Es necesario mantener y replicar los datos en las tablas de referencia de las particiones individuales para proporcionar datos de referencia locales razonablemente coherentes.

  • Reequilibrio de particiones. Las particiones individuales pueden llegar estar desequilibradas, ya sea por consumir demasiados recursos y convertirse en un cuello de botella o por hacer un uso insuficiente de los recursos o desperdiciarlos. En estas situaciones, las particiones se deben reequilibrar para reasignar los recursos. El mecanismo de reequilibrio depende en gran medida de la estrategia y la implementación de particiones. En la mayoría de los escenarios el reequilibrio normalmente implica:

    • Copiar los datos existentes de una partición en una o más particiones nuevas, a través del mecanismo de dividir y combinar (para el particionamiento basado en intervalos) o una copia y reasignación de nivel de entidad (para el particionamiento basado en búsquedas).

    • Actualizar el mapa de particiones para que apunte a la nueva partición y, a continuación, compensar los datos escritos en las particiones antiguas durante la transición.

  • Poda de datos. A medida que una aplicación aumenta y recopila datos, considere la poda periódica de los datos antiguos no usados para aumentar el espacio disponible y la capacidad del sistema principal. Los datos podados (eliminados) no se purgan sincrónicamente en la Base de datos SQL; en su lugar, se marcan para su eliminación y se limpian mediante un proceso en segundo plano. Un método común para marcar los datos para la eliminación es una columna de marca que puede designar una fila como activa, inactiva o marcada para su eliminación. Esto permite enmascarar los datos de las consultas durante un período de tiempo, lo que permite mover los datos con facilidad a producción si los usuarios indican que todavía son necesarios.

    La eliminación de los datos también puede desencadenar la fragmentación, que potencialmente requeriría volver a generar el índice para que las operaciones de consulta sean eficaces. Los datos antiguos se pueden almacenar en:

    • Un almacén en línea (una Base de datos SQL secundaria); esto aumenta el espacio disponible en el sistema principal, pero no reduce el costo.

    • Un almacén sin conexión, por ejemplo, un archivo bcp o bacpac del almacenamiento de blob; esto aumenta el espacio disponible en el sistema principal y reduce el costo.

    • El depósito de bits. Puede elegir que se eliminen permanentemente los datos del sistema principal para aumentar el espacio disponible.

Varias acciones comunes de la Base de datos SQL pueden activar errores transitorios de conexión, por ejemplo, un conmutación por error de réplica. Las aplicaciones deben implementar el código adecuado para controlar los errores transitorios y responder correctamente el agotamiento y la limitación de recursos:

  • Control de error transitorio de conexión con reintento. El código de acceso a datos debe aprovechar un mecanismo de reintento controlado por directivas para compensar los errores transitorios de conexión. El mecanismo de reintento debe detectar los errores temporales de conexión, volver a conectar a la Base de datos SQL de destino y volver a emitir el comando.

  • Control de la limitación con reintento y lógica de interrupción. El código de acceso a datos debe aprovechar un mecanismo de reintento e interrupción controlado por directivas para tratar con las condiciones de limitación. El mecanismo de reintento debe detectar la limitación e interrumpir gradualmente los intentos de volver a emitir el comando (para evitar los efectos de convoy que podrían prolongar la condición de limitación).

    • El código de acceso a datos también debe implementar la capacidad de retroceder a un almacén de datos alternativo, por ejemplo, el almacenamiento de blob. Este almacén alternativo proporciona un mecanismo duradero para capturar las actividades, los datos y el estado, que evita la pérdida de datos en el caso de una limitación prolongada o un evento de disponibilidad.

Las aplicaciones .NET pueden usar los marcos de trabajo de la lógica de reintentos e interrupción preparados para la Base de datos SQL, por ejemplo, el marco de aplicación en la nube (CloudFx) o el controlador de errores transitorios de la biblioteca empresarial. Estos marcos de trabajo proporcionan los contenedores para las clases comunes de acceso a datos (como SqlConnection y SqlCommand), así como las directivas que pueden invocarse directamente.

var retryPolicy = RetryPolicy.Create<SqlAzureTransientErrorDetectionStrategy>(
    retryCount: 3, 
    initialInterval: TimeSpan.FromSeconds(5),
    increment: TimeSpan.FromSeconds(2));
                
using (var conn = new ReliableSqlConnection(connStr))
{
    conn.Open();
    using (var cmd = conn.CreateCommand())
    {

    }
    conn.Close();
}

El fragmento de código anterior muestra el uso de la clase CloudFx ReliableSqlConnection para controlar los errores de conexión transitorios al trabajar con la Base de datos SQL.

Preste un cuidado y atención especial al registro de las llamadas de API a los servicios, por ejemplo, a la Base de datos SQL, que tienen modos de error potencialmente complicados. Intente capturar los elementos clave de la información de contexto y de rendimiento. Por ejemplo, todas las sesiones de Base de datos SQL contienen un identificador de sesión, que se puede usar en las llamadas de soporte técnico como ayuda para aislar directamente el problema subyacente. Se recomienda encarecidamente que todas las llamadas, comandos y consultas de la Base de datos SQL registren lo siguiente:

  • Servidor y nombre de base de datos. Dado que posiblemente habrá cientos de bases de datos, el servidor de destino es crítico en el seguimiento y aislamiento de problemas.

  • Según corresponda, el procedimiento almacenado o el texto del comando de SQL. Tenga cuidado de que no se escape información confidencial en el archivo de registro; por lo general, evite registrar el texto de comandos.

  • Latencia integral de la llamada. Ajuste la llamada en un delegado de tiempo mediante el cronómetro u otro temporizador ligero.

  • Código de resultado de la llamada (correcto o error), así como el número de reintentos y la causa del error (conexión anulada, limitada, etc.).

  • Id. de sesión de la conexión, accesible a través de la propiedad CONTEXT_INFO() (o la propiedad SessionTracingId si se usa ReliableSqlConnection). Sin embargo, no recupere la propiedad de id. de sesión de CONTEXT_INFO() en cada llamada del cliente, porque este comando activa otro recorrido de ida y vuelta al servidor.

Para hacer un uso más eficaz de la Base de datos SQL, las consultas y las inserciones de datos en la Base de datos SQL deben procesarse por lotes y ejecutarse de forma asincrónica cuando sea posible. Esto no solo mejora la eficacia de aplicación, pero reduce la carga total del sistema en la Base de datos SQL (lo que permite más rendimiento).

  • Inserción por lotes. Para las operaciones de inserción de datos continua, por ejemplo, el registro de nuevos usuarios, los datos deben procesarse por lotes e insertarse en las particiones de destino. Estos lotes se deben escribir periódicamente (y de forma asincrónica) en la Base de datos SQL basándose en los desencadenadores, por ejemplo, en un tamaño de lote de destino o en una ventana de tiempo. Para los tamaños de lote inferiores a 100 filas, las funciones con valores de tabla suelen ser más eficaces que una operación de copia masiva.

  • Evite las interfaces locuaces. Reduzca el número de recorridos de ida y vuelta necesarios para que la base de datos realice una consulta o un conjunto de operaciones. Las interfaces locuaces tienen un alto grado de sobrecarga, lo que aumenta la carga del sistema y reduce el rendimiento y la eficacia. Intente combinar las operaciones relacionadas mediante un procedimiento almacenado para reducir los recorridos de ida y vuelta.

Como parte de un método global de continuidad empresarial, los datos almacenados en la Base de datos SQL deben exportarse periódicamente al almacenamiento de blob. El almacenamiento de blob admite la disponibilidad y la replicación geográfica de forma predeterminada.

Implemente una tarea programada que exporte periódicamente las bases de datos al almacenamiento de blob. Use una cuenta de almacenamiento dedicada. Esta tarea debe ejecutarse en el mismo centro de datos que las bases de datos de destino, no en un escritorio o servidor local.

Programe la tarea de exportación en horas de poca actividad para minimizar el impacto en la experiencia del usuario final. Cuando exporte varias bases de datos, limite el grado de exportación en paralelo para reducir el impacto del sistema.

Una visión general del estado, el rendimiento y el espacio disponible de las Bases de datos SQL es un componente esencial del suministro de servicios global. La Base de datos SQL proporciona la información sin formato necesaria a través de las vistas de administración dinámica, pero no hay actualmente una infraestructura preparada para capturar, analizar y notificar las métricas de clave. Para entregar esta capacidad para la Base de datos SQL, considere los procedimientos siguientes:

  • Implemente una tarea periódica para recopilar los datos de rendimiento clave relacionados con la carga del sistema, los recursos usados (subprocesos de trabajo, espacio de almacenamiento) y los datos de un repositorio común. Por ejemplo, considere las tablas usadas por los Diagnósticos de Azure. Esta tarea debe recopilar datos de todas las bases de datos que pertenecen a la aplicación. Esta colección, aparece normalmente en un modo de escala horizontal (que recopila los datos de varias bases de datos simultáneamente).

  • Implemente una tarea periódica para agregar esta información y generar los indicadores clave de rendimiento del estado y la capacidad de las bases de datos implementadas.

Los Diagnósticos de Azure proporcionan una línea base para recopilar la telemetría de la aplicación y de nivel de instancia. No obstante, proporcionar una visión general de las aplicaciones a gran escala que se ejecutan en Azure requiere una configuración y administración cuidadosas de los flujos de datos. A diferencia de las aplicaciones centralizadas de escala vertical que pueden aprovechar las utilidades enriquecidas de diagnóstico de Windows, los diagnósticos en un sistema distribuido de escala horizontal deben implementarse antes de poner en marcha el sistema, no pueden ser una idea de último momento.

El control de errores, el seguimiento contextual y la captura de la telemetría son fundamentales para proporcionar una descripción de los eventos de error, las causas originales y las soluciones.

  • No publique los datos y la telemetría del sitio en directo en la misma cuenta de almacenamiento. Use una cuenta de almacenamiento dedicada para los diagnósticos.

  • Cree canales independientes para la telemetría en bloques (gran volumen, alta latencia, datos pormenorizados) y para la locuaz (poco volumen, baja latencia, datos de gran valor).

    • Use los orígenes estándar de Diagnósticos de Azure, como contadores de rendimiento y seguimientos, para la información locuaz.

    • Use las bibliotecas comunes de registro, como la biblioteca del marco de la aplicación empresarial, log4net o NLog, para implementar el registro masivo en los archivos locales. Use un origen de datos personalizado en la configuración del monitor diagnóstico para copiar esta información periódicamente en el almacenamiento de blob.

  • Registre todas las llamadas API a los servicios externos con el contexto, destino, método, información de tiempo (latencia) y el resultado (correcto, error o reintentos). Use el canal de registro en bloques para evitar inundar el sistema de diagnóstico con la información de telemetría.

  • Los datos escritos en el almacenamiento de tabla (contadores de rendimiento, registros de eventos, eventos de seguimiento) se escriben en una partición temporal que es de 60 segundos. Un intento de escribir demasiados datos (muchos orígenes de punto, un intervalo de recopilación demasiado bajo) puede inundar esta partición. Asegúrese de que los picos de error no desencadenen un intento de gran volumen de inserciones en el almacenamiento de tabla, ya que esto puede activar un evento de limitación.

    • Elija los datos de mayor valor que se recopilarán de estos orígenes, como son los contadores de rendimiento clave, los eventos críticos y de error o los registros de seguimiento.

    • Elija un intervalo adecuado de recopilación (de 5 a 15 minutos) para reducir la cantidad de datos que se deben transferir y analizar.

  • Asegúrese de que la configuración de registro se puede modificar en tiempo de ejecución sin forzar los restablecimientos de instancia. Compruebe también que la configuración es suficientemente pormenorizada para habilitar el registro de los aspectos específicos del sistema, como la base de datos, la memoria caché u otros servicios.

Diagnósticos de Azure no proporciona recopilación de datos para los servicios dependientes, como la Base de datos SQL o una memoria caché distribuida. Para proporcionar una vista completa de la aplicación y de sus características de rendimiento, agregue la infraestructura para recopilar los datos de los servicios dependientes:

  • Recopile los datos de rendimiento clave y de utilización de los servicios dependientes y publíquelos en el repositorio de WAD como registros del contador de rendimiento.

    • Almacenamiento de Azure mediante el Análisis de almacenamiento de Azure.

    • Base de datos SQL a través de vistas de administración dinámica.

    • Caché distribuida mediante los contadores de rendimiento o las API de seguimiento de estado.

  • Analice los datos sin formato de la telemetría para crear agregaciones y resúmenes (como una tarea programada).

¿Te ha resultado útil?
(Caracteres restantes: 1500)
Gracias por sus comentarios
Mostrar:
© 2014 Microsoft