developing event-driven microservices with event sourcing and cqrs (svcc, svcc2015)

92
@crichardson Developing event-driven microservices with event sourcing and CQRS Chris Richardson Author of POJOs in Action Founder of the original CloudFoundry.com @crichardson [email protected] http://plainoldobjects.com http://microservices.io

Upload: chris-richardson

Post on 16-Apr-2017

37.369 views

Category:

Software


9 download

TRANSCRIPT

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

@crichardson

Developing event-driven microservices with event

sourcing and CQRSChris Richardson

Author of POJOs in Action Founder of the original CloudFoundry.com

@crichardson [email protected] http://plainoldobjects.com http://microservices.io

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

@crichardson

Presentation goal

Show how Event Sourcing and Command Query Responsibility Segregation

(CQRS) are a great way to implement microservices

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

@crichardson

About Chris

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

@crichardson

About Chris

Consultant and trainer focusing on microservices (http://www.chrisrichardson.net/)

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

@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)

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

@crichardson

For more information

https://github.com/cer/event-sourcing-examples

http://microservices.io

http://plainoldobjects.com/

https://twitter.com/crichardson

http://eventuate.io/

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

@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

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

@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

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

@crichardson

But that leads* to monolithic hell

For large and/or complex applications…

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

@crichardson

Today: use a microservice, polyglot architecture

Shopping UI

Orders Service Customer Service

Order Database Customer Database

Standalone services

Sharded SQLNoSQL DB

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

@crichardson

But now we have distributed data management

problems

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

@crichardson

Example: placing an order

Order Service Customer Service

Order Database

Customer Database

Order #1 Customer #1

No 2PC

No ACID

NoSQL SQL

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

@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

?

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

@crichardson

Use an event-driven architecture….

http://www.merriam-webster.com/dictionary/event

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

@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

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

@crichardson

Order ManagementOrder

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

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

@crichardson

Now there are two problems to solve….

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

@crichardson

Problem #1: How to design eventually consistent business logic?

More on that later….

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

@crichardson

Problem #2: How atomicity update database and publish an event

Order Service

Order Database

Message Broker

insert Order

publish OrderCreatedEvent

dual write problem

?

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

@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

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

@crichardson

Transaction log tailingHow:

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

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

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

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

@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

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

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

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

@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

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

Application created eventsBenefits

High-level domain events

No 2PC

Drawbacks

Requires changes to the application

Only works for SQL and some NoSQL databases

Error-prone

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

@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

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

@crichardson

Just publish events

Application

Database

Message Broker

update

publish

X

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

@crichardson

Event sourcingFor each aggregate (business entity):

Identify (state-changing) domain events

Define Event classes

For example,

ShoppingCart: ItemAddedEvent, ItemRemovedEvent, OrderPlacedEvent

Order: OrderCreated, OrderCancelled, OrderApproved, OrderRejected, OrderShipped

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

@crichardson

Persists events NOT current state

Order

status ….

Event table

101 ACCEPTED

Order tableXOrderCreated101 901 …

OrderApproved101 902 …

OrderShipped101 903 …

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

@crichardson

Replay events to recreate state

Order

state

OrderCreated(…) OrderAccepted(…) OrderShipped(…)

Events

Periodically snapshot to avoid loading all events

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

@crichardson

The present is a fold over history

currentState = foldl(applyEvent, initialState, events)

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

@crichardson

Event

Aggregates: Command ⇒ Events

AggregateCommand Event

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

@crichardson

Aggregates: Event ⇒ Updated aggregate

AggregateEvent Aggregate’

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

@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)

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

@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

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

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

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

@crichardson

Benefits of event sourcingSolves 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

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

@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

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

@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

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

@crichardson

Implementing createOrder()

POST /orders

class OrderServiceImpl {

public Order createOrder() { … Creates Order … }

}

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

@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

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

@crichardson

createOrder() updates multiple aggregates

Updates Customer aggregate’s available credit

Creates Order aggregate

Associates Order with Customer

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

@crichardson

Old-style ACID…BEGIN TRANSACTION

… VERIFY CREDIT …

… CREATE ORDER…

COMMIT TRANSACTION

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

@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

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

@crichardson

Creating an order

Order

Customer

CreatedCredit reserved

public Order createOrder() { … Creates Order … }

Approved

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

@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

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

@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

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

@crichardson

Use the familiar building blocks of DDD

Entity

Value object

Services

Repositories

Aggregates ⟸ essential

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

Aggregate designGraph 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 …

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

@crichardson

Partition the domain model into Aggregates

Order

OrderLine Item

quantity

Addressstreet city …

Customer

Productname price

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

@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

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

@crichardson

Aggregate granularity

Consistency Scalability/ User experience

Customer

Order

Product

Customer

Order

Product

Customer

Order

Product

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

Designing domain eventsRecord 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

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

@crichardson

Example event

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

@crichardson

Designing commandsCreated by a service from incoming request

Processed by an aggregate

Immutable

Contains value objects for

Validating request

Creating event

Auditing user activity

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

@crichardson

Example command

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

@crichardson

Hybrid OO/FP domain objects

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

@crichardson

OO = State + Behavior

creditLimit creditReservations : Map[OrderId, Money]

Customer

List<Event> processCommand ( Command aCommand) { … }

void applyEvent (Event anEvent) { … }

State

Behavior

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

@crichardson

Aggregate traits

Map Command to Events

Apply event returning updated Aggregate

Used by Event Store

to reconstitute aggregate

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

@crichardson

ReflectiveMutableCommandProcessingAggregate

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

@crichardson

Customer - command processing

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

@crichardson

Customer - applying events

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

@crichardson

Event Store APIT is a subclass of Aggregate[T]

Rx Observable = Future++

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

@crichardson

Creating an order

save() concisely specifies: 1.Creates Customer aggregate 2.Processes command 3.Applies events 4.Persists events

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

@crichardson

Event handling in Customers

1.Load Customer aggregate 2.Processes command 3.Applies events 4.Persists events

Triggers BeanPostProcessor Durable subscription name

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

@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

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

@crichardson

Let’s imagine you want to display a customer and their recent orders

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

@crichardson

Need to ‘join’ customers and orders BUT

Event store only supports primary key lookup

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

@crichardson

Use Command Query Responsibility Segregation

(CQRS)

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

@crichardson

Command Query Responsibility Segregation (CQRS)

Command-side

Commands

Aggregate

Event Store

Events

Query-side

Queries

(Denormalized) View

Events

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

@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

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

@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

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

@crichardson

Persisting customers and order info using Spring Data for MongoDB...

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

@crichardson

Persisting customers and order using Spring Data for MongoDB...

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

Other kinds of viewsAWS 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

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

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

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

@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

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

@crichardson

Partitioning into microservices: Use Strategic DDD

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

@crichardson

Strategic design: identify sub-domains and bounded contexts

Online store domain

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

@crichardson

Strategic design: identify sub-domains and bounded contexts

Customer Management Order

ManagementCatalog

management …

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

@crichardson

Bounded context = microservices

Customer management

domain model

Order management

domain model

Catalog management

domain model

domain model

Customer view

Command side Query side

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

@crichardsonEvent Store

HTTP Request

HTTP Adapter

Event Handler

Cmd

Cmd

Events

Events

Xyz Adapter

Xyz Requestmicroservice

Aggregate

Service

Event Adapter

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

@crichardson

Order Controller

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

@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

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

@crichardson

Aggregates + Event Sourcing =

Modular domain model

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

@crichardson

Modular domain model

Tightly coupled ACID

Loosely coupled aggregates Eventually consistent

Customer

Order

Product

Customer

Order

Product

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

@crichardson

MonolithicFirst approach

Tomcat

WAR/EAR

Not entirely free though - Event Sourcing premium

Customer

Order

Product

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

@crichardson

But no Big Ball of Mud to untangle

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

@crichardson

Microservices deployment

Tomcat

WAR/EAR

Much higher - microservices premium

Customer

Tomcat

WAR/EAR

Order

Tomcat

WAR/EAR

Product

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

@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

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

@crichardson

@crichardson [email protected]

http://plainoldobjects.com http://microservices.io