Patrones de apps escalables y resilientes

Last reviewed 2022-10-28 UTC

En este documento, se presentan algunos patrones y prácticas para crear apps resilientes y escalables, dos objetivos esenciales de muchos ejercicios de arquitectura moderna. Una app bien diseñada aumenta y disminuye la escala a medida que sube y baja la demanda, y es lo suficientemente resiliente como para hacer frente a las interrupciones del servicio. Compilar y hacer funcionar apps que cumplan estos requisitos requiere una planificación y un diseño cuidadosos.

Escalabilidad: Ajuste de la capacidad para cumplir con la demanda

La escalabilidad es la medida de la capacidad de un sistema para manejar cantidades variables de trabajo mediante la adición o eliminación de recursos del sistema. Por ejemplo, una app web escalable es una que funciona bien con un usuario o con muchos usuarios, y que controla con facilidad los picos y las caídas del tráfico.

La flexibilidad para ajustar los recursos que consume una app es un factor clave para el traspaso a la nube. Con un diseño adecuado, puedes reducir los costos si quitas los recursos infrautilizados sin comprometer el rendimiento ni la experiencia del usuario. De manera similar, puedes mantener una buena experiencia del usuario durante períodos de mucho tráfico si agregas más recursos. De esta manera, tu app solo puede consumir los recursos necesarios para satisfacer la demanda.

Google Cloud proporciona productos y funciones para ayudarte a crear apps escalables y eficientes:

  • Las máquinas virtuales de Compute Engine y los clústeres de Google Kubernetes Engine (GKE) se integran con escaladores automáticos que te permiten aumentar o reducir el consumo de recursos según las métricas que definas.
  • La plataforma sin servidores de Google Cloud proporciona procesamiento administrado, bases de datos y otros servicios que escalan con rapidez de cero a grandes volúmenes de solicitudes, y solo pagas por lo que usas.
  • Los productos de base de datos como BigQuery, Spanner y Bigtable pueden ofrecer un rendimiento coherente en tamaños de datos masivos.
  • Cloud Monitoring proporciona métricas de todas tus apps y la infraestructura, lo que te ayuda a tomar decisiones de escalamiento basadas en datos.

Resiliencia: Diseño para hacer frente a los errores

Una app resiliente es una que continúa funcionando a pesar de tener fallas en los componentes del sistema. La resiliencia requiere planificación en todos los niveles de la arquitectura. Influye en el diseño de la infraestructura y la red, y en el diseño de la app y el almacenamiento de datos. La resiliencia también se extiende a las personas y la cultura.

Compilar y hacer funcionar apps resilientes es difícil. Sobre todo, en el caso de apps distribuidas, que pueden contener varias capas de infraestructura, redes y servicios. Se producen errores e interrupciones, y mejorar la resiliencia de la app es un proceso continuo. Con una planificación cuidadosa, puedes mejorar la capacidad de la app para hacer frente a las fallas. Con los procesos y la cultura organizativa adecuados, también puedes aprender de los errores para aumentar aún más la resiliencia de la app.

Google Cloud proporciona herramientas y servicios para ayudarte a crear apps con alta disponibilidad y resiliencia:

  • Los servicios de Google Cloud están disponibles en regiones y zonas de todo el mundo, lo que te permite implementar tu app para cumplir mejor tus objetivos de disponibilidad.
  • Los grupos de instancias de Compute Engine y los clústeres de GKE se pueden distribuir y administrar en las zonas disponibles de una región.
  • Los discos persistentes regionales de Compute Engine se replican de forma síncrona en las zonas de una región.
  • Google Cloud proporciona una variedad de opciones de balanceo de cargas para administrar el tráfico de la app, incluido el balanceo de cargas global que puede dirigir el tráfico a la región en buen estado más cercana a tus usuarios.
  • La plataforma sin servidores de Google Cloud incluye productos de procesamiento y de base de datos administrados que ofrecen redundancia y balanceo de cargas integrados.
  • Google Cloud admite CI/CD mediante integraciones y herramientas nativas con tecnologías populares de código abierto para automatizar la compilación y la implementación de tus apps.
  • Cloud Monitoring proporciona métricas en las apps y la infraestructura, lo que te ayuda a tomar decisiones basadas en datos sobre el rendimiento y el estado de las apps.

Controladores y restricciones

Existen diferentes requisitos y motivaciones para mejorar la escalabilidad y resiliencia de tu app. También pueden aplicarse limitaciones a tu capacidad de cumplir tus objetivos de escalabilidad y resiliencia. La importancia relativa de estos requisitos y limitaciones varía según el tipo de app, el perfil de los usuarios y la escala y madurez de tu organización.

Controladores

Para priorizar tus requisitos, considera los controladores de las diferentes partes de tu organización.

Controladores de negocios

Entre los conductores comunes del negocio, se incluyen los siguientes:

  • Optimización de costos y consumo de recursos
  • Minimización del tiempo de inactividad de la app
  • Garantía de que se pueda satisfacer la demanda de los usuarios durante los períodos de uso elevado
  • Mejora de la calidad y disponibilidad del servicio
  • Garantía de que la experiencia del usuario y la confianza se mantengan durante cualquier interrupción
  • Aumento de la flexibilidad y agilidad para manejar las cambiantes demandas del mercado

Controladores de desarrollo

Los controladores comunes del desarrollo incluyen lo siguiente:

  • Minimización del tiempo dedicado a investigar fallas
  • Aumento del tiempo dedicado al desarrollo de nuevas funciones
  • Minimización del trabajo repetitivo a través de la automatización
  • Compilación de apps mediante los patrones y las prácticas más recientes modernos del sector

