Upload
markus-eisele
View
4.167
Download
12
Embed Size (px)
Citation preview
CQRS and Event Sourcing for Java Developers
@myfearblog.eisele.nethttps://keybase.io/myfear
• Classicalarchitecturesandmodernization• CRUDvs.CQRS• Alittleexample• Wrappingitup
Agenda
Classical Architectures
ApplicationServer
EAR- EnterpriseArchive
RESTMobileWebUI
.JAR.JAR.JAR
.JAR.JAR.JAR.JAR
.JAR.JAR.JAR
Browser RDBMS
ApplicationServer
ApplicationServer
ApplicationServer
EAR- EnterpriseArchive
RESTMobileWebUI
.JAR.JAR.JAR
.JAR.JAR.JAR.JAR
.JAR.JAR.JAR
Browser RDBMS
Modernization
Module
Module
Module
WebUI
.JAR.JAR.JAR
.JAR.JAR.JAR.JAR
.JAR.JAR.JARBrowser RDBMS
RDBMS
RDBMS
RoutingModule
TrackingModule
OrderModule
Tracker UIBrowser HistoryDB
OrderDB
RoutesDB
CRUD is OK!
• Forsimpledomainmodels!
• Complexmodelsstarttoshowweaknesses• DTOvs.VO• Readvs.Writeperformance• OptimisticLocking• DistributedCaches
but only …
But what else?
ComplexityofDomainModel
Effortto
cha
nge/e
nhan
ce
CRUD
CQRS
• CommandQueryResponsibilitySegregation
CQRS
• TheCommand– forWrites• e.g.CreateCargo
• TheQuery– forReads• e.g.ListCargo
Commands and Queries
Just separating reads from writes?
• TheCommand• handle(CreateCargo command) {…}
• TheEvent• on(CargoCreated event) {…}
Commands evolve into Events
• Occurredinthepast• Changedthesystemstate(Writeoperation)
• CargoCreated,LegAdded,CargoRouted,…
Events
WAIT! WHAT DID YOU DO TO MY ENTITIES?
• Book-keepingofchanges• Containsafullhistoryimplicitly• Storingeventsinsequencewithastrictglobalorder(time-stampbased)
• Noupdatesordeletes.Ever!• Nosingle“currentstate”.Thecollectionofeventsmakeupthesystemstateinanypointoftime.
Persistent Events
• CapturingChangesinsteadofupdatingObjects
JPA Entities vs. Immutable Facts
Current Stateis a second class citizen
• CapturingChangesinsteadofupdatingObjects
The read-side
• Wherewasmyvessellastweek?• Whocreatedtheshippingrequest?• Howmuchcargodidweshiplastyear?• Whichvesselshavebeenre-routedmorethantwiceinunderanhour?
Answer all kind of new questions
The read-side
cargoId location
Location
Cargo1 1.2,3Cargo2 1.3,2Cargo3 1.4,1Cargo4 2.2,5
CargoRouted(1.2,3)
CargoRouted(1.3,2)
CargoRouted(1.4,1)
Neo4J
Cassandra
Cassandra
Implementationexample. A little one.
CargoTrackerhttps://github.com/lagom/activator-lagom-cargotracker
Registration
Shipping
Frontend Cassandra
restCall(Method.POST, "/api/registration", register()),
restCall(Method.GET, "/api/registration/all",getAllRegistrations()),
Write-Side
Read-Side
The PersistentEntity
public class CargoEntity extends PersistentEntity<RegistrationCommand, RegistrationEvent, CargoState> {//...}
CargoEntity.java
The write-side
PersistentEntityRef<RegistrationCommand> ref =persistentEntityRegistry.refFor(
CargoEntity.class, request.getId());
RegistrationServiceImpl.java
The read-side (preparation)
prepareCreateTables(session).thenCompose(a -> prepareWriteCargo(session).thenCompose(b -> prepareWriteOffset(session).thenCompose(c -> selectOffset(session))));
CargoEventProcessor.java
The read-side (1)
private CompletionStage<Done> prepareCreateTables(CassandraSession session) {
return session.executeCreateTable("CREATE TABLE IF NOT EXISTS cargo ("+ "cargoId text, name text, description text,"+ "PRIMARY KEY (cargoId, destination))") );
}
The read-side (2)
private CompletionStage<Done> prepareWriteCargo(CassandraSession session) {
return session.prepare("INSERT INTO cargo (cargoId, name, description, "
+ " owner,destination) VALUES (?, ?,?,?,?)")
.thenApply(ps -> {setWriteCargo(ps);return Done.getInstance();
});
The read-side (offsets?)
private CompletionStage<Optional<UUID>> selectOffset(CassandraSession session) { return session.selectOne("SELECT offset FROM blogevent_offset")
.thenApply( optionalRow -> optionalRow.map(r -> r.getUUID("offset"))); }
The read-side (event trigger) @Overridepublic EventHandlersdefineEventHandlers(EventHandlersBuilder builder) {
builder.setEventHandler(CargoRegistered.class, this::processCargoRegistered);
return builder.build();}
RegistrationEvent!
The read-side (actual persistence) private CompletionStage<List<BoundStatement>> processCargoRegistered(CargoRegistered event, UUID offset) {
BoundStatement bindWriteCargo = writeCargo.bind();bindWriteCargo.setString("cargoId",
event.getCargo().getId());bindWriteCargo.setString("name",
event.getCargo().getName());bindWriteCargo.setString("description");
//...}
WHY IS THIS SO..complicated?
BECAUSE..it’s lightning FAST for users!!
[info] s.c.r.i.RegistrationServiceImpl - Cargo ID: 322667.
[info] s.c.r.i.CargoEventProcessor - Persisted 322667
• Alldatakeptinmemory!• Allstatechangesstoredasevents• ReplayeventsofanPersistentEntity torecreateit• StrongconsistencyforPersistentEntity’s and
Journal-Entries• EventualConsistencyforReadSide
More precisely, because:
BECAUSE..you can do a lot more a lot easier!!
• Recreatebugs• Migratesystems• Introducenewread-sides• Processhighervolumes• Extendedcachingscenarios
For example:
BECAUSE..the examples are based on LAGOM and
it DOES A LOT MORE for you!!
..oO(you can do this with Spring / Hibernate / Java EE – your choice)
• Lagomisasynchronousbydefault.• Developerproductivity• Buildformicroservices• Takesyoutoproduction• ….
You’ve heard this before, but:
..oO(you can do this with Spring / Hibernate / Java EE – your choice)
Links and further reading
ProjectSite:http://www.lightbend.com/lagom
GitHubRepo:https://github.com/lagom
Documentation:http://www.lagomframework.com/documentation/1.0.x/java/Home.html
CargoTrackerExample:https://github.com/lagom/activator-lagom-cargotracker
•Keep all data in memory!• Store all state changes as events• Replay all events of an actor to recreate it • Strong consistency for Actor (aggregate) and Journal• Eventual Consistency for Read Side
https://msdn.microsoft.com/en-us/library/jj554200.aspx
https://www.infoq.com/minibooks/domain-driven-design-quickly
Written for architects and developers that must quickly gain a fundamental understanding of microservice-based architectures, this free O’Reilly report explores the journey from SOA to microservices, discusses approaches to dismantling your monolith, and reviews the key tenets of a Reactive microservice:
• Isolate all the Things• Act Autonomously• Do One Thing, and Do It Well• Own Your State, Exclusively• Embrace Asynchronous Message-Passing• Stay Mobile, but Addressable• Collaborate as Systems to Solve Problems
http://bit.ly/ReactiveMicroservice
The detailed example in this report is based on Lagom, a new framework that helps you follow the requirements for building distributed, reactive systems.
• Get an overview of the Reactive Programming model and basic requirements for developing reactive microservices
• Learn how to create base services, expose endpoints, and then connect them with a simple, web-based user interface
• Understand how to deal with persistence, state, and clients
• Use integration technologies to start a successful migration away from legacy systems
http://bit.ly/DevelopReactiveMicroservice
http://bit.ly/SustainableEnterprise
• Understand the challenges of starting a greenfield development vs tearing apart an existing brownfield application into services
• Examine your business domain to see if microservices would be a good fit
• Explore best practices for automation, high availability, data separation, and performance
• Align your development teams around business capabilities and responsibilities
• Inspect design patterns such as aggregator, proxy, pipeline, or shared resources to model service interactions