¿Cómo escalar MongoDB? ¿Cuáles son las mejores prácticas de fragmentación?

Si bien el esquema flexible es la forma en que la mayoría de las personas se familiarizan MongoDB, también es una de las mejores bases de datos (tal vez incluso La mejor cuando se trata de aplicaciones cotidianas) para manejar conjuntos de datos muy, muy grandes. Si bien la justificación de este argumento requiere un artículo completo en sí mismo (¡espero poder encontrar tiempo para escribirlo algún día!), la idea general es que las soluciones basadas en SQL no son compatibles con la fragmentación, y construirlo a partir de ti apesta.

Lo mejor que puede esperar es crear un clúster (que, por cierto, no tiene nada que ver con la fragmentación fundamentalmente) o buscar una solución administrada como RDS de Amazon o Cloud SQL de Google, que se vuelven prohibitivamente costosas a medida que crecen sus datos.

En este artículo, veremos una de las técnicas esenciales para escala de base de datos horizontal: fragmentación, para MongoDB, y recomendar algunas mejores prácticas para el mismo. Sin embargo, creo que es mejor comenzar con los conceptos básicos de fragmentación, porque muchas personas que buscan escalar MongoDB pueden no estar muy familiarizadas con él.

Sin embargo, si está al tanto de la fragmentación, no dude en hojear la siguiente sección.

Sharding Basics

Es posible que haya notado el uso de la palabra "horizontal" en el último párrafo de la sección anterior. Sin lanzarme a otro desvío masivo, quiero sacar este punto rápidamente. Se considera que el escalado es de dos tipos: o obtiene una máquina más potente con mayor capacidad de almacenamiento (vertical), o conecta varias computadoras más pequeñas y forma una colección (horizontal).

Ahora, dado que incluso los mejores servidores en la actualidad no tienen más de 256 GB de RAM o 16 TB de disco duro, pronto te encuentras con una pared de ladrillos al intentar escalar verticalmente (o "escalar", como dice la terminología). Sin embargo, puede conectar tantas máquinas individuales juntas (al menos en teoría) y evitar esta limitación fácilmente.

Por supuesto, el desafío ahora es coordinar entre todas estas máquinas.

Fragmentación de base de datos

El término "fragmentación" generalmente se aplica a las bases de datos, la idea es que una sola máquina nunca puede ser suficiente para almacenar todos los datos. Al fragmentar, la base de datos se "divide" en fragmentos separados que residen en diferentes máquinas. Un ejemplo simple podría ser: suponga que una empresa tiene máquinas que pueden almacenar hasta 2 millones de elementos de datos de clientes. Ahora, el negocio está llegando a ese punto de quiebre y probablemente superará los 2.5 millones de usuarios pronto. Entonces, deciden dividir su base de datos en dos:

¡Y mágicamente, la capacidad del sistema ahora se duplica!

Bueno, ¡si la vida fuera así de simple! 🙂

Desafíos en la fragmentación de bases de datos

Tan pronto como estabas pensando un poco más en la fragmentación, algunos desafíos nefastos asoman su fea cabeza.

Sin claves primarias

Tan pronto como sale de una sola base de datos, las claves principales pierden su significado. Como ejemplo, si sus claves principales están configuradas para incrementarse automáticamente y mueve la mitad de los datos a otra base de datos, ahora tendrá dos elementos de datos diferentes para cada clave principal.

Sin claves externas

Dado que no hay soporte en las bases de datos para apuntar a entidades fuera de la base de datos actual (bueno, incluso una base de datos diferente en la misma máquina no es compatible, así que olvídate de una base de datos en un una experiencia diferente machine), el concepto de claves foráneas también es válido. De repente, la base de datos se vuelve "tonta" y la integridad de los datos es su problema.

Errores de datos extraños

Si una sola máquina se apaga, al usuario final se le puede mostrar un "¡Vaya, algo se rompió!" página, que sin duda molestará, pero la vida estará encarrilada después de un tiempo.

Ahora considere lo que sucede en una base de datos fragmentada. Suponga que la base de datos fragmentada en nuestro ejemplo anterior es una base de datos bancaria y un cliente está enviando dinero a otro. Supongamos también que los datos del primer cliente viven en el primer fragmento, mientras que los datos del segundo cliente viven en el segundo fragmento (¿ven a dónde voy con esto?). Si la máquina que contiene el segundo fragmento falla, ¿te imaginas en qué estado estará el sistema? ¿Adónde irá el dinero de la transacción? ¿Qué verá el primer usuario? ¿Qué verá el segundo usuario? ¿Qué verán ambos cuando los fragmentos vuelvan a estar en línea?

