Procedimientos recomendados para el SDK de .NET de Azure Cosmos DB

SE APLICA A: NoSQL

Este artículo le guía por los procedimientos recomendados para usar el SDK de .NET de Azure Cosmos DB. Seguir estos procedimientos le ayudará a mejorar su latencia, disponibilidad y mejorar el rendimiento general.

¡Vea el vídeo siguiente para obtener más información sobre el uso del SDK de .NET de un ingeniero de Azure Cosmos DB!

Lista de comprobación

Activada Asunto Detalles o vínculos
Versión del SDK Use siempre la versión más reciente del SDK de Azure Cosmos DB disponible para obtener un rendimiento óptimo.
Cliente singleton Use una sola instancia de CosmosClientdurante la vigencia de la aplicación para mejorar el rendimiento.
Regions Asegúrese de ejecutar la aplicación en la misma región de Azure que su cuenta de Azure Cosmos DB, siempre que sea posible, para reducir la latencia. Habilite de 2 a 4 regiones y replique las cuentas en varias regiones para obtener la máxima disponibilidad. Para cargas de trabajo de producción, habilite la conmutación por error administrada por el servicio. En ausencia de esta configuración, la cuenta experimentará la pérdida de la disponibilidad de escritura durante todo el tiempo que dure la interrupción de la región de escritura, ya que la conmutación por error manual no se realizará correctamente debido a la falta de conectividad con la región. Para aprender a agregar varias regiones mediante el SDK de .NET, visite este vínculo.
Disponibilidad y conmutaciones por error Establezca ApplicationPreferredRegions o ApplicationRegion en el SDK v3 y PreferredLocations en el SDK v2 mediante la lista de regiones preferidas. Durante las conmutaciones por error, las operaciones de escritura se envían a la región de escritura actual y todas las lecturas se envían a la primera región de la lista de regiones preferidas. Para más información sobre la mecánica de conmutación por error regional, consulte la guía de solución de problemas de disponibilidad.
CPU Es posible que experimente problemas de conectividad o disponibilidad debido a falta de recursos en el equipo cliente. Supervise el uso de la CPU en los nodos que ejecutan el cliente de Azure Cosmos DB y escale vertical u horizontalmente si el uso es alto.
Hosting Use el procesamiento de host de 64 bits de Windows para obtener el mejor rendimiento, siempre que sea posible. En las cargas de trabajo de producción dependientes de la latencia del modo Directo, se recomienda encarecidamente usar máquinas virtuales de al menos 4 núcleos y 8 GB de memoria siempre que sea posible.
Modos de conectividad Use el modo Directo para obtener el mejor rendimiento. Para instrucciones sobre cómo hacerlo, consulte la documentación del SDK V3 o la documentación del SDK V2.
Redes Si usa una máquina virtual para ejecutar la aplicación, habilite las redes aceleradas en la VM para ayudar con los cuellos de botella debidos al tráfico elevado y reducir la latencia o la inestabilidad de la CPU. También puede considerar la posibilidad de usar una máquina virtual de un extremo superior en la que el uso máximo de CPU sea inferior al 70 %.
Agotamiento de puertos efímeros Para las conexiones dispersas o esporádicas, establecemos IdleConnectionTimeout y PortReuseMode en PrivatePortPool. La propiedad IdleConnectionTimeout ayuda a controlar el tiempo hasta que se cierran las conexiones sin usar. Esto reduce el número de conexiones que no se usan. De forma predeterminada, las conexiones inactivas se mantienen abiertas indefinidamente. El valor establecido debe ser mayor o igual que 10 minutos. Se recomienda usar valores entre 20 minutos y 24 horas. La propiedad PortReuseMode permite al SDK usar un pequeño grupo de puertos efímeros para varios puntos de conexión de destino de Azure Cosmos DB.
Uso de Async/Await Evite las llamadas de bloqueo: Task.Result, Task.Wait y Task.GetAwaiter().GetResult(). Toda la pila de llamadas es asincrónica para beneficiarse de los patrones async/await. Muchas llamadas de bloqueo sincrónicas conducen a la escasez del grupo de subprocesos y a tiempos de respuesta degradados.
Tiempos de espera de un extremo a otro Para obtener tiempos de espera de un extremo a otro, use los parámetros RequestTimeout y CancellationToken. Para más información , visite nuestra guía de solución de problemas de tiempo de espera.
Lógica de reintento Para más información sobre los errores que reintentar y cuáles son los SDK , consulte nuestra guía de diseño. En el caso de las cuentas configuradas con varias regiones, hay algunos escenarios en los que el SDK hará reintentos automáticamente en otras regiones. Para obtener detalles de implementación específicos de .NET, visite el repositorio de origen del SDK.
Almacenamiento en caché de nombres de base de datos o colección Durante el inicio, recupere los nombres de las bases de datos y los contenedores de la configuración o almacénelos en memoria caché. Las llamadas como ReadDatabaseAsync o ReadDocumentCollectionAsync y CreateDatabaseQuery o CreateDocumentCollectionQuery darán lugar a llamadas de metadatos al servicio, que consumen desde el límite de RU reservado por el sistema. CreateIfNotExist también debe usarse solo una vez para configurar la base de datos. En general, estas operaciones rara vez deben realizarse.
Compatibilidad masiva En escenarios en los que es posible que no necesite optimizar la latencia, se recomienda habilitar la compatibilidad masiva para volcar grandes volúmenes de datos.
Consultas en paralelo El SDK de Azure Cosmos DB admite la ejecución de consultas en paralelo para mejorar la latencia y el rendimiento de las consultas. Se recomienda establecer la propiedad MaxConcurrency dentro de QueryRequestsOptions en el número de particiones que tiene. Si no conoce el número de particiones, empiece por usar int.MaxValue, que le dará la mejor latencia. A continuación, reduzca el número hasta que se ajuste a las restricciones de recursos del entorno para evitar problemas elevados de CPU. Además, establezca MaxBufferedItemCount en el número esperado de resultados devueltos para limitar el número de resultados capturados previamente.
Retrocesos de pruebas de rendimiento Al realizar pruebas en la aplicación, debe implementar los retrocesos a intervalos de RetryAfter. Respetar el retroceso ayuda a garantizar una cantidad mínima de tiempo en espera entre reintentos.
Indización La directiva de indexación de Azure Cosmos DB también le permite especificar las rutas de acceso de documentos que se van a incluir o excluir de la indexación mediante rutas de acceso de indexación (IndexingPolicy.IncludedPaths e IndexingPolicy.ExcludedPaths). Asegúrese de excluir las rutas de acceso sin utilizar de la indexación para acelerar las escrituras. Para obtener más información sobre cómo crear índices mediante el SDK, consulte Sugerencias de rendimiento del SDK de .NET v3.
Tamaño del documento El cargo de la solicitud de una operación determinada se correlaciona directamente con el tamaño del documento. Se recomienda reducir el tamaño de los documentos, ya que las operaciones en documentos grandes cuestan más que las operaciones en documentos más pequeños.
Aumentar el número de subprocesos o tareas Como las llamadas a Azure Cosmos DB se realizan a través de la red, es posible que tenga que cambiar el grado de simultaneidad de las solicitudes para que la aplicación cliente dedique un tiempo mínimo a esperar entre solicitudes. Por ejemplo, si usa la biblioteca TPL de .NET, cree en el orden de cientos de tareas que leen o escriben en Azure Cosmos DB.
Habilitación de métricas de consulta Para el registro adicional de las ejecuciones de consultas de back-end, puede habilitar las métricas de consulta SQL mediante nuestro SDK de .NET. Para más información sobre cómo recopilar métricas de consulta SQL, consulte métricas de consulta y rendimiento.
Registro del SDK Diagnósticos del SDK de registro para escenarios pendientes, como las excepciones o cuando las solicitudes superan la latencia esperada.
DefaultTraceListener DefaultTraceListener plantea problemas de rendimiento en entornos de producción que provocan cuellos de botella altos de CPU y E/S. Asegúrese de que usa las versiones más recientes del SDK o quite DefaultTraceListener de la aplicación
Evite utilizar caracteres especiales en los identificadores Algunos caracteres están restringidos y no pueden utilizarse en algunos identificadores: "/", "\", "?", "#". La recomendación general es no utilizar ningún carácter especial en identificadores como el nombre de la base de datos, el nombre de la colección, el id de elemento o la clave de partición para evitar cualquier comportamiento inesperado.

Captura de diagnósticos

Todas las respuestas del SDK, incluida CosmosException, tienen una propiedad Diagnostics. Esta propiedad registra toda la información relacionada con la solicitud única, incluidos los reintentos o errores transitorios.

Los diagnósticos se devuelven como una cadena. La cadena cambia con cada versión a medida que se mejora para ofrecer mejores soluciones a los problemas de los distintos escenarios. Con cada versión del SDK, la cadena tendrá cambios importantes en el formato. No analice la cadena para evitar cambios importantes. En el siguiente ejemplo de código se muestra cómo leer los registros de diagnóstico mediante el SDK de .NET:

try
{
    ItemResponse<Book> response = await this.Container.CreateItemAsync<Book>(item: testItem);
    if (response.Diagnostics.GetClientElapsedTime() > ConfigurableSlowRequestTimeSpan)
    {
        // Log the response.Diagnostics.ToString() and add any additional info necessary to correlate to other logs 
    }
}
catch (CosmosException cosmosException)
{
    // Log the full exception including the stack trace with: cosmosException.ToString()
    
    // The Diagnostics can be logged separately if required with: cosmosException.Diagnostics.ToString()
}

// When using Stream APIs
ResponseMessage response = await this.Container.CreateItemStreamAsync(partitionKey, stream);
if (response.Diagnostics.GetClientElapsedTime() > ConfigurableSlowRequestTimeSpan || !response.IsSuccessStatusCode)
{
    // Log the diagnostics and add any additional info necessary to correlate to other logs with: response.Diagnostics.ToString()
}