Controladores de operaciones

Los requisitos que debes considerar desde el punto de vista de las operaciones incluyen lo siguiente:

  • Reducción de la frecuencia de fallas que requieren intervención humana
  • Aumento de la capacidad de recuperación automática ante fallas
  • Minimización del trabajo repetitivo a través de la automatización
  • Minimización del impacto de la falla de cualquier componente en particular

Limitaciones

Las restricciones pueden limitar tu capacidad de aumentar la escalabilidad y resiliencia de tu app. Asegúrate de que tus decisiones de diseño no introduzcan ni contribuyan a estas restricciones:

  • Dependencias de hardware o software difíciles de escalar
  • Dependencias de hardware o software difíciles de operar en una configuración de alta disponibilidad
  • Dependencias entre apps
  • Restricciones de licencias
  • Falta de habilidades o experiencia de tus equipos de desarrollo y operaciones
  • Resistencia organizativa a la automatización

Patrones y prácticas

En el resto de este documento, se definen patrones y prácticas para ayudarte a compilar apps resilientes y escalables. Estos patrones están presentes en todos los aspectos del ciclo de vida de tu app, incluido el diseño de la infraestructura, la arquitectura de la app, las opciones de almacenamiento, los procesos de implementación y la cultura organizacional.

En los patrones, se observan tres temas:

  • Automatización. La compilación de apps escalables y resilientes requiere automatización. La automatización del aprovisionamiento, las pruebas y las implementaciones de la app de la infraestructura aumenta la coherencia y la velocidad, y minimiza los errores humanos.
  • Acoplamiento flexible. Tratar tu sistema como una colección de componentes independientes y de acoplamiento flexible permite la flexibilidad y resiliencia. La independencia abarca la forma en que distribuyes a nivel físico tus recursos, cómo diseñas la arquitectura de la app y el diseño del almacenamiento.
  • Diseño basado en datos. Recopilar métricas para comprender el comportamiento de la app es fundamental. Las decisiones sobre cuándo escalar la app o si un servicio en particular no está en buen estado deben basarse en los datos. Las métricas y los registros deben ser las funciones principales.

Automatiza el aprovisionamiento de tu infraestructura

Crea una infraestructura inmutable a través de la automatización para mejorar la coherencia de tus entornos y aumentar el éxito de tus implementaciones.

Trata tu infraestructura como código

La infraestructura como código (IaC) es una técnica que te impulsa a tratar el aprovisionamiento y la configuración de tu infraestructura de la misma manera en que manejas el código de la aplicación. Tu lógica de aprovisionamiento y configuración se almacena en el control de origen para que sea detectable y se le pueda aplicar control de versiones y auditorías. Debido a que está en un repositorio de código, puedes aprovechar las canalizaciones de integración continua y de implementación continua (CI/CD) para que cualquier cambio en tu configuración se pueda probar y, luego, implementar de forma automática.

Al quitar los pasos manuales del aprovisionamiento de la infraestructura, IaC minimiza los errores humanos y mejora la coherencia y reproducibilidad de las apps y entornos. De esta manera, la adopción de IaC aumenta la resiliencia de las apps.

Cloud Deployment Manager permite automatizar la creación y administración de recursos de Google Cloud con plantillas flexibles. Como alternativa, Config Connector te permite administrar tus recursos mediante técnicas y flujos de trabajo de Kubernetes. Google Cloud también tiene compatibilidad integrada con herramientas populares de IaC de terceros, como Terraform, Chef y Puppet.

Crea una infraestructura inmutable

La infraestructura inmutable es una filosofía que se basa en los beneficios de la infraestructura como código. Esta exige que los recursos nunca se modifiquen una vez implementados. Si necesitas actualizar una máquina virtual, un clúster de Kubernetes o una regla de firewall, puedes actualizar la configuración del recurso en el repositorio de origen. Después de probar y validar los cambios, vuelves a implementar por completo el recurso mediante la nueva configuración. En otras palabras, en lugar de modificar los recursos, los vuelves a crear.

Crear una infraestructura inmutable genera implementaciones y reversiones más predecibles. También mitiga los problemas comunes en las infraestructuras mutables, como el desvío de configuración y los servidores de copo de nieve. De esta manera, adoptar una infraestructura inmutable mejora aún más la coherencia y la confiabilidad de tus entornos.

Diseño para alta disponibilidad

La disponibilidad es una medida de la fracción de tiempo en que se puede usar un servicio. A menudo, se usa como un indicador clave del estado general del servicio. Las arquitecturas con alta disponibilidad tienen como objetivo maximizar la disponibilidad del servicio, por lo general, mediante la implementación redundante de componentes. En términos más simples, lograr una alta disponibilidad suele implicar la distribución de recursos de procesamiento, el balanceo de cargas y la replicación de datos.

Distribuye recursos a nivel físico

Los servicios de Google Cloud están disponibles en ubicaciones de todo el mundo. Estas ubicaciones se dividen en regiones y zonas. La forma en que implementas tu app en estas regiones y zonas afecta la disponibilidad, la latencia y otras propiedades de la app. Para obtener más información, consulta las recomendaciones para la selección de la región de Compute Engine.

La redundancia es la duplicación de componentes de un sistema para aumentar la disponibilidad general de ese sistema. En Google Cloud, la redundancia suele lograrse mediante la implementación de tu app o servicio en varias zonas, o incluso en varias regiones. Si un servicio existe en varias zonas o regiones, puede tolerar mejor las interrupciones del servicio en una zona o región en particular. Aunque Google Cloud hace todo lo posible para evitar estas interrupciones, algunos eventos son impredecibles y es mejor estar preparado.