Gestión de transacciones

Consideremos también el caso siempre crítico de la gestión de transacciones. Esta vez, suponga que el sistema funciona al 100% bien. Ahora, dos personas (A y B) hacen un pago a una tercera (C). Es muy probable que ambas transacciones lean el saldo de la cuenta de C simultáneamente, causando esta confusión:

  • Saldo de la cuenta de C = $100.
  • La transacción de A lee el saldo de C: $100.
  • La transacción de B lee el saldo de C: $100.
  • La transacción de A agrega $50 y actualiza el saldo: $100 + 50 = $150.
  • La transacción de B agrega $50 y actualiza el saldo: $100 + 50 = $150.

¡Maldición! ¡$ 50 simplemente desaparecieron en el aire!

Los sistemas SQL tradicionales lo salvan de esto al proporcionar una gestión de transacciones integrada, pero tan pronto como sale de una sola máquina, está frito.

El punto es que, con tales sistemas, es fácil encontrarse con problemas de corrupción de datos de los que es imposible recuperarse. ¡Tirar de tu cabello tampoco ayudará! 🙂

MongoDB Sharding

Para los arquitectos de software, el entusiasmo por MongoDB no radicaba tanto en su esquema flexible, sino en su soporte integrado de fragmentación. Con solo unas pocas reglas simples y máquinas conectadas, estuvo listo para ejecutar un clúster de MongoDB fragmentado en muy poco tiempo.

La siguiente imagen muestra cómo se ve esto en una implementación de aplicación web típica.

Crédito de la imagen: mongodb.com

La mejor parte de la fragmentación de MongoDB es que incluso el equilibrio de fragmentos es automático. Es decir, si tiene cinco fragmentos y dos de ellos están casi vacíos, puede decirle a MongoDB que reequilibre las cosas de manera que todos los fragmentos estén igualmente llenos.

Como desarrollador o administrador, no necesita preocuparse mucho, ya que MongoDB detrás de escena hace la mayor parte del trabajo pesado. Lo mismo ocurre con la falla parcial de los nodos; si tiene conjuntos de réplicas correctamente configurados y ejecutándose en su clúster, las interrupciones parciales no afectarán el tiempo de actividad del sistema.

La explicación completa sería bastante breve, así que cerraré esta sección diciendo que MongoDB tiene varias herramientas integradas para fragmentación, replicación y recuperación, lo que facilita mucho a los desarrolladores la creación de aplicaciones a gran escala. Si desea una guía más completa sobre las capacidades de fragmentación de MongoDB, la documentos oficiales son el lugar para estar.

Consulte esta guía práctica para implementar fragmentación. También te puede interesar este guía completa del desarrollador.

MongoDB Sharding Best Practices

Si bien MongoDB "simplemente funciona" desde el primer momento para la fragmentación, no significa que podamos dormirnos en los laureles. La fragmentación puede hacer o deshacer su proyecto para siempre, dependiendo de qué tan bien o mal se haya hecho.

Además, hay muchos pequeños detalles que deben tenerse en cuenta y, en su defecto, no es raro que los proyectos se derrumben. La intención no es asustarlo, sino resaltar la necesidad de planificar y ser extremadamente cuidadoso incluso con las decisiones pequeñas.

La clave de fragmentación inevitablemente controla la fragmentación en MongoDB, por lo que es ideal que comencemos nuestra encuesta con eso.

Alta cardinalidad

Cardinalidad significa la cantidad de variación. Por ejemplo, una colección de un país favorito de 1 millón de personas tendrá variaciones bajas (¡hay tantos países en el mundo!), mientras que una colección de sus direcciones de correo electrónico tendrá una cardinalidad (perfectamente) alta. ¿Por qué eso importa? Supongamos que elige un esquema ingenuo que fragmenta los datos en función del nombre de pila de un usuario.

