In this contemporary world of enterprise application development, Microservice Architecture has become defacto paradigm. With this new paradigm, an application is going to have myriad set of independent and autonomous (micro)services which will be calling each other. One of the fundamental characteristics of Microservice Architecture is
Services must be easily consumable
Hence most of the services implemented will be exposing REST APIs. In order to consume these REST APIs, each Microservice application will have to implement a REST client. As most of the applications are built using Spring Boot, it is quite obvious that REST clients must be realized by using Spring’s RestTemplate. Since Performance of application is of paramount importance, input / output operation that happens whilst invoking REST api via RestTemplate assumes lot of significance. Hence I felt a need to not only pen down various aspects to be kept in mind while implementing REST client using RestTemplate & Apache HttpClient but also demonstrate it via a full blown implementation
Source Code @ Github
If you have come this far 🙂 and are convinced to go through remaining of the article, this is what I will be covering :
- Optimal connection pool management
- Resilient REST client invocation
- Observable connection pool
- Implementing secured REST client
Optimal Connection Pool Management
I am pretty much sure that most of us would have encountered issues pertaining to connection pool of REST clients – e.g. Connection pool getting exhausted because of incorrect configuration, or connections once acquired not being released and cleaned up etc. One can optimize the overall implementation if one really knows key configurable parameters and ways to manage them.
RequestConfig needs to be customized for finer control on key HTTP connection parameters –
- CONNECT_TIMEOUT – Indicates timeout in milliseconds until a connection is established
- CONNECTION_REQUEST_TIMEOUT – Indicates timeout when requesting a connection from the connection manager
- SOCKET_TIMEOUT – Indicates timeout for waiting for data OR maximum period of inactivity between 2 consecutive data packets
Connection pool management via PoolingHttpClientConnectionManager
ConnectionManager needs to be instantiated so that application can manage certain key configurations –
- MAX_CONNECTIONS – Sets maximum number of total connections
- MAX_PER_ROUTE_CONNECTION – Sets maximum number of connections per route
- VALIDATE_AFTER_INACTIVITY – Sets duration after which persistent connections needs to be re-validated before leasing
Configuring ConnectionKeepAlive strategy
This configuration is also equally important, as its absence from Http Headers will lead httpclient to assume that connection can be kept alive till eternity. For finer control on http connection parameters it would be prudent to implement a custom keep alive strategy
Housekeeping connection pool
So far we saw that connection pool as an application resource is being managed with various configuration parameters. As these resources are key to optimal functioning of application, it needs to perform periodic house keeping which does the following –
- Evicts connection that are expired due to prolonged period of inactivity
- Evicts connection that have been idle based on application configured IDLE_CONNECTION_WAIT_TIME_SECS
- From performance standpoint, it is recommended to execute such house keeping jobs at configured interval in a separate thread with its own thread pool configuration using ScheduledThreadPoolExecutor
While we all know the reasons for adopting Microservice Architecture, we are also cognizant of the fact that it comes with its own set of complexities and challenges. With distributed architecture, few of the major pain points for any application which consumes REST API are –
- Socket Exception – Caused by temporary server overload due to which it rejects incoming requests
- Timeout Exception – Caused by temporary input / output latency. E.g. Extremely slow DB query resulting in timeout
Phew ! Things are going damn crazy with Microservice Architecture 🙂 Thankfully we have Spring to our rescue with Spring Retry library. We can use its capabilities to make our REST API calls more resilient. I have used @Retryable and @Recover to configure retry strategy with exponential back-off and fallback strategy.
For our application we have configured retry (using @Retryable) for RemoteServiceUnavailableException with maxAttempts as 8 and with an exponential back-off policy i.e. 1000 * (2 to the power of n) seconds, where n = no. of retry attempt. We have also configured a fallback strategy using @Recover
Spring Retry in itself is a candidate for a separate blog, hence we are not delving deeper beyond this.
Observable connection pool
As we all know that in distributed architecture, observability of application / infrastructure resources is extremely important. The same holds good for Http connection pool. ConnectionManager provides methods to fetch its total statistics and statistics for each route at a given point of time. In order to avoid any performance issues, it is recommended to execute such metric logger at configured interval in a separate thread with its own thread pool configuration using ScheduledThreadPoolExecutor
Captured metrics can be used for better monitoring and alerting which can not only assist in proactive addressing of Http Client’s connection pool issues, but it may also help in troubleshooting production incidents pertaining to connection pool. This implicitly will help in reducing MTTR
Implementing secured REST client
For lot of APIs, depending on the nature of data it deals with, one may need to implement secured REST client. This is also demonstrated in code by using HttpClientSslHelper which will be responsible for setting up the SSLContext. This SSLContext can than be used to instantiate Registry of ConnectionSocketFactory.
Note – HttpClientSslHelper should be conditionally instantiated based on what kind of security strategy (i.e. Untrusted / Trusted) needs to be in place for the corresponding environment and profile (viz test, CI, dev etc.)
By knowing and understanding various aspects of HttpClient along with its key configuration parameters we can now build a highly performant, resilient, observable and secured REST client using RestTemplate.