Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /

Consideraciones sobre el rendimiento

En esta guía, aprenderá a optimizar el rendimiento del controlador de Rust. Para conectarse a MongoDB, debe crear un Client instancia. Tu instancia de Client gestiona automáticamente la mayoría de los aspectos de la conexión, como el descubrimiento de la topología del servidor, la supervisión de tu conexión y el mantenimiento de un pool de conexiones internos. Esta guía describe las mejores prácticas para configurar y utilizar tu instancia Client.

Esta guía incluye las siguientes secciones:

  • Ciclo de vida del cliente describe las mejores prácticas para crear y gestionar una instancia Client

  • agrupamiento de conexiones describe cómo funciona el pool de conexiones en el driver

  • Paralelismo proporciona código de muestra para ejecutar tareas paralelas y asíncronas.

  • Tiempo de ejecución describe cómo gestionar los tiempos de ejecución utilizando funcionalidades de las cajas tokio y async_std

  • Información adicional proporciona enlaces a recursos y documentación de la API para los tipos y métodos mencionados en esta guía

Se recomienda reutilizar el cliente en sesiones y operaciones. Puedes utilizar la misma instancia Client para realizar múltiples tareas, ya que el tipo Client es seguro para el uso concurrente de múltiples hilos. Crear una nueva instancia Client para cada solicitud genera un desempeño más lento.

El siguiente código crea un método que acepta un puntero a una instancia Client existente, lo que le permite realizar muchas solicitudes utilizando el mismo cliente:

// ... Create a client earlier in your code
async fn make_request(client: &Client) -> Result<(), Box<dyn Error>> {
// Use the client to perform operations
Ok(())
}

Cada instancia de Client tiene un pool de conexiones integrado para cada servidor en tu topología de MongoDB. Los pools de conexiones abren sockets on-demand para admitir solicitudes concurrentes a MongoDB en tu aplicación.

La configuración por defecto para un Client funciona para la mayoría de las aplicaciones. El siguiente código muestra cómo crear un cliente con la configuración de conexión por defecto:

let client = Client::with_uri_str("<connection string>").await?;

Alternativamente, puede ajustar el pool de conexiones para que se adapte mejor a las necesidades de su aplicación y optimice el rendimiento. Para obtener más información sobre cómo personalizar la configuración de conexión, consulte las siguientes subsecciones de esta guía:

Tip

Para obtener más información sobre cómo configurar un pool de conexiones, consulte Ajuste de la configuración de su pool de conexiones en el manual del servidor.

El tamaño máximo de cada pool de conexiones se configura mediante la opción max_pool_size, cuyo valor por defecto es 10. Si el número de conexiones en uso de un servidor alcanza el valor de max_pool_size, la siguiente solicitud a ese servidor esperará hasta que una conexión esté disponible.

Además de los sockets necesarios para admitir las solicitudes de tu aplicación, cada instancia de Client abre dos sockets adicionales por servidor en tu topología de MongoDB para la supervisión del estado del servidor. Por ejemplo, un cliente conectado a un set de réplicas de tres nodos abre seis sockets de supervisión. Si la aplicación utiliza la configuración por defecto para max_pool_size y solo hace query al nodo primario (por defecto), entonces puede haber un máximo de 16 conexiones totales en el pool de conexiones. Si la aplicación utiliza una preferencia de lectura para query los nodos secundarios, esos grupos de conexiones crecen y puede haber 36 conexiones totales.

Para admitir un gran número de solicitudes simultáneas de MongoDB dentro de un proceso, puedes aumentar el valor de la opción max_pool_size. El siguiente código demuestra cómo especificar un valor para max_pool_size al crear una instancia de un Client:

let mut client_options = ClientOptions::parse("<connection string>").await?;
client_options.max_pool_size = Some(20);
let client = Client::with_options(client_options)?;

Los pools de conexiones tienen limitaciones de velocidad. La opción max_connecting determina cuántas conexiones puede crear el pool en paralelo en cualquier momento. Por ejemplo, si el valor de max_connecting es 2, el valor por defecto, la tercera solicitud que intenta obtener una conexión simultáneamente solo tiene éxito cuando ocurre uno de los siguientes casos:

  • El pool de conexiones termina de crear una conexión y el número de conexiones en el pool es menor o igual al valor de max_pool_size.

  • Se vuelve a registrar una conexión existente en el pool.

  • La capacidad del driver de reutilizar conexiones existentes mejora debido a los límites de frecuencia en la creación de conexiones.

