3 patrones de diseño imprescindibles que deberías conocer para tu sistema en cloud: Retry, Valet Key y Sharding

El desarrollo en Cloud implica una serie de diferencias que debo tomar en consideración cuando voy a desarrollar aplicaciones para ser publicadas en este ambiente.

Aunque voy a conseguir acceso a capacidades de desarrollo horizontal y vertical en mi infraestructura y servicios, con niveles de disponibilidad y seguridad difícilmente obtenibles en mis instalaciones locales; asimismo es verdad que un despliegue a la Nube significa más que correr mi código en este nuevo ambiente.

Y más si estoy efectuando un desarrollo desde cero, o bien efectuando padeciendo en mis carnes una migración/transformación. En donde debo tener presente, como poco, estos tres básicos patrones de diseño.

Retry Pattern

Tengo mis servicios en Cloud, y me comunico con ellos o bien mediante una aplicación local (sea de escritorio o bien nativa de mi dispositivo móvil), o bien a través de un usuario Web que está publicado en un Web Aplicación.

Todo marcha de forma correcta hasta el momento en que me encuentro con lo que lleva por nombre una “Transient Fault”, o bien fallo temporal del servicio, y mi aplicación no debe romperse ni quedarse congelada.

Lo primero es saber que puedo tener 3 géneros de acontencimientos que hagan inalcanzable al servicio:

Que el propio servicio Cloud se haya caído o bien roto. Teóricamente esto no debería ser posible que ocurriese, mas todas y cada una de las grandes plataformas han sufrido incidencias graves en donde han ofrecido un desempeño limitadísimo o bien, de manera directa, han quedado inalcanzables.
Que el inconveniente esté en las comunicaciones. Así sea por el hecho de que tenga interrupciones, caídas, una latencia demasiado alta o bien un ancho de banda demasiado pequeño. Pudiendo, además de esto, estar ubicado el cuello de botella en cualquiera de los nodos por donde pasa la comunicación, este bajo mi control o bien no.
Que el inconveniente esté en mi servicio. Pues esté bajo una demanda que exceda las capacidades del mismo, por el hecho de que esté bajo un ataque, o bien por fallos que degraden el desempeño hasta un nivel que genere fallos.

Sea como sea el fallo temporal, en mi aplicación debería incorporar un patrón de “Reintento”, a fin de que esta incidencia sea soportada por el sistema. Y de este modo, en dependencia de la relevancia de la interrupción, actúe de una forma o bien otra.

Mi aplicación lanza una solicitud contra un servicio recóndito en Cloud, y se halla con que el servicio no responde, por lo que hago que espere un tiempo y que lo vuelva a procurar otra vez en un lapso temporal determinado.

Un buena política de reintentos hace nuestra aplicación considerablemente más resiliente

Para eludir que los propios reintentos puedan sobresaturar el sistema cuando esté de nuevo marchando, configuro que el tiempo entre reintento y reintento sea poco a poco más largo, hasta el momento en que supere un límite en donde (por último) me devuelve un mensaje de fallo o bien salvedad que alerte de un fallo que no es temporal.

Otra forma, si tengo muchos clientes del servicio accediendo de forma simultánea, es que el tiempo entre reintentos sea azaroso (en unos límites), huyendo asimismo de poder tumbar el sistema al volverse a levantar.

O sea, hay que tener precaución en la configuración de los tiempos de reintento definidos en la implantación del patrón, en tanto que son muy dependientes de las demandas del negocio; y probablemente sea preciso un trabajo de optimización y ajuste regular, basado en métricas.

Por otro lado, si bien no sea una parte del patrón, mas si resultado, debo elegir entre múltiples posibilidades de notificación al usuario del fallo:

Ofrecerle un substituto. Por poner un ejemplo, si busca en el catálogo de series le muestro el catálogo de películas. Esto implica una lógica de redirección basada en las preferencias de los usuarios y puede ser un tema tan complejo como efectivo y de dar las gracias. La primordial ventaja, es que el usuario prosigue usando la plataforma mientras que se recobra el servicio.
No decir nada. El usuario se queda aguardando a que el servicio se recupere, manteniéndose en la última pantalla de interacción. Transmitiendo la sensación de que no ha ocurrido nada.
Informar cuanto antes. Es la estrategia conveniente si el número de usuarios es muy elevado, en tanto que evita una saturación por reintentos. En un caso así se muestra una notificación que indique que no se puede cumplir la solicitud y se ofrece links para salir de la solicitud al servicio caído.

No obstante, hay consideraciones a tener en consideración al decidir incorporar este patrón.

Una política demasiado violenta de reintentos puede llevar al servicio a sus límites operativos. Además de esto, es crítico que las solicitudes puedan ser admitidas y procesadas de forma unitaria, sin tener dependencias que requieren un instante o bien orden concreto de llegada.

Este patrón ha de ser eludido caso de que la realidad o bien las pruebas señalen que el género de fallo con el que me puedo localizar es por norma general permanente, o bien las operaciones del servicio al que lanzo la solicitud consumen un buen tiempo.