Procedimientos recomendados para conexiones HTTP

El SDK de .NET usa HttpClient para realizar solicitudes HTTP independientemente del modo de conectividad configurado. En el modo Directo, HTTP se usa para las operaciones de metadatos y en modo de puerta de enlace, se usa para las operaciones de plano de datos y metadatos. Uno de los aspectos básicos de HttpClient es asegurarse de que HttpClient puede reaccionar a los cambios de DNS en su cuenta personalizando la duración de la conexión agrupada. Siempre que las conexiones agrupadas se mantengan abiertas, no reaccionan a los cambios de DNS. Esta configuración obliga a que las conexiones agrupadas se cierren periódicamente, lo que garantiza que la aplicación reaccione a los cambios de DNS. Nuestra recomendación es que personalice este valor según el modo de conectividad y la carga de trabajo para equilibrar el impacto en el rendimiento de la creación de nuevas conexiones con frecuencia, con la necesidad de reaccionar ante los cambios de DNS (disponibilidad). Un valor de 5 minutos sería un buen comienzo que se puede aumentar si afecta al rendimiento especialmente para el modo de puerta de enlace.

Puede insertar su HttpClient personalizado a través de CosmosClientOptions.HttpClientFactory, por ejemplo:

// Use a Singleton instance of the SocketsHttpHandler, which you can share across any HttpClient in your application
SocketsHttpHandler socketsHttpHandler = new SocketsHttpHandler();
// Customize this value based on desired DNS refresh timer
socketsHttpHandler.PooledConnectionLifetime = TimeSpan.FromMinutes(5);

CosmosClientOptions cosmosClientOptions = new CosmosClientOptions()
{
    // Pass your customized SocketHttpHandler to be used by the CosmosClient
    // Make sure `disposeHandler` is `false`
    HttpClientFactory = () => new HttpClient(socketsHttpHandler, disposeHandler: false)
};

// Use a Singleton instance of the CosmosClient
return new CosmosClient("<connection-string>", cosmosClientOptions);

Si usa la inserción de dependencias de .NET, puede simplificar el proceso singleton:

SocketsHttpHandler socketsHttpHandler = new SocketsHttpHandler();
// Customize this value based on desired DNS refresh timer
socketsHttpHandler.PooledConnectionLifetime = TimeSpan.FromMinutes(5);
// Registering the Singleton SocketsHttpHandler lets you reuse it across any HttpClient in your application
services.AddSingleton<SocketsHttpHandler>(socketsHttpHandler);

// Use a Singleton instance of the CosmosClient
services.AddSingleton<CosmosClient>(serviceProvider =>
{
    SocketsHttpHandler socketsHttpHandler = serviceProvider.GetRequiredService<SocketsHttpHandler>();
    CosmosClientOptions cosmosClientOptions = new CosmosClientOptions()
    {
        HttpClientFactory = () => new HttpClient(socketsHttpHandler, disposeHandler: false)
    };

    return new CosmosClient("<connection-string>", cosmosClientOptions);
});

Procedimientos recomendados al usar el modo de puerta de enlace

