Skip to content

Commit 9745cef

Browse files
committed
Improve connection pooling docs
This commit improves the connection pooling docs by hiding test assertions from being output in documentation, and linking to sniffing and pinging behaviour docs.
1 parent b6c3b13 commit 9745cef

File tree

2 files changed

+174
-260
lines changed

2 files changed

+174
-260
lines changed

docs/client-concepts/connection-pooling/building-blocks/connection-pooling.asciidoc

Lines changed: 52 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ NEST can use to issue client calls on.
2323
Despite the name, a connection pool in NEST is **not** like connection pooling that you may be familiar with from
2424
https://msdn.microsoft.com/en-us/library/bb399543(v=vs.110).aspx[interacting with a database using ADO.Net]; for example,
2525
a connection pool in NEST is **not** responsible for managing an underlying pool of TCP connections to Elasticsearch,
26-
this is https://blogs.msdn.microsoft.com/adarshk/2005/01/02/understanding-system-net-connection-management-and-servicepointmanager/[handled by the ServicePointManager in Desktop CLR]
27-
and can be controlled by <<servicepoint-behaviour,changing the ServicePoint behaviour>> on `HttpConnection`.
26+
this is https://blogs.msdn.microsoft.com/adarshk/2005/01/02/understanding-system-net-connection-management-and-servicepointmanager/[handled by the ServicePointManager in Desktop CLR].
2827

2928
--
3029

@@ -60,51 +59,25 @@ your cluster through a single load balancer instance.
6059
----
6160
var uri = new Uri("http://localhost:9201");
6261
var pool = new SingleNodeConnectionPool(uri);
63-
pool.Nodes.Should().HaveCount(1);
64-
var node = pool.Nodes.First();
65-
node.Uri.Port.Should().Be(9201);
62+
var client = new ElasticClient(new ConnectionSettings(pool));
6663
----
6764

68-
This type of pool is hardwired to opt out of reseeding (thus, sniffing) as well as pinging
69-
70-
[source,csharp]
71-
----
72-
pool.SupportsReseeding.Should().BeFalse();
73-
pool.SupportsPinging.Should().BeFalse();
74-
----
65+
This type of pool is hardwired to opt out of reseeding (<<sniffing-behaviour, sniffing>>) as well as <<pinging-behaviour, pinging>>
7566

7667
When you use the low ceremony `ElasticClient` constructor that takes a single `Uri`,
7768
internally a `SingleNodeConnectionPool` is used
7869

7970
[source,csharp]
8071
----
81-
var client = new ElasticClient(uri);
82-
client.ConnectionSettings.ConnectionPool
83-
.Should().BeOfType<SingleNodeConnectionPool>();
84-
----
85-
86-
However we urge that you always pass your connection settings explicitly
87-
88-
[source,csharp]
89-
----
90-
client = new ElasticClient(new ConnectionSettings(uri));
91-
client.ConnectionSettings.ConnectionPool
92-
.Should().BeOfType<SingleNodeConnectionPool>();
72+
client = new ElasticClient(uri);
9373
----
9474

95-
or even better pass the connection pool explicitly
96-
97-
[source,csharp]
98-
----
99-
client = new ElasticClient(new ConnectionSettings(pool));
100-
client.ConnectionSettings.ConnectionPool
101-
.Should().BeOfType<SingleNodeConnectionPool>();
102-
----
75+
However we encourage you to pass connection settings explicitly.
10376

10477
[[cloud-connection-pool]]
10578
==== CloudConnectionPool
10679

107-
A specialized subclass of `SingleNodeConnectionPool that accepts a Cloud Id and credentials.
80+
A specialized subclass of `SingleNodeConnectionPool` that accepts a Cloud Id and credentials.
10881
When used the client will also pick Elastic Cloud optmized defaults for the connection settings.
10982

11083
A Cloud Id for your cluster can be fetched from your Elastic Cloud cluster administration console.
@@ -115,67 +88,26 @@ A Cloud Id should be in the form of `cluster_name:base_64_data` where `base_64_d
11588

11689
Out of these, only `host_name` and `elasticsearch_uuid` are always available.
11790

