Compartir a través de


Claves de partición jerárquicas en Azure Cosmos DB

SE APLICA A: NoSQL

Azure Cosmos DB distribuye los datos entre particiones lógicas y físicas en función de las claves de partición para soportar el escalado horizontal. Mediante el uso de claves de partición jerárquicas (también llamadas subparticiones), puede configurar hasta una jerarquía de tres niveles para sus claves de partición para optimizar aún más la distribución de datos y para un mayor nivel de escalado.

Si usa claves sintéticas en la actualidad, tiene escenarios en los que las claves de partición pueden superar los 20 GB de datos, o desea asegurarse de que cada documento de los inquilinos se asigna a su propia partición lógica, la subpartición puede ayudarle. Si usa esta característica, los prefijos de clave de partición lógica pueden superar los 20 GB y 10 000 unidades de solicitud por segundo (RU/s). Las consultas por prefijo se enrutan eficazmente al subconjunto de particiones que contienen los datos.

Selección de las claves de partición jerárquica

Si tiene aplicaciones multiinquilino y actualmente aísla los inquilinos por clave de partición, las particiones jerárquicas podrían beneficiarle. Las particiones jerárquicas le permiten escalar más allá del límite de clave de partición lógica de 20 GB, y son una buena solución si desea asegurarse de que cada uno de los documentos de sus inquilinos puede escalar infinitamente. Si la clave de partición actual o una clave de partición única suelen alcanzar los 20 GB, las particiones jerárquicas son una excelente opción para la carga de trabajo.

Sin embargo, en función de la naturaleza de la carga de trabajo y de la cardinalidad que tenga la clave de primer nivel, puede haber algunos inconvenientes que tratamos en profundidad en nuestra página de escenarios de partición jerárquicos.

Cuando seleccione cada nivel de su clave de partición jerárquica, es importante tener en cuenta los siguientes conceptos generales de partición y comprender cómo cada uno de ellos puede afectar a su carga de trabajo:

  • Para todos los contenedores, cada nivel de la ruta de acceso completa (empezando por el primer nivel) de la clave de partición jerárquica debe:

    • Tener una cardinalidad alta. Las claves primera, segunda y tercera (si procede) de la partición jerárquica deben tener una amplia gama de valores posibles.

      • Tener una cardinalidad baja en el primer nivel de la clave de partición jerárquica limitará todas sus operaciones de escritura en el momento de la ingesta a una sola partición física hasta que alcance los 50 GB y se divida en dos particiones físicas. Por ejemplo, suponga que su clave de primer nivel está activada TenantId y solo tiene 5 inquilinos únicos. Cada una de las operaciones de estos inquilinos se limitará a una única partición física, limitando el consumo de rendimiento a lo que haya en esa única partición física. Esto se debe a que las particiones jerárquicas optimizan para que todos los documentos con la misma clave de primer nivel se coloquen en la misma partición física para evitar consultas completas.
      • Si bien esto puede estar bien para cargas de trabajo en las que hacemos una única ingesta de todos los datos de nuestros inquilinos y las siguientes operaciones son principalmente de lectura pesada después, esto puede ser poco ideal para cargas de trabajo en las que sus requisitos de negocio implican la ingesta de datos dentro de un tiempo específico. Por ejemplo, si tiene requisitos empresariales estrictos para evitar latencias, el rendimiento máximo que su carga de trabajo puede alcanzar teóricamente para ingerir datos es el número de particiones físicas * 10k. Si su clave de nivel superior tiene una cardinalidad baja, su número de particiones físicas será probablemente 1, a menos que haya suficientes datos para la clave de nivel 1 como para que se distribuyan en varias particiones después de las divisiones, que pueden tardar entre 4 y 6 horas en completarse.
    • Distribuir el consumo de unidades de solicitud (RU) y el almacenamiento de datos uniformemente en todas las particiones lógicas. Esto garantiza una distribución uniforme del consumo de RU y el almacenamiento en las particiones físicas.

      • Si elige una clave de primer nivel que parece tener una cardinalidad alta como UserId, pero en la práctica la carga de trabajo realiza operaciones en solo una UserId específica, es probable que se ejecute en una partición activa, ya que todas las operaciones se limitarán a una o pocas particiones físicas.
  • Cargas de trabajo de lectura intensiva: recomendamos elegir claves de partición jerárquicas que aparecen con frecuencia en las consultas.

    • Por ejemplo, una carga de trabajo que ejecuta consultas con frecuencia para filtrar sesiones de usuario específicas en una aplicación multiinquilino puede beneficiarse de las claves de partición jerárquicas de TenantId, UserId y SessionId, en ese orden. Las consultas se pueden enrutar de manera eficaz solo a las particiones físicas pertinentes si se incluye la clave de partición en el predicado de filtro. Para obtener más información sobre la elección de las claves de partición para cargas de trabajo de lectura intensiva, consulta la descripción general de partición.
  • Cargas de trabajo de escritura intensiva: recomendamos utilizar un valor cardinal alto para el primer nivel de la clave de partición jerárquica. La cardinalidad alta significa que la clave de primer nivel (y los niveles posteriores) también tiene al menos miles de valores únicos y más valores únicos que el número de particiones físicas.

    • Por ejemplo, supongamos que tenemos una carga de trabajo que aísla los inquilinos por clave de partición y tiene algunos inquilinos grandes que son más pesados de escritura que otros. En la actualidad, Azure Cosmos DB dejará de ingerir datos en cualquier valor de clave de partición si supera los 20 GB de datos. En esta carga de trabajo, Microsoft y Contoso son grandes inquilinos y prevemos que crezca mucho más rápido que nuestros otros inquilinos. Para evitar el riesgo de no poder ingerir datos para estos inquilinos, las claves de partición jerárquicas nos permiten escalar estos inquilinos más allá del límite de 20 GB. Podemos agregar más niveles, como UserId y SessionId, para garantizar una mayor escalabilidad entre los inquilinos.

    • Para asegurarse de que la carga de trabajo puede dar cabida a las escrituras de todos los documentos con la misma clave de primer nivel, considere la posibilidad de usar el id. de elemento como clave de segundo o tercer nivel.

    • Si su primer nivel no tiene una cardinalidad alta y está alcanzando el límite de 20 GB de partición lógica en su clave de partición actual, le sugerimos que utilice una clave de partición sintética en lugar de una clave de partición jerárquica.