Con los grupos de instancias administrados de Compute Engine, puedes distribuir instancias de máquina virtual en varias zonas de una región y puedes administrar las instancias como una unidad lógica. Google Cloud también ofrece discos persistentes regionales para replicar tus datos automáticamente en dos zonas de una región.

También puedes mejorar la disponibilidad y resiliencia de tus apps implementadas en GKE si creas clústeres regionales. Un clúster regional distribuye los componentes del plano de control de GKE, los nodos y los pods en varias zonas dentro de una región. Debido a que los componentes del plano de control están distribuidos, puedes seguir accediendo al plano de control del clúster incluso durante una interrupción que involucre una o más zonas (pero no todas).

Favorecer los servicios administrados

En lugar de instalar, admitir y operar de forma independiente todas las partes de tu pila de aplicaciones, puedes usar servicios administrados para consumir partes de ella como servicios. Por ejemplo, en lugar de instalar y administrar una base de datos MySQL en máquinas virtuales (VM), puedes usar una base de datos MySQL que proporciona Cloud SQL. Luego, obtienes un Acuerdo de Nivel de Servicio (ANS) de disponibilidad y puedes confiar en Google Cloud para administrar la replicación de datos, las copias de seguridad y la infraestructura subyacente. Si usas servicios administrados, puedes dedicar menos tiempo a administrar la infraestructura y más a mejorar la confiabilidad de tu app.

Muchos de los servicios de procesamiento, base de datos y almacenamiento administrados de Google Cloud ofrecen redundancia integrada, lo que puede ayudarte a cumplir tus objetivos de disponibilidad. Muchos de estos servicios ofrecen un modelo regional, lo que significa que la infraestructura que ejecuta tu app se encuentra en una región específica y Google la administra de forma redundante en todas las zonas dentro de esa región. Si una zona deja de estar disponible, tu app o tus datos se ponen en funcionamiento automáticamente desde otra zona de la región.

Ciertos servicios de base de datos y almacenamiento también ofrecen disponibilidad multirregional, lo que significa que la infraestructura que ejecuta tu app se encuentra en varias regiones. Los servicios multirregionales pueden hacer frente a la pérdida de toda una región, pero suelen tener un costo mayor para la latencia.

Balanceo de cargas en todos los niveles

El balanceo de cargas te permite distribuir el tráfico entre grupos de recursos. Cuando distribuyes tráfico, ayudas a garantizar que los recursos individuales no se sobrecarguen mientras que otros permanecen inactivos. La mayoría de los balanceadores de cargas también proporcionan funciones de verificación de estado para ayudar a garantizar que el tráfico no se enrute a recursos en mal estado o no disponibles.

Google Cloud ofrece varias opciones de balanceo de cargas. Si tu app se ejecuta en Compute Engine o GKE, puedes elegir el tipo de balanceador de cargas más apropiado según el tipo, la fuente y otros aspectos del tráfico. Para obtener más información, consulta la descripción general del balanceo de cargas y la descripción general de herramientas de redes de GKE.

Como alternativa, algunos servicios administrados por Google Cloud, como App Engine y Cloud Run, balancean las cargas automáticamente.

Es una práctica común balancear las cargas de solicitudes provenientes de fuentes externas, como los clientes web o móviles. Sin embargo, el uso de balanceadores de cargas entre diferentes servicios o niveles dentro de tu app también puede aumentar la resiliencia y la flexibilidad. Google Cloud proporciona balanceo de cargas interno de capa 4 y capa 7 para este propósito.

En el siguiente diagrama, se muestra un balanceador de cargas externo que distribuye el tráfico global en dos regiones, us-central1 y asia-east1. También muestra el balanceo de cargas interno que distribuye el tráfico del nivel web al nivel interno dentro de cada región.

Distribución del tráfico global entre regiones

Supervisa tu infraestructura y apps

Antes de decidir cómo mejorar la resiliencia y escalabilidad de tu app, debes comprender su comportamiento. Tener acceso a un conjunto completo de métricas relevantes y series temporales sobre el rendimiento y el estado de la app puede ayudarte a descubrir posibles problemas antes de que se produzca una interrupción. También pueden ayudarte a diagnosticar y resolver una interrupción si ocurre. El capítulo supervisión de sistemas distribuidos en el libro de SRE de Google, se proporciona una buena descripción general de algunos enfoques de supervisión.

Además de proporcionar estadísticas sobre el estado de la app, las métricas también se pueden usar para controlar el comportamiento del ajuste de escala automático de tus servicios.

Cloud Monitoring es la herramienta de supervisión integrada de Google Cloud. Cloud Monitoring transfiere eventos, métricas y metadatos, y proporciona estadísticas a través de paneles y alertas. La mayoría de los servicios de Google Cloud envían automáticamente métricas a Cloud Monitoring, y Google Cloud también admite muchas fuentes de terceros. Cloud Monitoring también se puede usar como backend para herramientas de supervisión de código abierto populares, que proporcionan un "panel único" para observar la app.

Supervisa en todos los niveles

La recopilación de métricas en varios niveles dentro de la arquitectura proporciona un panorama integral del estado y el comportamiento de la app.

Supervisión de la infraestructura

La supervisión a nivel de la infraestructura proporciona el estado de referencia y el rendimiento de la app. Con este enfoque, se captura información como la carga de la CPU, el uso de memoria y la cantidad de bytes escritos en el disco. Estas métricas pueden indicar si una máquina está sobrecargada o no funciona como se espera.

