Overview
En esta guía, puede aprender a configurar las opciones de preocupación de escritura, preocupación de lectura y preferencia de lectura para modificar la forma en que el controlador Kotlin ejecuta operaciones de lectura y escritura en conjuntos de réplicas.
Precedencia de configuración de lectura y escritura
Puede establecer opciones de preocupación de escritura, preocupación de lectura y preferencia de lectura en los siguientes niveles:
Cliente, que establece el valor predeterminado para todas las ejecuciones de operaciones a menos que se anule
Transacción
Database
Colección
Esta lista también indica el orden de precedencia creciente de la configuración de las opciones. Por ejemplo, si se configura una preocupación de lectura para una transacción, esta anulará la configuración de preocupación de lectura heredada del cliente.
Las opciones de escritura, lectura y preferencia de lectura permiten personalizar la consistencia causal y la disponibilidad de los datos en los conjuntos de réplicas. Para ver una lista completa de estas opciones, consulte las siguientes guías en el manual del servidor MongoDB:
Configurar operaciones de lectura y escritura
Puede controlar cómo el controlador enruta las operaciones de lectura entre los miembros del conjunto de réplicas configurando una preferencia de lectura. También puede controlar cómo el controlador espera la confirmación de las operaciones de lectura y escritura en un conjunto de réplicas configurando preocupaciones de lectura y escritura.
Las siguientes secciones muestran cómo configurar estos ajustes de lectura y escritura en varios niveles.
Configuración del cliente
Este ejemplo muestra cómo establecer la preferencia de lectura, la preocupación de lectura y la preocupación de escritura de un MongoClient instancia pasando una instancia MongoClientSettings al método MongoClient.create(). El código configura los siguientes ajustes:
secondarypreferencia de lectura: las operaciones de lectura recuperan datos de los miembros del conjunto de réplicas secundarias.LOCALPreocupación de lectura: las operaciones de lectura devuelven los datos más recientes de la instancia sin garantizar que los datos se hayan escrito en la mayoría de los miembros del conjunto de réplicas.W2Preocupación de escritura: el miembro principal del conjunto de réplicas y un miembro secundario deben reconocer la operación de escritura.
val settings = MongoClientSettings.builder() .applyConnectionString(ConnectionString("mongodb://localhost:27017/")) .readPreference(ReadPreference.secondary()) .readConcern(ReadConcern.LOCAL) .writeConcern(WriteConcern.W2) .build() val mongoClient = MongoClient.create(settings)
Como alternativa, puede especificar las configuraciones de lectura y escritura en la URI de conexión, que se pasa como parámetro al método MongoClient.create():
val uri = "mongodb://localhost:27017/?readPreference=secondary&w=2&readConcernLevel=local" val uriClient = MongoClient.create(uri)
Configuración de transacciones
Este ejemplo muestra cómo establecer la preferencia de lectura, el nivel de consistencia de lectura y el nivel de confirmación de escritura (write concern) de una transacción pasando una instancia de TransactionOptions al método startTransaction(). Las transacciones se ejecutan dentro de sesiones, que son agrupaciones de operaciones de lectura o escritura relacionadas que se pretende ejecutar de forma secuencial.
Tip
Para obtener más información sobre las sesiones, consulte Sesiones de servidor en el manual del servidor MongoDB.
El ejemplo configura los siguientes ajustes:
primarypreferencia de lectura: las operaciones de lectura recuperan datos del miembro del conjunto de réplicas principal.MAJORITYpreocupación de lectura: las operaciones de lectura devuelven los datos más recientes de la instancia que se han escrito en la mayoría de los miembros del conjunto de réplicas.W1Preocupación de escritura: el miembro principal del conjunto de réplicas debe reconocer la operación de escritura.
mongoClient.startSession().use { session -> try { // Sets transaction read and write settings val txnOptions = TransactionOptions.builder() .readPreference(ReadPreference.primary()) .readConcern(ReadConcern.MAJORITY) .writeConcern(WriteConcern.W1) .build() runBlocking { session.startTransaction(txnOptions) // Specify transaction operations here session.commitTransaction() } } catch (e: Exception) { println("Transaction failed: ${e.message}") } }
Configuración de la base de datos
Este ejemplo muestra cómo establecer la preferencia de lectura, la preocupación de lectura y la preocupación de escritura de una base de datos llamada test_database encadenando métodos setter al método getDatabase(). El código configura los siguientes ajustes:
primaryPreferredpreferencia de lectura: las operaciones de lectura recuperan datos del miembro del conjunto de réplicas principal o de miembros secundarios si el principal no está disponible.AVAILABLEPreocupación de lectura: las operaciones de lectura devuelven los datos más recientes de la instancia sin garantizar que los datos se hayan escrito en la mayoría de los miembros del conjunto de réplicas.MAJORITYnivel de confirmación de escritura (write concern): La mayoría de todos los miembros del set de réplicas deben reconocer la operación de escritura.
val database = mongoClient.getDatabase("test_database") .withReadPreference(ReadPreference.primaryPreferred()) .withReadConcern(ReadConcern.AVAILABLE) .withWriteConcern(WriteConcern.MAJORITY)
Configuración de la colección
Este ejemplo muestra cómo establecer la preferencia de lectura, la preocupación de lectura y la preocupación de escritura de una colección llamada test_collection encadenando métodos setter al método getCollection(). El código configura los siguientes ajustes:
secondaryPreferredpreferencia de lectura: las operaciones de lectura recuperan datos de los miembros del conjunto de réplicas secundarias o de los miembros principales si no hay miembros secundarios disponibles.AVAILABLEPreocupación de lectura: las operaciones de lectura devuelven los datos más recientes de la instancia sin garantizar que los datos se hayan escrito en la mayoría de los miembros del conjunto de réplicas.UNACKNOWLEDGEDPreocupación de escritura: los miembros del conjunto de réplicas no necesitan reconocer la operación de escritura.
val collection = database.getCollection<Document>("test_collection") .withReadPreference(ReadPreference.secondaryPreferred()) .withReadConcern(ReadConcern.AVAILABLE) .withWriteConcern(WriteConcern.UNACKNOWLEDGED)
Configuraciones de lectura avanzadas
Las siguientes secciones describen formas de personalizar aún más la forma en que el controlador Kotlin enruta las operaciones de lectura.
Clústeres fragmentados
Puede especificar una preferencia de lectura al conectarse a un clúster fragmentado. MongoDB utiliza la fragmentación para dividir los conjuntos de datos por rangos de claves y distribuir los datos entre varias instancias de base de datos. Un clúster fragmentado, o el conjunto de nodos en una implementación fragmentada, incluye los siguientes componentes:
Fragmento: un conjunto de réplicas que contiene un subconjunto de los datos fragmentados.
Mongos: un enrutador de consultas que proporciona una interfaz entre su aplicación y el clúster fragmentado.
Servidores de configuración: servidores que almacenan la configuración y los metadatos del clúster.
Tip
Para obtener más información sobre los clústeres fragmentados, consulte Fragmentación en el manual del servidor MongoDB.
Al leer desde los fragmentos del conjunto de réplicas, mongos aplica la preferencia de lectura especificada. Esta preferencia se reevalúa en cada operación.
El siguiente ejemplo muestra cómo conectarse a un clúster fragmentado y especificar una preferencia de lectura secondary en su cadena de conexión:
val shardedClient = MongoClient.create( "mongodb://user:password@mongos1.example.com,mongos2.example.com/?readPreference=secondary" )
Conjuntos de etiquetas
En el servidor MongoDB, puede aplicar etiquetas clave-valor a los miembros del conjunto de réplicas según el criterio que elija. Después, puede usar esas etiquetas para seleccionar uno o más miembros para una operación de lectura.
De forma predeterminada, el controlador de Kotlin ignora las etiquetas al elegir un miembro para leer. Para indicarle que prefiera ciertas etiquetas, páselas como una lista a su método de configuración de preferencias de lectura.
Supongamos que está conectado a un conjunto de réplicas que contiene miembros alojados en varios centros de datos en Estados Unidos. Quiere que el controlador prefiera las lecturas de los miembros del conjunto de réplicas secundario en el siguiente orden:
Miembros del centro de datos de Nueva York, etiquetados con
("dc", "ny")Miembros del centro de datos de San Francisco, etiquetados con
("dc", "sf")Cualquier miembro secundario
Este ejemplo de código pasa una lista de etiquetas que representan los miembros del conjunto de réplicas anterior al método de establecimiento ReadPreference.secondary(). A continuación, el código pasa la información de preferencia de lectura al método withReadPreference() para establecer el orden de lectura en la base de datos:
val tag1 = TagSet(Tag("dc", "ny")) val tag2 = TagSet(Tag("dc", "sf")) val tag3 = TagSet() // Empty tag set as fallback val readPref = ReadPreference.secondary(listOf(tag1, tag2, tag3)) val taggedDb = mongoClient.getDatabase("test_database") .withReadPreference(readPref)
Equilibrio de carga
Al conectarse a un clúster fragmentado o a un conjunto de réplicas, el controlador Kotlin utiliza el balanceo de carga para gestionar las solicitudes de lectura y escritura. El balanceo de carga permite al controlador distribuir estas solicitudes entre varios servidores, lo que evita la sobrecarga de un servidor y garantiza un rendimiento óptimo.
Al conectarse a un clúster fragmentado, el controlador de Kotlin determina la instancia más cercana mongos calculando cuál tiene el menor tiempo de ida y vuelta de red. A continuación, el controlador determina la ventana de latencia sumando el mongos tiempo de ida y vuelta promedio de esta instancia al valor de localThresholdMS. El controlador distribuye la carga de las solicitudes entre hasta dos instancias aleatorias mongos dentro de la ventana de latencia. Para cada solicitud, el controlador elige el servidor con la menor carga operativa determinando su operationCount valor.
Al conectarse a un conjunto de réplicas, el controlador de Kotlin primero selecciona los miembros del conjunto según sus preferencias de lectura. A continuación, sigue el mismo proceso descrito en el párrafo anterior. Tras calcular la ventana de latencia, selecciona hasta dos miembros aleatorios del conjunto de réplicas que se encuentren dentro de la ventana y elige el miembro con el valor operationCount más bajo para recibir la solicitud.
Tip
Para obtener más información sobre el equilibrio de carga, consulte Sharded Cluster Balancer en el manual del servidor MongoDB.
Umbral local
El controlador Kotlin utiliza el valor del umbral local para calcular la ventana de latencia para la selección del servidor. Este valor determina los servidores que pueden recibir solicitudes de lectura y escritura.
De forma predeterminada, el controlador solo utiliza instancias mongos o miembros del conjunto de réplicas cuyos tiempos de ping se encuentran a menos de 15 milisegundos del servidor más cercano. Para distribuir las lecturas entre servidores con latencias más altas, configure la opción localThreshold en una instancia MongoClientSettings o la opción localThresholdMS en la URI de su conexión.
Nota
Al seleccionar miembros del conjunto de réplicas de una sola mongos instancia, el controlador de Kotlin ignora la localThresholdMS opción. En este caso, utilice la opción de línea de comandos localThreshold.
El siguiente ejemplo se conecta a un conjunto de réplicas y especifica un umbral local de 35 milisegundos. Seleccione el MongoClientSettings o la pestaña Connection URI para ver el código correspondiente para cada enfoque:
val latencySettings = MongoClientSettings.builder() .applyConnectionString(ConnectionString("mongodb://localhost:27017/")) .applyToClusterSettings { builder -> builder.localThreshold(35, TimeUnit.MILLISECONDS) } .build() val latencyClient2 = MongoClient.create(latencySettings)
val latencyClient1 = MongoClient.create( "mongodb://localhost:27017/?replicaSet=repl0&localThresholdMS=35" )
En el ejemplo anterior, el controlador Kotlin distribuye lecturas entre los miembros coincidentes dentro de 35 milisegundos del tiempo de ping del miembro más cercano.
Lecturas y escrituras reintentables
El driver de Kotlin reintenta automáticamente algunas operaciones de lectura y guardado una sola vez si fallan debido a un error de red o del servidor.
Puede deshabilitar explícitamente las lecturas o escrituras reintentables configurando la opción retryReads o retryWrites en false en una instancia MongoClientSettings. También puede configurar las opciones retryReads o retryWrites en la URI de su conexión.
El siguiente ejemplo establece las lecturas y escrituras reintentables en false. Seleccione la pestaña MongoClientSettings o Connection URI para ver el código correspondiente a cada enfoque:
val retrySettings = MongoClientSettings.builder() .applyConnectionString(ConnectionString("mongodb://localhost:27017/")) .retryReads(false) // Disables automatic retries of read operations .retryWrites(false) // Disables automatic retries of write operations .build() val retryClient = MongoClient.create(retrySettings)
val retryUri = "mongodb://localhost:27017/?retryReads=false&retryWrites=false" val retryUriClient = MongoClient.create(retryUri)
Para obtener más información sobre las operaciones de lectura reintentable compatibles, consulte "Lecturas reintentables" en el manual del servidor MongoDB. Para obtener más información sobre las operaciones de escritura reintentable compatibles, consulte "Escrituras reintentables" en el manual del servidor MongoDB.
Documentación de la API
Para aprender más sobre cualquiera de los métodos o tipos analizados en esta guía, consulta la siguiente documentación de API: