Sunday, February 8, 2015

Moving from Ratpack 0.9.12 to 0.9.13

one of the biggest and most appreciated change is the removal of LaunchConfig and introduction of ratpack-config.  it's not yet really documented, but you can find out how it works by looking at the commits in the book-example and java gradle example regarding the change.

so, now, you don't have the RatpackMain, and you've to build your own.  first thing to do is to set the mainClassname in the build.gradle.  this will tell the application plugin which is the main class (ratpack-java gradle plugin extends application plugin.)  and shadow plugin will automatically pull the value from the application plugin and set the manifest correctly.

here's what the main class could looks like.
it starts by composing ConfigData (ratpack-config) from a yaml file (you can also use property or json, or all of them), env (with prefix) and system properties (also with prefix).

then you can get the ServerConfig you'll need to start the RatpackServer from the ConfigData (and i put everything under "server")

here's how application.yaml looks like.

how, for your existing HandlerFactory, all you have to do is to add a constructor to pass in ConfigData and change the create method to Handler create(Registry registry).

note that i have a section "idol" in the yaml config.  to pass the configuration to the Idol module, all we have to do is get it from ConfigData, it'll populate IdolConfig, and then, set that to the registry.

To use it, just @Inject IdolConfig.

btw, i've also show here how to setup the hystrix sse.  :D

also, the ratpack-jackson used to bind the objectmapper instance directly, leaving us no way to extend it.  i've developed a jackson module to serialize an annotated pojo to HAL format.  in 0.9.12, i have to extend the JacksonModule and @Provides the ObjectMapper.  however, in 0.9.13, it's now configurable.  we can simply set the jackson module in the config!

there's a small change to the http client too.  gone are HttpClients to get an instance of HttpClient with LaunchConfig, just @Inject it!  

Dockerize hystrix dashboard & turbine

i'm pretty surprise that there are no docker image for either hystrix dashboard or turbine on docker hub.  and i build one.  to run hystrix dashboard with turbine

docker run -d --name=turbine -p 8000 -e TURBINE_STREAMS="http://192.168.1.14:9500/hystrix.stream" arthurtsang/docker-hystrix-turbine
docker run -d --name=dashboard --link turbine:turbine -p 7979:8080 arthurtsang/docker-hystrix-dashboard

where TURBINE_STREAMS points to all msvc implements hystrix sse (server side event)

the turbine container will link to the dashboard container (and since we don't need to access the turbine directly, it's mapped to a random high number port on the host os).

to use, access http://localhost:7979 and enter http://turbine:8000/turbine/turbine.stream.  (... maybe i should export port 80 on turbine instead)

Gradle shadow plugin

Gradle has a very convinent shadow plugin.  all you really have to do is to apply the plugin and you can build with ./gradlew shadowJar.

then i found an example of adding all the build information to the jar's manifest, and turns out that forces me to rebuild the jar every time it build as i simply put new Date() to the build date!  gradle will smart enough to know the manifest has change!!  (as new Date() will output not only the current date, but the time!)

here's what i do to avoid it.

well, we could add a property and only on the CI server, it'll include the time for release (if we needed that) and all local dev, should have no reason to build it everytime!  every second counts!


Ratpack + Gradle + Docker


we'd like to put docker into the dev workflow and ship the docker images.  it's important the developer can develop/test on the docker image to get the max benefit out of docker in devops: no more "but it works on my machine."  since building the ratpack application is using gradle, it'd make sense to add docker plugin to gradle build script.  (developer has less command to deal with)

inspired by this post http://kyleboon.org/blog/2014/08/14/ratpack-plus-docker-plus-gradle/, i started to do the same thing but choose the bmuschko gradle plugin https://github.com/bmuschko/gradle-docker-plugin instead.  it's using later version of docker-java https://github.com/docker-java/docker-java.  and can do much more than just creating an image and publish to docker registry.

Add the followings to your build.gradle -
you can put the docker.url & registryUrl in gradle.properties, so it won't be hardcoded

Add the Dockerfile to your project root directory
To minimize the file size, we use busybox.
docker images