Aumente System.Net MaxConnections por host cuando use el modo de puerta de enlace. Las solicitudes de Azure Cosmos DB se realizan mediante HTTPS o REST cuando se usa el modo de puerta de enlace. Están sujetas al límite de conexiones predeterminado por nombre de host o dirección IP. Es posible que tenga que establecer MaxConnections en un valor superior (de 100 a 1000) para que la biblioteca cliente pueda utilizar varias conexiones simultáneas con Azure Cosmos DB. En el SDK de .NET 1.8.0 y versiones posteriores, el valor predeterminado de ServicePointManager.DefaultConnectionLimit es 50. Para cambiar el valor, puede establecer CosmosClientOptions.GatewayModeMaxConnectionLimit en un valor superior.

Prácticas recomendadas para cargas de trabajo de escritura intensiva

En el caso de cargas de trabajo con cargas útiles de operaciones de creación intensivas, establezca la opción de solicitud EnableContentResponseOnWrite en false. El servicio ya no devolverá al SDK el recurso creado o actualizado. Normalmente, dado que la aplicación tiene el objeto que se crea, no necesita que el servicio lo devuelva. Todavía se puede acceder a los valores de encabezado, como un cargo de solicitud. Deshabilitar el contenido de la respuesta puede ayudar a mejorar el rendimiento, porque el SDK ya no tendrá que asignar memoria ni serializar el cuerpo de la respuesta. También reduce el uso de ancho de banda de red para mejorar más el rendimiento.

Importante

Al establecer EnableContentResponseOnWrite en false también se deshabilitará la respuesta de una operación de desencadenador.

Procedimientos recomendados para aplicaciones multiinquilino

Las aplicaciones que distribuyen el uso entre varios inquilinos en los que cada inquilino está representado por una base de datos, un contenedor o una clave de partición diferentes dentro de la misma cuenta de Azure Cosmos DB deben usar una única instancia de cliente. Una única instancia de cliente puede interactuar con todas las bases de datos, contenedores y claves de partición dentro de una cuenta y es recomendable usar el patrón singleton.

Sin embargo, cuando cada inquilino se representa mediante una cuenta de Azure Cosmos DB diferente, es necesario crear una instancia de cliente independiente por cuenta. El patrón singleton se sigue aplicando para cada cliente (un cliente para cada cuenta durante la vigencia de la aplicación), pero si el volumen de inquilinos es alto, el número de clientes puede ser difícil de administrar. Las conexiones pueden aumentar más allá de los límites del entorno de proceso y causar problemas de conectividad.

En estos casos se recomienda lo siguiente:

  • Comprenda las limitaciones del entorno de proceso (recursos de CPU y conexión). Se recomienda usar máquinas virtuales con al menos 4 núcleos y 8 GB de memoria siempre que sea posible.
  • En función de las limitaciones del entorno de proceso, determine el número de instancias de cliente (y, por tanto, el número de inquilinos) que una única instancia de proceso puede controlar. Puede calcular el número de conexiones que se abrirán por cliente en función del modo de conexión elegido.
  • Evalúe la distribución de inquilinos entre instancias. Si cada instancia de proceso puede controlar correctamente una cantidad limitada de inquilinos, el equilibrio de carga y el enrutamiento de los inquilinos a diferentes instancias de proceso permitirían el escalado a medida que crece el número de inquilinos.
  • En el caso de las cargas de trabajo dispersas, puede emplear una caché usada con menos frecuencia como estructura para contener las instancias de cliente y eliminar los clientes de los inquilinos a los que no se ha accedido dentro de un período de tiempo. Una opción en .NET es MemoryCacheEntryOptions, donde RegisterPostEvictionCallback se puede usar para eliminar clientes inactivos y SetSlidingExpiration se puede usar para definir el tiempo máximo para mantener conexiones inactivas.
  • Evalúe el uso del modo de puerta de enlace para reducir el número de conexiones de red.
  • Al usar el modo directo, considere la posibilidad de ajustar CosmosClientOptions.IdleTcpConnectionTimeout y CosmosClientOptions.PortReuseMode en la configuración del modo directo para cerrar las conexiones sin usar y mantener el volumen de conexiones bajo control.

Pasos siguientes

Para obtener una aplicación de ejemplo que se usa para evaluar Azure Cosmos DB en escenarios de alto rendimiento en algunos equipos del cliente, consulte Rendimiento y pruebas de escalado con Azure Cosmos DB.

Para más información sobre cómo diseñar la aplicación para escalarla y obtener un alto rendimiento, consulte Partición y escalado en Azure Cosmos DB.

¿Intenta planear la capacidad de una migración a Azure Cosmos DB? Para ello, puede usar información sobre el clúster de bases de datos existente.