BT

Ratpack 1.0 Launches Aiming to make Asynchronous Programming Easier on the JVM

by Charles Humble on Sep 25, 2015 |

Ratpack, a high performance Java web framework, has reached 1.0 status. The 1.0 release is API-stable and can be considered production ready. The main thing that makes Ratpack interesting is the execution model, which aims to make asynchronous programming on the JVM easier. "There’s a problem domain in the JVM space that doesn’t have a solution at this point," Dan Woods argued during his presentation at SpringOne2GX, "so Ratpack has taken that on".

The Ratpack processing model is similar to node.js. This is what it looks like:

In a four core set-up like this one, when a Ratpack application starts up an event loop gets bound to each of the cores. From a performance standpoint, in common with most frameworks, Ratpack is CPU-bound in the sense that when it starts up the event loop it’s using for non-blocking processing it ties one thread per event loop to each of the cores on the system; in other words the more cores you have the more traffic you can satisfy. This is somewhat similar to how Servlet applications work except that with Servlets each request gets a new thread. The Servlet approach has the advantage of a straightforward programming model, but if you need to move data from one thread to another then, of course, you incur a CPU context switch and a corresponding performance penalty as the data is moved on from one core to another.

Through Netty, Ratpack creates an "Event Loop Group", which binds a single-threaded event loop to each available CPU core. Each event loop is participant in processing any of the non-blocking networking requests that come into an application. As non-blocking requests are received into an event loop, they are asynchronously delegated to Ratpack for processing.  

Woods points out that there are several trouble points for building non-blocking, asynchronous web applications on the JVM. Specifically, he notes that many JVM libraries - like those build on JDBC - are not built to be used asynchronously. He goes on to state that a value proposition of Ratpack's is that it can make "any API asynchronous". That is to say, through its "execution model", Ratpack is able to seamlessly schedule work between the event loop ("compute thread") or a blocking thread. Non-asynchronous, JDBC-like calls can then be wrapped in an asynchronous fixture that will place their processing outside of the request-taking thread pool. When the call completes, processing is returned to the event loop. An important attribute of this flow is that when blocking calls return, their processing is returned to the originating computation thread, thus not requiring an additional context switch to resume processing. This means that any data that was computed prior to the blocking call is already primed in the CPU's cache, leading to better performance and overall efficiency. This is very efficient. On a 32 core machine “we can get pretty close to a million requests/second for a simple “hello world” application using just a single instance of Ratpack,” Woods said.

Asynchronous programming on the JVM is notoriously hard partly because the virtual machine has no inherent concept of Continuations. It’s typically also non-deterministic, which is far from ideal for a web application where waiting for a timeout in order to know that a problem has occurred is hardly satisfactory. Ratpack has a concept the team refer to as an execution, a processing stream which is somewhat analogous to a continuation. For each promise type (a representation of a value which will become available later) where you are doing an asynchronous operation the framework creates a sub-processing stream which can be thought of as a continuation in its own right. The complete chain of these will execute in FIFO order. The stream is started with a marker, so that the framework can determine when the end of the stream is reached. If something goes wrong in an individual sub-stream, say some sort of silent failure, Ratpack has awareness of what processing should have happened so it can inform the client that it isn’t going to get a response, thus providing a mechanism for giving deterministic behaviour.

The core of Ratpack 1.0 is written in Java, requiring Java 8, with the build system using Gradle 2.6. It is built on top of the Netty non-blocking event-driven networking engine and provides a number of low-level constructs for working with asynchronous APIs. It has been specifically designed for building microservices with first class support for language agnostic transports such as JSON. Optional support for Netflix’s circuit breaker library Hystrix is provided, and it integrates with Dropwizard Metrics for reporting. Ratpack has an extensive configuration model with support for YAML, JSON, Java properties, system properties, environment variables and so on, and integrates with Pac4j for authentication. HTML templating is provided by both Groovy and Handlebars.