118-
[source,csharp]
119-
----
120-
string ToBase64(string s) => Convert.ToBase64String(Encoding.UTF8.GetBytes(s));
121-
/* Here we obviously use a ficticuous Cloud Id so lets create a fake one. */
122-
123-
var hostName = "cloud-endpoint.example";
124-
var elasticsearchUuid = "3dadf823f05388497ea684236d918a1a";
125-
var services = $"{hostName}${elasticsearchUuid}$3f26e1609cf54a0f80137a80de560da4";
126-
var cloudId = $"my_cluster:{ToBase64(services)}";
127-
128-
/*
129-
* In a real scenario you would be able to copy paste `cloudId`
130-
*
131-
* A cloud connection pool always needs credentials as well here opt for basic auth
132-
*/
133-
var credentials = new BasicAuthenticationCredentials("username", "password");
134-
var pool = new CloudConnectionPool(cloudId, credentials);
135-
pool.UsingSsl.Should().BeTrue();
136-
pool.Nodes.Should().HaveCount(1);
137-
var node = pool.Nodes.First();
138-
node.Uri.Port.Should().Be(443);
139-
node.Uri.Host.Should().Be($"{elasticsearchUuid}.{hostName}");
140-
node.Uri.Scheme.Should().Be("https");
141-
----
142-
143-
This type of pool like its parent the `SingleNodeConnectionPool` is hardwired to opt out of
144-
reseeding (thus, sniffing) as well as pinging
91+
A cloud connection pool can be created using credentials and a `cloudId`
14592

14693
[source,csharp]
14794
----
148-
pool.SupportsReseeding.Should().BeFalse();
149-
pool.SupportsPinging.Should().BeFalse();
95+
var credentials = new BasicAuthenticationCredentials("username", "password"); <1>
96+
var pool = new CloudConnectionPool(cloudId, credentials); <2>
97+
var client = new ElasticClient(new ConnectionSettings(pool));
15098
----
99+
<1> a username and password that can access Elasticsearch service on Elastic Cloud
151100

152-
You can also directly create a cloud enabled connection using the clients constructor
101+
<2> `cloudId` is a value that can be retrieved from the Elastic Cloud web console
153102

154-
[source,csharp]
155-
----
156-
var client = new ElasticClient(cloudId, credentials);
157-
client.ConnectionSettings.ConnectionPool
158-
.Should()
159-
.BeOfType<CloudConnectionPool>();
160-
----
103+
This type of pool, like its parent the `SingleNodeConnectionPool`, is hardwired to opt out of
104+
reseeding (<<sniffing-behaviour, sniffing>>) as well as <<pinging-behaviour, pinging>>.
161105

162-
However we urge that you always pass your connection settings explicitly
106+
You can also directly create a cloud enabled connection using the `ElasticClient`'s constructor
163107

164108
[source,csharp]
165109
----
166-
client = new ElasticClient(new ConnectionSettings(pool));
167-
client.ConnectionSettings.ConnectionPool.Should().BeOfType<CloudConnectionPool>();
168-
169-
client.ConnectionSettings.EnableHttpCompression.Should().BeTrue();
170-
client.ConnectionSettings.BasicAuthenticationCredentials.Should().NotBeNull();
171-
client.ConnectionSettings.BasicAuthenticationCredentials.Username.Should().Be("username");
172-
foreach (var id in badCloudIds)
173-
{
174-
Action create = () => new ElasticClient(id, credentials);
175-
176-
create.ShouldThrow<ArgumentException>()
177-
.And.Message.Should().Contain("should be a string in the form of cluster_name:base_64_data");
178-
}
110+
client = new ElasticClient(cloudId, credentials);
179111
----
180112

181113
[[static-connection-pool]]
@@ -184,17 +116,20 @@ foreach (var id in badCloudIds)
184116
The static connection pool is great if you have a known small sized cluster and do no want to enable
185117
sniffing to find out the cluster topology.
186118

119+
Given a collection of `Uri`
120+
187121
[source,csharp]
188122
----
189123
var uris = Enumerable.Range(9200, 5)
190124
.Select(port => new Uri($"http://localhost:{port}"));
191125
----
192126

193-
a connection pool can be seeded using an enumerable of `Uri`
127+
a connection pool can be seeded with this collection
194128

