div | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||
|
Overview
Excerpt |
---|
Of Talon's two High Availability models, Event Sourcing requires more discipline to use |
...
but can yield better performance particularly for latency sensitive applications. In event sourcing |
...
, rather than replicating changes to state object and outbound messages, an application's inbound messages are replicated and replayed to produce the same application state and outbound messages. This section discusses the anatomy of an application coded for Event Sourcing. |
Event Sourcing has several performance advantages that are of particular interest to applications concerns with very low latency. With event sourcing, replication is much cheaper because:
- Received messages don't require re-serialization before replication (they are received in serialized form)
- Received messages can be replicated in parallel with the execution of business logic which can effectively reduce the storage cost overhead to 0.zero!
While the premise behind Event Sourcing is simple, it requires discipline on the part of the application developer to ensure that no business logic decisions are made based on any data but that in the inbound messages and the state generated by those message to date, otherwise it would lead to divergent state on the primary and backup members. For example, something as simple as making a logical decision based on System.currentTimeMillis() could lead to the primary instance accepting an order and a backup instance rejecting an order as stale because of clock skew. In the event that the primary instance fails, the order would then not exist on the backup.
Unlike a State Replication application, the Talon does not need to be made aware of or manage your application's state because it reconstituted on recovery purely through message replay. This means that your application is not required to use ADM modeled state. One downside to Event Sourcing is that for an application to recover from a cold start (e.g. no backup running), the application's entire inbound message stream needs to be replayed from disk. For many classes of applications this is not an issue, but for applications that run 24x7x365 with long-lived state such an approach would be infeasible - the disk space and recovery time would be enormous! On Talon's roadmap is a feature that will allow Event Sourcing application's applications to use ADM modeled state which can be periodically checkpointed in the background to allow older messages in the inbound stream to be discarded.
...
A basic event sourcing application is straightforward to create and working with event sourcing is very similar to Working with State Replication with the exception that the application does not need to expose a state factory to the underlying AepEngine. Your application state does not even need to be modeled via ADM, because the underlying engine and store does do not need to be aware of it.
A quick way to get started is to use the nvx-talon-es-processor-archetype described in Maven Archetype Quick Starts. The general flow for creating a an event sourcing application involves:
- Modeling Messages and State
- Declaring a main class annotated for with an HAPolicy of EventSourcing
- Writing message handlers to perform business logic.
...
When working with an application using EventSourcing you can annotate handler methods that accept the received message type with an EventHandler. With event sourcing Event Sourcing, you do not need to to make Talon aware of your application state it remains completely private to your application.
...
Register Messaging Factories
When working with state replication both the ADM and message and state object event sourcing only message factories need to be registered with the runtime. Registering the state factory allows the underlying state replication machinery to deserialize replicated state objects based on the ids encoded in the replication stream. The message factories allow are used for deserializing replicated outbound the application's inbound messages as well as messages received from message buses. The state , and also when replaying them from the application's transaction log or during receipt by a backup instance when the inbound messaging stream is replicated from the primary instance. The message factories can be declared in your config.xml or programmatically:
...
To actually achieve high availability storage must be configured for the application. The primary means of storage is for Talon apps is through clustered replication to a backup instance. Talon also logs state changes to a disk-based transaction log as a fallback mechanism. Storage and persistence can be enabled in the application's configuration xml.
...
Enabling clustering allows 2 two applications of the same name to discover one another and form an HA cluster. When one or more instances of an application connect to one another one instance is elected as the primary via a leadership election algorithm. The primary member will establish messaging connections and begin invoking message handlers in your application.
Enabling persistence causes the replication stream that is sent to backup instances to also be logged locally on disk to a transaction log file. The transaction log file can be used to recover application state from a cold start , and is also used to initialize new cluster members that connect to it so when clustering is enabled, persistence must be enabled as well.
...
Event Sourcing applications must take special care not to reference the local environment to avoid situations that would cause the primary and backup state to diverge. Talon provides several facilities to help with this.
...
The AepEngine provides a getEngineTime() that is intended for use by applications using event sourcing that do time-dependent message processing. This method provides the current wall time (in millisecond resolution) as perceived by the engine. If invoked from within a message processor handler and the HA policy is set to event sourcing, this method returns the time stamped on the message event (stamped just before the method is dispatched to the application for processing). Since, for event sourced applications, the message is also replicated for parallel processing on the backup, the backup will receive the same time when invoking this method thus ensuring identical processing. If this method is called on an engine operating in state replication mode or called from outside a message processor, then this method will return the value returned by the java.lang.System.currentTimeMillis
method
...
- To schedule deferred processing against application state in a fault tolerant fashion. For example, if you need to schedule work to be done at a later date, you can inject a message with a delay and it will be queued for deferred execution.
- If processing of a message must be done by another thread, the results of that thread's processing can be injected back into the engine with a message.
- If you are working with a 3rd party library or other application locally that does processing that may be based on the local environment, you add the results of that processing to message and inject into it back into the engine for fault tolerant processing. In this case, you might also consider using environment based replication (see below).
In the contrived example below, injection is used to broadcast the current hostname in a an HA safe fashion.
Code Block | ||||
---|---|---|---|---|
| ||||
private volatile AepEngine engine; @AppInjectionPoint public void initialize(AepEngine engine) { this.engine = engine; } @EventHandler public void onMessage(BroadcastHostNameRequest message) { InetAddress.getLocalHost().getHostName(); } @EventHandler public void onMessage(SendHostNameCommand command) { BroadcastHostNameResponse response = BroadcastHostNameResponse.create(); response.setHostName(command.getHostName()); send("hostname-response", response); } |
The above technique can be used to
See Scheduling and Injection of Messages for more information.
...
Above we showed how to inject the host name hostname from the local environment into the replication stream, but that has the drawback of creating a new transaction. Talon provides a mechanism to record and tunnel local environment data into the current transactions transaction's replication stream. This feature is called environment replication and allows application developers to write environment providers that record calls into buffers that are serialized for use on the backup so that they can operate on the same data as the primary. With environment replication, the above logic would look like:
...