Despite the core being written in Java Ratpack has good support for Groovy, making use of some of the advanced features of the Groovy compiler. During his presentation Woods stated that these include “the ability to inform a closure as to what object type you’ll be delegating the processing to, so we can still get, for example, a statically typed DSL out of this thing… And at this point Groovy is performant enough, with static compilation and even with InvokeDynamic, that we can get pretty close to the performance that Java offers”.

Ratpack has a long history. Starting as a Groovy DSL implementation example in 2010, it evolved into a JVM Sinatra clone before dumping that legacy and focussing on NIO/Performance in 2012. As such, if you’re familiar with some of the early legacy and haven’t followed it since, it may well be worth another look.

Rate this Article

Relevance
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

I've been waiting for this... by Florin Dragu

For me Ratpack is definitely one of the best Netty based frameworks out there.
I'm waiting for their full support for proxy style requests - it's been under work for a while.
I would also love to see support for distributed tracing the Zipkin style.

Re: I've been waiting for this... by Russell Hart

Hey Florin! I'd be really interested to know what you are waiting for specifically with regards to proxy style requests. I worked a lot on the proxy support that's there now and apart from adding some docs there were no plans in the short term to do any more. But if there is something you need then please feel free to raise an issue (github.com/ratpack/ratpack/issues) or come chat in our slack channel (slack-signup.ratpack.io/)

Unrelated to Ratpack I have also been playing around with Zipkin and Brave. I think this would be a great next integration module too. If this is something you are interested in and maybe even work on then again, please come chat.

Re: I've been waiting for this... by Florin Dragu

Cool, I wasn't aware just the docs are missing for proxy style requests.
I'll go on slack or open an issue/feature request for distributed tracing and maybe provide some ideas and snippets I used for other frameworks, including some custom netty code.

Re: I've been waiting for this... by Russell Hart

Great.

You can get a feel for what's there from this test github.com/ratpack/ratpack/blob/master/ratpack-... and this gist gist.github.com/rhart/eb1b701f348a155f2dad

Vert.x by Ersin Er

I wonder how is Ratpack different from Vert.x. They seem to be following quite similar approaches.

Vert.x clone? by Jakob Jenkov

I would say the very same thing. It sounds like the design is very close to Vert.x, only with less features. Performance is also about the same from the last benchmarks I have seen. What is the primary difference to Vert.x?

Validation for the Vert.x model? by Tim Fox

Firstly, congratulations on the Ratpack 1.0 release!

I have to say I almost spilled my coffee when I read "There’s a problem domain in the JVM space that doesn’t have a solution at this point,". As far as I can tell, almost everything in the description of Ratpack above could equally be applied to Vert.x too, and we've been doing it for 3+ years ;)

For those of you interested in high performance, asynchronous, event driven applications for the JVM with loads of features, please take a look at vertx.io :)

Re: Validation for the Vert.x model? by Dan W

Validation? Perhaps not.

I almost spilled my coffee when I read, "[Vert.x has] been doing it for 3+ years". But, that's not a criticism of Vert.x itself. Indeed, for a short -- albeit, very short -- period of time, Ratpack was built on Vert.x. After discovering that Ratpack could get much higher performance and build better fixtures in support of asynchronous web development, the internals were moved to build on top of Netty directly. Vert.x provides a fundamentally different programming model than Ratpack, and thus satisfies a different audience. To say, though, that any of the description of Ratpack could be applied to Vert.x is simply misleading...

The biggest, most glaring difference between Ratpack and Vert.x is Ratpack's execution model, which provides guaranteed and deterministic processing of asynchronous calls. Through the execution model, Ratpack is able to emulate something akin to a continuation, where asynchronous segments are serialized, allowing async apps to be written with determinism and confidence.