REPOSITORYTAGIMAGE IDCREATEDVIRTUAL SIZE
msvc-search1.014c228ee14356 seconds ago197.9 MB
hystrix-dashboardlatest6b93ff8445719 hours ago479.8 MB
centos7dade6cb4530a2 days ago210.1 MB
registrylatestc55308716b3610 days ago414.2 MB
ubuntulatest5ba9dab4745910 days ago188.3 MB
peelsky/zulu-openjdk-busyboxlatest050380da31ed13 days ago181.8 MB
progrium/busyboxlatest8cee90767cfe2 weeks ago4.789 MB
atcol/docker-registry-uilatest28d7d683c7a95 weeks ago908.6 MB

progrium/busybox is just 5MB! And we have license issue to ship with oracle jdk, so we use openjdk. But appears openjdk are only distributed through yum/apt and i can't find any way to install that on busybox as it only has opkg. Zulu http://www.azulsystems.com/products/zulu, is certified build of openjdk and it's 100% opensource and free. It also provides official docker image, however, they are not using busybox. Luckily someone already did that! thanks to peelsky/zulu-openjdk-busybox.  with the jdk it's mere 182MB.

Also, since the Dockerfile is put on the project root, it'll tar up the whole project and send to the docker deamon while we only need the fat jar!  to avoid that, add .dockerignore to your project root.

Now when you run ./gradlew --info buildDocker, only the necessary file are sent to the docker daemon.

Sending build context to Docker daemon 16.12 MB
Sending build context to Docker daemon
Step 0 : FROM peelsky/zulu-openjdk-busybox
 ---> 050380da31ed
Step 1 : WORKDIR /app
 ---> Using cache
 ---> 954a21f6409e
Step 2 : USER daemon
 ---> Using cache
 ---> 208cd5606087
Step 3 : ADD ./build/libs/msvc-search-1.0-all.jar /app/msvc-search-1.0-all.jar
 ---> 6e11e87fb593
Removing intermediate container c109ca327f00
Step 4 : CMD java -jar /app/msvc-search-1.0-all.jar
 ---> Running in bea41332ae6a
 ---> 82e41217ecd2
Removing intermediate container bea41332ae6a
Step 5 : EXPOSE 9500
 ---> Running in 40d91cd09bd0
 ---> b4e042fa2a6e
Removing intermediate container 40d91cd09bd0
Successfully built b4e042fa2a6e

16MB is pretty much the size of the fat jar.

Saturday, February 7, 2015

Docker behind firewall

In the container, i wanted to use curl to download something, i'll always get a bad address error.  and even the proxy server hostname fail to resolve.

I'm using ubuntu, it set the dns to 127.0.0.1, however, docker can't use it, so docker use 8.8.8.8 (google public dns) by default.

the problem is behind firewall, i can't access 8.8.8.8, so we'll have to add the dns setting to docker

in /etc/default/docker add --dns for your dns ip.

DOCKER_OPTS="--dns <ip1> --dns <ip2> --dns 8.8.8.8 --dns 8.8.4.4"

I keep the google dns here so when i'm not behind firewall, i can resolve hostname with google dns.

and if you need Docker to use an HTTP proxy, it can also be specified here.

export http_proxy="http://proxy:8008"
so, no more ENV http_proxy in the Dockerfile, it's not portable and should not be specified in the Dockerfile.

and don't forget to restart docker service after making the change.

service docker restart
UPDATE:
if you're using systemd, the /etc/default/docker is not used.  you'll have to add the following to
/etc/systemd/system/docker.service.d$ cat docker.conf 
[Service]
EnvironmentFile=-/etc/default/docker
ExecStart=
ExecStart=/usr/bin/docker -d $DOCKER_OPTS -H fd://


Docker registry

the easiest way is to start them as a container.

docker run -d --name=registry -p 5000 -v /tmp/registry:/home/arthur/docker/registry registry
docker run -d --name=registry-ui --link registry:registry -p 8080:8080 -e REG1=http://registry:5000/v1/ atcol/docker-registry-ui

that's it.  you can push your docker image to port 5000 and access the web ui on port 8080.

of course, if it is a production env, you probably don't want to put the docker file on a local file system and docker registry don't have any authentication support.  you will want to use other 3rd solution, e.g. artifactory pro.

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).