Backends y UX consistentes: ¿por qué debería importarle?
Serie de artículos
- ¿Por qué debería importarte?
- ¿Qué puede ser malo?
- ¿Cuáles son las barreras para la adopción?
- ¿Cómo ayudan los nuevos algoritmos?
- La búsqueda de la distribución
- El enfoque de distribución de las bases de datos tradicionales
- La primera generación de bases de datos distribuidas.
- Interpretaciones erróneas del teorema CAP
- ¿Cómo se relaciona esto con la experiencia del usuario?
- Impuesto de Consistencia
- La segunda generación de bases de datos distribuidas.
- El teorema PACELC revisado
- ¿Estas bases de datos siguen siendo NoSQL?
- Conclusión
Más que nunca, los nuevos productos pretenden tener un impacto a escala global, y la experiencia del usuario se está convirtiendo rápidamente en el factor determinante para su éxito o no. Estas propiedades de su aplicación pueden influir significativamente en la experiencia del usuario:
- Rendimiento y baja latencia
- La aplicación hace lo que esperas.
- Seguridad
- Funciones e interfaz de usuario
¡Comencemos nuestra búsqueda hacia la experiencia de usuario perfecta!
1) Rendimiento y baja latencia
Otros lo han dicho antes; el rendimiento es la experiencia del usuario ( 1 , 2 ). Cuando hayas llamado la atención de visitantes potenciales, un ligero aumento de la latencia puede hacerte perder esa atención nuevamente.
2) La aplicación hace lo que esperas.
¿Qué significa “cumple lo que esperas”? Significa que si cambio mi nombre en mi solicitud a 'Robert' y vuelvo a cargar la solicitud, mi nombre será Robert y no Brecht. Parece importante que una aplicación ofrezca estas garantías, ¿verdad?
Que la aplicación pueda cumplir con estas garantías depende de la base de datos. Cuando buscamos baja latencia y rendimiento, terminamos en el ámbito de las bases de datos distribuidas, donde solo unas pocas de las bases de datos más recientes ofrecen estas garantías. En el ámbito de las bases de datos distribuidas, puede haber dragones, a menos que elijamos una base de datos fuertemente (en lugar de eventualmente) consistente. En esta serie, entraremos en detalles sobre lo que esto significa, qué bases de datos proporcionan esta característica llamada consistente fuerte y cómo puede ayudar a crear aplicaciones increíblemente rápidas con un mínimo esfuerzo.
3) seguridad
Al principio, la seguridad no siempre parece afectar la experiencia del usuario. Sin embargo, tan pronto como los usuarios notan fallas de seguridad, las relaciones pueden dañarse irreparablemente.
4) Funciones e interfaz de usuario
Funciones impresionantes y una excelente interfaz de usuario tienen un gran impacto en la mente consciente e inconsciente. A menudo, las personas sólo desean un producto específico después de haber experimentado cómo se ve y se siente.
Si una base de datos ahorra tiempo en la instalación y configuración, entonces el resto de nuestros esfuerzos pueden centrarse en ofrecer funciones impresionantes y una excelente interfaz de usuario. Hay buenas noticias para ti; Hoy en día, existen bases de datos que cumplen con todo lo anterior, no requieren configuración ni aprovisionamiento de servidor y proporcionan API fáciles de usar, como GraphQL, listas para usar.
¿Qué tiene de diferente esta nueva generación de bases de datos? Demos un paso atrás y mostraremos cómo la búsqueda constante de una latencia más baja y una mejor experiencia de usuario, en combinación con los avances en la investigación de bases de datos, finalmente condujo a una nueva generación de bases de datos que son los componentes básicos. ideales para las aplicaciones modernas.
La búsqueda de la distribución
I. Redes de distribución de contenidos
Como mencionamos antes, el rendimiento tiene un impacto significativo en la UX. Hay varias formas de mejorar la latencia, siendo la más obvia optimizar el código de su aplicación. Una vez que el código de su aplicación es bastante óptimo, la latencia de la red y el rendimiento de escritura/lectura de la base de datos a menudo siguen siendo el cuello de botella. Para lograr nuestro requisito de baja latencia, debemos asegurarnos de que nuestros datos estén lo más cerca posible del cliente distribuyéndolos globalmente. Podemos cumplir el segundo requisito (rendimiento de escritura/lectura) haciendo que varias máquinas trabajen juntas o, en otras palabras, replicando datos.
La distribución conduce a un mejor rendimiento y, en consecuencia, a una buena experiencia de usuario. Ya hemos visto un uso extensivo de una solución de distribución que acelera la entrega de datos estáticos; se llama red de entrega de contenido (CDN). Las CDN son muy valoradas por la comunidad Jamstack para reducir la latencia de sus aplicaciones. Por lo general, utilizan marcos y herramientas como Next.js/Now, Gatsby y Netlify para preensamblar el código front-end React / Angular / Vue en sitios web estáticos para que puedan servirlos desde una CDN.
Desafortunadamente, las CDN no son suficientes para todos los casos de uso, porque no podemos confiar en páginas HTML generadas estáticamente para todas las aplicaciones. Hay muchos tipos de aplicaciones altamente dinámicas en las que no se puede generar todo estáticamente. Por ejemplo:
- Aplicaciones que requieren actualizaciones en tiempo real para la comunicación instantánea entre usuarios (por ejemplo, aplicaciones de chat, dibujo o escritura colaborativa, juegos).
- Aplicaciones que presentan datos en muchas formas diferentes filtrando, agregando, clasificando y manipulando datos de tantas maneras que no se puede generar todo por adelantado.
II. Bases de datos distribuidas
En general, una aplicación altamente dinámica requerirá una base de datos distribuida para mejorar el rendimiento. Al igual que una CDN, una base de datos distribuida también pretende convertirse en una red global en lugar de un nodo único. En esencia, queremos pasar de un escenario con un único nodo de base de datos…
…a un escenario donde la base de datos se convierte en una red. Cuando un usuario se conecta desde un continente específico, automáticamente será redirigido a la base de datos más cercana. Esto da como resultado latencias más bajas y usuarios finales más felices.
Si las bases de datos eran empleados esperando junto a un teléfono, el empleado de la base de datos le informaría que hay un empleado más cerca y reenviaría la llamada. Afortunadamente, las bases de datos distribuidas nos dirigen automáticamente al empleado de la base de datos más cercana, por lo que nunca tendremos que molestar al empleado de la base de datos en el otro continente.
Las bases de datos distribuidas son multirregionales y siempre te redirigen al nodo más cercano.
Además de la latencia, las bases de datos distribuidas también ofrecen una segunda y una tercera ventaja. El segundo es la redundancia, lo que significa que si una de las ubicaciones de la base de datos en la red fuera completamente destruida por un ataque de Godzilla, sus datos no se perderían ya que otros nodos todavía tienen duplicados de sus datos.
Por último, pero no menos importante, la tercera ventaja de utilizar una base de datos distribuida es la escalabilidad. Una base de datos que se ejecuta en un servidor puede convertirse rápidamente en el cuello de botella de su aplicación. Por el contrario, las bases de datos distribuidas replican datos en múltiples servidores y pueden escalar hacia arriba y hacia abajo automáticamente según las demandas de las aplicaciones. En algunas bases de datos distribuidas avanzadas, este aspecto está completamente solucionado por usted. Estas bases de datos se conocen como "sin servidor", lo que significa que ni siquiera tiene que configurar cuándo la base de datos debe ampliarse o reducirse, y solo paga por el uso de su aplicación, nada más.
La distribución de datos dinámicos nos lleva al ámbito de las bases de datos distribuidas. Como se mencionó anteriormente, puede haber dragones. A diferencia de las CDN, los datos son muy dinámicos; los datos pueden cambiar rápidamente y pueden filtrarse y ordenarse, lo que conlleva complejidades adicionales. El mundo de las bases de datos examinó diferentes enfoques para lograrlo. Los primeros enfoques tuvieron que hacer sacrificios para lograr el rendimiento y la escalabilidad deseados. Veamos cómo evolucionó la búsqueda de la distribución.
El enfoque de distribución de las bases de datos tradicionales
Una opción lógica fue basarse en bases de datos tradicionales (MySQL, PostgreSQL, SQL Server), ya que ya se ha invertido mucho esfuerzo en ellas. Sin embargo, las bases de datos tradicionales no fueron creadas para ser distribuidas y, por lo tanto, adoptaron un enfoque de distribución bastante simple. El enfoque típico para escalar lecturas era utilizar réplicas de lectura. Una réplica de lectura es solo una copia de sus datos desde la cual puede leer pero no escribir. Dicha copia (o réplica) descarga consultas del nodo que contiene los datos originales. Este mecanismo es muy simple porque los datos se copian incrementalmente en las réplicas a medida que llegan.
Debido a este enfoque relativamente simple, los datos de una réplica siempre son más antiguos que los datos originales. Si lee los datos de un nodo de réplica en un momento específico, es posible que obtenga un valor más antiguo que si leyera desde el nodo principal. Esto se llama "lectura obsoleta". Los programadores que utilizan bases de datos tradicionales deben ser conscientes de esta posibilidad y programar teniendo en cuenta esta limitación. ¿Recuerda el ejemplo que dimos al principio donde escribimos un valor y lo volvemos a leer? Cuando se trabaja con réplicas de bases de datos tradicionales, no se puede esperar leer lo que se escribe.
Podría mejorar ligeramente la experiencia del usuario aplicando de manera optimista los resultados de las escrituras en el front-end antes de que todas las réplicas tengan conocimiento de las escrituras. Sin embargo, una recarga de la página web podría devolver la interfaz de usuario a un estado anterior si la actualización aún no llegó a la réplica. El usuario entonces pensaría que sus cambios nunca se guardaron.
La primera generación de bases de datos distribuidas.
En el enfoque de replicación de las bases de datos tradicionales, el cuello de botella obvio es que todas las escrituras van al mismo nodo. La máquina se puede ampliar, pero inevitablemente chocará contra el techo. A medida que su aplicación gane popularidad y aumenten las escrituras, la base de datos ya no será lo suficientemente rápida para aceptar nuevos datos. Para escalar horizontalmente tanto para lecturas como para escrituras, se inventaron las bases de datos distribuidas. Una base de datos distribuida también contiene varias copias de los datos, pero puede escribir en cada una de estas copias. Dado que los datos se actualizan a través de cada nodo, todos los nodos deben comunicarse entre sí e informar a otros sobre los nuevos datos. En otras palabras, ya no se trata de una dirección unidireccional como en el sistema tradicional.
Sin embargo, este tipo de bases de datos aún pueden sufrir las lecturas obsoletas antes mencionadas e introducir muchos otros problemas potenciales relacionados con las escrituras. Que sufran estos problemas depende de la decisión que tomaron en términos de disponibilidad y coherencia.
Esta primera generación de bases de datos distribuidas fue a menudo denominada “movimiento NoSQL”, nombre influenciado por bases de datos como MongoDB y Neo4j, que también proporcionaron lenguajes alternativos a SQL y diferentes estrategias de modelado (documentos o gráficos en lugar de tablas). Las bases de datos NoSQL a menudo no tenían las características típicas de las bases de datos tradicionales, como restricciones y uniones. Con el paso del tiempo, este nombre parecía ser un nombre terrible ya que muchas bases de datos que se consideraban NoSQL proporcionaban una forma de SQL. Surgieron múltiples interpretaciones que afirmaban que las bases de datos NoSQL:
- no proporcione SQL como lenguaje de consulta.
- no solo proporcione SQL (NoSQL = No solo SQL)
- no proporciona características tradicionales típicas como uniones, restricciones y garantías ACID.
- modelar sus datos de manera diferente (gráfico, documento o modelo temporal)
Algunas de las bases de datos más nuevas que no eran relacionales pero que ofrecían SQL se denominaron "NewSQL" para evitar confusiones.
Interpretaciones erróneas del teorema CAP
La primera generación de bases de datos se inspiró fuertemente en el teorema CAP, que dicta que no se puede tener consistencia y disponibilidad al mismo tiempo durante una partición de red. Una partición de red ocurre esencialmente cuando sucede algo que hace que dos nodos ya no puedan comunicarse entre sí sobre nuevos datos, y puede surgir por muchas razones (por ejemplo, aparentemente los tiburones a veces muerden los cables de Google). La coherencia significa que los datos de su base de datos siempre son correctos, pero no necesariamente están disponibles para su aplicación. Disponibilidad significa que su base de datos está siempre en línea y que su aplicación siempre puede acceder a esos datos, pero no garantiza que los datos sean correctos o iguales en varios nodos. Generalmente hablamos de alta disponibilidad ya que no existe el 100% de disponibilidad. La disponibilidad se menciona en dígitos de 9 (por ejemplo, 99,9999 % de disponibilidad), ya que siempre existe la posibilidad de que una serie de eventos provoquen un tiempo de inactividad.
Pero ¿qué pasa si no hay una partición de red? Los proveedores de bases de datos tomaron el teorema CAP de manera demasiado general y optaron por aceptar una posible pérdida de datos o estar disponibles, haya o no una partición de red. Si bien el teorema CAP fue un buen comienzo, no enfatizó que es posible tener alta disponibilidad y consistencia cuando no hay una partición de red. La mayoría de las veces, no hay particiones de red, por lo que tenía sentido describir este caso expandiendo el teorema CAP al teorema PACELC. La diferencia clave son las tres últimas letras (ELC) que significan Else Latency Consistency. Este teorema dicta que si no hay una partición de red, la base de datos debe equilibrar la latencia y la coherencia.
En términos simples: cuando no hay partición de red, la latencia aumenta cuando aumentan las garantías de coherencia. Sin embargo, veremos que la realidad es aún más sutil que esto.
¿Cómo se relaciona esto con la experiencia del usuario?
Veamos un ejemplo de cómo renunciar a la coherencia puede afectar la experiencia del usuario. Considere una aplicación que le brinde una interfaz amigable para formar equipos de personas; arrastras y sueltas personas en diferentes equipos.
Una vez que arrastras a una persona a un equipo, se activa una actualización para actualizar ese equipo. Si la base de datos no garantiza que su aplicación pueda leer el resultado de esta actualización inmediatamente, entonces la interfaz de usuario debe aplicar esos cambios de manera optimista. En ese caso, pueden pasar cosas malas:
- El usuario actualiza la página y ya no ve su actualización y cree que ya no está. Cuando vuelve a refrescarse, de repente vuelve.
- La base de datos no almacenó la actualización correctamente debido a un conflicto con otra actualización. En este caso, la actualización podría cancelarse y el usuario nunca lo sabrá. Es posible que sólo note que sus cambios han desaparecido la próxima vez que recargue.
Esta compensación entre coherencia y latencia ha provocado muchas discusiones acaloradas entre desarrolladores de front-end y back-end. El primer grupo quería una excelente experiencia de usuario en la que los usuarios recibieran comentarios cuando realizan acciones y pudieran estar 100% seguros de que una vez que reciban estos comentarios y respondan, los resultados de sus acciones se guardarán constantemente. El segundo grupo quería construir un backend escalable y de alto rendimiento y no vio otra manera que sacrificar los requisitos de UX antes mencionados para lograrlo.
Ambos grupos tenían puntos válidos, pero no había una fórmula mágica para satisfacer a ambos. Cuando las transacciones aumentaron y la base de datos se convirtió en el cuello de botella, su única opción era optar por la replicación de la base de datos tradicional o por una base de datos distribuida que sacrificara una fuerte coherencia por algo llamado "coherencia eventual". Con el tiempo, se aplicará una actualización de la base de datos en todas las máquinas, pero no hay garantía de que la siguiente transacción pueda leer el valor actualizado. En otras palabras, si actualizo mi nombre a "Robert", no hay garantía de que realmente reciba "Robert" si consulto mi nombre inmediatamente después de la actualización.
Impuesto de Consistencia
Para lograr una eventual coherencia, los desarrolladores deben ser conscientes de las limitaciones de dicha base de datos y hacer mucho trabajo adicional. Los programadores a menudo recurren a trucos de la experiencia del usuario para ocultar las limitaciones de la base de datos, y los backends tienen que escribir muchas capas adicionales de código para adaptarse a diversos escenarios de falla. Encontrar y crear soluciones creativas en torno a estas limitaciones ha impactado profundamente la forma en que los desarrolladores front-end y back-end han hecho su trabajo, aumentando significativamente la complejidad técnica sin ofrecer una experiencia de usuario ideal.
Podemos considerar este trabajo adicional necesario para garantizar la exactitud de los datos como un “impuesto” que un desarrollador de aplicaciones debe pagar para ofrecer buenas experiencias de usuario. Ése es el coste de utilizar un sistema de software que no ofrece garantías de coherencia que se mantengan en los entornos concurrentes a escala web actuales. A esto lo llamamos Impuesto de Consistencia.
Afortunadamente, ha evolucionado una nueva generación de bases de datos que no requieren pagar el Impuesto de Consistencia y pueden escalar sin sacrificar la consistencia.
La segunda generación de bases de datos distribuidas.
Ha surgido una segunda generación de bases de datos distribuidas para proporcionar una coherencia sólida (en lugar de eventual). Estas bases de datos se escalan bien, no perderán datos y no devolverán datos obsoletos. En otras palabras, hacen lo que usted espera y ya no es necesario conocer las limitaciones ni pagar el Impuesto de Consistencia. Si actualiza un valor, la próxima vez que lea ese valor, siempre reflejará el valor actualizado y se aplicarán diferentes actualizaciones en el mismo orden temporal en que se escribieron. FaunaDB, Spanner y FoundationDB son las únicas bases de datos en el momento de escribir este artículo que ofrecen una gran coherencia sin limitaciones (también denominada serialización estricta).
El teorema PACELC revisado
La segunda generación de bases de datos distribuidas ha logrado algo que antes se consideraba imposible; favorecen la coherencia y aún ofrecen latencias bajas. Esto fue posible gracias a mecanismos de sincronización inteligentes como Calvin, Spanner y Percolator, que analizaremos en detalle en el artículo 4 de esta serie. Si bien las bases de datos más antiguas todavía luchan por ofrecer garantías de alta coherencia con latencias más bajas, las bases de datos creadas sobre estos nuevos algoritmos inteligentes no sufren tales limitaciones.
Los diseños de bases de datos influyen enormemente en la latencia alcanzable con alta coherencia.
Dado que estos nuevos algoritmos permiten que las bases de datos proporcionen una gran coherencia y bajas latencias, normalmente no hay una buena razón para renunciar a la coherencia (al menos en ausencia de una partición de red). La única vez que haría esto es si lo único que realmente importa es una latencia de escritura extremadamente baja y está dispuesto a perder datos para lograrlo.
¿Estas bases de datos siguen siendo NoSQL?
Ya no es trivial categorizar esta nueva generación de bases de datos distribuidas. Todavía se hacen muchos esfuerzos (1, 2) para explicar lo que significa NoSQL, pero ninguno de ellos todavía tiene perfecto sentido ya que las bases de datos NoSQL y SQL se están acercando entre sí. Las nuevas bases de datos distribuidas toman prestado de diferentes modelos de datos (Documento, Gráfico, Relacional, Temporal), y algunas de ellas brindan garantías ACID o incluso admiten SQL. Todavía tienen una cosa en común con NoSQL: están diseñados para resolver las limitaciones de las bases de datos tradicionales. Una palabra nunca podrá describir cómo se comporta una base de datos. En el futuro, tendría más sentido describir las bases de datos distribuidas respondiendo estas preguntas:
- ¿Es fuertemente consistente?
- ¿La distribución depende de réplicas de lectura o está realmente distribuida?
- ¿De qué modelos de datos toma prestado?
- ¿Qué tan expresivo es el lenguaje de consulta y cuáles son sus limitaciones?
Conclusión
Explicamos cómo las aplicaciones ahora pueden beneficiarse de una nueva generación de bases de datos distribuidas globalmente que pueden servir datos dinámicos desde la ubicación más cercana en forma similar a una CDN. Repasamos brevemente la historia de las bases de datos distribuidas y vimos que no fue un viaje fácil. Se desarrollaron muchas bases de datos de primera generación, y sus opciones de coherencia, que fueron impulsadas principalmente por el teorema CAP, nos obligaron a escribir más código y al mismo tiempo disminuir la experiencia del usuario. Sólo recientemente la comunidad de bases de datos ha desarrollado algoritmos que permiten que las bases de datos distribuidas combinen una baja latencia con una gran coherencia. ¡Se acerca una nueva era, una época en la que ya no tendremos que hacer concesiones entre el acceso a los datos y la coherencia!
Llegados a este punto, probablemente desee ver ejemplos concretos de los posibles peligros de bases de datos eventualmente consistentes. En el próximo artículo de esta serie, cubriremos exactamente eso. Estén atentos a estos próximos artículos:
Serie de artículos
- ¿Por qué debería importarte?
- ¿Qué puede ir mal?
- ¿Cuáles son las barreras para la adopción?
- ¿Cómo ayudan los nuevos algoritmos?
Deja un comentario