Puede establecer el número mínimo de conexiones simultáneas a cada servidor con la opción min_pool_size, cuyo valor predeterminado es 0. El controlador inicializa el pool de conexiones con este número de sockets. Si se cierran los sockets y el número total de sockets, tanto en uso como inactivos, cae por debajo del mínimo, el pool de conexiones abre más sockets hasta alcanzarlo.

El código siguiente establece las opciones max_connecting y min_pool_size al crear una instancia de Client:

let mut client_options = ClientOptions::parse("<connection string>").await?;
client_options.max_connecting = Some(3);
client_options.min_pool_size = Some(1);
let client = Client::with_options(client_options)?;

Puede establecer el tiempo máximo que una conexión puede permanecer inactiva en el pool configurando la opción max_idle_time. Una vez que una conexión ha estado inactiva durante el tiempo especificado en max_idle_time, el pool la elimina y la reemplaza. Esta opción tiene como valor predeterminado 0, es decir, sin límite.

Cuando se llama al método Client::shutdown() en cualquier momento en su aplicación, el driver cierra todos los sockets inactivos y cierra todos los sockets en uso cuando se devuelven al pool. Al invocar Client::shutdown() solo se cierran los sockets inactivos, por lo que no puede interrumpir ni terminar ninguna operación en curso utilizando este método. El controlador cierra estos sockets solo cuando el proceso se completa.

El siguiente código establece el valor de la opción max_idle_time en 90 segundos al instanciar un Client:

let mut client_options = ClientOptions::parse("<connection string>").await?;
client_options.max_idle_time = Some(Duration::new(90, 0));
let client = Client::with_options(client_options)?;

Si puedes ejecutar operaciones de datos en paralelo, puedes optimizar el rendimiento ejecutando tareas asíncronas y concurrentes. El siguiente código utiliza el método spawn() del módulo tokio::task para crear tareas independientes y concurrentes con el fin de realizar operaciones de inserción:

let client = Client::with_uri_str("<connection string>").await?;
let data = doc! { "title": "1984", "author": "George Orwell" };
for i in 0..5 {
let client_ref = client.clone();
let data_ref = data.clone();
task::spawn(async move {
let collection = client_ref
.database("items")
.collection::<Document>(&format!("coll{}", i));
collection.insert_one(data_ref).await
});
}

Una instancia de Client está vinculada a la instancia del entorno de ejecución tokio o async-std en la que se creó. Si utiliza una instancia Client para realizar operaciones en un entorno de ejecución diferente, podría experimentar comportamientos inesperados o errores.

Si usa el macro asistente test de la caja tokio o async_std para probar su aplicación, podría ejecutar operaciones accidentalmente en un entorno diferente al previsto. Esto se debe a que estos macros asistentes crean un nuevo entorno en tiempo de ejecución para cada prueba. Sin embargo, puedes utilizar una de las siguientes estrategias para evitar este problema:

  • Adjunta el runtime a la instancia Client sin usar los macros asistentes test.

  • Crea una nueva instancia de Client para cada prueba de async.

Este ejemplo sigue la primera estrategia y crea un entorno de ejecución global que se usa solo para pruebas. En el siguiente código, el método test_list_dbs() utiliza un cliente que se conecta manualmente a este entorno de ejecución para listar las bases de datos en la implementación:

use tokio::runtime::Runtime;
use once_cell::sync::Lazy;
static CLIENT_RUNTIME: Lazy<(Client, Runtime)> = Lazy::new(|| {
let rt = Runtime::new().unwrap();
let client = rt.block_on(async {
Client::with_uri_str("<connection string>").await.unwrap()
});
(client, rt)
});
#[test]
fn test_list_dbs() -> Result<(), Box<dyn Error>> {
let (client, rt) = &*CLIENT_RUNTIME;
rt.block_on(async {
client.list_database_names().await
})?;
Ok(())
}

Al implementar la segunda estrategia, el siguiente código crea una nueva instancia Client para cada ejecución de prueba con tokio::test, asegurando que no haya interacciones no deseadas entre los entornos de ejecución:

#[tokio::test]
async fn test_list_dbs() -> Result<(), Box<dyn Error>> {
let client = Client::with_uri_str("<connection string>").await?;
client.list_database_names().await?;
Ok(())
}

Para obtener más información sobre cómo conectarse a MongoDB, consulte la Guía de conexión.

Para obtener más información sobre los tiempos de ejecución disponibles para el controlador Rust, consulte la guía sobre API asincrónicas y sincrónicas.

Volver

Comandos de base de datos

En esta página