Además de las métricas recopiladas automáticamente, Cloud Monitoring proporciona un agente que se puede instalar para recopilar información más detallada de las VM de Compute Engine, incluidas las de apps de terceros que se ejecutan en esas máquinas.

Supervisión de apps

Te recomendamos que captures métricas a nivel de la app. Por ejemplo, es posible que necesites tomar cuánto tiempo se tarda en ejecutar una consulta en particular o una secuencia relacionada de llamadas de servicio. Tú mismo defines estas métricas a nivel de la app. Estas capturan información que las métricas integradas de Cloud Monitoring no pueden. Las métricas a nivel de la app pueden capturar condiciones agregadas que reflejan con mayor precisión los flujos de trabajo clave y pueden revelar problemas que las métricas de infraestructura de bajo nivel no pueden.

También recomendamos usar OpenTelemetry para capturar las métricas a nivel de la app. OpenTelemetry proporciona un estándar único abierto para datos de telemetría. Usa OpenTelemetry para recopilar y exportar datos desde tu infraestructura y aplicaciones centradas en la nube. Luego, puedes supervisar y analizar los datos de telemetría exportados.

Supervisión de servicios

En el caso de las apps distribuidas y basadas en microservicios, es importante supervisar las interacciones entre los diferentes servicios y componentes de las apps. Estas métricas pueden ayudarte a diagnosticar problemas como el aumento de la cantidad de errores o la latencia entre servicios.

Istio es una herramienta de código abierto que proporciona estadísticas y control operativo sobre tu red de microservicios. Istio genera una telemetría detallada para todas las comunicaciones de servicio y se puede configurar a fin de enviar las métricas a Cloud Monitoring.

Supervisión de extremo a extremo

La supervisión de extremo a extremo, también llamada supervisión de caja negra, prueba el comportamiento visible a nivel externo de la manera en que un usuario lo ve. Este tipo de supervisión verifica si un usuario puede completar acciones críticas dentro de los límites definidos. Mediante esta supervisión general, se pueden descubrir errores o latencia que la supervisión detallada no puede revelar, y revela la disponibilidad según lo percibe el usuario.

Expón el estado de tus apps

Un sistema con alta disponibilidad debe tener alguna forma de determinar qué partes del sistema funcionan de forma correcta. Si ciertos recursos parecen estar en mal estado, el sistema puede enviar solicitudes a otro lugar. Por lo general, las verificaciones de estado implican extraer datos de un extremo para determinar el estado de un servicio.

La verificación de estado es una responsabilidad clave de los balanceadores de cargas. Cuando creas un balanceador de cargas asociado con un grupo de instancias de máquina virtual, también defines una verificación de estado. La verificación de estado define cómo el balanceador de cargas se comunica con las máquinas virtuales para evaluar si las instancias específicas deben seguir recibiendo tráfico. Las verificaciones de estado del balanceador de cargas también se pueden usar para la reparación automática de grupos de instancias en las que se vuelven a crear máquinas en mal estado. Si ejecutas en GKE y balanceas la carga del tráfico externo a través de un recurso de entrada, GKE crea automáticamente las verificaciones de estado adecuadas para el balanceador de cargas.

Kubernetes tiene compatibilidad integrada con sondeos de funcionamiento y preparación. Estos sondeos ayudan al organizador de Kubernetes a decidir cómo administrar pods y solicitudes dentro de tu clúster. Si tu app está implementada en Kubernetes, es una buena idea exponer su estado a estos sondeos mediante extremos apropiados.

Establece métricas clave

La supervisión y la verificación de estado proporcionan métricas sobre el comportamiento y el estado de la app. El siguiente paso es analizar estas métricas para determinar cuáles son las más descriptivas o de mayor impacto. Las métricas clave varían según la plataforma en la que se implementa la app y el trabajo que realiza.

Es poco probable que encuentres solo una métrica que indique si debes escalar tu app o si un servicio en particular está en mal estado. A menudo, es una combinación de factores que en asociación indican un conjunto determinado de condiciones. Con Cloud Monitoring, puedes crear métricas personalizadas para ayudar a capturar estas condiciones. El libro SRE de Google recomienda cuatro indicadores de oro para supervisar un sistema orientado al usuario: latencia, tráfico, errores y saturación.

También debes considerar tu tolerancia a los valores atípicos. El uso de un valor promedio o medio para medir el estado o el rendimiento podría no ser la mejor opción, ya que estas medidas pueden ocultar grandes desequilibrios. Por lo tanto, es importante considerar la métrica distribución; el percentil 99 podría ser una medida más informativa que el promedio.

Define objetivos de nivel de servicio (SLO)

Puedes usar las métricas que recopila el sistema de supervisión para definir objetivos de nivel de servicio (SLO). Los SLO especifican un nivel objetivo para el rendimiento o la confiabilidad de tu servicio. Los SLO son un pilar clave de las prácticas de SRE y se describen de forma detallada en el capítulo sobre los objetivos de nivel de servicio del libro de SRE y también en el capítulo sobre la implementación de SLO del libro de actividades de SRE.

Puedes usar la supervisión de servicios para definir los SLO en función de las métricas de Cloud Monitoring. Puede crear políticas de alertas en los SLO para que se te informe si corres el riesgo de incumplir uno de ellos.

Almacena las métricas

Las métricas de tu sistema de supervisión son útiles a corto plazo para ayudar con las verificaciones de estado en tiempo real o para investigar problemas recientes. Cloud Monitoring retiene tus métricas durante varias semanas para satisfacer mejor esos casos prácticos.

