diff --git a/source/crud/configure.txt b/source/crud/configure.txt index f2e20e7b..175dd382 100644 --- a/source/crud/configure.txt +++ b/source/crud/configure.txt @@ -8,4 +8,333 @@ Configure CRUD Operations :local: :backlinks: none :depth: 2 - :class: singlecol \ No newline at end of file + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: customize, preferences, replica set, consistency, kotlin + +Overview +-------- + +In this guide, you can learn how to configure **write concern**, **read concern**, +and **read preference** options to modify the way that the {+driver-short+} runs +read and write operations on replica sets. + +Read and Write Settings Precedence +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can set write concern, read concern, and read preference options at the following +levels: + +- Client, which sets the *default for all operation executions* unless overridden +- Transaction +- Database +- Collection + +This list also indicates the increasing order of precedence of the option settings. For +example, if you set a read concern for a transaction, it will override the read +concern settings inherited from the client. + +Write concern, read concern, and read preference options allow you to customize the +causal consistency and availability of the data in your replica sets. To see a full +list of these options, see the following guides in the {+mdb-server+} manual: + +- :manual:`Read Preference ` +- :manual:`Read Concern ` +- :manual:`Write Concern ` + +.. _kotlin-sync-read-write-config: + +Configure Read and Write Operations +----------------------------------- + +You can control how the driver routes read operations among replica set members +by setting a read preference. You can also control how the driver waits for +acknowledgment of read and write operations on a replica set by setting read and +write concerns. + +The following sections show how to configure these read and write settings +at various levels. + +.. _kotlin-sync-read-write-client: + +Client Configuration +~~~~~~~~~~~~~~~~~~~~ + +This example shows how to set the read preference, read concern, and +write concern of a ``MongoClient`` instance by passing a ``MongoClientSettings`` +instance to the ``MongoClient.create()`` method. The code configures the +following settings: + +- ``secondary`` read preference: Read operations retrieve data from + secondary replica set members. +- ``LOCAL`` read concern: Read operations return the instance's most recent data + without guaranteeing that the data has been written to a majority of the replica + set members. +- ``W2`` write concern: The primary replica set member and one secondary member + must acknowledge the write operation. + +.. literalinclude:: /includes/configure-crud.kt + :language: kotlin + :dedent: + :start-after: start-client-settings + :end-before: end-client-settings + +Alternatively, you can specify the read and write settings in the connection +URI, which is passed as a parameter to the ``MongoClient.create()`` method: + +.. literalinclude:: /includes/configure-crud.kt + :language: kotlin + :dedent: + :start-after: start-client-settings-uri + :end-before: end-client-settings-uri + +.. _kotlin-sync-read-write-transaction: + +Transaction Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~ + +This example shows how to set the read preference, read concern, and +write concern of a transaction by passing a ``TransactionOptions`` +instance to the ``withTransaction()`` method. Transactions run within +**sessions**, which are groupings of related read or write operations that you +intend to run sequentially. Before applying the transaction options, use the +``startSession()`` method to start a session. + +.. tip:: + + To learn more about sessions, see :manual:`Server Sessions ` + in the {+mdb-server+} manual. + +The example configures the following settings: + +- ``primary`` read preference: Read operations retrieve data from + the primary replica set member. +- ``MAJORITY`` read concern: Read operations return the instance's most recent data + that has been written to a majority of replica set members. +- ``W1`` write concern: The primary replica set member must acknowledge the + write operation. + +.. literalinclude:: /includes/configure-crud.kt + :language: kotlin + :dedent: + :start-after: start-transaction-settings + :end-before: end-transaction-settings + +.. _kotlin-sync-read-write-database: + +Database Configuration +~~~~~~~~~~~~~~~~~~~~~~ + +This example shows how to set the read preference, read concern, and +write concern of a database called ``test_database`` by chaining setter +methods to the ``getDatabase()`` method. The code configures the following +settings: + +- ``primaryPreferred`` read preference: Read operations retrieve data from + the primary replica set member, or secondary members if the primary is unavailable. +- ``AVAILABLE`` read concern: Read operations return the instance's most recent data + without guaranteeing that the data has been written to a majority of the replica + set members. +- ``MAJORITY`` write concern: The majority of all replica set members + must acknowledge the write operation. + +.. literalinclude:: /includes/configure-crud.kt + :language: kotlin + :dedent: + :start-after: start-database-settings + :end-before: end-database-settings + +.. _kotlin-sync-read-write-collection: + +Collection Configuration +~~~~~~~~~~~~~~~~~~~~~~~~ + +This example shows how to set the read preference, read concern, and +write concern of a collection called ``test_collection`` by chaining setter +methods to the ``getCollection()`` method. The code configures the following +settings: + +- ``secondaryPreferred`` read preference: Read operations retrieve data from + secondary replica set members, or the primary members if no secondary members are + available. +- ``AVAILABLE`` read concern: Read operations return the instance's most recent data + without guaranteeing that the data has been written to a majority of the replica + set members. +- ``UNACKNOWLEDGED`` write concern: Replica set members do not need to acknowledge + the write operation. + +.. literalinclude:: /includes/configure-crud.kt + :language: kotlin + :dedent: + :start-after: start-collection-settings + :end-before: end-collection-settings + +.. _kotlin-sync-read-write-advanced: + +Advanced Read Configurations +---------------------------- + +The following sections describe ways to further customize how the {+driver-short+} +routes read operations. + +.. _kotlin-sync-sharded-clusters: + +Sharded Clusters +~~~~~~~~~~~~~~~~ + +You can specify a read preference when connecting to a sharded cluster. +MongoDB uses sharding to divide datasets by key ranges and distribute data across multiple +database instances. A sharded cluster, or the set of nodes in a sharded deployment, +includes the following components: + +- **Shard**: A replica set that contains a subset of the sharded data. +- **Mongos**: A query router that provides an interface between your + application and the sharded cluster. +- **Config servers**: Servers that store the cluster's configuration settings + and metadata. + +.. tip:: + + To learn more about sharded clusters, see :manual:`Sharding ` + in the {+mdb-server+} manual. + +When reading from the replica set shards, ``mongos`` applies your specified read +preference. The read preference is re-evaluated for each operation. + +The following example shows how to connect to a sharded cluster and specify a +``secondary`` read preference in your connection string: + +.. literalinclude:: /includes/configure-crud.kt + :language: kotlin + :dedent: + :start-after: start-sharded-cluster-uri + :end-before: end-sharded-cluster-uri + +.. _kotlin-sync-tag-sets: + +Tag Sets +~~~~~~~~ + +In {+mdb-server+}, you can apply key-value :manual:`tags +` to replica set members +according to any criteria you choose. You can then use those +tags to target one or more members for a read operation. + +By default, the {+driver-short+} ignores tags when choosing a member +to read from. To instruct the {+driver-short+} to prefer certain tags, +pass the tags as a list to your read preference setter method. + +Suppose you are connected to a replica set that contains members hosted +at multiple data centers across the United States. You want the driver to +prefer reads from secondary replica set members in the following order: + +1. Members from the New York data center, tagged with ``("dc", "ny")`` +#. Members from the San Francisco data center, tagged with ``("dc", "sf")`` +#. Any secondary members + +This code example passes a list of tags representing the preceding replica +set members to the ``ReadPreference.secondary()`` setter method. Then, the code +passes the read preference information to the ``withReadPreference()`` method +to set the read order on the database: + +.. literalinclude:: /includes/configure-crud.kt + :language: kotlin + :dedent: + :start-after: start-tag-set + :end-before: end-tag-set + +Load Balancing +~~~~~~~~~~~~~~ + +When connecting to a sharded cluster or a replica set, the {+driver-short+} uses +**load balancing** to handle read and write requests. Load balancing allows the driver to +distribute these requests across multiple servers, which avoids overwhelming +any one server and ensures optimal performance. + +When connecting to a sharded cluster, the {+driver-short+} determines the closest ``mongos`` +instance by calculating which one has the lowest network round-trip time. Then, the driver +determines the latency window by adding this ``mongos``'s average round-trip time to the +:ref:`localThresholdMS value `. The driver load balances requests +across up to two random ``mongos`` instances that fall within the latency window. For each request, +the driver chooses the server with the lower operation load by determining its ``operationCount`` +value. + +When connecting to a replica set, the {+driver-short+} first selects replica set members +according to your read preference. Then, the driver follows the same process as +described in the preceding paragraph. After calculating the latency window, the driver +selects up to two random replica set members that fall within the window and chooses +the member with the lower ``operationCount`` value to receive the request. + +.. tip:: + + To learn more about load balancing, see :manual:`Sharded Cluster Balancer + ` in the {+mdb-server+} manual. + +.. _kotlin-sync-local-threshold: + +Local Threshold +``````````````` + +The {+driver-short+} uses the local threshold value to calculate the +latency window for server selection. This value determines the servers +that are eligible to receive read and write requests. + +By default, the driver uses only ``mongos`` instances or replica set members whose +ping times are within 15 milliseconds of the nearest server. To +distribute reads among servers with higher latencies, set the ``localThreshold`` +option in a ``MongoClientSettings`` instance or the ``localThresholdMS`` option +in your connection URI. + +.. note:: + + When selecting replica set members from a single ``mongos`` instance, the + {+driver-short+} ignores the ``localThresholdMS`` option. In this case, use the + :manual:`localThreshold ` + command-line option. + +The following example connects to a replica set and specifies a local threshold +of 35 milliseconds. Select the :guilabel:`MongoClientSettings` or :guilabel:`Connection URI` +tab to see corresponding code for each approach: + +.. tabs:: + + .. tab:: MongoClientSettings + :tabid: settings + + .. literalinclude:: /includes/configure-crud.kt + :language: rust + :dedent: + :start-after: start-local-threshold-settings + :end-before: end-local-threshold-settings + + + .. tab:: Connection URI + :tabid: uri + + .. literalinclude:: /includes/configure-crud.kt + :language: rust + :dedent: + :start-after: start-local-threshold-uri + :end-before: end-local-threshold-uri + +In the preceding example, the {+driver-short+} distributes reads among matching members +within 35 milliseconds of the closest member's ping time. + +API Documentation +----------------- + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- `MongoClient <{+driver-api+}/-mongo-client/index.html>`__ +- `MongoClientSettings <{+core-api+}/MongoClientSettings.html>`__ +- `TransactionOptions <{+core-api+}/TransactionOptions.html>`_ +- `startTransaction() <{+driver-api+}/-client-session/start-transaction.html>`__ +- `MongoDatabase <{+driver-api+}/-mongo-database/index.html>`__ +- `MongoCollection <{+driver-api+}/-mongo-collection/index.html>`__ +- `TagSet <{+core-api+}/TagSet.html>`_ \ No newline at end of file diff --git a/source/includes/configure-crud.kt b/source/includes/configure-crud.kt new file mode 100644 index 00000000..3d5150dd --- /dev/null +++ b/source/includes/configure-crud.kt @@ -0,0 +1,111 @@ +import org.bson.Document +import com.mongodb.ConnectionString +import com.mongodb.MongoClientSettings +import com.mongodb.ReadConcern +import com.mongodb.ReadPreference +import com.mongodb.Tag +import com.mongodb.TagSet +import com.mongodb.TransactionOptions +import com.mongodb.WriteConcern +import com.mongodb.kotlin.client.MongoClient +import java.util.concurrent.TimeUnit + +fun main() { + // Uses the settings builder methods to set read and write settings for the client + // start-client-settings + val settings = MongoClientSettings.builder() + .applyConnectionString(ConnectionString("mongodb://localhost:27017/")) + .readPreference(ReadPreference.secondary()) + .readConcern(ReadConcern.LOCAL) + .writeConcern(WriteConcern.W2) + .build() + + val mongoClient = MongoClient.create(settings) + // end-client-settings + + // Uses connection URI parameters to set read and write settings for the client + // start-client-settings-uri + val uri = "mongodb://localhost:27017/?readPreference=secondary&w=2&readConcernLevel=local" + val uriClient = MongoClient.create(uri) + // end-client-settings-uri + + // Sets read and write settings for the transaction + // start-transaction-settings + 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() + + session.withTransaction({ + // Specify transaction operations here + }, txnOptions) + } catch (e: Exception) { + println("Transaction failed: ${e.message}") + } + } + // end-transaction-settings + + // Sets read and write settings for the "test_database" database + // start-database-settings + val database = mongoClient.getDatabase("test_database") + .withReadPreference(ReadPreference.primaryPreferred()) + .withReadConcern(ReadConcern.AVAILABLE) + .withWriteConcern(WriteConcern.MAJORITY) + // end-database-settings + + // Sets read and write settings for the "test_collection" collection + // start-collection-settings + val collection = database.getCollection("test_collection") + .withReadPreference(ReadPreference.secondaryPreferred()) + .withReadConcern(ReadConcern.AVAILABLE) + .withWriteConcern(WriteConcern.UNACKNOWLEDGED) + // end-collection-settings + + // Uses connection URI parameters to set a sharded cluster read preference + // start-sharded-cluster-uri + val shardedClient = MongoClient.create( + "mongodb://user:password@mongos1.example.com,mongos2.example.com/?readPreference=secondary" + ) + // end-sharded-cluster-uri + + // Instructs the driver to prefer reads from secondary replica set members + // located in New York, then San Francisco, then fallback to any secondary. + // start-tag-set + 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) + // end-tag-set + + // Instructs the library to distribute reads between members within 35 milliseconds + // of the closest member's ping time using client settings + // start-local-threshold-uri + val latencyClient1 = MongoClient.create( + "mongodb://localhost:27017/?replicaSet=repl0&localThresholdMS=35" + ) + // end-local-threshold-uri + + // Instructs the library to distribute reads between members within 35 milliseconds + // of the closest member's ping time using a URI option + // start-local-threshold-settings + val latencySettings = MongoClientSettings.builder() + .applyConnectionString(ConnectionString("mongodb://localhost:27017/")) + .applyToClusterSettings { builder -> + builder.localThreshold(35, TimeUnit.MILLISECONDS) + } + .build() + + val latencyClient2 = MongoClient.create(latencySettings) + // end-local-threshold-settings + + // Close the MongoClient connection + mongoClient.close() +}