Reactor - a foundation for asynchronous applications on the JVM

Engineering
Jon Brisbin
May 13, 2013

We’re pleased to announce that, after a long period of internal incubation, we’re releasing a foundational framework for asynchronous applications on the JVM which we’re calling Reactor. It provides abstractions for Java, Groovy and other JVM languages to make building event and data-driven applications easier. It’s also really fast. On modest hardware, it’s possible to process over 15,000,000 events per second with the fastest non-blocking Dispatcher. Other dispatchers are available to provide the developer with a range of choices from thread-pool style, long-running task execution to non-blocking, high-volume task dispatching. The GitHub repo is here https://github.com/reactor/reactor.

Reactor, as the name suggests, is heavily influenced by the well-known Reactor design pattern. But it is also influenced by other event-driven design practices, as well as several awesome JVM-based solutions that have been developed over the years. Reactor’s goal is to condense these ideas and patterns into a simple and reusable foundation for making event-driven programming much easier.

Reactor’s abstractions give the developer a set of tools to not just develop but compose applications in a way that more efficiently uses system resources–which is particularly important when running in the cloud–and reduce or eliminate the spaghetti of nested callbacks (aptly named “callback hell”) that has so far burdened most asynchronous applications.
What is Reactor good for?

While you can make Reactor do a lot of things because of its inherent flexibility, it’s really designed to be a foundational framework for applications that need high throughput when performing reasonably small chunks of stateless, asynchronous processing. The sheer volume of non-human-generated data in modern applications can easily overtake a traditional single-threaded, blocking design model. From mobile applications that generate streams of location information to computerized manufacturing machines that send out vast amounts of geometric data to big data applications mining real-time logs to generate business metrics: modern data-driven applications demand better resource utilization and higher throughput than a traditional imperative, blocking application can usually provide.

That’s why the Spring XD project (as well as several other Spring ecosystem projects like Spring Integration and Spring Batch) intend to take advantage of Reactor. Combining Reactor’s async dispatch with the NIO-based TCP adapters from Spring Integration to provide high throughput syslog and MQTT ingestion is just one example.
Selectors, Consumers and Events

Three of the most foundational components in Reactor’s reactor-core module are the Selector, the Consumer, and the Event. A Consumer can be assigned to a Reactor by using a Selector, which is a simple abstraction to provide flexibility when finding the Consumers to invoke for an Event. A range of default selectors are available. From plain Strings to regular expressions to Spring MVC-style URL templates

Here’s some example code to show how easy it is to create event-driven applications using Reactor:

// This helper method is like jQuery’s.
// It creates a Selector instance so you don’t have
// to construct one using ‘new Selector(“parse”)’
import static reactor.Fn.$;

Reactor reactor = R.create();

// Register interest in events published to key “parse”
reactor.on($(“parse”), new Consumer<Event>() {
public void call(Event ev) {
service.handleEvent(ev);
}
});

// Send an event to this Reactor and trigger all actions
// that match the given Selector
reactor.notify(“parse”, Fn.event(“Hello World!”));

To Groovy, with Love

Included in the Reactor distribution is a module called reactor-groovy. It includes a Groovy binding which provides an expressive syntax, compile-time checking with @CompileStatic, implicit transformation of Closures into Consumers, as well as other Groovy-specific time-savers.

// Assign a Closure as a Consumer
reactor.on($(‘hello’)) { Event ev ->
if(ev.headers[‘specialHeader’]) { // Events can have metadata
doSomethingWith(ev.data)
}
}

// Use Groovy helpers for notify
reactor.notify for: ‘hello’, data: ‘Hello World!’, specialHeader: ‘specialValue’

And the best part: we didn’t have to trade performance to get there. The same JVM optimizations apply to Groovy code that apply to Java code. We’re continually (some would say “obsessively”) micro-benchmarking the dispatching code to make it as fast as possible and provide both Java and Groovy users the highest possible throughput.
Ready for Java 8 when you are

Reactor is also designed to be friendly with Java SE 8’s lambda expressions and many components within Reactor can be replaced with lambdas to make your Java code more succinct. We’ve also found that using Java 8 lambdas (and method references) results in slightly higher throughput. When Java 8 goes GA, you won’t have to wait for Reactor to support it. It will Just Work ™.

// Use a POJO as an event handler
class Service {
public void handleEvent(Event ev) {
// handle the event data
}
}

@Inject
Service service;

// Use a method reference to create a Consumer<Event>
reactor.on($(“parse”), service::handleEvent);

// Notify consumers of the ‘parse’ topic that data is ready
// by passing a Supplier<Event> in the form of a lambda
reactor.notify(“parse”, () -> {
slurpNextEvent()
});

Functional, Imperative, Callback or Promise: you pick

Executor, Event Loop, Actor, Distributed–there are many shapes for one of the most important use-cases in event-driven programming: task dispatching. Reactor supports several styles of event-driven programming. In addition to the traditional callback-oriented Consumer interface, Reactor has an interpretation of the Promises/A+ spec that makes working with deferred values and consumers very easy.