Sin embargo, también es valioso almacenar tus métricas de supervisión para un análisis a más largo plazo. Tener acceso a un registro histórico puede ayudarte a adoptar un enfoque basado en datos para definir mejor la arquitectura de tu app. Puedes usar los datos recopilados durante una interrupción y después de ella para identificar cuellos de botella e interdependencias en tus apps. También puedes usar los datos para ayudar a crear y validar pruebas significativas.

Los datos históricos también pueden ayudar a validar que tu app sea compatible con los objetivos comerciales durante los períodos clave. Por ejemplo, los datos pueden ayudarte a analizar cómo escaló tu app durante los eventos promocionales con mucho tráfico durante los últimos meses o incluso años.

Para obtener detalles sobre cómo exportar y almacenar tus métricas, consulta la solución Exportación de métricas de Cloud Monitoring.

Determina el perfil de escalamiento

Querrás que tu app cumpla sus objetivos de rendimiento y experiencia del usuario sin sobreaprovisionar recursos.

En el siguiente diagrama, se muestra una representación simplificada del perfil de escalamiento de una app. Esta mantiene un nivel de referencia de recursos y usa el ajuste de escala automático para responder a los cambios en la demanda.

Perfil de escalamiento de apps

Balancea el costo y la experiencia del usuario

La decisión de escalar tu app se basa en esencia en equilibrar el costo con la experiencia del usuario. Decide cuál es tu nivel mínimo de rendimiento aceptable y, también, dónde establecer un límite. Estos límites varían entre las apps y, posiblemente, entre diferentes componentes o servicios dentro de una sola app.

Por ejemplo, una app web o para dispositivos móviles orientada al consumidor podría tener objetivos de latencia estrictos. Investigaciones demuestran que incluso las pequeñas demoras pueden afectar negativamente la forma en que los usuarios perciben tu app, lo que genera menos conversiones y menos registros. Por lo tanto, es importante asegurarse de que tu app tenga capacidad suficiente para responder con rapidez frente a las solicitudes de los usuarios. En este caso, los costos mayores de ejecutar más servidores web podrían estar justificados.

La relación entre costo y rendimiento puede ser diferente en el caso de una app interna que no es fundamental para la empresa, en la que los usuarios son más tolerantes a las pequeñas demoras. Por lo tanto, tu perfil de escalamiento puede ser menos agresivo. En este caso, mantener los costos bajos puede ser más importante que optimizar la experiencia del usuario.

Establece recursos de referencia

Otro componente clave de tu perfil de escalamiento es decidir sobre un conjunto mínimo de recursos.

Por lo general, las máquinas virtuales de Compute Engine o los clústeres de GKE tardan en escalar, ya que se deben crear y, luego, inicializar nuevos nodos. Por lo tanto, podría ser necesario mantener un conjunto mínimo de recursos, incluso si no hay tráfico. Una vez más, la extensión de los recursos de referencia está influenciada por el tipo de app y el perfil de tráfico.

Por el contrario, las tecnologías sin servidores, como App Engine, Cloud Functions y Cloud Run, están diseñadas con el fin de escalar a cero y para iniciarse y escalar con rapidez, incluso en el caso de un inicio en frío. Según el tipo de app y el perfil de tráfico, estas tecnologías pueden brindar eficiencia para algunas partes de la app.

Configurar ajuste de escala automático

El ajuste de escala automático te ayuda a escalar automáticamente los recursos de procesamiento que consume tu app. Por lo general, este se produce cuando se superan ciertas métricas o se cumplen ciertas condiciones. Por ejemplo, si las latencias de solicitud a tu nivel web comienzan a superar un valor determinado, es posible que desees agregar automáticamente más máquinas para aumentar la capacidad de entrega.

Muchos productos de procesamiento de Google Cloud tienen funciones de ajuste de escala automático. Los servicios administrados sin servidores, como Cloud Run, Cloud Functions y App Engine, están diseñados para escalar con rapidez. Estos servicios suelen ofrecer opciones de configuración para limitar o influir en el comportamiento del ajuste de escala automático, pero, en general, gran parte del comportamiento del escalador automático está oculto para el operador.

Compute Engine y GKE ofrecen más opciones para controlar el comportamiento de escalamiento. Con Compute Engine, puedes escalar en función de varias entradas, incluidas las métricas personalizadas de Cloud Monitoring y la capacidad de entrega del balanceador de cargas. Puedes establecer límites mínimos y máximos en el comportamiento de escalamiento y puedes definir una política de ajuste de escala automático con varias señales para manejar diferentes situaciones. Al igual que con GKE, puede configurar el escalador automático de clústeres para agregar o quitar nodos según la carga de trabajo o las métricas del pod o las métricas externas al clúster.

Te recomendamos configurar el comportamiento del ajuste de escala automático en función de las métricas clave de la app, en tu perfil de costos y en el nivel mínimo de recursos definido.

Minimiza el tiempo de inicio

Para que el escalamiento sea efectivo, debe suceder lo suficientemente rápido como para manejar la carga creciente. Este es especialmente el caso cuando se agrega capacidad de procesamiento o entrega.

Usa imágenes ya preparadas

Si tu app se ejecuta en VM de Compute Engine, es probable que debas instalar software y configurar las instancias para ejecutarla. Aunque puedes usar secuencias de comandos de inicio para configurar instancias nuevas, una forma más eficiente es crear una imagen personalizada. Una imagen personalizada es un disco de arranque que configuras con el software y la configuración específicos de tu app.

Para obtener más información sobre la administración de imágenes, consulta el artículo prácticas recomendadas de administración de imágenes.

