¿Qué son las shard keys en MongoDB? ¿Cómo se crea una sharded database en MongoDB?

Categoría
Descripción

Las shard keys son las claves indexadas que se usan en MongoDB para partir las colecciones fragmentadas (sharded collections) y distribuirlas en el conjunto fragmentado (sharded cluster).

MongoDB usa estas claves para crear agrupaciones lógicas de documentos que MongoS se encargará de distribuir entre los distintos shards. A cada uno de estos grupos lógicos se le denomina chunk. El campo o campos utilizados para definir la shard key son los utilizados para definir el valor mínimo inclusivo y máximo exclusivo que MongoDB utilizará para decidir qué documentos se destinan a cada chunk.

Cuando mongos recibe una petición para añadir un documento, consulta el valor de la shard key, y decide el chunk de destino en base a los valores mínimo y máximo de cada uno.

Esto obliga a que todos los documentos de una sharded collection contengan el valor correspondiente a la shard key. Por lo tanto, los documentos que se vayan a añadir deben alimentar ese dato. Cuando se van a realizar operaciones de lectura, se hace necesario que las condiciones de búsqueda incluyan la shard key, de forma que mongos pueda recuperar directamente el dato del chunk correcto. De no ser así, mongos tendrá que consultar todos los chunks para comprobar qué documentos cumplen la condición de búsqueda.

Características de las shard keys

Las shard keys deben cumplir con las siguientes características:

  • Sus campos deben estar indexados. Los índices deben existir antes de crear la shard key.
  • El fragmentado (sharded) es una operación permanente. No se pueden modificar los campos de la shard key una vez creada. Tampoco se pueden modificar los valores correspondientes a los campos de la shard key en los documentos.
  • Una vez que se crea una colección fragmentada (sharded), no se puede desfragmentar.

Quiero que mi base de datos se fragmente. ¿Qué debo hacer?

Para empezar a trabajar con una base de datos fragmentada (sharded database), se deben seguir los pasos indicados a continuación:

  1. Usar el comando sh.enableSharding("<base_de_datos>") para habilitar el fragmentado para la base de datos. Con esto no se fragmentan directamente los datos, sino que le decimos a mongos que queremos que sus colecciones sean elegibles para fragmentar.
  2. Crear un índice para la colección que queremos fragmentar: db.<coleccion>.createIndex(), donde <coleccion> es la colección que queremos fragmentar. Si se va a querer crear una hashed shard key, se deberá utilizar db.<coleccion>.createIndex( { "<clave>": "hashed" }).
  3. Usar sh.shardCollection("<base_de_datos>.<coleccion>, { <shard_key> }) para fragmentar la colección. Si se quiere crear una hashed shard key, se usará sh.shardCollection("<base_de_datos>.<coleccion>, { <shard_key>: "hashed" }).

Consejos para escoger una shard key

Para escoger una buena shard key, que nos proporcione una distribución correcta en chunks, ésta debe tener 3 propiedades:

  • Cardinalidad: la cardinalidad hace referencia al número de elementos que existen dentro de un conjunto. Hablando de shard keys, se refiere al número de elementos únicos que la clave puede contener. Las claves escogidas deben tener una alta cardinalidad, por dos motivos:
    • Si tiene un rango pequeño de posibles valores, limita el número de shards que se pueden incluir en el cluster. Los chunks deben tener un límite inferior y superior. Cada valor único sólo puede existir en un chunk. Si la cardinalidad es baja, resulta muy complicado establecer unos límites que permitan fragmentar adecuadamente la información en los distintos chunks.
    • Cuanto más alta sea la cardinalidad, menor es la posibilidad de que los valores se repitan (ver "frecuencia").
  • Frecuencia: se refiere al número de veces que un valor se repite dentro de un conjunto. Las claves escogidas deben tener una frecuencia baja, es decir, cada valor debería repetirse el menor número de veces posible. Si un valor se repite muchas veces, todos los documentos irán a parar al mismo chunk, saturándolo y dejando al resto de chunks con una carga de trabajo baja.
  • Cambios monótonos: se debe evitar que los cambios entre el valor de la clave en un documento y el valor de la clave en el siguiente documento, tengan una tasa estable y predecible. Un cambio monótono puede ser el uso de fechas sucesivas, o claves numéricas sucesivas.

Además de estas propiedades, se debe tener en cuenta la capacidad de aislamiento de las consultas, de forma que cuando se efectúe una búsqueda por un dato de la clave, el router de mongos deba acceder únicamente a uno de los chunks, y no consultar todos los chunks para recuperar los datos.

Teniendo en cuenta las limitaciones de las shard keys (inmutabilidad y permanencia) es muy recomendable probar previamente el fragmentado en un entorno de desarrollo, para posteriormente pasarlo a un entorno de producción.

¿Qué son las hashed shard keys?

Las hashed shard keys son shard keys especiales que calculan el valor hash de la clave, y lo utilizan para decidir el chunk donde almacenar el documento. El valor no cambia, es decir, el valor no se sustituye por su hash, pero sí se utiliza el hash en el índice correspondiente a la hash key, y que se utiliza para la distribución de documentos entre chunks. Esto facilita una mejor repartición de documentos entre chunks.

Las hashed shard keys se suelen utilizar cuando las claves a utilizar incumplen las condiciones indicadas en la sección de consejos. Imaginemos un timestamp: la diferencia entre 2 timestamps puede ser de 1 segundo, y corremos el riesgo de que varios documentos caigan en el mismo chunk, provocando su saturación. Si aplicamos una función hash al timestamp, una variación de 1 segundo supone un cambio drástico en el valor de la shard key, facilitando así la alta cardinalidad y baja frecuencia.

Hay que tener varias cuestiones en cuenta:

  • Al aplicar una función hash a la clave, se corre el riesgo de que los documentos se distribuyan siempre entre todos los chunks, y se deba consultar todos ellos para obtener un dato concreto.
  • Se pierde la posibilidad de usar operaciones de lectura aisladas geográficamente cuando se usa el fragmentado por zonas.
  • El hash debe calcularse sobre un único campo que además no sea un array
  • Los indices hash no soportan el ordenado rápido