Aquí tenemos un arreglo bastante simple; el documento entrante se escanea en busca de nombre de usuario y, dependiendo de dónde se encuentre la primera letra en el alfabeto inglés, se ubica en uno de los tres fragmentos. De manera similar, buscar un documento es fácil: los detalles de "Peter", por ejemplo, estarán en el segundo fragmento con seguridad.

Todo suena bien, pero el punto es que no controlamos los nombres de los usuarios de documentos entrantes. ¿Qué pasa si solo obtenemos nombres en el rango de B a F la mayor parte del tiempo? Si es así, tendremos lo que se llama un fragmento "jumbo" en el fragmento 1: la mayoría de los datos del sistema estarán abarrotados allí, convirtiendo la configuración en un solo sistema de base de datos.

¿La cura?

Elija una clave con alta cardinalidad, por ejemplo, la dirección de correo electrónico de los usuarios, o incluso puede optar por una clave de fragmento compuesto, que es una combinación de varios campos.

Monotónicamente cambiante

Un error común en la fragmentación de MongoDB es utilizar claves de aumento monotónico (o de aumento automático, si lo desea) como clave de fragmentación.

Generalmente, se utiliza la clave principal del documento. La idea aquí es bien intencionada, es decir, a medida que se sigan creando nuevos documentos, caerán uniformemente en uno de los fragmentos disponibles. Desafortunadamente, tal configuración es un error clásico. Esto es así porque si la clave del fragmento siempre aumenta, después de un punto, los datos comenzarán a acumularse en el lado de alto valor de los fragmentos, lo que provocará un desequilibrio en el sistema.

Crédito de la imagen: mongodb.com

Como puede ver en la imagen, una vez que pasamos el rango 20, todos los documentos comienzan a acumularse en el Chunk C, lo que genera un monolito allí. La solución es optar por un esquema de clave de fragmentación con hash, que crea una clave de fragmentación mediante el hash de uno de los campos proporcionados y usándolo para determinar el fragmento.

Crédito de la imagen: Mongodb.com

Una clave de fragmento hash se ve así:

 {"_id": "6b85117af532da651cc912cd"}

. . . y se puede crear en el shell del cliente de Mongo usando:

 db.collection.createIndex ({_id: hashedValue})

Fragmento temprano

Uno de los consejos más útiles directamente desde las trincheras es fragmentar temprano, incluso si terminas con un grupo pequeño de dos trozos. Una vez que los datos superan los 500 GB o algo así, la fragmentación se convierte en un proceso complicado en MongoDB, y debería estar preparado para sorpresas desagradables. Además, el proceso de reequilibrio consume cantidades muy altas de ancho de banda de la red, lo que puede ahogar el sistema si no se tiene cuidado.

Sin embargo, no todo el mundo es pro-sharding. Como ejemplo interesante (el aprendizaje está realmente en los comentarios), mira este bonito Percona blog.

Ejecutando el equilibrador

Otra buena idea es monitorear sus patrones de tráfico y ejecutar el equilibrador de fragmentos solo en momentos de poco tráfico. Como ya mencioné, el reequilibrio en sí mismo requiere un ancho de banda considerable, lo que podría hacer que todo el sistema se ralentice rápidamente. Recuerde, los fragmentos desequilibrados no son motivo de pánico inmediato. ¡Simplemente deje que el uso normal persista, espere oportunidades de poco tráfico y deje que el equilibrador haga el resto!

Así es como puede lograr esto (asumiendo que tiene poco tráfico de 3 a. m. a 5 a. m.):

 use config db.settings.update ({_id: "balanceador"}, {$ set: {activeWindow: {start: "03:00", stop: "05:00"}}}, {upsert: true})

Conclusion

Fragmentar y escalar cualquier base de datos es una tarea complicada, pero afortunadamente MongoDB la hace más manejable que otras bases de datos populares.

De hecho, hubo un momento en que MongoDB no era la opción correcta para ningún proyecto (gracias a sus varios problemas críticos y comportamientos predeterminados), pero eso ya pasó. Junto con la fragmentación, el reequilibrio, la compresión automática, el bloqueo distribuido a nivel agregado y muchas de esas funciones, MongoDB ha avanzado mucho y es hoy la primera opción del arquitecto de software.

Espero que este artículo haya podido arrojar algo de luz sobre qué es la fragmentación en MongoDB y de qué debe ocuparse el desarrollador cuando vaya a escalar. A continuación, familiarícese con populares Comandos de MongoDB.