Through the execution model constructs, non-blocking and blocking calls can also be interleaved in a processing flow. This means that apps can be written in a reactive way that seamlessly integrates both async and non-async APIs, without any fear of blocking the event loop. As the article points out, processing-after-blocking is always returned to the originating thread, allowing the continuation to resume without any incurred context switch (highly performant).

Also, Ratpack's RxJava integration provides a scheduler that allows Observables to be integrated into the execution model. This means that apps can be written entirely using RxJava constructs, but still leverage Ratpack's deterministic processing flow. Observables can be easily (a single static call in Java, a single method invocation in Groovy) be translated to Promises, and vice-versa, meaning that Ratpack's core has no dependency on RxJava, but can still use all of its reactive capabilities. Observables in Vert.x are just a fixture over the asynchronous APIs, but don't provide any underlying processing guarantees.

Even with all this, it's not enough to say that async == performance. Vert.x, for example, has no automatic detection of NIO vs. EPOLL capabilities. This means that the vast majority of Vert.x applications are building on NIO itself, and thus sacraficing performance. Ratpack automatically detects and enables EPOLL when it's available, ensuring that apps are always delivering the highest level of performance possible.

Vert.x also has no inherent abstraction on dependency injection, meaning that DI is something that is affixed to an application after-the-fact. In Ratpack, the "Registry" concept allows dependency injection to be backed by zero-or-more DI providers. This is how Ratpack accommodates a mixed integration between both Guice (which the framework modules are built upon) and Spring Boot. Registries can be scoped globally, to an execution, or even to a single request. They can be built ad-hoc and cascaded to offer specific components according to the context in which processors need component resolution. This has been proven to be effective in high performance apps that require sharded database access. According to a request's attributes, an appropriate database handle can be resolved and used. We have seen applications from the community that leverage Guice, Spring Boot, and Netflix Governator all without conflict. Apps can also be easily built with no DI framework, but still leverage DI-like capabilities.

In terms of developer productivity and efficiency, Vert.x has no out-of-the-box support for hot reloading a project. You need to have integration with JRebel or Spring Loaded to get any reloading capabilities. In Ratpack, even the simplest of Groovy script applications can be development-time reloaded without the need for agent-based reloading libraries. Large projects can leverage the deep integration with Gradle's continuous build system to reload on-the-fly.

Ratpack's integration with Gradle doesn't stop there. Through the provided Gradle plugin, robust apps to be built upon concise build scripts. Additionally, the plugin provides version-locked resolution of framework libraries. For example, adding RxJava to a project is as simple as adding `compile ratpack.dependency("rx")` to the build script's `dependencies` block. And, the same goes for any of the framework's modules. This ensures dependency versions are properly aligned and upgrades are simple.

So, no, I don't think "validation" is the right feeling here. And, perhaps the only parallels that we can draw between Ratpack and Vert.x are that they are both asynchronous, non-blocking web frameworks for the JVM. That's about where they stop being similar, and Ratpack goes much further.

Re: Validation for the Vert.x model? by Tim Fox

Hi Dan,

Let me deal with your points one by one:

"But, that's not a criticism of Vert.x itself. Indeed, for a short -- albeit, very short -- period of time, Ratpack was built on Vert.x.
After discovering that Ratpack could get much higher performance and build better fixtures in support of asynchronous web development, the internals were moved to build on top of Netty directly."

Firstly, that was a long time ago. And secondly.. performance is certainly one of Vert.x's strong points. The last time we submitted to techempower we came out right at the top in basic HTTP performance across _all_ frameworks. We need to submit again once Vert.x 3.1 is out. But suffice to say, very few JVM frameworks can touch Vert.x when it comes to performance.

You mention 1M HTTP req/response per second on commodity hardware for Ratpack, the last time I tried with Vert.x we had something around 4 or 5 million HTTP req/response per second on some prety basic hardware. Like I say, we'll resubmit to techempower before long, I invite you to do the same :)

"Vert.x provides a fundamentally different programming model than Ratpack, and thus satisfies a different audience."

