Fabric3 2.0: Bridging Service-Oriented and Event-Based Architectures
I'm excited to announce the release of Fabric3 2.0. This milestone introduces a number of new features. In particular, a major theme of the 2.0 release is creating a platform that brings service-oriented and event-based design closer together.
In this post, I will briefly touch on how Fabric3 does this and also identify some of the other important features in this release.
The area we invested in most heavily for the Fabric3 2.0 release is improving support for building event-based systems. presentation on event-based architectures. Peter Lawrey and Martin Fowler have also written very nice synopses here and here.
Fabric3 already has a rich dependency-injection model for event-sourced (pub/sub) interactions based on the concept of channels. In this release we have significantly refactored the Fabric3 internals to accommodate custom channels and low-latency requirements.
Now it is possible to plugin alternative channel implementations based on application requirements. One out-of-the-box channel type we have added is the ring buffer channel based on the LMAX Disruptor. This provides extremely low-latency, lock-free pub/sub capabilities:
We also have plans in the future to add more specialty channel types. For example, one based on coalescing buffers that is capable of dropping older unprocessed messages as newer ones arrive.
Ring buffer channels can be bound to transports such as ZeroMQ using simple configuration. This makes it possible to develop performant architectures using straightforward Java with no boilerplate API code:
For complete example, checkout the FastQuote trading platform sample.
One knock against middleware in general and dependency injection-based platforms in particular is that they introduce overhead during processing by proxying references to injected instances. Fabric3 has always had the ability to optimize wiring to perform direct (i.e. proxy-less) injection for local services. This means a local service invocation is a Java method invocation with no runtime intervention. Using this approach, we are able to achieve microsecond processing times for fairly complex tasks such as foreign exchange rate streaming.
In Fabric3 2.0 we took this concept further and applied it to channel injection. In Fabric3, channels are strongly-typed and represented by Java interfaces. At runtime, Fabric3 creates a proxy implementing the interface, which is then injected on a component that publishes events to the channel. By default, Fabric3 uses JDK proxies. For many applications, JDK proxies are sufficient.
However, for low latency systems, JDK proxies introduce relatively significant overhead. Perhaps more importantly, they create garbage as invocation parameters are wrapped in an array. When messages are processed at high volume in a system, the garbage resulting from the creation of parameter arrays can lead to excessive GC pauses, which negatively impacts latency.
Our solution to this problem is to use bytecode generation (via the ASM library) to implement the channel interface dynamically. The generated implementation directly calls into the Fabric3 channel infrastructure without using reflection or wrapping parameters. This results in garbage-free invocations that are as fast as handwritten code. In the next release we plan to go further and combine this with support for zero-copy message passing to ZeroMQ.
High Performance Logging
After working with a number of clients, we found a major bottleneck in many applications was logging. Part of the problem is that applications often log too much information. In fact, logging in the traditional sense is probably not necessary for many event-based systems, but that’s a subject for another blog.
Another culprit is the logging subsystem itself: most third-party logging implementations perform poorly in highly concurrent scenarios even when they support asynchronous writes. This is because the logging implementations are often subject to contention when placing messages in a queue that is read by a background thread persisting to disk. In addition, we have seen logging implementations produce a fair amount of garbage leading to unacceptable CG pauses.
To alleviate these problems, we re-wrote the Fabric3 logging framework to take advantage of the Disruptor for asynchronous writes and bytecode generation to provide high-performance, garbage-free operation. You can read more about it here.
Standards Support: SCA Conformance and JAX-RS 2.0 Support
One of Fabric3’s advantages with respect to proprietary Enterprise Service Bus products and integration platforms is that it is standards-based from the ground up. In this release we expanded our standards support to cover 100% conformance with the OASIS SCA Assembly, Policy, WS Binding and Spring Specifications. This includes all mandatory and optional features. In this context it is also noteworthy that we upgraded our support for RESTful Web Services to JAX-RS 2.0.
Get Started with Fabric3
To get started with Fabric3 2.0, try the sample applications, which contain all you need to get up and running with a cluster installation in less than five minutes.