Valet Key

Cuando hablamos de una aplicación “normal” web o bien de escritorio, indudablemente debo aplicar la programación asíncrona como estándar de los procesos pesados que limitan la experiencia de usuario.

Mas debo ir un paso más allí y adoptar uno de los patrones más conocidos y empleados tanto en plataformas Cloud, como en todas y cada una aquellas en donde se efectúa la autentificación y validación de un usuario para, por servirnos de un ejemplo, pueda acceder a una librería de fotografías y descargarlas en su máquina local.

Si estuviese efectuando un desarrollo acoplado, incluso siendo asíncrono, llamaría primero al servicio para identificarme como usuario; dicho servicio verificaría que tengo autorización y permisos convenientes y también invocaría al servicio de almacenaje para devolver las fotografías pedidas.

No obstante hay una forma un tanto más indirecta, mas considerablemente más potente para desajustar las dos operaciones y que cada servicio sea responsable únicamente de su campo.

Como se observa en la figura, el usuario primero hace una llamada de identificación y autentificación al worker de la aplicación dedicado a ello. Este, el servicio de validación de usuarios, aplica la lógica que sea precisa para revisar que el usuario puede acceder a los recursos que está solicitando, y edifica un token que le resulta devuelto al usuario.

Ahora, el usuario manda la solicitud de los recursos al servicio de almacenaje así como el token recibido; en el que se incluye el periodo de valía del mismo – para complicar que pueda ser empleado de forma maliciosa- y los privilegios que se le han concedido.

Hay otros veintiuno patrones que deberíamos conocer para nuestras arquitecturas en Cloud

Fíjate que con este patrón reparto la necesidad de procesamiento entre 2 servicios, logrando una optimización de los recursos que tendrá un impacto conveniente en el costo de operación y desajustando entre sí los servicios, con todas y cada una los beneficios de mantenimiento, despliegue y escalado que acarrea.

Otra ventaja es el poder guardar una traza detallada de cada petición de requisitos recibida en todos y cada uno de ellos de los módulos separadamente.

Mas, por el lado negativo, tengo el incremento de la dificultad del código y que el worker de autorización no tiene perseverancia ni seguimiento de las operaciones efectuadas en el servicio de almacenaje con los token que ha entregado.

Y por este motivo no se puede aplicar el Valet Key si debemos efectuar alguna operación o bien validación antes que los datos sean guardados o bien mandados al usuario.

Sharding Pattern

Las bases de datos, en su concepción tradicional, tienen una capacidad limitada de escalado. Esto es, si deseo que mi instancia tenga más capacidad de cálculo primero le incremento la memoria y optimizo el sistema de almacenaje (escalado vertical), y después comienzo a contestar la arquitectura física (escalado horizontal).

Eso sí, a un costo de infraestructura, puesta en producción y mantenimiento en especial altos.

Asimismo me enfrento con las posibles restricciones de ancho de banda – todavía más si estoy en un sistema Cloud con comunicaciones no dedicadas – y con retos frente a las latencias que puedo padecer si tengo a mis clientes del servicio ubicados en localizaciones geográficas distantes entre sí.

Para solucionar estos inconvenientes, el patrón Sharding define la manera de optimar la explotación de la base de datos a través de la división horizontal del conjunto de datos en nodos distinguidos.

En un caso muy simplificado, podría separar los datos de la tabla de usuarios de manera que los primeros cinco millones estuviesen en el shard 1, los próximos cinco en el shard dos y de esta manera ahora.

Cada shard va a tener su instancia, consiguiendo mejores posibilidades en las operaciones siendo el número de registros menor que si tuviese una gigantesca BD con cientos y cientos de millones de registros.

Siendo, además de esto, más simple escalar – de forma vertical-, y considerablemente más si estamos usando una base de datos en Software as a Service, en tanto que todas y cada una incluyen este patrón por defecto de forma interna.

Cada uno de ellos de estos patrones es una capsula de conocimiento para solucionar los desafíos del Cloud

El mayor inconveniente, indudablemente, es la dificultad añadida al codificar el patrón desde de cero, obviando que los ORM más modernos y los servicios de bases de datos en Cloud ya incluyen este modo de dividir y explotar los datos. A lo que hay que sumar la resolución de cuando ha llegado el instante de aplicarlo. Puesto que está orientado a la optimización de grandes volúmenes de datos, y conseguir una substancial mejora en las IOPS del repositorio de datos.

Finalmente, Sharding es un patrón que se conjunta y complementa con otras técnicas de división del conjunto de datos, así sea de forma vertical, por dominio, por funcionalidad, etcétera

Y mucho más

Estos 3 patrones concretos para desarrollo en Cloud, han de ser conocidos y reconocidos por los desarrolladores. Mas no por este motivo son los únicos.

En verdad, Microsoft, en su libro Cloud Design Patterns, describe veinticuatro patrones (incluyendo los descritos en el artículo) que todo arquitecto técnico de Cloud debe incluir en su toolbox de soluciones.

Event Sourcing, CQRS, Circuit Breaker, GateKeeper, Piper