Cuando hayas creado tu imagen, puedes definir una plantilla de instancias. Las plantillas de instancias combinan la imagen del disco de arranque, el tipo de máquina y otras propiedades de la instancia. Luego, puedes usar una plantilla de instancias para crear instancias de VM individuales o un grupo de instancias administrado. Las plantillas de instancias son una forma conveniente de guardar la configuración de una instancia de VM para que puedas usarla más adelante a fin de crear instancias de VM nuevas idénticas.

Aunque crear imágenes personalizadas y plantillas de instancias puede aumentar la velocidad de implementación, también puede aumentar los costos de mantenimiento porque es posible que las imágenes deban actualizarse con más frecuencia. Para obtener más información, consulta los documentos de balanceo de configuración de imágenes y velocidad de implementación.

Organiza tu app en contenedores

Una alternativa a compilar instancias de VM personalizadas es colocar tu app en contenedores. Un contenedor es un paquete de software liviano, independiente y ejecutable que incluye todo lo necesario para ejecutar una app: código, entorno de ejecución, herramientas del sistema, configuraciones y bibliotecas del sistema. Estas características hacen que las apps en contenedores sean más portátiles, más fáciles de implementar y de mantener a gran escala que las máquinas virtuales. Los contenedores también suelen iniciarse con rapidez, lo que los hace adecuados para apps escalables y resilientes.

Google Cloud ofrece varios servicios para ejecutar los contenedores de tu app. Cloud Run proporciona una plataforma de procesamiento administrada y sin servidores para alojar tus contenedores sin estado. El entorno flexible de App Engine aloja tus contenedores en una plataforma como servicio (PaaS) administrada. GKE proporciona un entorno de Kubernetes administrado para alojar y organizar tus apps en contenedores. También puedes ejecutar los contenedores de tu app en Compute Engine cuando necesites un control completo sobre tu entorno de contenedores.

Optimiza tu app para un inicio rápido

Además de garantizar que tu infraestructura y tu app se puedan implementar de la manera más eficiente posible, también es importante garantizar que tu app se conecte con rapidez.

Las optimizaciones que son adecuadas para tu app varían según las características y la plataforma de ejecución de la app. Es importante hacer lo siguiente:

  • Buscar y deshacerse de los cuellos de botella mediante el perfilado de las secciones críticas de la app que se invocan en el inicio.
  • Reducir el tiempo de inicio mediante la implementación de técnicas como la inicialización diferida, en especial, de recursos costosos.
  • Minimizar las dependencias de la app que podrían tener que cargarse en el momento del inicio.

Aprovecha las arquitecturas modulares

Puedes aumentar la flexibilidad de la app si eliges arquitecturas que permitan que los componentes se implementen, administren y escalen de forma independiente. Este patrón también puede mejorar la resiliencia mediante la eliminación de los puntos únicos de falla.

Divide tu app en servicios independientes

Si diseñas la app como un conjunto de servicios independientes y desvinculados, puedes aumentar su flexibilidad. Si adoptas un diseño flexible, tus servicios se lanzarán y se implementarán de forma independiente. Además de muchos otros beneficios, este enfoque permite que esos servicios usen diferentes tech stacks y las administren diferentes equipos. Este enfoque flexible es el tema clave de los patrones de arquitectura, como los microservicios y las SOA.

A medida que consideras cómo delimitar tus servicios, los requisitos de disponibilidad y escalabilidad son dimensiones clave. Por ejemplo, si un componente determinado tiene un requisito de disponibilidad o un perfil de escalamiento diferentes de tus otros componentes, podría ser un buen candidato para un servicio independiente.

Soluciona la falta de estado

Una app o servicio sin estado no conserva ningún estado ni dato local persistente. Un modelo sin estado garantiza que puedas manejar cada solicitud o interacción con el servicio independientemente de las solicitudes anteriores. Este modelo facilita la escalabilidad y la capacidad de recuperación, ya que significa que el servicio puede crecer, reducirse o reiniciarse sin perder los datos necesarios para manejar cualquier proceso o solicitud en tránsito. La falta de estado es especialmente importante cuando usas un escalador automático, ya que las instancias, los nodos o los pods que alojan el servicio se pueden crear y destruir de forma inesperada.

Es posible que no todos tus servicios no tengan estado. En ese caso, debes ser explícito con los servicios que requieren estado. Al garantizar una separación clara de los servicios sin estado y con estado, puedes garantizar una escalabilidad sencilla para los servicios sin estado y, al mismo tiempo, adoptar un enfoque más considerado para los servicios con estado.

Administra la comunicación entre servicios

Un desafío con las arquitecturas de microservicios distribuidos es administrar la comunicación entre servicios. A medida que tu red de servicios crezca, es probable que las interdependencias del servicio también lo hagan. No querrás que la falla de un servicio genere la falla de otros servicios, lo que se suele llamar falla en cascada.

Puedes ayudar a reducir el tráfico a un servicio sobrecargado o con errores si adoptas técnicas como el patrón de disyuntor, la retirada exponencial y la degradación elegante. Estos patrones aumentan la resiliencia de la app, ya que brindan a los servicios sobrecargados la oportunidad de recuperarse o controlan con facilidad los estados de error. Para obtener más información, consulta el capítulo Aborda fallas en cascada en el libro SRE de Google.

El uso de una malla de servicios puede ayudarte a administrar el tráfico en tus servicios distribuidos. Una malla de servicios es un software que vincula los servicios y ayuda a separar la lógica empresarial de las herramientas de redes. Por lo general, una malla de servicios proporciona características de resiliencia, como los reintentos de solicitudes, la conmutación por error y los disyuntores.

Usa tecnología de almacenamiento y de base de datos adecuada

Ciertas bases de datos y tipos de almacenamiento son difíciles de escalar y hacer resilientes. Asegúrate de que las opciones de base de datos no limiten la disponibilidad y escalabilidad de la app.