195129
[source,csharp]
196130
----
197131
var pool = new StaticConnectionPool(uris);
132+
var client = new ElasticClient(new ConnectionSettings(pool));
198133
----
199134

200135
Or using an enumerable of `Node`
@@ -203,33 +138,20 @@ Or using an enumerable of `Node`
203138
----
204139
var nodes = uris.Select(u => new Node(u));
205140
pool = new StaticConnectionPool(nodes);
141+
client = new ElasticClient(new ConnectionSettings(pool));
206142
----
207143

208144
This type of pool is hardwired to opt out of reseeding
209-
(and hence sniffing) but supports pinging when enabled
210-
211-
[source,csharp]
212-
----
213-
pool.SupportsReseeding.Should().BeFalse();
214-
pool.SupportsPinging.Should().BeTrue();
215-
----
216-
217-
To create a client using the static connection pool, pass
218-
the connection pool to the `ConnectionSettings` you pass to `ElasticClient`
219-
220-
[source,csharp]
221-
----
222-
var client = new ElasticClient(new ConnectionSettings(pool));
223-
client.ConnectionSettings.ConnectionPool
224-
.Should().BeOfType<StaticConnectionPool>();
225-
----
145+
(<<sniffing-behaviour, sniffing>>) but supports <<pinging-behaviour, pinging>> when enabled.
226146

227147
[[sniffing-connection-pool]]
228148
==== SniffingConnectionPool
229149

230150
A pool derived from `StaticConnectionPool`, a sniffing connection pool allows itself to be reseeded at run time.
231151
It comes with the very minor overhead of a `ReaderWriterLockSlim` to ensure thread safety.
232152

153+
Given a collection of `Uri`
154+
233155
[source,csharp]
234156
----
235157
var uris = Enumerable.Range(9200, 5)
@@ -241,36 +163,21 @@ a connection pool can be seeded using an enumerable of `Uri`
241163
[source,csharp]
242164
----
243165
var pool = new SniffingConnectionPool(uris);
166+
var client = new ElasticClient(new ConnectionSettings(pool));
244167
----
245168

246169
Or using an enumerable of `Node`. A major benefit in using nodes is that you can include
247-
known node roles when seeding which
248-
NEST can use to favour sniffing on master eligible nodes first,
249-
and take master only nodes out of rotation for issuing client calls on.
170+
known node roles when seeding, which NEST can then use to favour particular API requests. For example,
171+
sniffing on master eligible nodes first, and take master only nodes out of rotation for issuing client calls on.
250172

251173
[source,csharp]
252174
----
253175
var nodes = uris.Select(u=>new Node(u));
254176
pool = new SniffingConnectionPool(nodes);
177+
client = new ElasticClient(new ConnectionSettings(pool));
255178
----
256179

257-
This type of pool is hardwired to opt in to reseeding (and hence sniffing), and pinging
258-
259-
[source,csharp]
260-
----
261-
pool.SupportsReseeding.Should().BeTrue();
262-
pool.SupportsPinging.Should().BeTrue();
263-
----
264-
265-
To create a client using the sniffing connection pool pass
266-
the connection pool to the `ConnectionSettings` you pass to `ElasticClient`
267-
268-
[source,csharp]
269-
----
270-
var client = new ElasticClient(new ConnectionSettings(pool));
271-
client.ConnectionSettings.ConnectionPool
272-
.Should().BeOfType<SniffingConnectionPool>();
273-
----
180+
This type of pool is hardwired to opt in to reseeding (<<sniffing-behaviour, sniffing>>), and <<pinging-behaviour, pinging>>
274181

275182
[[sticky-connection-pool]]
276183
==== StickyConnectionPool
@@ -279,6 +186,8 @@ A type of connection pool that returns the first live node to issue a request ag
279186
It uses https://msdn.microsoft.com/en-us/library/system.threading.interlocked(v=vs.110).aspx[`System.Threading.Interlocked`]
280187
to keep an _indexer_ to the last live node in a thread safe manner.
281188