Nested callbacks, while straightforward and easy to use in an imperative language like Java, become hard to maintain when the complexity of the application increases. Reactor’s Composable and Promise are all about easy composition of actions. You can chain a Composable into a series of actions that transform values, save things to a datastore, aggregate values, or the like. And since they’re chainable, you can do all this in pure Java in a type-safe way. Here’s a quick example of using a Composable to easily chain a series of asynchronously-executed tasks that perform transformation and filtering on the data stream as it passes through the Composable:

Composable c = new Composable<>()
.map(new Function<Integer, Integer>() {
public Integer apply(Integer i) {
return i % 2;
}
})
.filter(new Function<Integer, Boolean>() {
public Boolean apply(Integer i) {
return i == 0;
}
})
.consume(new Consumer() {
public void accept(Integer eveni) {
// work with only even numbers here
}
});

Each step of the Composable is a potentially asynchronous task. Calls to map, filter, and consume assign tasks to execute when the value from the previous step is available–no callback hell required.
Dispatching

There is no silver bullet to any dispatching concern. Reactor provides different styles of Dispatchers because every asynchronous application has different dispatching needs in different parts of the application. When ingesting tidal waves of data, for example, a Reactor will want to use the high-speed non-blocking Dispatcher based on the venerable Disruptor RingBuffer. But if a Reactor is issuing a blocking call to a database server or storing a blob of data in S3, it will want to leverage the lower-throughput worker pool Dispatcher. Reactor provides several options so you can pick the right tool for the job.

If the built-in Dispatcher implementations don’t fit your needs, then Reactor provides a solid foundation on which you can build your own Dispatcher that is tailored to your problem domain.
Grails, meet Events, Events, meet Grails

Grails is a full-stack web application framework for the JVM. With its mature codebase backed by a thriving community, Grails is nonetheless facing new architectural challenges. Events were introduced into Grails through the platform-core plugin. But Events are so powerful that this feature really belongs in the core; so from version 2.3 on, Grails applications will have a built-in, extremely powerful yet easy to use, convention-based Events API that looks very similar to the current implementation in the platform-core plugin. This Events API will be built on a Reactor foundation.

The goal of integrating events into Grails is to target new kinds of development–especially “realtime web” and high-scale, non-blocking application development. Combined with the Asynchronous GORM features, the Events API will prove a powerful ally. Complex queries accessing Big Data stores–thus taking a long time to process–can react when their results are ready by pushing them directly to the browser.
A passionate community is essential

We’ll be working diligently over the next several months preparing for SpringOne, where many of our big, fast, and scalable data solutions will play first fiddle. If you haven’t made plans to attend yet, you definitely should! We’ll have a session on Reactor and how you can use it to create high-scale, high-throughput event-driven applications.

But we can’t do it without you! This effort will only succeed if you help us create a passionate and active community for big, fast, event-driven application development on the JVM. If you’re interested, check out the source code on GitHub, see some example code in the reactor-quickstart, report any issues you find, ask questions about Reactor on StackOverflow using hashtag #reactor, join the discussion on the reactor-framework Google Groups email list, or fork the repo to help add features, tweak things for higher throughput, and contribute new ideas.

We’d love to see you there!
comments powered by Disqus

translate:
翻译:

我们很高兴地宣布,经过长时间的内部孵化,我们正在JVM上发布一个异步应用程序的基础框架,我们称之为Reactor。它为Java、Groovy和其他JVM语言提供了抽象,使构建事件和数据驱动的应用程序更加容易。也很快。在一般的硬件上,使用最快的非阻塞调度程序每秒可以处理超过15000000个事件。其他分派器可以为开发人员提供一系列选择,从线程池样式、长时间运行的任务执行到无阻塞、大容量的任务分派。GitHub回购协议在这里https://GitHub.com/reactor/reactor。
反应堆,顾名思义,受众所周知的反应堆设计模式的影响很大。但它也受到其他事件驱动设计实践的影响,以及多年来开发的基于JVM的解决方案。反应器的目标是将这些思想和模式浓缩成一个简单且可重用的基础,使事件驱动的编程变得更加容易。
Reactor的抽象为开发人员提供了一套工具,不仅可以开发应用程序,还可以以更高效地使用系统资源(在云中运行时这一点尤为重要)的方式组合应用程序,并减少或消除迄今为止负担最重的嵌套回调(恰当地称为“回调地狱”)的麻烦异步应用程序。
反应堆有什么用?
尽管由于Reactor固有的灵活性,您可以让它做很多事情,但它实际上是为那些在执行相当小的无状态异步处理块时需要高吞吐量的应用程序设计的一个基础框架。现代应用程序中大量的非人工生成的数据可以轻松地取代传统的单线程、模块化设计模型。从生成位置信息流的移动应用程序到发送大量几何数据的计算机化制造机,再到挖掘实时日志以生成业务指标的大数据应用程序:现代数据驱动应用程序比传统应用程序需要更好的资源利用率和更高的吞吐量命令式、阻塞式应用程序通常可以提供。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值