Evalúa las necesidades de tu base de datos

El patrón de diseño de la app como un conjunto de servicios independientes también se extiende a tus bases de datos y almacenamiento. Puede ser apropiado elegir diferentes tipos de almacenamiento para distintas partes de la app, lo que da como resultado un almacenamiento variado.

Las apps tradicionales suelen funcionar exclusivamente con bases de datos relacionales. Las bases de datos relacionales ofrecen funcionalidades útiles, como transacciones, coherencia sólida, integridad referencial y consultas sofisticadas en las tablas. Estas funciones hacen que las bases de datos relacionales sean una buena opción para muchas funciones comunes de la app. Sin embargo, las bases de datos relacionales también tienen algunas restricciones. Por lo general, son difíciles de escalar y requieren una administración cuidadosa en una configuración de alta disponibilidad. Una base de datos relacional podría no ser la mejor opción para todas tus necesidades de base de datos.

Las bases de datos no relacionales, a menudo denominadas bases de datos NoSQL, adoptan un enfoque diferente. Aunque los detalles varían entre los productos, las bases de datos NoSQL suelen sacrificar algunas características de las bases de datos relacionales en favor de una mayor disponibilidad y una escalabilidad más fácil. En términos del teorema de CAP, las bases de datos NoSQL a menudo eligen la disponibilidad por sobre la coherencia.

Si una base de datos NoSQL es apropiada, se suele reducir al grado de coherencia requerido. Si tu modelo de datos para un servicio en particular no requiere todas las funciones de un RDBMS y se puede diseñar para que tenga coherencia eventual, elegir una base de datos NoSQL podría ofrecer una mayor disponibilidad y escalabilidad.

Además de un rango de bases de datos relacionales y NoSQL, Google Cloud también ofrece Spanner, una base de datos de coherencia sólida, alta disponibilidad y distribuida de forma global compatible con SQL. Para obtener información sobre cómo elegir una base de datos adecuada en Google Cloud, consulta Bases de datos de Google Cloud.

Implementa el almacenamiento en caché

El propósito principal de una caché es aumentar el rendimiento de la recuperación de datos mediante la reducción de la necesidad de acceder a la capa de almacenamiento más lenta subyacente.

El almacenamiento en caché admite una escalabilidad mejorada mediante la reducción de la dependencia del almacenamiento basado en discos. Debido a que las solicitudes se pueden entregar desde la memoria, se reducen las latencias de solicitudes a la capa de almacenamiento, lo que suele permitir que el servicio maneje más solicitudes. Además, el almacenamiento en caché puede reducir la carga en los servicios que están en sentido descendente en tu app, especialmente en las bases de datos, lo que permite que otros componentes que interactúan con ese servicio descendente también escalen con mayor facilidad.

El almacenamiento en caché también puede aumentar la resiliencia, ya que admite técnicas como la degradación elegante. Si la capa de almacenamiento subyacente está sobrecargada o no está disponible, la caché puede seguir administrando las solicitudes. Y aunque los datos que se muestran desde la caché pueden estar incompletos o desactualizados, esto puede ser aceptable para ciertas situaciones.

Memorystore para Redis proporciona un servicio completamente administrado impulsado por el almacén de datos en la memoria de Redis. Memorystore para Redis proporciona acceso de baja latencia y alta capacidad de procesamiento para los datos con alto nivel de acceso. Se puede implementar en una configuración de alta disponibilidad que proporciona replicación entre zonas y conmutación por error automática.

Moderniza tus procesos de desarrollo y cultura

DevOps se puede considerar una amplia colección de procesos, cultura y herramientas que promueven la agilidad y reducen el tiempo de salida al mercado de apps y funciones mediante el desglose de silos entre los equipos de desarrollo, operaciones y relacionados. El objetivo de las técnicas de DevOps es mejorar la calidad y la confiabilidad del software.

Un análisis detallado de DevOps va más allá del alcance de este artículo, pero en las siguientes secciones, se analizan algunos aspectos clave relacionados con la mejora de la confiabilidad y la resiliencia de la app. Para obtener más detalles, consulta la página de DevOps de Google Cloud.

Diseño para la capacidad de prueba

Las pruebas automatizadas son un componente clave de las prácticas modernas de entrega de software. La capacidad de ejecutar un conjunto completo de pruebas de unidades, integraciones y sistemas es esencial para verificar que tu app se comporte como se espera y que pueda avanzar a la siguiente etapa del ciclo de implementación. La capacidad de prueba es un criterio de diseño clave para las apps.

Te recomendamos usar pruebas de unidades para la mayoría de las pruebas, ya que son rápidas de ejecutar y, por lo general, fáciles de mantener. También te recomendamos automatizar la integración de nivel superior y las pruebas del sistema. Estas pruebas se simplifican enormemente si adoptas técnicas de infraestructura como código, ya que los entornos de prueba y los recursos dedicados se pueden crear a pedido y, luego, se borran una vez que se completan las pruebas.

A medida que aumenta el porcentaje de la base de código que cubren las pruebas, se reduce la inseguridad y la posible disminución de la confiabilidad de cada cambio de código. Una cobertura de prueba adecuada implica que puedes hacer más cambios antes de que la confiabilidad esté por debajo de un nivel aceptable.

Las pruebas automatizadas son un componente integral de la integración continua. Ejecutar un conjunto sólido de pruebas automatizadas en cada confirmación de código proporciona comentarios rápidos sobre los cambios, lo que mejora la calidad y la confiabilidad de tu software. Las herramientas nativas de Google Cloud, como Cloud Build, y herramientas de terceros como Jenkins, pueden ayudarte a implementar la integración continua.

