Skip to content

Commit 012b476

Browse files
authored
DOCSP-49056: Server Selection (#618)
1 parent c0ae698 commit 012b476

File tree

3 files changed

+299
-68
lines changed

3 files changed

+299
-68
lines changed
Lines changed: 195 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,195 @@
1-
.. TODO: Server Selection page
2-
3-
Why Does the Driver Throw a Timeout During Server Selection?
4-
------------------------------------------------------------
5-
6-
Each driver operation requires that you choose a healthy server
7-
satisfying the :manual:`server selection criteria
8-
</core/read-preference-mechanics>`. If you do not select an appropriate
9-
server within the `server selection timeout <{+new-api-root+}/MongoDB.Driver.Legacy/MongoDB.Driver.MongoServerSettings.ServerSelectionTimeout.html>`__, the driver throws a
10-
server selection timeout exception. The exception looks similar to the
11-
following:
12-
13-
.. code-block:: none
14-
15-
A timeout occurred after 30000ms selecting a server using CompositeServerSelector{ Selectors = MongoDB.Driver.MongoClient+AreSessionsSupportedServerSelector, LatencyLimitingServerSelector{ AllowedLatencyRange = 00:00:00.0150000 }, OperationsCountServerSelector }.
16-
Client view of cluster state is
17-
{
18-
ClusterId : "1",
19-
Type : "Unknown",
20-
State : "Disconnected",
21-
Servers :
22-
[{
23-
ServerId: "{ ClusterId : 1, EndPoint : "Unspecified/localhost:27017" }",
24-
EndPoint: "Unspecified/localhost:27017",
25-
ReasonChanged: "Heartbeat",
26-
State: "Disconnected",
27-
ServerVersion: ,
28-
TopologyVersion: ,
29-
Type: "Unknown",
30-
HeartbeatException: "<exception details>"
31-
}]
32-
}.
33-
34-
The error message consists of multiple parts:
35-
36-
1. The server selection timeout (30000 ms).
37-
#. The server selectors considered (``CompositeServerSelector``
38-
containing ``AreSessionsSupportedServerSelector``,
39-
``LatencyLimitingServerSelector``, and
40-
``OperationsCountServerSelector``).
41-
#. The driver’s current view of the cluster topology. The list of
42-
servers that the driver is aware of is a key part of this view. Each
43-
server description contains an exhaustive description of its current
44-
state including information about an endpoint, a server version, a
45-
server type, and its current health state. If the server encounters issues in
46-
reporting its health, ``HeartbeatException`` contains the exception from the
47-
last failed heartbeat. Analyzing the ``HeartbeatException`` on each
48-
cluster node can assist in diagnosing most server selection issues.
49-
The following heartbeat exceptions are common:
50-
51-
* ``No connection could be made because the target machine actively
52-
refused it``: The driver cannot see this cluster node. This can be
53-
because the cluster node has crashed, a firewall is preventing
54-
network traffic from reaching the cluster node or port, or some other
55-
network error is preventing traffic from being successfully routed to
56-
the cluster node.
57-
* ``Attempted to read past the end of the stream``: This error
58-
happens when the driver cannot connect to the cluster nodes due to a
59-
network error, misconfigured firewall, or other network issue. To
60-
address this exception, ensure that all cluster nodes are reachable.
61-
This error commonly occurs when the client machine’s IP address is
62-
not configured in the Atlas IPs Access List, which can be found under
63-
the :guilabel:`Network Access` tab for your Atlas Project.
64-
* ``The remote certificate is invalid according to the validation
65-
procedure``: This error typically indicates a TLS/SSL-related problem
66-
such as an expired/invalid certificate or an untrusted root CA. You
67-
can use tools like ``openssl s_client`` to debug TLS/SSL-related
68-
certificate problems.
1+
.. _csharp-server-selection:
2+
3+
==========================
4+
Customize Server Selection
5+
==========================
6+
7+
.. contents:: On this page
8+
:local:
9+
:backlinks: none
10+
:depth: 1
11+
:class: singlecol
12+
13+
.. facet::
14+
:name: genre
15+
:values: reference
16+
17+
.. meta::
18+
:keywords: code example, read preference, write
19+
20+
Overview
21+
--------
22+
23+
All MongoDB drivers follow a defined algorithm when selecting a server to read or write
24+
from. By using the ``ClusterConfigurator`` property of a ``MongoClient`` object, you can
25+
customize this algorithm to choose the server that works best for your application.
26+
27+
.. important::
28+
29+
Customizing the server selection algorithm might have unintended consequences,
30+
such as degraded read or write performance.
31+
32+
Default Algorithm
33+
-----------------
34+
35+
When the {+driver-short+} executes a read operation, it performs the following steps,
36+
in order, to select a MongoDB deployment:
37+
38+
1. Selects all servers that match the active read preference from the list of known servers.
39+
40+
#. If at least one readable server exists, the driver calls the user-defined
41+
server-selector function and passes in the list from the previous step.
42+
43+
#. Applies the ``LocalThreshold`` connection setting to the list of
44+
servers returned from the function.
45+
46+
#. Selects a server at random from the servers still on the list and
47+
executes the operation against this server.
48+
49+
When the {+driver-short+} executes a write operation, it begins by selecting all writeable
50+
servers, not just those that match the active read preference. The remaining steps are
51+
identical.
52+
53+
To learn more about the default server selection algorithm, which the driver follows
54+
when you don't specify any custom server selection logic, see
55+
:manual:`Server Selection Algorithm </core/read-preference-mechanics/>` in the
56+
{+mdb-server+} manual.
57+
58+
.. _csharp-server-selection-algorithm:
59+
60+
Specifying Other Server Selection Algorithms
61+
--------------------------------------------
62+
63+
You can specify different server selection logic by passing an instance of a server selector
64+
class to the ``PreServerSelector`` or ``PostServerSelector`` property of the ``ClusterConfigurator``. The
65+
``PreServerSelector`` property specifies a server selector that runs before the
66+
standard server selection logic runs, while the ``PostServerSelector`` property
67+
specifies a server selector that runs after standard server selection logic runs. You can
68+
then pass your ``ClusterConfigurator`` instance to the ``MongoClientSettings`` object when you create a
69+
``MongoClient`` instance to apply your custom server selection logic.
70+
71+
The following table lists the different types of server selectors you can pass to the
72+
``ClusterConfigurator`` property:
73+
74+
.. list-table::
75+
:header-rows: 1
76+
:widths: 40 60
77+
78+
* - Server Selector
79+
- Description
80+
81+
* - ``CompositeServerSelector``
82+
- Selects servers based on multiple partial selectors
83+
84+
* - ``DelegateServerSelector``
85+
- Wraps a delegate server selector
86+
87+
* - ``EndPointServerSelector``
88+
- Selects servers based on their endpoint
89+
90+
* - ``LatencyLimitingServerSelector``
91+
- Selects servers within an acceptable latency range
92+
93+
* - ``PriorityServerSelector``
94+
- Selects a server based on a collection of servers to deprioritize
95+
96+
* - ``RandomServerSelector``
97+
- Selects a random server
98+
99+
* - ``ReadPreferenceServerSelector``
100+
- Selects servers based on a specified read preference
101+
102+
The following example instructs a ``MongoClient`` to use the ``RandomServerSelector``
103+
class to select a server at random before the standard server selection logic runs:
104+
105+
.. literalinclude:: /includes/fundamentals/code-examples/connection/ServerSelection.cs
106+
:start-after: start-server-selector
107+
:end-before: end-server-selector
108+
:language: csharp
109+
:dedent:
110+
111+
To learn more about the different server selector classes, see the
112+
`ServerSelectors API documentation <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.Core.Clusters.ServerSelectors.html>`__.
113+
114+
Implementing Custom Server Selection Logic
115+
------------------------------------------
116+
117+
You can implement your own custom server selection logic by creating a class that
118+
inherits from the ``IServerSelector`` interface and overrides the
119+
``SelectServers()`` method. The following example shows a simple custom server
120+
selection class that selects servers with a ``ServerType`` of
121+
``ServerType.ReplicaSetSecondary``:
122+
123+
.. literalinclude:: /includes/fundamentals/code-examples/connection/ServerSelection.cs
124+
:start-after: start-custom-class
125+
:end-before: end-custom-class
126+
:language: csharp
127+
:dedent:
128+
129+
You can then pass an instance of this class to the ``PreServerSelector`` or
130+
``PostServerSelector`` property of a ``ClusterConfigurator`` instance, as shown in the
131+
:ref:`csharp-server-selection-algorithm` section.
132+
133+
Using Settings to Configure Server Selection
134+
--------------------------------------------
135+
136+
You can specify the following server selection settings in your ``MongoClient`` object or
137+
in your connection URI:
138+
139+
.. list-table::
140+
:widths: 30 70
141+
:header-rows: 1
142+
143+
* - Setting
144+
- Description
145+
146+
* - ``LocalThreshold``
147+
- | The latency window for server eligibility. If a server's round trip takes longer
148+
| than the fastest server's round-trip time plus this value, the server isn't
149+
| eligible for selection.
150+
|
151+
| **Data Type**: ``TimeSpan``
152+
| **Default**: 15 milliseconds
153+
| **Connection URI Example**: ``localThresholdMS=0``
154+
155+
* - ``ReadPreference``
156+
- | The client's default read-preference settings. ``MaxStaleness`` represents the
157+
| longest replication lag (in real time) that a secondary can experience and
158+
| still be eligible for server selection. Specifying ``-1`` means no maximum.
159+
| See :ref:`read preference <read-preference>` for more information.
160+
|
161+
| **Data Type**: `ReadPreference <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.ReadPreference.html>`__
162+
| **Default**: ``ReadPreference.Primary``
163+
| **Connection URI Example**:
164+
165+
.. code-block:: none
166+
:copyable: false
167+
168+
readPreference=primaryPreferred
169+
&maxStalenessSeconds=90
170+
&readPreferenceTags=dc:ny,rack:1
171+
172+
* - ``ServerSelectionTimeout``
173+
- | The length of time the driver tries to select a server before timing out.
174+
|
175+
| **Data Type**: ``TimeSpan``
176+
| **Default**: 30 seconds
177+
| **Connection URI Example**: ``serverSelectionTimeoutMS=15000``
178+
179+
Troubleshooting
180+
---------------
181+
182+
.. include:: /includes/troubleshooting/server-selection-timeout.rst
183+
184+
API Documentation
185+
-----------------
186+
187+
To learn more about the classes and methods used in this guide, see the following API
188+
documentation:
189+
190+
- `MongoClient <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.MongoClient.html>`__
191+
- `MongoClientSettings <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.MongoClientSettings.html>`__
192+
- `ClusterConfigurator <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.MongoClientSettings.ClusterConfigurator.html>`__
193+
- `ServerSelectors <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.Core.Clusters.ServerSelectors.html>`__
194+
- `IServerSelector <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.Core.Clusters.ServerSelectors.IServerSelector.html>`__
195+
- `SelectServer() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.Core.Clusters.ServerSelectors.IServerSelector.SelectServers.html>`__
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using MongoDB.Driver;
2+
using MongoDB.Driver.Core.Clusters;
3+
using MongoDB.Driver.Core.Clusters.ServerSelectors;
4+
using MongoDB.Driver.Core.Servers;
5+
6+
public class ServerSelection
7+
{
8+
// Replace with your connection string
9+
private const string MongoConnectionString = "<connection URI>";
10+
11+
public static void Main(string[] args)
12+
{
13+
{
14+
// start-server-selector
15+
var settings = MongoClientSettings.FromConnectionString("<connection string>");
16+
var clusterConfigurator = builder =>
17+
{
18+
builder.ConfigureCluster(c =>
19+
c.With(PreServerSelector: new RandomServerSelector()));
20+
};
21+
22+
settings.ClusterConfigurator = clusterConfigurator;
23+
var client = new MongoClient(settings);
24+
// end-server-selector
25+
}
26+
}
27+
}
28+
29+
// start-custom-class
30+
public class CustomServerSelector : IServerSelector
31+
{
32+
public IEnumerable<ServerDescription> SelectServers(ClusterDescription cluster,
33+
IEnumerable<ServerDescription> servers)
34+
{
35+
return servers.Where(server => server.Type == ServerType.ReplicaSetSecondary);
36+
}
37+
}
38+
// end-custom-class
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
Driver Throws a Timeout During Server Selection
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
Each driver operation requires that you choose a server that
5+
satisfies the :manual:`server selection criteria
6+
</core/read-preference-mechanics>`. If you do not select an appropriate
7+
server within the `server selection timeout <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.MongoClientSettings.ServerSelectionTimeout.html>`__, the driver throws a
8+
server selection timeout exception. The exception looks similar to the
9+
following:
10+
11+
.. code-block:: none
12+
13+
A timeout occurred after 30000ms selecting a server using CompositeServerSelector{ Selectors = MongoDB.Driver.MongoClient+AreSessionsSupportedServerSelector, LatencyLimitingServerSelector{ AllowedLatencyRange = 00:00:00.0150000 }, OperationsCountServerSelector }.
14+
Client view of cluster state is
15+
{
16+
ClusterId : "1",
17+
Type : "Unknown",
18+
State : "Disconnected",
19+
Servers :
20+
[{
21+
ServerId: "{ ClusterId : 1, EndPoint : "Unspecified/localhost:27017" }",
22+
EndPoint: "Unspecified/localhost:27017",
23+
ReasonChanged: "Heartbeat",
24+
State: "Disconnected",
25+
ServerVersion: ,
26+
TopologyVersion: ,
27+
Type: "Unknown",
28+
HeartbeatException: "<exception details>"
29+
}]
30+
}.
31+
32+
The error message consists of multiple parts:
33+
34+
1. The server selection timeout (30000 ms).
35+
#. The server selectors considered (``CompositeServerSelector``
36+
containing ``AreSessionsSupportedServerSelector``,
37+
``LatencyLimitingServerSelector``, and
38+
``OperationsCountServerSelector``).
39+
#. The driver’s current view of the cluster topology. The list of
40+
servers that the driver is aware of is a key part of this view. Each
41+
server description contains an exhaustive description of its current
42+
state including information about an endpoint, a server version, a
43+
server type, and its current health state. If the server encounters issues in
44+
reporting its health, ``HeartbeatException`` contains the exception from the
45+
last failed heartbeat. Analyzing the ``HeartbeatException`` on each
46+
cluster node can assist in diagnosing most server selection issues.
47+
The following heartbeat exceptions are common:
48+
49+
* ``No connection could be made because the target machine actively
50+
refused it``: The driver cannot see this cluster node. This might be
51+
because the cluster node has crashed, a firewall is preventing
52+
network traffic from reaching the cluster node or port, or some other
53+
network error is preventing traffic from being successfully routed to
54+
the cluster node.
55+
* ``Attempted to read past the end of the stream``: This error
56+
happens when the driver cannot connect to the cluster nodes due to a
57+
network error, misconfigured firewall, or other network issue. To
58+
address this exception, ensure that all cluster nodes are reachable.
59+
This error commonly occurs when the client machine’s IP address is
60+
not configured in the Atlas IPs Access List, which you can find under
61+
the :guilabel:`Network Access` tab for your Atlas Project.
62+
* ``The remote certificate is invalid according to the validation
63+
procedure``: This error typically indicates a TLS/SSL-related problem
64+
such as an expired/invalid certificate or an untrusted root CA. You
65+
can use tools like ``openssl s_client`` to debug TLS/SSL-related
66+
certificate problems.

0 commit comments

Comments
 (0)