Ejemplo de caso de uso

Supongamos que tiene un escenario multiinquilino en el que almacena información de eventos para los usuarios de cada inquilino. La información de evento puede incluir repeticiones de eventos, entre las que se incluyen, entre otras, eventos de inicio de sesión, secuencia de clics o de pago.

En un escenario real, algunos inquilinos pueden hacerse grandes con miles de usuarios, mientras que los muchos otros inquilinos son más pequeños y tienen unos pocos usuarios. La creación de particiones mediante /TenantId podría llevar a superar el límite de almacenamiento de 20 GB de Azure Cosmos DB en una única partición lógica. La creación de particiones mediante /UserId hace todas las consultas en una partición cruzada de inquilinos. Ambos enfoques tienen desventajas significativas.

El uso de una clave de partición sintética que combina TenantId y UserId agrega complejidad a la aplicación. Además, las consultas de clave de partición sintética para un inquilino se siguen realizando entre particiones, a menos que todos los usuarios sean conocidos y se especifiquen de antemano.

Si la carga de trabajo tiene inquilinos con aproximadamente los mismos patrones de carga de trabajo, la clave de partición jerárquica puede ayudar. Con las claves de partición jerárquicas, puede crear particiones primero en TenantId y, a continuación, en UserId. Si espera que la combinación TenantId y UserId genere particiones que superen los 20 GB, puede crear incluso particiones más abajo en otro nivel, como en SessionId. La profundidad general no puede superar tres niveles. Cuando una partición física supera los 50 GB de almacenamiento, Azure Cosmos DB divide automáticamente la partición física para que aproximadamente una mitad de los datos estén en una partición física y la otra mitad en la otra. De hecho, la subpartición significa que un único valor TenantId puede superar los 20 GB de datos y es posible que los datos de TenantId abarquen varias particiones físicas.

Las consultas que especifican TenantId, o TenantId y UserId, se enrutan de forma eficaz solo al subconjunto de particiones físicas que contienen los datos pertinentes. La especificación de la ruta de acceso de clave de partición con subpartición completa o prefijo evita eficazmente una consulta de distribución ramificada completa. Por ejemplo, si el contenedor tuviera 1000 particiones físicas, pero un valor TenantId específico solo estuviera en 5 particiones físicas, la consulta se dirigiría al menor número de particiones físicas relevantes.

Usar el id. de elemento en la jerarquía

Si el contenedor tiene una propiedad con una amplia gama de valores posibles, la propiedad es probable que sea una buena elección para el último nivel de la jerarquía. Un posible ejemplo de este tipo de propiedad es el ID del artículo. La propiedad del sistema id. de elemento existe en todos los elementos del contenedor. Agregar el identificador de elemento como otro nivel garantiza que se puede escalar más allá del límite de clave de partición lógica de 20 GB. Puede escalar más allá de este límite para el primer nivel o para el primer y segundo nivel de claves.

Por ejemplo, puede tener un contenedor para una carga de trabajo multiinquilino particionada por TenantId y UserId. Si es posible que una única combinación de TenantId y UserId supere los 20 GB, entonces se recomienda crear particiones mediante tres niveles de claves, y en los que la clave de tercer nivel tenga una alta cardinalidad. Un ejemplo de este escenario es si la clave de tercer nivel es un GUID que tiene una cardinalidad alta de forma natural. Es poco probable que la combinación de TenantId, UserId y un GUID supere los 20 GB, por lo que la combinación de TenantId y UserId puede escalar efectivamente más allá de los 20 GB.

Para obtener más información sobre el uso del id. de elemento como clave de partición, consulte la Introducción a la creación de particiones.

Introducción

Importante

Trabajar con contenedores que usan claves de partición jerárquicas solo se admite en las siguientes versiones del SDK. Debe usar el SDK compatible para crear nuevos contenedores con claves de partición jerárquicas y realizar operaciones de consulta o creación, lectura, actualización y eliminación (CRUD) de los datos. Si desea usar un SDK o un conector que no se admite actualmente, envíe una solicitud a nuestro foro de la comunidad.

Busque la versión preliminar más reciente de cada SDK compatible:

SDK Versiones compatibles Vínculo del administrador de paquetes
.NET SDK v3 >= 3.33.0 https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.33.0/
SDK de Java v4 >= 4.42.0 https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/cosmos/azure-cosmos/CHANGELOG.md#4420-2023-03-17/
JavaScript SDK v4 4.0.0 https://www.npmjs.com/package/@azure/cosmos/
SDK de Python >= 4.6.0 https://pypi.org/project/azure-cosmos/4.6.0/

Creación de un contenedor mediante claves de partición jerárquicas

Para empezar, cree un contenedor mediante una lista predefinida de rutas de acceso de clave de subpartición con hasta tres niveles de profundidad.

Puede crear un contenedor mediante una de estas opciones:

  • Azure portal
  • SDK
  • Plantilla del Administrador de recursos de Azure
  • Emulador de Azure Cosmos DB

Azure portal

La manera más sencilla de crear un contenedor y especificar claves de partición jerárquicas consiste en usar Azure Portal.

  1. Inicie sesión en Azure Portal.

  2. Vaya a la página de la cuenta de Azure Cosmos DB for NoSQL existente.

  3. En el menú de la izquierda, seleccione Explorador de datos.

    Captura de pantalla que muestra la página para una cuenta nueva de Azure Cosmos DB for NoSQL con la opción de menú Explorador de datos resaltada

  4. En Explorador de datos, seleccione la opción Nuevo contenedor.

    Captura de pantalla de la opción Nuevo contenedor en Explorador de datos

  5. En Nuevo contenedor, en Clave de partición, escriba /TenantId. Para los campos restantes, escriba cualquier valor que coincida con el escenario.

    Nota:

    Usamos /TenantId como ejemplo aquí. Puede especificar cualquier clave para el primer nivel al implementar claves de partición jerárquicas en contenedores propios.

  6. Seleccione dos veces Agregar clave de partición jerárquica.

    Captura de pantalla del botón para agregar una nueva clave de partición jerárquica.

  7. Para los niveles segundo y tercero de la subpartición, introduzca /UserId y /SessionId, respectivamente.

    Captura de pantalla de una lista de tres claves de partición jerárquicas.

  8. Seleccione Aceptar para crear el contenedor.

