1
1
[[connection_pool]]
2
2
== Connection Pool
3
3
4
- The connection pool is an object inside the client that is responsible for maintaining the current list of nodes.
5
- Theoretically, nodes are either dead or alive.
6
-
7
- However, in the real world, things are never so clear. Nodes are sometimes in a gray-zone of _"probably dead but not
8
- confirmed"_, _"timed-out but unclear why"_ or _"recently dead but now alive"_. The connection pool's job is to
9
- manage this set of unruly connections and try to provide the best behavior to the client.
10
-
11
- If a connection pool is unable to find an alive node to query against, it will return a `NoNodesAvailableException`.
12
- This is distinct from an exception due to maximum retries. For example, your cluster may have 10 nodes. You execute
13
- a request and 9 out of the 10 nodes fail due to connection timeouts. The tenth node succeeds and the query executes.
14
- The first nine nodes will be marked dead (depending on the connection pool being used) and their "dead" timers will begin
4
+ The connection pool is an object inside the client that is responsible for
5
+ maintaining the current list of nodes. Theoretically, nodes are either dead or
6
+ alive. However, in the real world, things are never so clear. Nodes are
7
+ sometimes in a gray-zone of _"probably dead but not confirmed"_, _"timed-out but
8
+ unclear why"_ or _"recently dead but now alive"_. The job of the connection pool
9
+ is to manage this set of unruly connections and try to provide the best behavior
10
+ to the client.
11
+
12
+ If a connection pool is unable to find an alive node to query against, it
13
+ returns a `NoNodesAvailableException`. This is distinct from an exception due to
14
+ maximum retries. For example, your cluster may have 10 nodes. You execute a
15
+ request and 9 out of the 10 nodes fail due to connection timeouts. The tenth
16
+ node succeeds and the query executes. The first nine nodes are marked dead
17
+ (depending on the connection pool being used) and their "dead" timers begin
15
18
ticking.
16
19
17
- When the next request is sent to the client, nodes 1-9 are still considered "dead", so they will be skipped. The request
18
- is sent to the only known alive node (#10), and if this node fails, a `NoNodesAvailableException` is returned. You'll note
19
- this is much less than the `retries` value, because `retries` only applies to retries against alive nodes. In this case,
20
- only one node is known to be alive, so `NoNodesAvailableException` is returned.
21
-
20
+ When the next request is sent to the client, nodes 1-9 are still considered
21
+ "dead", so they are skipped. The request is sent to the only known alive node
22
+ (#10), and if this node fails, a `NoNodesAvailableException` is returned. You
23
+ will note this much less than the `retries` value, because `retries` only
24
+ applies to retries against alive nodes. In this case, only one node is known to
25
+ be alive, so `NoNodesAvailableException` is returned.
22
26
23
27
There are several connection pool implementations that you can choose from:
24
28
29
+
25
30
=== staticNoPingConnectionPool (default)
26
31
27
- This connection pool maintains a static list of hosts, which are assumed to be alive when the client initializes. If
28
- a node fails a request, it is marked as `dead` for 60 seconds and the next node is tried. After 60 seconds, the node
29
- is revived and put back into rotation. Each additional failed request will cause the dead timeout to increase exponentially.
32
+ This connection pool maintains a static list of hosts which are assumed to be
33
+ alive when the client initializes. If a node fails a request, it is marked as
34
+ `dead` for 60 seconds and the next node is tried. After 60 seconds, the node is
35
+ revived and put back into rotation. Each additional failed request causes the
36
+ dead timeout to increase exponentially.
30
37
31
- A successful request will reset the "failed ping timeout" counter.
38
+ A successful request resets the "failed ping timeout" counter.
32
39
33
- If you wish to explicitly set the `StaticNoPingConnectionPool` implementation, you may do so with the `setConnectionPool()`
34
- method of the ClientBuilder object:
40
+ If you wish to explicitly set the `StaticNoPingConnectionPool` implementation,
41
+ you may do so with the `setConnectionPool()` method of the ClientBuilder object:
35
42
36
43
[source,php]
37
44
----
@@ -42,10 +49,13 @@ $client = ClientBuilder::create()
42
49
43
50
Note that the implementation is specified via a namespace path to the class.
44
51
52
+
45
53
=== staticConnectionPool
46
54
47
- Identical to the `StaticNoPingConnectionPool`, except it pings nodes before they are used to determine if they are alive.
48
- This may be useful for long-running scripts, but tends to be additional overhead that is unnecessary for average PHP scripts.
55
+ Identical to the `StaticNoPingConnectionPool`, except it pings nodes before they
56
+ are used to determine if they are alive. This may be useful for long-running
57
+ scripts but tends to be additional overhead that is unnecessary for average PHP
58
+ scripts.
49
59
50
60
To use the `StaticConnectionPool`:
51
61
@@ -58,13 +68,15 @@ $client = ClientBuilder::create()
58
68
59
69
Note that the implementation is specified via a namespace path to the class.
60
70
71
+
61
72
=== simpleConnectionPool
62
73
63
- The `SimpleConnectionPool` simply returns the next node as specified by the Selector; it does not perform track
64
- the "liveness" of nodes. This pool will return nodes whether they are alive or dead. It is just a simple pool of static
65
- hosts.
74
+ The `SimpleConnectionPool` returns the next node as specified by the selector;
75
+ it does not track node conditions. It returns nodes either they are dead or
76
+ alive. It is a simple pool of static hosts.
66
77
67
- The `SimpleConnectionPool` is not recommended for routine use, but it may be a useful debugging tool.
78
+ The `SimpleConnectionPool` is not recommended for routine use but it may be a
79
+ useful debugging tool.
68
80
69
81
To use the `SimpleConnectionPool`:
70
82
@@ -77,11 +89,13 @@ $client = ClientBuilder::create()
77
89
78
90
Note that the implementation is specified via a namespace path to the class.
79
91
92
+
80
93
=== sniffingConnectionPool
81
94
82
- Unlike the two previous static connection pools, this one is dynamic. The user provides a seed list of hosts, which the
83
- client uses to "sniff" and discover the rest of the cluster. It achieves this through the Cluster State API. As new
84
- nodes are added or removed from the cluster, the client will update it's pool of active connections.
95
+ Unlike the two previous static connection pools, this one is dynamic. The user
96
+ provides a seed list of hosts, which the client uses to "sniff" and discover the
97
+ rest of the cluster by using the Cluster State API. As new nodes are added or
98
+ removed from the cluster, the client updates its pool of active connections.
85
99
86
100
To use the `SniffingConnectionPool`:
87
101
@@ -97,7 +111,8 @@ Note that the implementation is specified via a namespace path to the class.
97
111
98
112
=== Custom Connection Pool
99
113
100
- If you wish to implement your own custom Connection Pool, your class must implement `ConnectionPoolInterface`:
114
+ If you wish to implement your own custom Connection Pool, your class must
115
+ implement `ConnectionPoolInterface`:
101
116
102
117
[source,php]
103
118
----
@@ -124,7 +139,9 @@ class MyCustomConnectionPool implements ConnectionPoolInterface
124
139
}
125
140
----
126
141
127
- You can then instantiate an instance of your ConnectionPool and inject it into the ClientBuilder:
142
+
143
+ You can then instantiate an instance of your ConnectionPool and inject it into
144
+ the ClientBuilder:
128
145
129
146
[source,php]
130
147
----
@@ -135,9 +152,11 @@ $client = ClientBuilder::create()
135
152
->build();
136
153
----
137
154
138
- If your connection pool only makes minor changes, you may consider extending `AbstractConnectionPool`, which provides
139
- some helper concrete methods. If you choose to go down this route, you need to make sure your ConnectionPool's implementation
140
- has a compatible constructor (since it is not defined in the interface):
155
+ If your connection pool only makes minor changes, you may consider extending
156
+ `AbstractConnectionPool` which provides some helper concrete methods. If you
157
+ choose to go down this route, you need to make sure your ConnectionPool
158
+ implementation has a compatible constructor (since it is not defined in the
159
+ interface):
141
160
142
161
[source,php]
143
162
----
@@ -169,7 +188,9 @@ class MyCustomConnectionPool extends AbstractConnectionPool implements Connectio
169
188
}
170
189
----
171
190
172
- If your constructor matches AbstractConnectionPool, you may use either object injection or namespace instantiation:
191
+
192
+ If your constructor matches AbstractConnectionPool, you may use either object
193
+ injection or namespace instantiation:
173
194
174
195
[source,php]
175
196
----
@@ -184,21 +205,27 @@ $client = ClientBuilder::create()
184
205
185
206
=== Which connection pool to choose? PHP and connection pooling
186
207
187
- At first glance, the `sniffingConnectionPool` implementation seems superior. For many languages, it is. In PHP, the
188
- conversation is a bit more nuanced.
189
-
190
- Because PHP is a share-nothing architecture, there is no way to maintain a connection pool across script instances.
191
- This means that every script is responsible for creating, maintaining, and destroying connections everytime the script
192
- is re-run.
193
-
194
- Sniffing is a relatively lightweight operation (one API call to `/_cluster/state`, followed by pings to each node) but
195
- it may be a non-negligible overhead for certain PHP applications. The average PHP script will likely load the client,
196
- execute a few queries and then close. Imagine this script being called 1000 times per second: the sniffing connection
197
- pool will perform the sniffing and pinging process 1000 times per second. The sniffing process will add a large
198
- amount of overhead
199
-
200
- In reality, if your script only executes a few queries, the sniffing concept is _too_ robust. It tends to be more
201
- useful in long-lived processes which potentially "out-live" a static list.
202
-
203
- For this reason the default connection pool is currently the `staticNoPingConnectionPool`. You can, of course, change
204
- this default - but we strongly recommend you load test and verify that it does not negatively impact your performance.
208
+ At first glance, the `sniffingConnectionPool` implementation seems superior. For
209
+ many languages, it is. In PHP, the conversation is a bit more nuanced.
210
+
211
+ Because PHP is a share-nothing architecture, there is no way to maintain a
212
+ connection pool across script instances. This means that every script is
213
+ responsible for creating, maintaining, and destroying connections everytime the
214
+ script is re-run.
215
+
216
+ Sniffing is a relatively lightweight operation (one API call to
217
+ `/_cluster/state`, followed by pings to each node) but it may be a
218
+ non-negligible overhead for certain PHP applications. The average PHP script
219
+ likely loads the client, executes a few queries and then closes. Imagine that
220
+ this script being called 1000 times per second: the sniffing connection pool
221
+ performS the sniffing and pinging process 1000 times per second. The sniffing
222
+ process eventually adds a large amount of overhead.
223
+
224
+ In reality, if your script only executes a few queries, the sniffing concept is
225
+ _too_ robust. It tends to be more useful in long-lived processes which
226
+ potentially "out-live" a static list.
227
+
228
+ For this reason the default connection pool is currently the
229
+ `staticNoPingConnectionPool`. You can, of course, change this default - but we
230
+ strongly recommend you to perform load test and to verify that the change does
231
+ not negatively impact the performance.
0 commit comments