189+
Given a collection of `Uri`
190+
282191
[source,csharp]
283192
----
284193
var uris = Enumerable.Range(9200, 5)
@@ -290,72 +199,54 @@ a connection pool can be seeded using an enumerable of `Uri`
290199
[source,csharp]
291200
----
292201
var pool = new StickyConnectionPool(uris);
202+
var client = new ElasticClient(new ConnectionSettings(pool));
293203
----
294204

295-
Or using an enumerable of `Node`.
296-
A major benefit here is you can include known node roles when seeding and
297-
NEST can use this information to favour sniffing on master eligible nodes first
298-
and take master only nodes out of rotation for issuing client calls on.
205+
Or using an enumerable of `Node`, similar to `SniffingConnectionPool`
299206

300207
[source,csharp]
301208
----
302209
var nodes = uris.Select(u=>new Node(u));
303210
pool = new StickyConnectionPool(nodes);
211+
client = new ElasticClient(new ConnectionSettings(pool));
304212
----
305213

306-
This type of pool is hardwired to opt out of reseeding (and hence sniffing), but does support sniffing
307-
308-
[source,csharp]
309-
----
310-
pool.SupportsReseeding.Should().BeFalse();
311-
pool.SupportsPinging.Should().BeTrue();
312-
----
313-
314-
To create a client using the sticky connection pool pass
315-
the connection pool to the `ConnectionSettings` you pass to `ElasticClient`
316-
317-
[source,csharp]
318-
----
319-
var client = new ElasticClient(new ConnectionSettings(pool));
320-
client.ConnectionSettings.ConnectionPool
321-
.Should().BeOfType<StickyConnectionPool>();
322-
----
214+
This type of pool is hardwired to opt out of reseeding (<<sniffing-behaviour, sniffing>>), but does support <<pinging-behaviour, pinging>>.
323215

324216
[[sticky-sniffing-connection-pool]]
325217
==== Sticky Sniffing Connection Pool
326218

327219
A type of connection pool that returns the first live node to issue a request against, such that the node is _sticky_ between requests.
328-
This implementation supports sniffing and sorting so that each instance of your application can favor a node in the same rack based
329-
on node attributes for instance.
220+
This implementation supports sniffing and sorting so that each instance of your application can favour a node. For example,
221+
a node in the same rack, based on node attributes.
222+
223+
Given a collection of `Uri`
330224

331225
[source,csharp]
332226
----
333227
var uris = Enumerable.Range(9200, 5)
334228
.Select(port => new Uri($"http://localhost:{port}"));
335229
----
336230

337-
a sniffing sorted sticky pool takes a second parameter `Func` takes a Node and returns a weight.
338-
Nodes will be sorted descending by weight. In the following example we score nodes that are client nodes
339-
AND in rack_id `rack_one` the highest
231+
a sniffing sorted sticky pool takes a second parameter, a delegate of `Func<Node, float>`, that takes a Node and returns a weight.
232+
Nodes will be sorted in descending order by weight. In the following example, nodes are scored so that client nodes
233+
in rack_id `rack_one` score the highest
340234

341235
[source,csharp]
342236
----
343-
var pool = new StickySniffingConnectionPool(uris, n =>
344-
(n.ClientNode ? 10 : 0)
345-
+ (n.Settings.TryGetValue("node.attr.rack_id", out var rackId)
346-
&& rackId.ToString() == "rack_one" ? 10 : 0));
237+
var pool = new StickySniffingConnectionPool(uris, node =>
238+
{
239+
var weight = 0f;
347240
348-
pool.SupportsReseeding.Should().BeTrue();
349-
pool.SupportsPinging.Should().BeTrue();
350-
----
241+
if (node.ClientNode)
242+
weight += 10;
351243
352-
To create a client using the sticky sniffing connection pool pass
353-
the connection pool to the `ConnectionSettings` you pass to `ElasticClient`
244+
if (node.Settings.TryGetValue("node.attr.rack_id", out var rackId) && rackId.ToString() == "rack_one")
245+
weight += 10;
246+
247+
return weight;
248+
});
354249
355-
[source,csharp]
356-
----
357250
var client = new ElasticClient(new ConnectionSettings(pool));
358-
client.ConnectionSettings.ConnectionPool
359-
.Should().BeOfType<StickySniffingConnectionPool>();
360251
----
361252

0 commit comments

Comments
 (0)