SDK

Al crear un contenedor mediante el SDK, defina una lista de rutas de acceso de clave de subpartición hasta tres niveles de profundidad. Use la lista de claves de subpartición al configurar las propiedades del nuevo contenedor.

// List of partition keys, in hierarchical order. You can have up to three levels of keys.
List<string> subpartitionKeyPaths = new List<string> { 
    "/TenantId",
    "/UserId",
    "/SessionId"
};

// Create a container properties object
ContainerProperties containerProperties = new ContainerProperties(
    id: "<container-name>",
    partitionKeyPaths: subpartitionKeyPaths
);

// Create a container that's subpartitioned by TenantId > UserId > SessionId
Container container = await database.CreateContainerIfNotExistsAsync(containerProperties, throughput: 400);

Plantillas del Administrador de recursos de Azure

La plantilla de Azure Resource Manager para un contenedor subparticionado es casi idéntica a la de un contenedor estándar. La única diferencia clave es el valor de la ruta de acceso properties/partitionKey. Para obtener más información sobre cómo crear una plantilla de Azure Resource Manager para un recurso de Azure Cosmos DB, consulte la documentación de plantillas de Azure Resource Manager para Azure Cosmos DB.

Configure el objeto partitionKey mediante los valores de la tabla siguiente para crear un contenedor subpartido:

Ruta de acceso Valor
paths Lista de claves de partición jerárquicas (máximo tres niveles de profundidad)
kind MultiHash
version 2

Ejemplo de definición de clave de partición

Por ejemplo, supongamos que tiene una clave de partición jerárquica compuesta por TenantId>UserId>SessionId. El objeto partitionKey se configuraría para incluir los tres valores de la propiedad paths, un valor kind de MultiHash y un valor version de 2.

partitionKey: {
  paths: [
    '/TenantId'
    '/UserId'
    '/SessionId'
  ]
  kind: 'MultiHash'
  version: 2
}

Para obtener más información sobre el objeto partitionKey, consulte la especificación ContainerPartitionKey.

Emulador de Azure Cosmos DB

Puede probar la característica de subpartición mediante la versión más reciente del emulador local para Azure Cosmos DB. Para habilitar la subpartición en el emulador, inicie el emulador desde el directorio de instalación con la marca /EnablePreview:

.\CosmosDB.Emulator.exe /EnablePreview

Advertencia

El emulador no admite actualmente todas las características de clave de partición jerárquica que admite el portal. El emulador no admite actualmente:

  • Uso de Data Explorer para crear contenedores con claves de partición jerárquica
  • Uso de Data Explorer para navegar e interactuar con elementos mediante claves de partición jerárquica

Para obtener más información, consulte Emulador de Azure Cosmos DB.

Uso de los SDK para trabajar con contenedores que tienen claves de partición jerárquicas

Cuando tenga un contenedor que tenga claves de partición jerárquica, use las versiones especificadas anteriormente de los SDK de .NET o Java para realizar operaciones y ejecutar consultas en ese contenedor.

Adición de un elemento a un contenedor

Hay dos opciones para agregar un nuevo elemento a un contenedor con claves de partición jerárquicas habilitadas:

  • Extracción automática
  • Especificación manual de la ruta de acceso

Extracción automática

Si pasa un objeto con el conjunto de valores de clave de partición, el SDK puede extraer automáticamente la ruta de acceso de clave de partición completa.

// Create a new item
UserSession item = new UserSession()
{
    id = "f7da01b0-090b-41d2-8416-dacae09fbb4a",
    TenantId = "Microsoft",
    UserId = "00aa00aa-bb11-cc22-dd33-44ee44ee44ee",
    SessionId = "0000-11-0000-1111"
};

// Pass in the object, and the SDK automatically extracts the full partition key path
ItemResponse<UserSession> createResponse = await container.CreateItemAsync(item);

Especificación manual de la ruta de acceso

La clase PartitionKeyBuilder del SDK puede construir un valor para una ruta de acceso de clave de partición jerárquica definida previamente. Use esta clase al agregar un nuevo elemento a un contenedor que tenga habilitada la subpartición.

Sugerencia

A gran escala, el rendimiento puede mejorar si se especifica la ruta de acceso de clave de partición completa incluso si el SDK puede extraer la ruta de acceso del objeto.

// Create a new item object
PaymentEvent item = new PaymentEvent()
{
    id = Guid.NewGuid().ToString(),
    TenantId = "Microsoft",
    UserId = "00aa00aa-bb11-cc22-dd33-44ee44ee44ee",
    SessionId = "0000-11-0000-1111"
};

// Specify the full partition key path when creating the item
PartitionKey partitionKey = new PartitionKeyBuilder()
            .Add(item.TenantId)
            .Add(item.UserId)
            .Add(item.SessionId)
            .Build();

// Create the item in the container
ItemResponse<PaymentEvent> createResponse = await container.CreateItemAsync(item, partitionKey);

Búsqueda de clave y valor (lectura puntual) de un elemento

Las búsquedas de clave y valor (lecturas puntuales) se realizan de forma similar a un contenedor no particionado. Por ejemplo, supongamos que tiene una clave de partición jerárquica que consta de TenantId>UserId>SessionId. El identificador único del elemento es un GUID. Está representado como una cadena que actúa como identificador de transacción de documento único. Para realizar una lectura puntual en un solo elemento, pase la propiedad id del elemento y el valor completo de la clave de partición, incluidos los tres componentes de la ruta de acceso.

// Store the unique identifier
string id = "f7da01b0-090b-41d2-8416-dacae09fbb4a";

// Build the full partition key path
PartitionKey partitionKey = new PartitionKeyBuilder()
    .Add("Microsoft") //TenantId
    .Add("00aa00aa-bb11-cc22-dd33-44ee44ee44ee") //UserId
    .Add("0000-11-0000-1111") //SessionId
    .Build();

// Perform a point read
ItemResponse<UserSession> readResponse = await container.ReadItemAsync<UserSession>(
    id,
    partitionKey
);

Ejecución de una consulta

El código del SDK que se usa para ejecutar una consulta en un contenedor con particiones secundarias es idéntico a ejecutar una consulta en un contenedor no particionado.

Cuando la consulta especifica todos los valores de las claves de partición en el filtro WHERE o en un prefijo de la jerarquía de claves, el SDK enruta automáticamente la consulta a las particiones físicas correspondientes. Las consultas que proporcionan solo el "centro" de la jerarquía son consultas entre particiones.

Por ejemplo, considere una clave de partición jerárquica compuesta por TenantId>UserId>SessionId. Los componentes del filtro de la consulta determinan si la consulta es una consulta de partición única, una consulta de partición cruzada de destino o una consulta de distribución ramificada.

Consultar Enrutamiento
SELECT * FROM c WHERE c.TenantId = 'Microsoft' AND c.UserId = '00aa00aa-bb11-cc22-dd33-44ee44ee44ee' AND c.SessionId = '0000-11-0000-1111' Enrutada a la única partición lógica y física que contiene los datos de los valores especificados de TenantId, UserId y SessionId.
SELECT * FROM c WHERE c.TenantId = 'Microsoft' AND c.UserId = '00aa00aa-bb11-cc22-dd33-44ee44ee44ee' Enrutada solo al subconjunto de destino de particiones lógicas y físicas que contienen datos para los valores especificados de TenantId y UserId. Esta consulta es una consulta entre particiones dirigida que devuelve datos de un usuario específico del inquilino.
SELECT * FROM c WHERE c.TenantId = 'Microsoft' Enrutada solo al subconjunto de destino de particiones lógicas y físicas que contienen datos para el valor especificado de TenantId. Esta consulta es una consulta entre particiones dirigida que devuelve datos para todos los usuarios de un inquilino.
SELECT * FROM c WHERE c.UserId = '00aa00aa-bb11-cc22-dd33-44ee44ee44ee' Enrutada a todas las particiones físicas, lo que da lugar a una consulta entre particiones de distribución ramificada.
SELECT * FROM c WHERE c.SessionId = '0000-11-0000-1111' Enrutada a todas las particiones físicas, lo que da lugar a una consulta entre particiones de distribución ramificada.

Consulta de partición única en un contenedor con particiones secundarias

Este es un ejemplo de ejecución de una consulta que incluye todos los niveles de subparticiones, lo que la convierte eficazmente en una consulta de partición única.

// Define a single-partition query that specifies the full partition key path
QueryDefinition query = new QueryDefinition(
    "SELECT * FROM c WHERE c.TenantId = @tenant-id AND c.UserId = @user-id AND c.SessionId = @session-id")
    .WithParameter("@tenant-id", "Microsoft")
    .WithParameter("@user-id", "00aa00aa-bb11-cc22-dd33-44ee44ee44ee")
    .WithParameter("@session-id", "0000-11-0000-1111");

// Retrieve an iterator for the result set
using FeedIterator<PaymentEvent> results = container.GetItemQueryIterator<PaymentEvent>(query);

while (results.HasMoreResults)
{
    FeedResponse<UserSession> resultsPage = await resultSet.ReadNextAsync();
    foreach(UserSession result in resultsPage)
    {
        // Process result
    }
}

Consulta de varias particiones dirigida en un contenedor con particiones secundarias

Este es un ejemplo de una consulta que incluye un subconjunto de los niveles de subparticiones lo que la convierte eficazmente en una consulta destinada a varias particiones.

// Define a targeted cross-partition query specifying prefix path[s]
QueryDefinition query = new QueryDefinition(
    "SELECT * FROM c WHERE c.TenantId = @tenant-id")
    .WithParameter("@tenant-id", "Microsoft")

// Retrieve an iterator for the result set
using FeedIterator<PaymentEvent> results = container.GetItemQueryIterator<PaymentEvent>(query);

while (results.HasMoreResults)
{
    FeedResponse<UserSession> resultsPage = await resultSet.ReadNextAsync();
    foreach(UserSession result in resultsPage)
    {
        // Process result
    }
}

Limitaciones y problemas conocidos

  • El trabajo con contenedores que utilizan claves de partición jerárquicas solo se admite en el SDK de .NET v3, en el SDK de Java v4, en el SDK de Python y en la versión preliminar del SDK de JavaScript. Debe usar el SDK compatible para crear nuevos contenedores que tengan claves de partición jerárquicas y realizar operaciones CRUD o consultas en los datos. La compatibilidad con otros SDK, incluido Python, no está disponible actualmente.
  • Existen limitaciones con varios conectores de Azure Cosmos DB (por ejemplo, con Azure Data Factory).
  • Solo puede especificar claves de partición jerárquicas de hasta tres capas en profundidad.
  • Actualmente, las claves de partición jerárquica solo se pueden habilitar en contenedores nuevos. Debe establecer rutas de acceso de clave de partición en el momento de la creación del contenedor y no puede cambiarlas más adelante. Para usar particiones jerárquicas en contenedores existentes, cree un nuevo contenedor con las claves de partición jerárquicas establecidas y mover los datos mediante trabajos de copia de contenedores.
  • Actualmente, las claves de partición jerárquicas solo son compatibles con las cuentas de API para NoSQL. Actualmente no se admiten las API de MongoDB ni de Cassandra.
  • No se admiten actualmente las claves de partición jerárquicas con la característica de usuarios y permisos. No se puede asignar un permiso a un prefijo parcial de la ruta de acceso de la clave de partición jerárquica. Los permisos solo se pueden asignar a toda la ruta de acceso de la clave de partición lógica. Por ejemplo, si ha particionado por TenantId, >UserId, no puede asignar un permiso que sea para un valor específico de TenantId. Sin embargo, puede asignar un permiso para una clave de partición si especifica el valor de TenantId y "UserId".

Pasos siguientes