Automatiza tus implementaciones

La integración continua y la automatización de pruebas integral brindan confianza en la estabilidad de tu software. Una vez en su lugar, el siguiente paso es automatizar la implementación de la app. El nivel de automatización de la implementación varía según la madurez de tu organización.

Elegir una estrategia de implementación adecuada es esencial para minimizar los riesgos asociados con la implementación de software nuevo. Con la estrategia adecuada, puedes aumentar gradualmente la exposición de las versiones nuevas a un público más amplio y verificar el comportamiento durante el proceso. También puedes establecer disposiciones claras para la reversión si ocurren problemas.

Adopta las prácticas de SRE para lidiar con las fallas

Para las apps distribuidas que operan a gran escala, es común algún grado de falla en uno o más componentes. Si adoptas los patrones que se mencionan en este documento, tu app puede manejar mejor las interrupciones causadas por una versión de software defectuosa, la terminación inesperada de máquinas virtuales o incluso una interrupción de infraestructura que afecta a toda una zona.

Sin embargo, incluso con un diseño cuidadoso de la app, es inevitable que experimentes eventos inesperados que requieran intervención humana. Si pone en marcha procesos estructurados para administrar estos eventos, podrás reducir en gran medida su impacto y resolverlos con mayor rapidez. Además, si examinas las causas y las respuestas al evento, puedes ayudar a proteger tu app contra eventos similares en el futuro.

Los procesos sólidos para administrar incidentes y realizar análisis retrospectivos son principios clave de SRE. Aunque implementar las prácticas completas de SRE de Google podría no ser práctico para tu organización, si adoptas un conjunto mínimo de lineamientos, puedes mejorar la resiliencia de tu app. Los apéndices del libro de SRE contienen algunas plantillas que pueden ayudarte a dar forma a tus procesos.

Valida y revisa tu arquitectura

A medida que tu app evoluciona, el comportamiento de los usuarios, los perfiles de tráfico y hasta las prioridades de la empresa pueden cambiar. Del mismo modo, otros servicios o infraestructura de los que depende tu app pueden evolucionar. Por lo tanto, es importante probar y validar periódicamente la resiliencia y la escalabilidad de tu app.

Pon tu resiliencia a prueba

Es fundamental probar que tu app responda a las fallas de la manera esperada. El tema principal es que la mejor manera de evitar errores es introducir errores y aprender de ellos.

La simulación y la introducción de fallas son complejas. Además de verificar el comportamiento de tu app o servicio, también debes asegurarte de que se generen las alertas esperadas y que se generen las métricas adecuadas. Recomendamos un enfoque estructurado, en el que se introducen fallas simples y, luego, se vuelven más complejas.

Por ejemplo, puedes proceder de la siguiente manera, validando y documentando el comportamiento en cada etapa:

  • Presenta errores intermitentes.
  • Bloquea el acceso a las dependencias del servicio.
  • Bloquea todas las comunicaciones de red.
  • Finaliza los hosts.

Para obtener más información, mira el video Breaking your systems to make them unbreakable (Ataca tus sistemas para que sean inquebrantables) de Google Cloud Next 2019.

Si usas una malla de servicios como Istio para administrar los servicios de la app, puedes inyectar fallas en la capa de la aplicación, en lugar de cerrar pods o máquinas, o puedes inyectar paquetes dañinos en la capa TCP. Puedes generar demoras para simular la latencia de red o un sistema ascendente sobrecargado. También puedes introducir abortos, que imitan fallas en sistemas ascendentes.

Prueba tu comportamiento de escalamiento

Te recomendamos que uses pruebas no funcionales automatizadas para verificar que tu app escale como se espera. A menudo, esta verificación se combina con el rendimiento o las pruebas de carga. Puedes usar herramientas simples como hey para enviar la carga a una app web. Para ver un ejemplo más detallado en el que se muestra cómo realizar pruebas de carga en un extremo de REST, consulta Prueba de cargas distribuidas mediante Google Kubernetes Engine.

Un enfoque común es asegurarse de que las métricas clave se mantengan dentro de los niveles esperados para cargas variables. Por ejemplo, si estás probando la escalabilidad de tu nivel web, puedes medir las latencias de solicitudes promedio para los volúmenes pico de solicitudes de usuarios. De manera similar, para una función de procesamiento de backend, puedes medir el tiempo promedio de procesamiento de tareas cuando el volumen de tareas aumenta repentinamente.

Además, necesitas que tus pruebas midan que la cantidad de recursos que se crearon para manejar la carga de prueba está dentro del rango esperado. Por ejemplo, tus pruebas pueden verificar que la cantidad de VM que se crearon para manejar algunas tareas de backend no exceda un valor determinado.

También es importante probar los casos extremos. ¿Cuál es el comportamiento de tu app o servicio cuando se alcanzan los límites máximos de escalamiento? ¿Cuál es el comportamiento si tu servicio reduce su escala y, luego, la carga vuelve a aumentar repentinamente?

Trabaja siempre con la arquitectura

El mundo de la tecnología se mueve rápido, sobre todo en la nube. Se lanzan nuevos productos y funciones con frecuencia, surgen nuevos patrones y las demandas de tus usuarios y partes interesadas internas siguen creciendo.

Como se define en la entrada de blog Principios para la arquitectura nativa de la nube, siempre debes buscar formas de definir mejor, simplificar y mejorar la arquitectura de tus apps. Los sistemas de software son seres vivos y deben adaptarse a tus prioridades cambiantes.

¿Qué sigue?