Improvements to the Jetty client documentation, connection pool section.
Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
parent
51c42f2849
commit
6e0b5f387b
|
@ -37,10 +37,10 @@ participant Application
|
|||
participant HttpClient
|
||||
participant Server
|
||||
|
||||
Application -> Server: GET /path
|
||||
Server -> HttpClient: 401 + WWW-Authenticate
|
||||
HttpClient -> Server: GET + Authentication
|
||||
Server -> Application: 200 OK
|
||||
Application -> Server : GET /path
|
||||
Server -> HttpClient : 401 + WWW-Authenticate
|
||||
HttpClient -> Server : GET + Authentication
|
||||
Server -> Application : 200 OK
|
||||
----
|
||||
|
||||
Upon receiving a HTTP 401 response code, `HttpClient` looks at the
|
||||
|
|
|
@ -108,8 +108,8 @@ following components:
|
|||
* a set of _destinations_.
|
||||
|
||||
A _destination_ is the client-side component that represent an _origin_ on
|
||||
a server, and manages a queue of requests for that origin, and a pool of
|
||||
connections to that origin.
|
||||
a server, and manages a queue of requests for that origin, and a
|
||||
link:#client-http-connection-pool[pool of connections] to that origin.
|
||||
|
||||
An _origin_ may be simply thought as the tuple `(scheme, host, port)` and it
|
||||
is where the client connects to in order to communicate with the server.
|
||||
|
@ -145,9 +145,75 @@ connection pools.
|
|||
Therefore an origin is identified by the tuple
|
||||
`(scheme, host, port, tag, protocol)`.
|
||||
|
||||
[[client-http-connection-pool]]
|
||||
==== HttpClient Connection Pooling
|
||||
|
||||
A destination manages a `org.eclipse.jetty.client.ConnectionPool`, where
|
||||
connections to a particular origin are pooled for performance reasons:
|
||||
opening a connection is a costly operation and it's better to reuse them
|
||||
for multiple requests.
|
||||
|
||||
NOTE: Remember that to select a specific destination you must select a
|
||||
specific origin, and that an origin is identified by the tuple
|
||||
`(scheme, host, port, tag, protocol)`, so you can have multiple destinations
|
||||
for the same `host` and `port`.
|
||||
|
||||
You can access the `ConnectionPool` in this way:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tags=getConnectionPool]
|
||||
----
|
||||
|
||||
Jetty's client library provides the following `ConnectionPool` implementations:
|
||||
|
||||
* `DuplexConnectionPool`, historically the first implementation, only used by
|
||||
the HTTP/1.1 transport.
|
||||
* `MultiplexConnectionPool`, the generic implementation valid for any transport
|
||||
where connections are reused with a MRU (most recently used) algorithm (that is,
|
||||
the connections most recently returned to the connection pool are the more
|
||||
likely to be used again).
|
||||
* `RoundRobinConnectionPool`, similar to `MultiplexConnectionPool` but where
|
||||
connections are reused with a round-robin algorithm.
|
||||
|
||||
The `ConnectionPool` implementation can be customized for each destination in
|
||||
by setting a `ConnectionPool.Factory` on the `HttpClientTransport`:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::../../{doc_code}/embedded/client/http/HTTPClientDocs.java[tags=setConnectionPool]
|
||||
----
|
||||
|
||||
[[client-http-request-processing]]
|
||||
==== HttpClient Request Processing
|
||||
|
||||
[plantuml]
|
||||
----
|
||||
skinparam backgroundColor transparent
|
||||
skinparam monochrome true
|
||||
skinparam shadowing false
|
||||
|
||||
participant Application
|
||||
participant Request
|
||||
participant HttpClient
|
||||
participant Destination
|
||||
participant ConnectionPool
|
||||
participant Connection
|
||||
|
||||
Application -> HttpClient : newRequest()
|
||||
HttpClient -> Request **
|
||||
Application -> Request : send()
|
||||
Request -> HttpClient : send()
|
||||
HttpClient -> Destination ** : get or create
|
||||
Destination -> ConnectionPool ** : create
|
||||
HttpClient -> Destination : send(Request)
|
||||
Destination -> Destination : enqueue(Request)
|
||||
Destination -> ConnectionPool : acquire()
|
||||
ConnectionPool -> Connection ** : create
|
||||
Destination -> Destination : dequeue(Request)
|
||||
Destination -> Connection : send(Request)
|
||||
----
|
||||
|
||||
When a request is sent, an origin is computed from the request; `HttpClient`
|
||||
uses that origin to find (or create if it does not exist) the correspondent
|
||||
destination.
|
||||
|
@ -160,8 +226,8 @@ and sends it over the connection.
|
|||
|
||||
The first request to a destination triggers the opening of the first
|
||||
connection.
|
||||
A second request with the same origin sent _after_ the first will reuse the
|
||||
same connection.
|
||||
A second request with the same origin sent _after_ the first request/response
|
||||
cycle is completed will reuse the same connection.
|
||||
A second request with the same origin sent _concurrently_ with the first
|
||||
request will cause the opening of a second connection.
|
||||
The configuration parameter `HttpClient.maxConnectionsPerDestination`
|
||||
|
@ -171,7 +237,7 @@ the max number of connections that can be opened for a destination.
|
|||
NOTE: If opening connections to a given origin takes a long time, then
|
||||
requests for that origin will queue up in the corresponding destination.
|
||||
|
||||
Each connection can handle a limited number of requests.
|
||||
Each connection can handle a limited number of concurrent requests.
|
||||
For HTTP/1.1, this number is always `1`: there can only be one outstanding
|
||||
request for each connection.
|
||||
For HTTP/2 this number is determined by the server `max_concurrent_stream`
|
||||
|
|
|
@ -71,17 +71,17 @@ participant HttpClient
|
|||
participant Proxy
|
||||
participant Server
|
||||
|
||||
Application -> Proxy: GET /path
|
||||
Proxy -> HttpClient: 407 + Proxy-Authenticate
|
||||
HttpClient -> Proxy: GET /path + Proxy-Authorization
|
||||
Proxy -> Server: GET /path
|
||||
Server -> Proxy: 401 + WWW-Authenticate
|
||||
Proxy -> HttpClient: 401 + WWW-Authenticate
|
||||
HttpClient -> Proxy: GET /path + Proxy-Authorization + Authorization
|
||||
Proxy -> Server: GET /path + Authorization
|
||||
Server -> Proxy: 200 OK
|
||||
Proxy -> HttpClient: 200 OK
|
||||
HttpClient -> Application: 200 OK
|
||||
Application -> Proxy : GET /path
|
||||
Proxy -> HttpClient : 407 + Proxy-Authenticate
|
||||
HttpClient -> Proxy : GET /path + Proxy-Authorization
|
||||
Proxy -> Server : GET /path
|
||||
Server -> Proxy : 401 + WWW-Authenticate
|
||||
Proxy -> HttpClient : 401 + WWW-Authenticate
|
||||
HttpClient -> Proxy : GET /path + Proxy-Authorization + Authorization
|
||||
Proxy -> Server : GET /path + Authorization
|
||||
Server -> Proxy : 200 OK
|
||||
Proxy -> HttpClient : 200 OK
|
||||
HttpClient -> Application : 200 OK
|
||||
----
|
||||
|
||||
The application does not receive events related to the responses with code 407
|
||||
|
|
|
@ -31,9 +31,13 @@ import java.util.List;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.LongConsumer;
|
||||
|
||||
import org.eclipse.jetty.client.ConnectionPool;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpClientTransport;
|
||||
import org.eclipse.jetty.client.HttpDestination;
|
||||
import org.eclipse.jetty.client.HttpProxy;
|
||||
import org.eclipse.jetty.client.ProxyConfiguration;
|
||||
import org.eclipse.jetty.client.RoundRobinConnectionPool;
|
||||
import org.eclipse.jetty.client.api.Authentication;
|
||||
import org.eclipse.jetty.client.api.AuthenticationStore;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
|
@ -800,4 +804,47 @@ public class HTTPClientDocs
|
|||
.send();
|
||||
// end::dynamicClearText[]
|
||||
}
|
||||
|
||||
public void getConnectionPool() throws Exception
|
||||
{
|
||||
// tag::getConnectionPool[]
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.start();
|
||||
|
||||
ConnectionPool connectionPool = httpClient.getDestinations().stream()
|
||||
// Cast to HttpDestination.
|
||||
.map(HttpDestination.class::cast)
|
||||
// Find the destination by filtering on the Origin.
|
||||
.filter(destination -> destination.getOrigin().getAddress().getHost().equals("domain.com"))
|
||||
.findAny()
|
||||
// Get the ConnectionPool.
|
||||
.map(HttpDestination::getConnectionPool)
|
||||
.orElse(null);
|
||||
// end::getConnectionPool[]
|
||||
}
|
||||
|
||||
public void setConnectionPool() throws Exception
|
||||
{
|
||||
// tag::setConnectionPool[]
|
||||
HttpClient httpClient = new HttpClient();
|
||||
httpClient.start();
|
||||
|
||||
// The max number of connections in the pool.
|
||||
int maxConnectionsPerDestination = httpClient.getMaxConnectionsPerDestination();
|
||||
|
||||
// The max number of requests per connection (multiplexing).
|
||||
// Start with 1, since this value is dynamically set to larger values if
|
||||
// the transport supports multiplexing requests on the same connection.
|
||||
int maxRequestsPerConnection = 1;
|
||||
|
||||
HttpClientTransport transport = httpClient.getTransport();
|
||||
|
||||
// Set the ConnectionPool.Factory using a lambda.
|
||||
transport.setConnectionPoolFactory(destination ->
|
||||
new RoundRobinConnectionPool(destination,
|
||||
maxConnectionsPerDestination,
|
||||
destination,
|
||||
maxRequestsPerConnection));
|
||||
// end::setConnectionPool[]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue