SlideShare a Scribd company logo
@crichardson
Developing event-driven
microservices with event
sourcing and CQRS
Chris Richardson
Author of POJOs in Action
Founder of the original CloudFoundry.com
@crichardson
chris@chrisrichardson.net
http://plainoldobjects.com
http://microservices.io
@crichardson
Presentation goal
Show how Event Sourcing and
Command Query Responsibility Segregation
(CQRS)
are a great way to implement microservices
@crichardson
About Chris
@crichardson
About Chris
Consultant and trainer focusing
on microservices
(http://www.chrisrichardson.net/)
@crichardson
About Chris
Founder of a startup that is creating
a platform that makes it easy for
application developers write
microservices
(http://bit.ly/trialeventuate)
@crichardson
For more information
https://github.com/cer/event-sourcing-examples
http://microservices.io
http://plainoldobjects.com/
https://twitter.com/crichardson
http://eventuate.io/
@crichardson
Agenda
Why event sourcing?
Overview of event sourcing
ACID-free design
Designing a domain model based on event sourcing
Implementing queries in an event sourced application
Event sourcing and microservices
@crichardson
Tomcat
Traditional monolithic architecture
Browser/
Client
WAR/EAR
RDBMS
…
Customers
Orders
StoreFront UI
develop
test
deploy
Simple to
Load
balancer
scale
Spring MVC
Spring
Hibernate
HTML
REST/JSON
ACID
Shopping cart
@crichardson
But that leads* to
monolithic hell
For large and/or complex applications…
@crichardson
Today: use a microservice, polyglot
architecture
Shopping UI
Orders Service Customer Service
Order
Database Customer Database
Standalone
services
Sharded SQLNoSQL DB
@crichardson
But now we have
distributed data management
problems
@crichardson
Example: placing an order
Order Service Customer Service
Order
Database
Customer Database
Order #1
Customer #1
No 2PC
No
ACID
NoSQL SQL
@crichardson
Customer management
How to maintain invariants?
Order management
Order Service
placeOrder()
Customer Service
updateCreditLimit()
Customer
creditLimit
...
has ordersbelongs toOrder
total
Invariant:
sum(open order.total) <= customer.creditLimit
?
@crichardson
Use an event-driven
architecture….
http://www.merriam-webster.com/dictionary/event
@crichardson
….Use an event-driven
architecture
Services publish events when something important happens,
e.g. state changes
Services subscribe to events and update their state
Maintain eventual consistency across multiple aggregates
(in multiple datastores)
Synchronize replicated data
@crichardson
Order Management
Order
id : 4567
total: 343
state = CREATED
Customer Management
Customer
creditLimit : 12000
creditReservations: {}
Customer
creditLimit : 12000
creditReservations: { 4567 -> 343}
Order
id : 4567
total: 343
state = OPEN
Eventually consistent credit checking
Message Bus
createOrder()
Publishes:
Subscribes to:
Subscribes to:
publishes:
OrderCreatedEvent
CreditReservedEvent
OrderCreatedEvent CreditReservedEvent
@crichardson
Now there are two problems
to solve….
@crichardson
Problem #1: How to design
eventually consistent business logic?
More on that later….
@crichardson
Problem #2: How atomicity update
database and publish an event
Order Service
Order
Database
Message Broker
insert Order
publish
OrderCreatedEvent
dual write problem
?
@crichardson
Update and publish using
2PC
Guaranteed atomicity BUT
Need a distributed transaction manager
Database and message broker must support 2PC
Impacts reliability
Not fashionable
2PC is best avoided
@crichardson
Transaction log tailing
How:
Read the database “transaction log” = single source of truth
Publish events to message broker
LinkedIn databus https://github.com/linkedin/databus
Supports Oracle and MySQL
Publish as events
AWS DynamoDB streams
Ordered sequence of creates, updates, deletes made to a DynamoDB table
Last 24 hours
Subscribe to get changes
MongoDB
Read the oplog
Transaction log tailing: benefits
and drawbacks
Benefits
No 2PC
No application changes
required
Guaranteed to be
accurate
Drawbacks
Immature
Database specific
solutions
Low-level DB changes
rather business level
events = need to reverse
engineer domain events
@crichardson
Use database triggers
Track changes to tables
Insert events into an event table
Use datastore as a message queue
Pull events from event table and write to message broker
Database triggers: benefits
and drawbacks
Benefits
No 2PC
No application changes
required

Drawbacks
Requires the database to
support them
Database specific solutions
Low-level DB changes rather
business level events = need
to reverse engineer domain
events
Error-prone, e.g. missing
trigger
@crichardson
Application created events
Use datastore as a message queue
Txn #1: Update database: new entity state & event
Txn #2: Consume event
Txn #3: Mark event as consumed
Eventually consistent mechanism (used by eBay)
See BASE: An Acid Alternative, http://bit.ly/ebaybase
Application created events
Benefits
High-level domain events
No 2PC
Drawbacks
Requires changes to the
application
Only works for SQL and
some NoSQL databases
Error-prone
@crichardson
Agenda
Why event sourcing?
Overview of event sourcing
ACID-free design
Designing a domain model based on event sourcing
Implementing queries in an event sourced application
Event sourcing and microservices
@crichardson
Just publish events
Application
Database
Message Broker
update
publish
X
@crichardson
Event sourcing
For each aggregate (business entity):
Identify (state-changing) domain events
Define Event classes
For example,
ShoppingCart: ItemAddedEvent, ItemRemovedEvent,
OrderPlacedEvent
Order: OrderCreated, OrderCancelled, OrderApproved,
OrderRejected, OrderShipped
@crichardson
Persists events
NOT current state
Order
status
….
Event table
101 ACCEPTED
Order table
X
OrderCreated101 901 …
OrderApproved101 902 …
OrderShipped101 903 …
@crichardson
Replay events to recreate
state
Order
state
OrderCreated(…)
OrderAccepted(…)
OrderShipped(…)
Events
Periodically snapshot to avoid loading all events
@crichardson
The present is a fold over
history
currentState = foldl(applyEvent, initialState, events)
@crichardson
Event
Aggregates: Command
Events
AggregateCommand Event
@crichardson
Aggregates: Event Updated
aggregate
AggregateEvent Aggregate’
@crichardson
Request handling in an event-sourced application
HTTP
Handler
Event
Store
pastEvents = findEvents(entityId)
Order
new()
applyEvents(pastEvents)
newEvents = processCmd(SomeCmd)
saveEvents(newEvents)
Microservice A
(optimistic locking)
@crichardson
Event Store publishes events -
consumed by other services
Event
Store
Event
Subscriber
subscribe(EventTypes)
publish(event)
publish(event)
Aggregate
CQRS View
update()
update()
Microservice B
send notifications
…
Event store = database + message
broker
Hybrid database and
message broker
Implementations:
Home-grown/DIY
geteventstore.com by
Greg Young
http://eventuate.io
(mine)
Event Store
Save
aggregate
events
Get
aggregate
events
Subscribe
to events
@crichardson
Benefits of event sourcing
Solves data consistency issues in a Microservice/NoSQL-based
architecture
Reliable event publishing: publishes events needed by predictive
analytics etc, user notifications,…
Eliminates O/R mapping problem (mostly)
Reifies state changes:
Built-in, reliable audit log,
temporal queries
Preserved history More easily implement future requirements
@crichardson
Drawbacks of event sourcing
Weird and unfamiliar
Events = a historical record of your bad design decisions
Handling duplicate events can be tricky
Application must handle eventually consistent data
Event store only directly supports PK-based lookup => use
Command Query Responsibility Segregation (CQRS) to handle
queries
@crichardson
Agenda
Why event sourcing?
Overview of event sourcing
ACID-free design
Designing a domain model based on event sourcing
Implementing queries in an event sourced application
Event sourcing and microservices
@crichardson
Implementing createOrder()
POST /orders
class OrderServiceImpl {
public Order createOrder() {
… Creates Order …
}
}
@crichardson
Implement requirements and preserve
invariants
As a customer
I want to place an order
So that I get the needed products
Given that my available credit is $1500
When I place a $250 order
Then the order is created
Then my available credit is $1250
Story
Scenario
Post
conditions
Pre
conditions
Given that my available credit is $1500
When I place a $2500 order
Then the order is rejected
Then my available credit is $1500
Scenario
Invariant:
sum(open order.total) <= customer.creditLimit
@crichardson
createOrder() updates multiple
aggregates
Updates Customer aggregate’s available credit
Creates Order aggregate
Associates Order with Customer
@crichardson
Old-style ACID…
BEGIN TRANSACTION
… VERIFY CREDIT …
… CREATE ORDER…
COMMIT TRANSACTION
@crichardson
… becomes eventually
consistent (BASE)
Updating multiple aggregates
multi-step, event-driven flow
each step updates one Aggregate
Service creates saga to coordinate workflow
A state machine
Part of the domain, e.g. Order aggregate OR Synthetic
aggregate
Post-conditions and invariants eventually become true
@crichardson
Creating an order
Order
Customer
Created
Credit reserved
public Order createOrder() {
… Creates Order …
}
Approved
@crichardson
Need compensating
transactions
Pre-conditions might be false when attempting to update an
aggregate
Credit check fails cancel order
Credit check succeeded but customer cancels order undo
credit reservation
…
@crichardson
Agenda
Why event sourcing?
Overview of event sourcing
ACID-free design
Designing a domain model based on event sourcing
Implementing queries in an event sourced application
Event sourcing and microservices
@crichardson
Use the familiar building
blocks of DDD
Entity
Value object
Services
Repositories
Aggregates ⟸ essential
Aggregate design
Graph consisting of a root
entity and one or more other
entities and value objects
Each core business entity =
Aggregate: e.g. customer,
Account, Order, Product, ….
Reference other aggregate
roots via primary key
Often contains partial copy
of other aggregates’ data
Order
OrderLine
Item
quantity
productId
productName
productPrice
customerId
Address
street
city
…
@crichardson
Partition the domain model
into Aggregates
Order
OrderLine
Item
quantity
…
Address
street
city
…
Customer
Product
name
price
@crichardson
Transaction = processing one
command by one aggregate
No opportunity to update multiple aggregates within a
transaction
Aggregate granularity is important
If an update must be atomic (i.e. no compensating
transaction) then it must be handled by a single aggregate
e.g. scanning boarding pass at security checkpoint or when
entering jetway
@crichardson
Aggregate granularity
Consistency
Scalability/
User experience
Customer
Order
Product
Customer
Order
Product
Customer
Order
Product
Designing domain events
Record state changes for an
aggregate
Part of the public API of the domain
model ProductAddedToCart
id : TimeUUID
productId
productName
productPrice
shoppingCartId
Required by
aggregate
Enrichment:
Required by by
consumers
@crichardson
Example event
@crichardson
Designing commands
Created by a service from incoming request
Processed by an aggregate
Immutable
Contains value objects for
Validating request
Creating event
Auditing user activity
@crichardson
Example command
@crichardson
Hybrid OO/FP domain objects
@crichardson
OO = State + Behavior
creditLimit
creditReservations : Map[OrderId, Money]
Customer
List<Event> processCommand (
Command aCommand) { … }
void applyEvent (Event anEvent) { … }
State
Behavior
@crichardson
Aggregate traits
Map Command to Events
Apply event returning
updated Aggregate
Used by
Event Store
to
reconstitute
aggregate
@crichardson
ReflectiveMutableCommand
ProcessingAggregate
@crichardson
Customer - command processing
@crichardson
Customer - applying events
@crichardson
Event Store API
T is a subclass of Aggregate[T]
Rx Observable = Future++
@crichardson
Creating an order
save() concisely specifies:
1.Creates Customer aggregate
2.Processes command
3.Applies events
4.Persists events
@crichardson
Event handling in Customers
1.Load Customer aggregate
2.Processes command
3.Applies events
4.Persists events
Triggers BeanPostProcessor
Durable subscription name
@crichardson
Agenda
Why event sourcing?
Overview of event sourcing
ACID-free design
Designing a domain model based on event sourcing
Implementing queries in an event sourced application
Event sourcing and microservices
@crichardson
Let’s imagine you want to
display a customer and their
recent orders
@crichardson
Need to ‘join’ customers and orders
BUT
Event store only supports primary
key lookup
@crichardson
Use Command Query
Responsibility Segregation
(CQRS)
@crichardson
Command Query Responsibility
Segregation (CQRS)
Command-side
Commands
Aggregate
Event Store
Events
Query-side
Queries
(Denormalized)
View
Events
@crichardson
Query-side design
Event Store
Updater
View Updater
Service
Events
Reader
HTTP GET
Request
View Query
Service
View
Store
e.g.
MongoDB
Neo4J
CloudSearch
update query
@crichardson
Persisting a customer and
order history in MongoDB
{
"_id" : "0000014f9a45004b-0a00270000000000",
"_class" : "net.chrisrichardson…..views.orderhistory.CustomerView",
"version" : NumberLong(5),
"orders" : {
"0000014f9a450063-0a00270000000000" : {
"state" : "APPROVED",
"orderId" : "0000014f9a450063-0a00270000000000",
"orderTotal" : {
"amount" : "1234"
}
},
"0000014f9a450063-0a00270000000001" : {
"state" : "REJECTED",
"orderId" : "0000014f9a450063-0a00270000000001",
"orderTotal" : {
"amount" : "3000"
}
}
},
"name" : "Fred",
"creditLimit" : {
"amount" : "2000"
}
}
Denormalized = efficient lookup
@crichardson
Persisting customers and order info
using Spring Data for MongoDB...
@crichardson
Persisting customers and order
using Spring Data for MongoDB...
Other kinds of views
AWS Cloud Search
Text search as-a-Service
View updater batches
aggregates to index
View query service does
text search
AWS DynamoDB
NoSQL as-a-Service
On-demand scalable -
specify desired read/write
capacity
Document and key-value
data models
Useful for denormalized,
UI oriented views
Benefits and drawbacks of
CQRS
Benefits
Necessary in an event-sourced
architecture
Separation of concerns =
simpler command and query
models
Supports multiple denormalized
views
Improved scalability and
performance
Drawbacks
Complexity
Potential code duplication
Replication lag/eventually
consistent views
@crichardson
Agenda
Why event sourcing?
Overview of event sourcing
ACID-free design
Designing a domain model based on event sourcing
Implementing queries in an event sourced application
Event sourcing and microservices
@crichardson
Partitioning into microservices:
Use Strategic DDD
@crichardson
Strategic design: identify sub-
domains and bounded contexts
Online store domain
@crichardson
Strategic design: identify sub-
domains and bounded contexts
Customer
Management Order
Management
Catalog
management
…
@crichardson
Bounded context = microservices
Customer
management
domain
model
Order management
domain
model
Catalog
management
domain
model
…
domain
model
Customer view
Command side Query side
@crichardson
Event Store
HTTP Request
HTTP Adapter
Event Handler
Cmd
Cmd
Events
Events
Xyz Adapter
Xyz Request
microservice
Aggregate
Service
Event Adapter
@crichardson
Order Controller
@crichardson
When to use microservices?
In the beginning:
•You don’t need it
•It will slow you down
Later on:
•You need it
•Refactoring dependencies
is painful
@crichardson
Aggregates + Event Sourcing
=
Modular domain model
@crichardson
Modular domain model
Tightly coupled
ACID
Loosely coupled aggregates
Eventually consistent
Customer
Order
Product
Customer
Order
Product
@crichardson
MonolithicFirst approach
Tomcat
WAR/EAR
Not entirely free though -
Event Sourcing premium
Customer
Order
Product
@crichardson
But no Big Ball of Mud to
untangle
@crichardson
Microservices deployment
Tomcat
WAR/EAR
Much higher -
microservices premium
Customer
Tomcat
WAR/EAR
Order
Tomcat
WAR/EAR
Product
@crichardson
Summary
Event sourcing solves key data consistency issues with:
Microservices
Partitioned SQL/NoSQL databases
Apply strategic DDD to identify microservices
Apply tactical DDD to design individual services
Use CQRS to implement materialized views for queries
@crichardson
@crichardson chris@chrisrichardson.net
http://plainoldobjects.com http://microservices.io

More Related Content

Developing event-driven microservices with event sourcing and CQRS (svcc, svcc2015)