Six Considerations When Building High-Performance Java Microservices With EDA
In this article, we will outline the six key considerations and tactics for building high-performance Java microservices using event-driven architecture.
Join the DZone community and get the full member experience.
Join For FreeEvent-Driven Architecture (EDA) is a design principle focused on the creation, detection, and reaction to events. Renowned for its resilience and low latency, EDA is a reliable choice for developing robust, high-performing microservices. Moreover, this method can be helpful in improving productivity and making the process of cloud migration smoother.
In this article, we will outline six key considerations and tactics for developing such services.
Crafting Event-Based Microservices
Within EDA, microservices interact with each other through events. An event is simply an immutable indication that something has happened. Microservices register their interest in a subset of events and perform their processing by reacting to these events when they occur. On completion of handling of an event, microservices will usually post one or more events reflecting the result of this processing, which will trigger further downstream microservices.
For simplicity, we treat all inputs as recorded, replayable events. These inputs include the wall clock, reference information, configuration details, commands, and queries. For instance, timestamps are derived from the most recent wall clock event, so they are replayable, and a command or query is modeled as an event signifying that such a command or query has been requested.
The EDA environment manages events using an immutable, ever-growing journal or log. This methodology means that microservices become less reliant on each others’ internal operation (loosely coupled), making systems more flexible in many ways, facilitating different deployment options, and improving scalability.
Microservices developed within an event-driven framework are inherently simpler to design, test, and reason about. Each microservice is a function of its code and all the events it has ever processed. This aspect simplifies the creation of behavior-driven tests, essentially boiling down to a data-in and data-out scenario. This simplifies the maintenance of the software.
Implementing Application Logic Within an Event-Driven Context
In an EDA application, events are defined to model those in your business domain. Application components react to these events in ways that model the activities of your business processes. Data associated with an event encapsulated within the event’s payload can be implemented in the application as a Data Transfer Object (DTO). Representing events in a single, immutable event stream has the additional advantage of providing an audit trail of all the state changes that have occurred during the execution of the application, making it easier to analyze unexpected behavior, generate test environments that mirror production environments, and satisfy regulatory requirements. The event stream becomes the single source of truth throughout the application.
Adopting a lightweight, comprehensive recording strategy eliminates the need for extensive logging, minimizing overhead and latency. To replicate the application’s state, retrieve the event journal and replay the microservices to the desired point. This approach allows you to debug and verify issue resolutions in the application proactively rather than waiting for the issues to recur.
Optimising Microservice Performance
Using high-performance, low-latency messaging, microservices can communicate as fast as threads in a monolith while still maintaining the key benefits of microservices. These include distinct contracts between components, independent testing, and development, a comprehensive record of all interactions, and independence in deployment strategies.
Despite a system being distributed across numerous data centers globally, the efficiency of these microservices means that a single machine can effectively handle the critical, most latency-sensitive processing tasks.
We generally conduct latency benchmarks for single-threaded services at one hundred thousand events per second. A service requiring higher throughput can handle loads exceeding a million events per second.
Moreover, each component will operate fastest when event processing is performed in a single thread since this eliminates the significant overhead of lock contention, as there will be no concurrent access to mutable states within the component.
Event Replication, Deterministic Services, and Live Upgrades
We use Chronicle Queue as an event store, with total ordering and replication of this journal from leader to followers. Followers will see exactly the same data in the same order, with the same identifier for each message.
Chronicle Services is a Java-based Microservices framework that provides features that can be used to ensure that services are deterministic. You can be sure that the follower services will be in the same state as the leader and be ready to take over from it.
We are seeing an increasing demand for support for live upgrades. Using this framework allows us to build services that can seamlessly transition between instances running different software versions and revert back if necessary.
Published at DZone with permission of Rob Austin. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments