Friday, February 6, 2015

Ratpack for reactive microservice

We are building a microsevice system and it's vital to build a microservice quick but still being reactive as defined in reactive manifesto.  the best way to do it is to build on a solid platform.  I've evaluated several options and picked Ratpack, here's why.

Goal


  1. To build a highly resilient, scalable & lightweight reactive microservices.
  2. To provide a framework developing new service only have to focus on the business/domain logic.

Resource contention

One of the resource contention we have in our application server is the use of thread pool when processing HTTP requests. Since the call is executed synchronously, the thread will be held up even though it's waiting for some other I/O operation. It wasted resources (thread) thus it's more resource is needed to scale the application. It also cascade the problem to higher level service. A database issue could led to the service depends on it holding up all its threads waiting for database's connection, a thread stavation. Which, in turns, cause hold all its request threads and the service depends on it will suffer too.
One solution is to use NIO, non-blocking I/O, so server will free up the request thread while processing I/O. Note that NIO does not always mean asynchrous. In some implementation, e.g. hystrix, an async operation will process the I/O in another thread while holding the main thread.

Netty

Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP and UDP socket server. It is an asynchronous event-driven network application framework.

Vs JAX-RS 2.0

jaxrs is a specification. it's, in fact, not comparable to Netty which is a server. jaxrs 2.0 does support async request, and implmentation includes Jersey, Resteasy & Netty. We'll have to compare the implementation and note that there's a Netty implementation for JAX-RS 2.0 too.

Vs Jersy on Jetty

Jersy documentation shows that to implement an async webservice, the API method needs to register a callback (which implements CompletionCallback) to the response and create a new Thread to perform expensive operation and call the resume method of the response to pass the result (and resume the suspended main thread?) Doesn't look like it releases the resource of the main request thread while it's waiting for the child thread to process.

Ratpack

The core of Ratpack is made up of only Java 8, Netty, Google Guava and Reactive Streams. It also has Hystrix and Groovy support. It does not take a heavily opinionated approach and too integration can be done easily using Guice. Since it's build on top of Netty, it has a the benefit Netty provides for async non-blocking I/O and event-driven. All its internal IO (e.g. HTTP request and response transfer) is all performed in a non blocking fashion. Blocking operations, like JDBC calls or existing libraries, are scheduled to an I/O bound thread pool. Developer just have to wrap the operation around with ExecControl.blocking which will return a Promise.
Instead of implementing JAX-RS, it support a Groovy DSL which makes route definition merely a "configuration".
For JDBC connection pooling, a HikariCP module is available where HikariCP has a phenomenally high performance. However, it's very simple to introduce other tools, e.g. JDBI or JOOQ.  I've developed a simple JDBI module which use HikariCP as datasource.
Ratpack supports both Spring Boot and Guice for dependency injection OOTB.
Note that Ratpack is completely build on top of Java 8.
Default configuration can be done via LaunchConfig which is a simple properties file. It also provides us environment-derivable configuration follows the principle of the 12 factor app, thus, it's docker friendly. It also provides a config module which supports yaml or json configurations.
Supports HTTP Streaming using Reactive Streams. It has flow control using backpressure paradigms.

Vs JBoss

JBoss is a application server, meaning it includes a lots of 3rd party libraries and sometimes, because of it's classloading structure, upgrading those libraries means patching JBoss's binary. Also, to deploy an JBoss application, JBoss needs to be installed and configured and the application is deployed as a war file.
Ratpack on the other hand is just a bunch of jar files which has a main method. A Ratpack application is a bunch of jar files which can be executed directly. It can also built as a fat jar, so all dependent jar files are expanded and put into one jar file. Deployment only have to copy that jar file and execute it with "java -jar".

Vs Dropwizard

As with Ratpack, Dropwizard also aims at a small, lean application which can be put together as a fat jar file. It is a opioninated framework, so it has configuration, application metrics, logging and operational tools, etc OOTB. However, it's less flexible than Ratpack in that sense (while providing more OOTB.)
Dropwizard used Jetty for HTTP connections and Jersy for JAX-RS 2.0 implementation. The latest version of Dropwizard (0.8.3-rc3) is using Jetty (9.2.6.v20141205) and Jersy (2.15) which supports async webserivce. Dropwizard documentation has no mention of async webservice but as discussed about for Jetty, even though it supports async requests, but it might not release the main request thread when waiting.
Dropwizard does has a Hystrix "plugin" ,Tenacity, developed by yammer.
Dropwizard does not have a dependency injection framework but integration with both Guice and Spring integration exists.
Dropwizard uses JDBI for database connection pooling and SQL creation. Also support flyway for database migration.

Hystrix

Async composition
Circuit breaker integration
Server-sent event streams for Hystrix dashboard

Guice

Vs Spring Framework

Gradle

Gradle is an open source build automation system which combines the power and flexibility of Ant with dependency management and conventions of Maven into a more effective way to build. It usage Groovy to provide DSL so developer can write code in the build script directly. It has been used in various project, Spring Framework since 3.2, Hibernate, all Netflix OSS projects and Android SDK.
Gradle has a wrapper so user do not need to install Gradle on their system but the wrapper will download it to the project.
Gradle also has plugin to generate docker image and build gulp projects. So we can have a single build system from code (either nodejs or java) to docker image.

Vs Maven

With DSL support, a gradle build script is much cleaner than Maven POM file. Maven has both "inherited POM data" (the parent POM) and "module aggregation" (child modules) in the same file. The problem is in terms of setting up after initial checkouts. You are not able to build modules unless its parent is there. But if the parent is the aggregator, the only way to make that happen is to install the entire project (or know your maven command switches and disable recursion).