DocumentDB - Partición

Cuando su base de datos comience a crecer más allá de los 10 GB, puede escalar horizontalmente simplemente creando nuevas colecciones y luego distribuyendo o particionando sus datos en más y más colecciones.

Tarde o temprano una sola colección, que tiene una capacidad de 10GB, no será suficiente para contener su base de datos. Ahora, 10GB puede no parecer un número muy grande, pero recuerde que estamos almacenando documentos JSON, que son solo texto sin formato y puede colocar muchos documentos de texto sin formato en 10GB, incluso si considera la sobrecarga de almacenamiento para los índices.

El almacenamiento no es la única preocupación cuando se trata de escalabilidad. El rendimiento máximo disponible en una colección es de dos mil quinientas unidades de solicitud por segundo que obtiene con una colección S3. Por lo tanto, si necesita un mayor rendimiento, también deberá escalar horizontalmente mediante la partición con varias colecciones. La partición escalable también se llamahorizontal partitioning.

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

  • Partición de desbordamiento
  • Partición de rango
  • Partición de búsqueda
  • Particionamiento hash

Partición de desbordamiento

La partición de desbordamiento es la estrategia más simple porque no hay una clave de partición. A menudo, es una buena opción para empezar 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 puede necesitar agregar o qué tan rápido puede necesitar agregarlas.

  • La partición de desbordamiento comienza con una sola colección y no hay una 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 comienzas a acercarte al límite de 10GB.

  • Cuando alcanza el 90 por ciento de la capacidad, pasa a una nueva colección y comienza a usarla para nuevos documentos.

  • Una vez que su base de datos se amplíe a una mayor cantidad de colecciones, probablemente querrá cambiar a una estrategia basada en una clave de partición.

  • Cuando haga eso, deberá reequilibrar sus datos moviendo documentos a diferentes colecciones según la estrategia a la que esté migrando.

Partición de rango

Una de las estrategias más comunes es la división de rangos. Con este enfoque, usted determina el rango de valores en el que podría caer la clave de partición de un documento y dirige el documento a una colección correspondiente a ese rango.

  • Las fechas se usan muy típicamente con esta estrategia en la que crea una colección para contener documentos que se encuentran dentro del rango de fechas definido. Cuando define rangos que son lo suficientemente pequeños, donde está seguro de que ninguna colección superará su límite de 10 GB. Por ejemplo, puede haber un escenario en el que una sola colección pueda manejar documentos de manera razonable durante todo un mes.

  • También puede darse el caso de que la mayoría de los usuarios busquen datos actuales, que serían datos de este mes o quizás del mes pasado, pero los usuarios rara vez buscan datos mucho más antiguos. Así que comienza en junio con una colección S3, que es la colección más cara que puede comprar y ofrece el mejor rendimiento que puede obtener.

  • En julio, compra otra colección S3 para almacenar los datos de julio y también escala los datos de junio a una colección S2 menos costosa. Luego, en agosto, obtienes otra colección S3 y escalas julio a un S2 y junio hasta un S1. Continúa, mes tras mes, donde siempre mantiene los datos actuales disponibles para un alto rendimiento y los datos más antiguos se mantienen disponibles a un rendimiento más bajo.

  • Siempre que la consulta proporcione una clave de partición, solo se consultará la colección que necesita ser consultada y no todas las colecciones en la base de datos como sucede con la partición de desbordamiento.

Partición de búsqueda

Con la búsqueda de particiones, puede definir un mapa de partición que enrute documentos a colecciones específicas en función de su clave de partició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 particiones y un solucionador de particiones de búsqueda puede averiguar en qué colección crear un documento y qué colecciones consultar, según la clave de partición, que es la propiedad de la región contenida en cada documento.

Particionamiento hash

En el particionamiento hash, las particiones se asignan en función del valor de una función hash, lo que le permite distribuir de manera uniforme las solicitudes y los datos en varias particiones.

Esto se usa comúnmente para particionar datos producidos o consumidos de una gran cantidad de clientes distintos y es útil para almacenar perfiles de usuario, elementos de catálogo, etc.

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

Step 1- Cree un nuevo DocumentClient y crearemos dos colecciones en la tarea CreateCollections. Uno contendrá documentos para los usuarios que tienen ID de usuario que comienzan 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” }); 
}

Step 2 - Registre el resolutor de rango para la base de datos.

Step 3- Cree un nuevo RangePartitionResolver <string>, que es el tipo de datos de nuestra clave de partición. El constructor toma dos parámetros, el nombre de propiedad de la clave de partición y un diccionario que es el mapa de particiones o mapa de partición, que es solo una lista de los rangos y las colecciones correspondientes que estamos predefiniendo para el resolutor.

private static void RegisterRangeResolver(DocumentClient client) {

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

Es necesario codificar aquí el valor UTF-8 más grande posible. De lo contrario, el primer rango no coincidiría con ninguna M excepto la única M, y lo mismo con Z en el segundo rango. Por lo tanto, puede pensar en este valor codificado aquí como un comodín para hacer coincidir la clave de partición.

Step 4- Después de crear el resolutor, regístrelo para la base de datos con el DocumentClient actual. Para hacer eso, simplemente asígnelo a la propiedad de diccionario de PartitionResolver.

Crearemos y consultaremos documentos contra la base de datos, no una colección como lo hace normalmente, el solucionador utilizará este mapa para enrutar las solicitudes a las colecciones apropiadas.

Ahora creemos algunos documentos. Primero crearemos uno para userId 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 un autoenlace a la base de datos, no una colección específica. Esto no es posible sin un solucionador de particiones, pero con uno funciona a la perfección.

Ambos documentos se guardaron en la base de datos myfirstdb, pero sabemos que Kirk se almacena en la colección de A a M y Spock se almacena en la colección de N a Z, si nuestro RangePartitionResolver funciona correctamente.

Llamemos a estos 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 se ve, los autovínculos de los dos documentos tienen diferentes ID de recursos porque existen en dos colecciones separadas.