DocumentDB – Seccionamiento

Cuando su base de datos comienza a exceder los 10 GB, puede escalar simplemente creando nuevas colecciones y luego distribuyendo o dividiendo sus datos en más y más colecciones.

Tarde o temprano, una sola colección de 10 GB no será suficiente para acomodar su base de datos. 10 GB puede no parecer mucho, pero recuerde que almacenamos documentos JSON, que son texto sin formato, y puede colocar muchos documentos de texto en 10 GB, incluso con la sobrecarga de almacenamiento para índices.

Cuando se trata de escalabilidad, el problema no es solo el almacenamiento. El rendimiento máximo disponible para una colección es de 2500 RPS, que se obtiene con una colección S3. Por lo tanto, si necesita un mayor ancho de banda, también debe escalar dividiéndose en varias colecciones. El particionamiento escalable también se llama separación horizontal

Hay muchos enfoques que puede usar para particionar datos con Azure DocumentDB. Las siguientes son las estrategias más comunes:

  • División adicional
  • Dividir un rango
  • Partición de búsqueda
  • División de hash

División adicional

La partición de desbordamiento es la estrategia más simple porque no hay clave de partición. Suele ser un buen punto de partida cuando no está seguro de muchas cosas. Es posible que no sepa si alguna vez necesitará escalar más allá de una sola colección, o cuántas colecciones necesitará agregar, o qué tan rápido puede necesitar agregarlas.

  • El particionamiento adicional comienza con una sola colección y no hay clave de partición.

  • La colección comienza a crecer, y luego crece un poco más, y luego un poco más, hasta que te acercas al límite de 10 GB.

  • Cuando alcance el 90 por ciento de su capacidad, pasará a una nueva colección y comenzará a usarla para nuevos documentos.

  • Una vez que su base de datos se amplíe a más colecciones, probablemente desee pasar a una estrategia basada en claves de partición.

  • Cuando haga esto, deberá reequilibrar los datos moviendo documentos a diferentes colecciones según la estrategia a la que se esté moviendo.

Dividir un rango

Una de las estrategias más comunes es la división de rango. Con este enfoque, define un rango de valores en los que puede caer la clave de sección del documento y dirige el documento a una colección que coincide con ese rango.

  • Las fechas se utilizan con mucha frecuencia con esta estrategia cuando se crea una colección para almacenar documentos que se encuentran dentro de un rango de fechas específico. Cuando define rangos que son lo suficientemente pequeños, cuando está seguro de que ninguna colección superará su límite de 10 GB. Por ejemplo, puede haber un escenario en el que una colección pueda procesar documentos de manera inteligente durante todo un mes.

  • También puede suceder que la mayoría de los usuarios soliciten datos actuales, que pueden ser datos de este mes o quizás del último mes, pero los usuarios rara vez buscan datos mucho más antiguos. Entonces, comienza en junio con la colección S3, que es la colección más cara que puede comprar y proporciona el mejor ancho de banda que puede obtener.

  • En julio, compra otra colección S3 para almacenar los datos de julio y también amplía los datos de junio a la colección S2 menos costosa. Luego, en agosto, obtiene otra colección S3 y reduce julio a S2 y junio a S1. Esto sucede mes tras mes, donde siempre mantiene los datos actuales disponibles para un ancho de banda alto y los datos más antiguos con un ancho de banda menor.

  • Siempre que la solicitud proporcione la clave de partición, solo se solicitará la colección solicitada, no todas las colecciones de la base de datos, como es el caso de las particiones adicionales.

Rompiendo secciones de búsqueda

Con una búsqueda de sección, puede definir un mapa de sección que dirige los documentos a colecciones específicas en función de su clave de sección. Por ejemplo, puede dividir por región.

  • Almacene todos los documentos estadounidenses en una colección, todos los documentos europeos en otra colección y todos los documentos de cualquier otra región en una tercera colección.

  • Utilice este mapa de sección, y el transformador de sección de búsqueda puede determinar en qué colección crear un documento y en qué colecciones consultar, según la clave de sección, que es una propiedad de región contenida en cada documento.

División de hash

La división hash asigna particiones en función del valor hash, lo que permite que las consultas y los datos se distribuyan de manera uniforme en varias particiones.

Esto se usa comúnmente para separar los datos creados o consumidos por una gran cantidad de clientes individuales y es útil para almacenar perfiles de usuario, artículos de catálogo, etc.

Echemos un vistazo a un ejemplo simple de división de rango utilizando RangePartitionResolver proporcionado por.NET SDK.

Paso 1 – Cree un nuevo DocumentClient y crearemos dos colecciones en la tarea CreateCollections. Uno contendrá documentos para usuarios cuyas ID comiencen con A a M, y el otro para ID de usuario N a Z.

private static async Task CreateCollections(DocumentClient client) {
   await client.CreateDocumentCollectionAsync(“dbs/myfirstdb”, new DocumentCollection {
      Id = “CollectionAM” }); 
		
   await client.CreateDocumentCollectionAsync(“dbs/myfirstdb”, new DocumentCollection {
      Id = “CollectionNZ” }); 
}

Paso 2 – Registrar un convertidor de rango para la base de datos.

Paso 3 – Cree un nuevo RangePartitionResolver que es el tipo de datos de nuestra clave de sección. El constructor toma dos parámetros: el nombre de la propiedad de la clave de sección y un diccionario, que es un mapa de segmento o un mapa de sección, que es simplemente una lista de rangos y colecciones correspondientes que predefinimos para el transformador.

private static void RegisterRangeResolver(DocumentClient client) {

   //Note: uffff is the largest UTF8 value, so Mufff includes all strings that start with M.
		
   var resolver = new RangePartitionResolver<string>(
      "userId", new Dictionary<Range<string>, string>() {
      { new Range<string>("A", "Muffff"), "dbs/myfirstdb/colls/CollectionAM" },
      { new Range<string>("N", "Zuffff"), "dbs/myfirstdb/colls/CollectionNZ" },
   });
	
   client.PartitionResolvers["dbs/myfirstdb"] = resolver;
 }

Aquí debe codificar el valor UTF-8 máximo posible. De lo contrario, el primer rango no coincidirá con ninguna M excepto una M, así como con Z en el segundo rango. Por lo tanto, puede pensar en este valor codificado aquí como un comodín para la asignación de claves para la sección.

Paso 4 – Después de crear el transformador, regístrelo para la base de datos con el DocumentClient actual. Para hacer esto, simplemente asígnelo a la propiedad PartitionResolver del diccionario.

Crearemos y consultaremos documentos en la base de datos, no en la colección como lo hace habitualmente, el transformador utilizará este mapa para enrutar las solicitudes a las colecciones correspondientes.

Ahora creemos algunos documentos. Primero crearemos uno para el userId de Kirk y luego uno para Spock.

private static async Task CreateDocumentsAcrossPartitions(DocumentClient client) { 
   Console.WriteLine(); 
   Console.WriteLine("**** Create Documents Across Partitions ****");
	
   var kirkDocument = await client.CreateDocumentAsync("dbs/myfirstdb", new { userId =
      "Kirk", title = "Captain" }); 
   Console.WriteLine("Document 1: {0}", kirkDocument.Resource.SelfLink);
	
   var spockDocument = await client.CreateDocumentAsync("dbs/myfirstdb", new { userId =
      "Spock", title = "Science Officer" });		
   Console.WriteLine("Document 2: {0}", spockDocument.Resource.SelfLink); 
}

El primer parámetro aquí es una referencia a la base de datos, no a una colección específica. Esto no es posible sin un convertidor de particiones, pero con uno funciona sin problemas.

Ambos documentos se almacenaron en la base de datos myfirstdb, pero sabemos que Kirk está almacenado en la colección A a M y Spock está almacenado en la colección N a Z si nuestro RangePartitionResolver está funcionando correctamente.

Vamos a llamarlos desde la tarea CreateDocumentClient como se muestra en el siguiente código.

private static async Task CreateDocumentClient() {
   // Create a new instance of the DocumentClient 
   using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
      await CreateCollections(client);  
      RegisterRangeResolver(client);  
      await CreateDocumentsAcrossPartitions(client); 
   } 
}

Cuando se ejecuta el código anterior, recibirá el siguiente resultado.

**** Create Documents Across Partitions **** 
Document 1: dbs/Ic8LAA==/colls/Ic8LAO2DxAA=/docs/Ic8LAO2DxAABAAAAAAAAAA==/ 
Document 2: dbs/Ic8LAA==/colls/Ic8LAP12QAE=/docs/Ic8LAP12QAEBAAAAAAAAAA==/

Como puede ver, las referencias a sí mismos en los dos documentos tienen diferentes ID de recurso porque existen en dos colecciones separadas.

🚫