Skip to content

Commit 811307d

Browse files
DOCSP-37528 - Server Selection (#45)
Co-authored-by: Jordan Smith <[email protected]>
1 parent 41b1a9a commit 811307d

File tree

2 files changed

+119
-70
lines changed

2 files changed

+119
-70
lines changed

source/connect/connection-options.txt

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ Network Compression
8181

8282
* - Connection Option
8383
- Description
84-
84+
8585
* - **compressors**
8686
- | The preferred compression types, in order, for wire-protocol messages sent to
8787
| or received from the server. The driver uses the first of these compression types
@@ -106,6 +106,26 @@ Network Compression
106106
| **MongoClient Example**: ``zlibCompressionLevel = 3``
107107
| **Connection URI Example**: ``zlibCompressionLevel=3``
108108

109+
Server Selection
110+
~~~~~~~~~~~~~~~~
111+
112+
.. list-table::
113+
:header-rows: 1
114+
:widths: 30 70
115+
116+
* - Connection Option
117+
- Description
118+
119+
* - **server_selector**
120+
- | A user-defined Python function called by {+driver-short+} to choose the server
121+
| to run an operation against. For more information, see
122+
| :ref:`<pymongo-server-selection>`.
123+
|
124+
| **Data Type**: ``callable``
125+
| **Default**: ``None``
126+
| **MongoClient Example**: ``server_selector = your_function``
127+
| **Connection URI Example**: N/A
128+
109129
.. _secondary-reads:
110130

111131
Secondary Reads
@@ -192,4 +212,4 @@ ms as shown in the following example:
192212

193213
Do **not** connect PyMongo to a pool of ``mongos`` instances through a
194214
load balancer. A single socket connection must always route to the same
195-
``mongos`` instance for proper cursor support.
215+
``mongos`` instance for proper cursor support.

source/connect/server-selection.txt

Lines changed: 97 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
.. uses server-selection.rst
2-
31
.. _pymongo-server-selection:
42

5-
================
6-
Server Selection
7-
================
3+
==========================
4+
Customize Server Selection
5+
==========================
86

97
.. contents:: On this page
108
:local:
@@ -17,88 +15,119 @@ Server Selection
1715
:values: reference
1816

1917
.. meta::
20-
:keywords: code example
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 ``server_selector`` property of ``MongoClient``, you can customize this
25+
algorithm to choose the server that works best for your application.
26+
27+
.. important::
28+
29+
Customizing the server-selection algorithm can have unintended consequences,
30+
such as degraded read or write performance.
31+
32+
Customized Selection Algorithm
33+
------------------------------
34+
35+
When {+driver-short+} executes a read operation, it performs the following steps,
36+
in order, to select a MongoDB deployment:
2137

22-
Users can exert fine-grained control over the :manual:`Server Selection
23-
Algorithm </core/read-preference-mechanics/>` by setting the ``server_selector``
24-
option on the ``~pymongo.MongoClient`` to an appropriate callable. This guide
25-
shows you how to use this functionality to prefer servers running on ``localhost``.
38+
1. From the list of known servers, {+driver-short+} selects all servers
39+
that match the active read preference.
2640

27-
.. warning::
41+
#. If at least one readable server exists, {+driver-short+} calls the user-defined
42+
server-selector function and passes in the list from the previous step.
2843

29-
Use of custom server selector functions is a power-user feature. Misusing
30-
custom server selectors can have unintended consequences, such as degraded
31-
read or write performance.
44+
#. {+driver-short+} applies the ``localThresholdMS`` connection setting to the list of
45+
servers returned from the function.
3246

33-
Example: Selecting Servers Running on ``localhost``
34-
---------------------------------------------------
47+
#. {+driver-short+} selects a server at random from the servers still on the list and
48+
executes the operation against this server.
3549

36-
First, write the server selector function.
37-
The server selector function should accept a list of
38-
``~pymongo.server_description.ServerDescription`` objects, and return a
39-
list of server descriptions that are suitable for the read or write operation.
40-
A server selector must not create or modify
41-
``~pymongo.server_description.ServerDescription`` objects, and must return
42-
the selected instances unchanged.
50+
When {+driver-short+} executes a write operation, it begins by selecting all writeable
51+
servers, not just those that match the active read preference. The remaining steps are
52+
identical.
4353

44-
This example shows a server selector that prioritizes servers running on
45-
``localhost``. This can be desirable when using a sharded cluster with multiple
46-
``mongos`` servers, because locally run queries usually have lower latency and higher
47-
throughput. However, the benefit of preferring ``localhost`` is highly dependent on the
48-
application.
54+
To learn more about the default server-selection algorithm, which the driver follows
55+
when you don't use the ``server_selector`` argument, see
56+
:manual:`Server Selection Algorithm </core/read-preference-mechanics/>` in the
57+
MongoDB Server manual.
4958

50-
In addition to comparing the hostname with ``localhost``, the server selector
51-
function accounts for the edge case when no servers are running on
52-
``localhost``. In this case, the default server selection logic
53-
prevails by returning the received server description list unchanged.
54-
Failure to do this renders the client unable to communicate with MongoDB
55-
if no servers are running on ``localhost``.
59+
Example: Select Servers on ``localhost``
60+
----------------------------------------
5661

57-
The following example implements the server selection logic:
62+
When using a sharded cluster with multiple ``mongos`` servers, you might want to prefer
63+
deployments running on ``localhost``. Operations against these deployments
64+
usually have lower latency and higher throughput.
65+
This example shows how to customize the server-selection algorithm to favor
66+
servers running on ``localhost``.
67+
68+
First, write a Python function to select your preferred servers.
69+
The server-selection function must meet the following criteria:
70+
71+
- Accepts a list of ``ServerDescription`` objects as a parameter
72+
- Returns the list of ``ServerDescription`` objects suitable for the read or write operation
73+
- Doesn't create or modify any ``ServerDescription`` objects
74+
75+
The following example defines a function named ``prefer_local`` that accepts and returns a list of
76+
``ServerDescription`` objects:
5877

5978
.. code-block:: python
79+
:emphasize-lines: 1,3
80+
81+
def prefer_local(server_descriptions):
82+
...
83+
return servers # list containing preferred servers
84+
85+
Next, implement your server-selection logic in the function body. You can use any
86+
property defined in the ``ServerDescription`` class to select your preferred servers.
87+
To return only MongoDB deployments running on ``localhost``, this example loops on the
88+
servers in ``server_descriptions`` and checks the ``address`` property of each server
89+
for the value ``"localhost"``:
6090

61-
>>> def server_selector(server_descriptions):
62-
... servers = [
63-
... server for server in server_descriptions if server.address[0] == "localhost"
64-
... ]
65-
... if not servers:
66-
... return server_descriptions
67-
... return servers
68-
...
91+
.. code-block:: python
92+
:emphasize-lines: 2-4
93+
94+
def prefer_local(server_descriptions):
95+
servers = [
96+
server for server in server_descriptions if server.address[0] == "localhost"
97+
]
98+
return servers
99+
100+
Next, consider the case when your algorithm finds no matching servers. If your function
101+
returns an empty list, your application can't communicate with MongoDB. Therefore,
102+
return a list containing at least one ``ServerDescription`` object from your function.
69103

70-
Finally, create a ``~pymongo.MongoClient`` instance with the
71-
server selector:
104+
In this example, if no matching server is found, the ``prefer_local`` function returns
105+
the list of servers originally passed as an argument:
72106

73107
.. code-block:: python
108+
:emphasize-lines: 6-7
74109

75-
>>> client = MongoClient(server_selector=server_selector)
110+
def prefer_local(server_descriptions):
111+
servers = [
112+
server for server in server_descriptions if server.address[0] == "localhost"
113+
]
76114

77-
Server Selection Process
78-
------------------------
115+
if not servers:
116+
return server_descriptions
117+
return servers
79118

80-
This section describes the server selection process for reads and
81-
writes. For writes, the driver performs the following operations, in order,
82-
during the selection process:
119+
Finally, instruct {+driver-short+} to use your function. To do so, call the ``MongoClient``
120+
constructor and pass the ``server_selector`` argument with your function name as the value:
83121

84-
1. Select all writeable servers from the list of known hosts. For a replica set,
85-
the writeable server is the primary. For a sharded cluster, the
86-
writeable servers are all the known ``mongos`` servers.
122+
.. code-block:: python
87123

88-
#. Apply the user-defined server selector function. The custom server
89-
selector is **not** called if there are no servers left from the previous
90-
filtering stage.
124+
client = MongoClient(server_selector=prefer_local)
91125

92-
#. Apply the ``localThresholdMS`` setting to the list of remaining hosts. This
93-
whittles the host list down to contain only servers whose latency is at most
94-
``localThresholdMS`` milliseconds higher than the lowest observed latency.
126+
API Documentation
127+
-----------------
95128

96-
#. Select a server at random from the remaining host list. The appropriate
97-
operation is then performed against the selected server.
129+
For more information about customizing {+driver-short+}'s server-selection algorithm,
130+
see the following API documentation:
98131

99-
For reads, the process is identical, except for the first step.
100-
Instead of selecting all writeable servers, the driver selects all servers from the
101-
list of known hosts that match the user's
102-
``~pymongo.read_preferences.ReadPreference``. For example, for a 3-member
103-
replica set with a ``~pymongo.read_preferences.Secondary`` read preference,
104-
the driver selects all available secondaries.
132+
- `MongoClient <{+api-root+}pymongo/mongo_client.html#pymongo.mongo_client.MongoClient>`__
133+
- `ServerDescription <{+api-root+}pymongo/server_description.html#pymongo.server_description.ServerDescription>`__

0 commit comments

Comments
 (0)