Programar en sistemas distribuidos es diferente a programar para solo un sistema. Algoritmos eficientes de forma secuencial pueden no serlo tanto cuando desarrollamos de forma distribuida, pero ¿qué hay de todo el código escrito tomando ciertos axiomas como completamente ciertos cuando no lo son?
Una falacia es un engaño, un fraude o una mentira. No tiene porqué ser intencionado. Muchas de las falacias derivadas de la programación distribuida se basan en el desconocimiento o la ignorancia de ciertas partes del sistema o información errónea recibida y no corroborada en la que aún seguimos confiando.
La idea de mostrar estas falacias surge de la antigua Sun Microsystems, concretamente de Bill Joy y Tom Lyon quienes escribieron las primeras cuatro falacias. Peter Deustch completaría estas falacias agregando otras tres más y finalmente James Gosling completaría la lista.
Iré enumerando cada una de las falacias y no hace falta que me creas. Te animo a buscar información sobre cada una de ellas y hacer un comentario para debatir un poco más sobre cada una de ellas. ¡Comencemos!
1. La Red es Confiable
Es una falacia bastante extendida y por eso la primera de la lista. La mayoría de desarrollos en backend se realizan dando por hecho la confiabilidad de la red. Siempre funcionará. Es muy raro o difícil que caiga. ¡No es así!
La red tiene problemas y podemos encontrar desde latencia, paquetes perdidos, hasta directamente momentos en los que no responde. Ya sea por una pérdida momentánea o por una caída completa de un nodo de conexión.
En el desarrollo distribuido debemos jugar con todos estos elementos. Incluso en una red local podemos encontrar problemas a varios niveles. Disponer de una buena monitorización a nivel de sistemas es importante, pero también tener nuestro código preparado para cuando un trozo de información no ha podido ser entregado de forma correcta. No hablo de programación defensiva sino más bien de obtener rupturas del flujo de ejecución en un punto concreto y la posibilidad de retomarlo a través de reintentos.
2. La Latencia es Cero
Uno de los grandes problemas a la hora de realizar sincronización de información no es tanto el ancho de banda como la latencia. Incluso teniendo un ancho de banda enorme, si nuestra latencia es mayor, podemos encontrar muchos problemas. En el teorema CAP hablamos de consistencia eventual. Esta es posible solo si la latencia no es muy alta. En caso de tener una latencia demasiado alta subsanar la consistencia es una tarea difícil y costosa.
Otro de los problemas de la latencia puede venir determinado por los tiempos de espera. Podemos dar una transacción como errónea por sobrepasar un tiempo de espera considerando un error en el otro extremo cuando el problema real fue una latencia. La operación ha sido realizada pero uno de los extremos considera que no fue así.
En estos casos hay que tener mucho cuidado con las respuestas tardías. Tener mecanismos para desecharlas y teniendo en cuenta los reintentos del sistema, hacer nuestras peticiones idempotentes: ante una repetición de cambio de información ya realizada, responder con la misma información dejando el sistema en el mismo estado que si hubiese llegado de nuevas.
3. El Ancho de Banda es Infinito
No, el ancho de banda no es infinito. Es finito. Tiene un límite y es un error muy común en sistemas de telecomunicaciones. Cuando una empresa migra sus redes de telefonía convencionales rígidas de un número de canales fijo a una conexión de datos en una conexión a Internet usando SIP de repente consideran el ancho de banda infinito.
Es importante medir el caudal de nuestra conexión. ¿Cuánto ancho hay de subida? ¿Cuánto de bajada? No con la información proporcionada por el proveedor sino a través de pruebas realizadas por nosotros mismos. En base al uso, si trabajamos con un servidor web donde la media de peticiones pesa 50 kB, si recibimos picos de 1.000 peticiones simultáneas sabemos que nuestro uso máximo rondará los 50 MB en el peor de los casos. Teniendo una conexión que nos permita 100MB de subida no tendremos ningún problema. Pero si comenzamos a duplicar nuestras visitas y llegamos a picos de 10.000 peticiones simultáneas, entonces sí comenzaremos a experimentar problemas en el servicio y los tan famosos cuellos de botella.
También habrá que leer la letra pequeña de nuestro proveedor de infraestructura. Normalmente todos tienen un límite en la transferencia de información desde los servidores contratados. El mayor problema surge cuando además del límite inmediato se agrega un límite mensual.
Cuando programamos de forma distribuida no solo hay que contar el tráfico que consume el servicio sino también el tráfico consumido en las conexiones de sincronización o paso de tareas entre nuestros servicios. Más aún si hemos desarrollado un sistema basado en microservicios y se comunican entre ellos para obtener información. De nuevo, hay proveedores que nos permitirán un ancho de banda específico para acceder a otros servidores dentro de la misma red pero también otros proveedores tomarán esta comunicación como parte del cupo.
Si nuestro ancho de banda se ve afectado puede significar un incremento de latencia en el mejor de los casos o pérdida de paquetes en el peor de los casos. Nuestros sistemas deben estar preparados para este supuesto.
4. La Red es Segura
¿Estás seguro de ello? Cuando abrimos un servicio de hacia Internet, incluso manteniendo una zona desmilitarizada (DMZ) con una muy buena configuración para evitar acceder a esos servidores desde fuera puede darse el caso de un atacante aprovechando una vulnerabilidad 0day y accediendo al sistema al completo. También incluyo esos servidores (como los proporcionados por OVH que aún dan usuario y clave) con acceso sin certificado y sin sistemas de bloqueo para evitar ataques de fuerza bruta.
Desde una vista de programación podemos encontrar una ruptura en el protocolo. Por ejemplo, nuestra web está programada para obtener una cierta información en pasos, cada paso contempla un formulario y hemos realizado la validación en JavaScript. Todo debe estar bien. Recibimos los datos de forma correcta porque así los envía la web. ¿Pero qué pasa si el atacante realiza una petición directa y resulta que provoca un error fatal en nuestro sistema? o peor aún, ¿qué sucede si consigue hacer una inyección de SQL y puede obtener parte o toda nuestra base de datos?
Es importante no considerar seguro ningún punto. Incluso en los enlaces de sincronización de datos se establecen contraseñas y se encripta la comunicación normalmente cuando hay que pasar por Internet. Un error con el cortafuegos podría dejar al descubierto puertos de comunicación que hablen más que Tom Holland haciendo spoiler de las películas en las que participa.
También señalar que un alto porcentaje de los ataques se produce desde dentro ya sea por malicia, negligencia o por accidente.
5. La Topología No Cambia
Podemos dar por hecho que nuestros sistemas se van a comunicar siempre empleando IPv4, tendrán la misma IP, se conectarán al mismo puerto e incluso reservar algunos números dentro del rango privado para crecer. Pero nunca debemos agregar esta información de forma fija en nuestro código. Esta información debe ser siempre de configuración.
Ya sea por un proveedor o por aprovechar mejor las ventajas de IPv6, la conectividad y topología de tu red puede cambiar. De hecho, con el uso de virtualización y contenedores a día de hoy ya cambió con respecto a los últimos 5 años.
Si eres programador puede que te suene la frase: ¡no hardcodees eso! Lo mismo pasa con la red. Toma siempre la topología de la red como un dato configurable y no como un dato fijo.
Este caso es bastante rígido en sistemas de configuración de algunas bases de datos o sistemas de concurrencia. Por ejemplo, en sistemas de hace una década en Erlang puedes encontrar la necesidad de cambiar la configuración e incluso a veces el código para permitir conectar un nuevo nodo y escalar el sistema. Cassandra también requería reconfigurar los parámetros de interconexión solo para poder agregar un nuevo nodo.
No digo que deba ser fácil agregar, eliminar o cambiar la red de un sistema desarrollado. Pero sí hacerlo posible y si es sin necesidad de reiniciar todo el clúster, mejor.
Además, otro de los problemas de los cambios de topología que incide directamente sobre el sistema es cuando la topología se comporta de forma diferente con respecto a la latencia o ancho de banda. Los valores para los tiempos de espera y la cantidad de información a intercambiar entre los servidores debe ser configurable. Por ejemplo el número de conexiones a una base de datos y el tiempo de espera por una respuesta de la base de datos.
6. Hay un Único Administrador
En pequeñas empresas esto no suele ser un problema, pero en medianas y grandes donde los sistemas están gestionados en diferentes departamentos (bases de datos, web o red entre otros), esto es un gran problema porque no solo implica a empleados sino también subcontratas.
En mi experiencia personal me he encontrado dos veces en esta situación. Un sistema funcionando de repente comienza a dar problemas. Los administradores de sistemas de puesta en producción dan fe de no haber modificado la configuración del sistema en ejecución. Los administradores de red dan fe de no haber modificado nada en la red. Los administradores de virtualización dicen no haber modificado o cambiado nada y los sistemas no se han reajustado. Pero algo se modificó. Termina convirtiéndose en una novela de Agatha Christie para encontrar el problema (que no al culpable, prima mucho más poder volver a tener el servicio activo y funcionando).
A este respecto no hay que dar por hecho que cada elemento dentro de la infraestructura se mantendrá, como en el punto anterior. Pero incluso si no cambia, debemos anticipar otros cambios más sutiles o problemas potenciales a tener en cuenta. Con la virtualización problemas como la gestión de ciclos de reloj dentro de la aplicación no están asegurados, por ejemplo.
Igualmente, es conveniente conocer muy muy bien todas las tecnologías que se emplearán en producción en algún ambiente controlado antes de pasar a producción para poder anticipar esos potenciales problemas. Realizar pruebas de carga y de duración de ejecución. Son costosas pero merecen mucho la pena.
7. El Coste de Transporte es Cero
Este punto puede estar relacionado con el tercer punto sobre el ancho de banda. No obstante, creo que en este caso se refiere más al factor de transporte de la información. La serialización necesaria para transportar la información y el tamaño, y cómo esto se traduce en coste computacional y tiempo.
Por ejemplo, si elegimos serializar toda nuestra información para sincronizar en XML con validación de esquemas es válido. Tenemos incluso una capa de comprobación de esta información, sabemos que siempre será correcta. Pero el coste tanto en ancho de banda como en tiempo para transferir esta información puede ser muy elevado.
Los mejores serializadores no son únicamente los que consiguen información compacta, sino los que consiguen realizar esta actividad en el menor tiempo posible y consumiendo el menor número de recursos para ello.
8. La Red es Homogénea
Toda la red se basa en la misma tecnología, tiene la misma configuración y las mismas características. ¡Falso! Incluso en la red del hogar esto es completamente falso. En mi caso tengo una red local con cable para un par de computadores, una red inalámbrica donde está el router y otra red de extensión para zonas donde no llega la red inalámbrica principal.
En este caso los ordenadores conectados por cable dependen de si tiene tarjetas Ethernet de 100MB o 1GB y de si el router permite esas velocidades. La red inalámbrica principal tiene una velocidad máxima de 54GB y la de extensión algo menos. Tan solo en ancho de banda ya difieren bastante. Pero además, en latencia y cantidad de paquetes perdidos también.
Hay protocolos pensados para conectarse tan solo a redes locales. Estos protocolos funcionarían bien para los equipos que estén dentro de la misma red pero pueden no funcionar si el extensor en lugar de hacer una extensión hace un proxy configurando su propia red. Igualmente la red de cable puede tener otra configuración de red diferente.
Debemos preparar nuestro software para acceder a sistemas incluso empleando diferentes protocolos dependiendo de la situación en cada momento. CIFS puede estar bien dentro de la misma red para compartir ficheros pero puede que entre redes necesitemos FTP.
Conclusiones
Estas son las 8 falacias. Obviamente he tenido que desarrollar según mi parecer algunas de ellas. No hay mucha información, los creadores solo proporcionaron las frases y dejaron las explicaciones y buenas prácticas para cada cual.
¿Qué te parecen? ¿Coherentes, las tienes en cuenta? ¿Cambiarías o agregarías algo a alguna de ellas? ¿Quizás una novena e incluso décima falacia? ¡Déjanos un comentario!