This is a misunderstanding of Vert.x. Unlike most frameworks/libraries around today Vert.x is _unopinionated_, in other words we don't provide a single programming model, we provide a variety. So you can use callbacks if you like, or you can use RxJava or you can vertx-sync (synchronous fiber based model). Vert.x doesn't satisfy a different audience - it satisfies a much broader audience - a subset of which might be those users who like the Ratpack programming model.

"The biggest, most glaring difference between Ratpack and Vert.x is Ratpack's execution model, which provides guaranteed and deterministic processing of asynchronous calls. Through the execution model, Ratpack is able to emulate something akin to a continuation, where asynchronous segments are serialized, allowing async apps to be written with determinism and confidence."

So you have an RxJava-like, composable programming model? This is hardly something groundbreaking or unique. As mentioned before, if you like this kind of thing we provide RxJava support. If you don't like it we provide other options (these kind of programming models can be pretty hard for some developers to grok), e.g. we provide _real_ continuations so you can write your non blocking code in a sync way :)

"Through the execution model constructs, non-blocking and blocking calls can also be interleaved in a processing flow. This means that apps can be written in a reactive way that seamlessly integrates both async and non-async APIs, without any fear of blocking the event loop. As the article points out, processing-after-blocking is always returned to the originating thread, allowing the continuation to resume without any incurred context switch (highly performant)."

We support this in Vert.x too. You can interleave blocking code with non blocking code (see execute blocking) in a way that will never block the event loop.

"Also, Ratpack's RxJava integration provides a scheduler that allows Observables to be integrated into the execution model. This means that apps can be written entirely using RxJava constructs, but still leverage Ratpack's deterministic processing flow. Observables can be easily (a single static call in Java, a single method invocation in Groovy) be translated to Promises, and vice-versa, meaning that Ratpack's core has no dependency on RxJava, but can still use all of its reactive capabilities. Observables in Vert.x are just a fixture over the asynchronous APIs, but don't provide any underlying processing guarantees."

That's not true. Our RxJava support also implements schedulers which play nicely with the Vert.x execution model.

"Even with all this, it's not enough to say that async == performance. Vert.x, for example, has no automatic detection of NIO vs. EPOLL capabilities. This means that the vast majority of Vert.x applications are building on NIO itself, and thus sacraficing performance. Ratpack automatically detects and enables EPOLL when it's available, ensuring that apps are always delivering the highest level of performance possible."

Again, untrue. EPoll will automatically be used on platforms that support it.

"Vert.x also has no inherent abstraction on dependency injection, meaning that DI is something that is affixed to an application after-the-fact."

I'd consider that a good thing. Vert.x doesn't require dependency injection but it's agnostic about it so you can use it easily inside a DI framework (e.g. see our Spring examples). But if you don't like or don't want DI you can just as easily use it without DI.

"In terms of developer productivity and efficiency, Vert.x has no out-of-the-box support for hot reloading a project. You need to have integration with JRebel or Spring Loaded to reloading capabilities. In Ratpack, even the simplest of Groovy script applications can be development-time reloaded without the need for agent-based reloading libraries. Large projects can leverage the deep integration with Gradle's continuous build system to reload on-the-fly."

This is not really true. We've had reloading since very early versions of Vert.x. We dropped hot reload temporarily in 3.0 but it's been re-implemented for 3.1 (to be released next week)

"So, no, I don't think "validation" is the right feeling here. And, perhaps the only parallels that we can draw between Ratpack and Vert.x are that they are both asynchronous, non-blocking web frameworks for the JVM."

Ratpack started out as a sinatra-like web framework for Java/Groovy and now has morphed into a fully-fledged platform for writing asynchronous applications on the JVM. I would disagree that there are few similarities - a simple reading of the Ratpack and Vert.x docs will make that clear to the user.

But.... let me be clear. I welcome this! The fact that Ratpack has decided to take such a "Vert.x-like" path is a good thing. It's testament to the way the industry is moving with respect to application development. So let me say again, I wish Ratpack the best of luck. It just raises a few eyebrows when you write an article that more or less exactly describes the Vert.x execution model and raison d'etre and then claim that this is something new and "There’s a problem domain in the JVM space that doesn’t have a solution at this point," - well try telling that to some of our high profile production users vertx.io/whos_using/ who have been using this model for some significant time ;)

"That's about where they stop being similar, and Ratpack goes much further."

That's a pretty absurd statement - the feature set of Vert.x is much larger. That's self evident to anyone who has taken more than a 5 minute look!

I wish you the best of luck with Ratpack and it's great to see reactive/non blocking application development on the JVM gaining strength :)

Re: Vert.x clone? by Luke Daley

Hi Jakob,

The design is close to Vertx in that it's built on Netty, and everything that implies. That's about it.

It's correct to say that Vertx has “more features”. It has an in-built message bus, in-built clustering, multi net protocol support, polyglot support and many add on modules. In terms of performance, while comparable, Vertx is almost certainly better if for no other reason than Norman Maurer worked on it for a time and made many optimisations. In my tests, they are comparable in this regard though.

I started Ratpack about two years ago, when Vertx was early in its 2.x period. I originally attempted to build Ratpack on top of Vertx. In the end, it wasn't a good fit. That doesn't mean that Vertx isn't a fine bit of technology.

My goals were:

1. Simplest possible build time integration
2. No runtime container
3. Focus on HTTP apps
4. Approachable async
5. No opinion on application structure beyond request processing (i.e. no actors, message bus, whatever)
6. Testability
7. No code generation (WYSIWYG)

There's a lot of overlap there with Vertx (based on my understanding), and I'd say that there's even more convergence with Vertx 3 (opposed to 2). However, there are enough differences between the implementations of these goals at least to differentiate the two.

For most people, the main tangible difference I would expect them to feel first is that Ratpack promotes composition of request processing logic through a function graph as opposed to actors/message bus (disclaimer: my Vertx knowledge is based on 2, things may have changed). That's only better or worse depending on your perspective and tastes.

In summary, I don't think there's any convincing argument that I could put forward that would sway a discerning programmer who is very happy with Vert.x that they would be happier with Ratpack. There are plenty of differences, but they mostly come down to style.

Re: Validation for the Vert.x model? by Luke Daley

Thanks for the congratulations Tim.

Re: Validation for the Vert.x model? by Joshua White

I really enjoy the competition between teams. Game on.

Re: Vert.x clone? by PeiSong Xiong

The style matters.

The first time I saw vertx was like 'what the hell, nodejs in java?'.

Anyway you guys need work harder on documentation, it's not very helpful for now.

Re: Vert.x clone? by Christian Oestreich

We are in the middle of a bake off testing several async non-blocking stacks and frameworks. In regards to this direct topic I have a proclivity for Ratpack over Vert.x for the nice integrations directly with Spring Boot and Gradle and our teams familiarity with these supporting technologies.

As a framework designer it is the golden standard to build the un-opinionated swiss army knife, but sometimes the the opinionated frameworks end up being the most productive in the long run due to abstracting the repetitive and mundane tasks that mire down productivity.

Sadly the amount of useful sample projects and code using Ratpack doing anything beyond Hello World are limited to a very small set mostly from Dan Woods and Mr. Haki.

After reading this article and the ensuing discussions I really wanted to see Vert.x in the latest TechEmpower round 11 results, but it was removed and the results are unavailable.

In the end, we may pick something completely unrelated to either framework, but it has been interesting learning about each one and struggling through the simple tasks with each.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

14 Discuss
General Feedback
Bugs
Advertising
Editorial
Marketing
InfoQ.com and all content copyright © 2006-2016 C4Media Inc. InfoQ.com hosted at Contegix, the best ISP we've ever worked with.
Privacy policy
BT