¿Qué es el sharding en MongoDB? ¿Cómo funciona el sharding en MongoDB?

Categoría
Descripción

Cuando no es posible almacenar la totalidad de datos en un único servidor, MongoDB permite una operación de escalado horizontal. Esto quiere decir que la información puede repartirse en varios servidores, de forma que cada servidor tenga una parte del conjunto completo de datos. A este proceso se le llama sharding (fragmentación). El conjunto de servidores que contiene la totalidad de un conjunto de datos se le denomina sharded cluster (conjunto fragmentado).

Para asegurar la alta disponibilidad del conjunto, cada fragmento (shard) se configura como un conjunto replicado. De esta forma, se asegura la tolerancia a fallos de cada shard por separado, independientemente de cuál de ellos almacene un dato concreto.

Cuando se hace una consulta sobre un conjunto fragmentado, se debe pasar por un proceso de enrutado que indique dónde ir a buscar el dato dentro del conjunto. De este proceso de enrutado se encarga el proceso MongoS. Para ello, utiliza los metadatos asociados a los datos almacenados en cada fragmento, que están almacenados en un servidor de configuración. Para asegurar la alta disponibilidad de este servidor se utiliza un conjunto replicado.

El proceso MongoS puede instanciarse tantas veces como se desee, para poder ser invocado por distintas aplicaciones, atacando al mismo conjunto fragmentado. 

¿Cuándo utilizar sharding?

Antes de utilizar el método de fragmentado (sharding) se debería comprobar la viabilidad de un escalado vertical (es decir, ampliar las capacidades de RAM, CPU, red o disco en el servidor), teniendo en cuenta ciertos aspectos:

  • Coste económico: si el incremento de rendimiento no es proporcional al incremento de coste dentro de unos márgenes, entonces se debe descartar. Imaginemos que por necesidades se debe ampliar la memoria RAM del servidor, pero la ampliación nos supone un desembolso económico de 10 veces el coste inicial para una mejora en rendimiento del doble de rendimiento inicial. El escalado vertical no será la mejor opción.
  • Coste operacional: se debe tener en cuenta, por ejemplo, que una ampliación de la capacidad de disco también supone una ampliación de los tiempos necesarios para backup y restore, así como cierto impacto sobre las conexiones de red. En este caso, distribuir los datos en varios fragmentos permitirá una copia más rápida por unidad, al permitir paralelización y un uso menor de ancho de banda. También se debe tener en cuenta que unos ficheros de datos de 15Tb implicará unos ficheros de índice de tamaño proporcional. Unos índices grandes requerirán mucho acceso a disco y el uso de una mayor cantidad de RAM por unidad de proceso

En resumidas cuentas, la primera opción debería ser el escalado vertical, a no ser que los costes no sean proporcionales al incremento de rendimiento obtenido, en cuyo caso se debe optar por un escalado horizontal. Como norma general, se dice que cada servidor debería alojar un máximo de entre 2Tb y 5Tb de información. Exceder esta cifra incrementa el tiempo de consulta.

El sharding también se recomienda cuando el acceso a datos se vea beneficiado por procesos de paralelización o cuando los datos se puedan distribuir geográficamente de forma que los clientes puedan acceder a su información estando almacenada en servidores cercanos.

¿Cómo se realiza la comunicación al trabajar con sharded clusters (conjuntos fragmentados)?

Cuando la información se encuentra distribuida en shards (fragmentos), la comunicación del cliente no se realiza directamente con los conjuntos replicados que almacenan la información, sino que se realiza con el proceso MongoS. Este proceso debe averiguar en qué shard se almacena la información solicitada, la localiza y la devuelve al cliente. Para ello, utiliza los metadatos almacenados en el servidor de configuración. Estos metadatos indican qué conjuntos de información están almacenados en cada shard, de forma que MongoS sabe a qué servidor debe acudir para obtener la información. Los servidores de configuración se encargan de mover los datos de forma que se distribuyan por igual a lo largo de todos los shards.

No todas las colecciones deben ser necesariamente distribuidas en todos los shards. El servidor de configuración, asigna a cada base de datos, un fragmento primario (primary shard) en el que se almacenarán todas las colecciones que no se vayan a fragmentar (non-sharded collections). El fragmento primario de cada base de datos se puede modificar. Este primary shard también se encarga de otras operaciones, como las operaciones de unión (merge) de los comandos de agregado.

Cuando se ejecuta una consulta sobre un dato del que no se disponen metadatos, MongoS lanza la consulta a todos los shards del conjunto, y posteriormente los junta. A este proceso se le llama SHARD_MERGE. Una vez se hayan juntado todos los datos, se devuelve toda la información al cliente.

¿Qué es el balanceo?

El balanceo es la operación mediante la cual MongoDB distribuye de la manera más uniforme posible los datos entre los distintos shards. La información dentro de los shards se distribuye en chunks, que son agrupaciones lógicas de documentos que pertenecen a un rango concreto en función de su clave. Cuando MongoDB detecta que hay un exceso de chunks en un shard, mueve los sobrantes a otro shard asegurando así una distribución regular de los mismos.

El balanceador se ejecuta en el miembro primario del conjunto replicado de configuración (Config Server Replica Set). Este proceso de balanceo comprueba la distribución de los chunks entre los distintos shards, y analiza los umbrales de migración. Cuando detecta una descompensación, empiezan las rondas de balanceo. Este proceso se ejecuta en paralelo, pero un shard no puede participar en más de una migración de forma simultánea. Para saber cuántos chunks se pueden migrar de forma simultánea, dividiremos por 2 el número de shards y lo redondearemos a la baja. Por ejemplo, para un escenario de 3 shards, sólo se podrá mover de forma simultánea 1 chunk. Las rondas de balanceo se repiten tantas veces como sea necesario para obtener una distribución correcta de los chunks. El balanceador tiene la posibilidad también de dividir los chunks en varias partes en caso de que detecte esta necesidad, o como parte de la definición de rangos de chunks al realizar zone sharding.

Cualquier operación de balanceo impacta en el rendimiento. Es por esto que MongoDB dispone de 3 métodos para el control del comportamiento del balanceador:

  • sh.startBalancer(timeout, intervalo) inicia el proceso de balanceo. Permite establecer un tiempo de espera (timeout) para que se inicie el proceso. El intervalo especifica el tiempo que el cliente deberá esperar antes de comprobar nuevamente el estado del balanceador.
  • sh.stopBalancer(timeout, intervalo) detiene el proceso de balanceo. En caso de detenerse en mitad de una ronda de balanceo, éste se detiene cuando finaliza dicha ronda. Permite establecer un tiempo de espera (timeout) para que se detenga el proceso. El intervalo especifica el tiempo que el cliente deberá esperar antes de comprobar nuevamente el estado del balanceador.
  • sh.setBalancerState(boolean) activa o desactiva el balanceador

Mediante el fichero de configuración, se puede establecer una ventana de ejecución para el balanceador.