Building and deploying microservices with event sourcing, CQRS and - - PowerPoint PPT Presentation

building and deploying microservices with event sourcing
SMART_READER_LITE
LIVE PREVIEW

Building and deploying microservices with event sourcing, CQRS and - - PowerPoint PPT Presentation

Building and deploying microservices with event sourcing, CQRS and Docker Chris Richardson Author of POJOs in Action Founder of the original CloudFoundry.com @crichardson chris@chrisrichardson.net http://plainoldobjects.com


slide-1
SLIDE 1

@crichardson

Building and deploying microservices with event sourcing, CQRS and Docker

Chris Richardson

Author of POJOs in Action Founder of the original CloudFoundry.com @crichardson chris@chrisrichardson.net http://plainoldobjects.com http://microservices.io

slide-2
SLIDE 2

@crichardson

Presentation goal

Share my experiences with building and deploying an application using Scala, functional domain models, microservices, event sourcing, CQRS, and Docker

slide-3
SLIDE 3

@crichardson

About Chris

slide-4
SLIDE 4

@crichardson

About Chris

Founder of a buzzword compliant (stealthy, social, mobile, big data, machine learning, ...) startup Consultant helping organizations improve how they architect and deploy applications using cloud, micro services, polyglot applications, NoSQL, ... Creator of http://microservices.io

slide-5
SLIDE 5

@crichardson

For more information

https://github.com/cer/event-sourcing-examples http://microservices.io http://plainoldobjects.com/ https://twitter.com/crichardson

slide-6
SLIDE 6

@crichardson

Agenda

Why build event-driven microservices? Overview of event sourcing Designing microservices with event sourcing Implementing queries in an event sourced application Building and deploying microservices

slide-7
SLIDE 7

@crichardson

Tomcat

Traditional application architecture

Browser/ Client

WAR/EAR

RDBMS

Customers Accounts

Transfers

Banking

develop test deploy

Simple

Load balancer

scale

Spring MVC Spring Hibernate ... HTML REST/JSON

ACID

slide-8
SLIDE 8

@crichardson

Limitations of the monolithic architecture

Intimidates developers Obstacle to frequent deployments Overloads your IDE and container Obstacle to scaling development Modules having conflicting scaling requirements Requires long-term commitment to a technology stack

slide-9
SLIDE 9

@crichardson

Apply the scale cube

X axis

  • horizontal duplication

Z a x i s

  • d

a t a p a r t i t i

  • n

i n g Y axis - functional decomposition S c a l e b y s p l i t t i n g s i m i l a r t h i n g s Scale by splitting different things

slide-10
SLIDE 10

@crichardson

Use a microservice architecture

Banking UI Account Management Service MoneyTransfer Management Service Account Database MoneyTransfer Database

Standalone services

slide-11
SLIDE 11

@crichardson

Limitations of a single relational database

Scalability Distribution Schema updates O/R impedance mismatch Handling semi-structured data

slide-12
SLIDE 12

@crichardson

Use a sharded relational database

slide-13
SLIDE 13

@crichardson

Use NoSQL databases

Avoids the limitations of RDBMS For example, text search ⇒ Solr/Cloud Search social (graph) data ⇒ Neo4J highly distributed/available database ⇒ Cassandra ...

slide-14
SLIDE 14

@crichardson

Different modules use different types of databases

IEEE Software Sept/October 2010 - Debasish Ghosh / Twitter @debasishg

slide-15
SLIDE 15

@crichardson

But this results in distributed data management problems

slide-16
SLIDE 16

@crichardson

Example #1 - SQL + Text Search engine

Application MySQL ElasticSearch

How to maintain consistency without 2PC?

Product #1 Product #1

slide-17
SLIDE 17

@crichardson

Example #2 - Cassandra main table <=> index table

Application Cassandra

How to maintain consistency without 2PC?

Main Table Denormalized view Index Table

slide-18
SLIDE 18

@crichardson

Example #3: Money transfer

Account Management Service MoneyTransfer Management Service Account Database MoneyTransfer Database Account #2 Account #1 Money Transfer

How to maintain consistency without 2PC?

slide-19
SLIDE 19

@crichardson

Event-based architecture to the rescue

Components (e.g. services) publish events when state changes Components subscribe to events Maintains eventual consistency across multiple aggregates (in multiple datastores) Synchronize replicated data

slide-20
SLIDE 20

@crichardson

Event-driven synchronization: SQL + Text Search engine

Catalog Service MySQL ElasticSearch Product #1 Product #1 Search Service Message Bus

Insert Product Created Product Created Index Doc create product

slide-21
SLIDE 21

@crichardson

MoneyTransferService

MoneyTransfer fromAccountId = 101 toAccountId = 202 amount = 55 state = INITIAL MoneyTransfer fromAccountId = 101 toAccountId = 202 amount = 55 state = DEBITED MoneyTransfer fromAccountId = 101 toAccountId = 202 amount = 55 state = COMPLETED

Eventually consistent money transfer

Message Bus AccountService

transferMoney()

Publishes: Subscribes to: Subscribes to: publishes:

MoneyTransferCreatedEvent AccountDebitedEvent DebitRecordedEvent AccountCreditedEvent MoneyTransferCreatedEvent DebitRecordedEvent AccountDebitedEvent AccountCreditedEvent Account id = 101 balance = 250 Account id = 202 balance = 125 Account id = 101 balance = 195 Account id = 202 balance = 180

slide-22
SLIDE 22

@crichardson

To maintain consistency a service must atomically publish an event whenever a domain object changes

slide-23
SLIDE 23

How to atomically update the datastore and publish event(s)?

Use 2PC Guaranteed atomicity BUT Need a distributed transaction manager Database and message broker must support 2PC Impacts reliability Not fashionable 2PC is best avoided Use datastore as a message queue

  • 1. Update database: new entity state

& event

  • 2. Consume event & mark event as

consumed Eventually consistent mechanism See BASE: An Acid Alternative, http://bit.ly/ebaybase

  • BUT Tangled business logic and

event publishing code

  • Difficult to implement when using a

NoSQL database :-(

slide-24
SLIDE 24

@crichardson

Agenda

Why build event-driven microservices? Overview of event sourcing Designing microservices with event sourcing Implementing queries in an event sourced application Building and deploying microservices

slide-25
SLIDE 25

@crichardson

Event sourcing

For each aggregate: Identify (state-changing) domain events Define Event classes For example, Account: AccountOpenedEvent, AccountDebitedEvent, AccountCreditedEvent ShoppingCart: ItemAddedEvent, ItemRemovedEvent, OrderPlacedEvent

slide-26
SLIDE 26

@crichardson

Persists events NOT current state

Account balance

  • pen(initial)

debit(amount) credit(amount) AccountOpened

Event table

AccountCredited AccountDebited 101 450

Account table

X

101 101 101 901 902 903 500 250 300

slide-27
SLIDE 27

@crichardson

Replay events to recreate state

Account balance

AccountOpenedEvent(balance) AccountDebitedEvent(amount) AccountCreditedEvent(amount)

Events

slide-28
SLIDE 28

@crichardson

Before: update state + publish events

Two actions that must be atomic Single action that can be done atomically

Now: persist (and publish) events

slide-29
SLIDE 29

@crichardson

Aggregate traits

Map Command to Events Apply event returning updated Aggregate

slide-30
SLIDE 30

@crichardson

Account - command processing

Prevent

  • verdraft
slide-31
SLIDE 31

@crichardson

Account - applying events

Immutable

slide-32
SLIDE 32

@crichardson

Request handling in an event-sourced application

HTTP Handler Event Store

pastEvents = findEvents(entityId)

Account

new() applyEvents(pastEvents) newEvents = processCmd(SomeCmd) saveEvents(newEvents)

Microservice A

slide-33
SLIDE 33

@crichardson

Event Store publishes events - consumed by other services

Event Store Event Subscriber

subscribe(EventTypes) publish(event) publish(event)

Aggregate NoSQL materialized view

update() update()

Microservice B

slide-34
SLIDE 34

@crichardson

Optimizing using snapshots

Most aggregates have relatively few events BUT consider a 10-year old Account ⇒ many transactions Therefore, use snapshots: Periodically save snapshot of aggregate state Typically serialize a memento of the aggregate Load latest snapshot + subsequent events

slide-35
SLIDE 35

@crichardson

Event Store API

trait EventStore { def save[T <: Aggregate[T]](entity: T, events: Seq[Event], assignedId : Option[EntityId] = None): Future[EntityWithIdAndVersion[T]] def update[T <: Aggregate[T]](entityIdAndVersion : EntityIdAndVersion, entity: T, events: Seq[Event]): Future[EntityWithIdAndVersion[T]] def find[T <: Aggregate[T] : ClassTag](entityId: EntityId) : Future[EntityWithIdAndVersion[T]] def findOptional[T <: Aggregate[T] : ClassTag](entityId: EntityId) Future[Option[EntityWithIdAndVersion[T]]] def subscribe(subscriptionId: SubscriptionId): Future[AcknowledgableEventStream] }

slide-36
SLIDE 36

@crichardson

Event store implementations

Home-grown/DIY geteventstore.com by Greg Young Talk to me about my project :-)

slide-37
SLIDE 37

@crichardson

Business benefits of event sourcing

Built-in, reliable audit log Enables temporal queries Publishes events needed by big data/predictive analytics etc. Preserved history ⇒ More easily implement future requirements

slide-38
SLIDE 38

@crichardson

Technical benefits of event sourcing

Solves data consistency issues in a Microservice/NoSQL- based architecture: Atomically save and publish events Event subscribers update other aggregates ensuring eventual consistency Event subscribers update materialized views in SQL and NoSQL databases (more on that later) Eliminates O/R mapping problem

slide-39
SLIDE 39

@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 (more on that later)

slide-40
SLIDE 40

@crichardson

Agenda

Why build event-driven microservices? Overview of event sourcing Designing microservices with event sourcing Implementing queries in an event sourced application Building and deploying microservices

slide-41
SLIDE 41

@crichardson

The anatomy of a microservice

Event Store

HTTP Request

HTTP Adapter Aggregate Event Adapter

Cmd Cmd

Events Events

Xyz Adapter

Xyz Request microservice

slide-42
SLIDE 42

@crichardson

Asynchronous Spring MVC controller

slide-43
SLIDE 43

@crichardson

MoneyTransferService

DSL concisely specifies: 1.Creates MoneyTransfer aggregate 2.Processes command 3.Applies events 4.Persists events

slide-44
SLIDE 44

@crichardson

MoneyTransfer Aggregate

slide-45
SLIDE 45

@crichardson

Handling events published by Accounts

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

slide-46
SLIDE 46

@crichardson

Agenda

Why build event-driven microservices? Overview of event sourcing Designing microservices with event sourcing Implementing queries in an event sourced application Building and deploying microservices

slide-47
SLIDE 47

@crichardson

Let’s imagine that you want to display an account and it’s recent transactions...

slide-48
SLIDE 48

@crichardson

Displaying balance + recent credits and debits

We need to do a “join: between the Account and the corresponding MoneyTransfers (Assuming Debit/Credit events don’t include other account, ...) BUT Event Store = primary key lookup of individual aggregates, ...

Use Command Query Responsibility Segregation

slide-49
SLIDE 49

@crichardson

Command Query Responsibility Segregation (CQRS)

Command-side

Commands

Aggregate Event Store

Events

Query-side

Queries

(Denormalized) View

Events

slide-50
SLIDE 50

@crichardson

Query-side microservices

Event Store

Updater - microservice

View Updater Service

Events

Reader - microservice

HTTP GET Request

View Query Service View Store e.g. MongoDB Neo4J CloudSearch

update query

slide-51
SLIDE 51

@crichardson

Persisting account balance and recent transactions in MongoDB

{ id: "298993498", balance: 100000, transfers : [ {"transferId" : "4552840948484", "fromAccountId" : 298993498, "toAccountId" : 3483948934, "amount" : 5000}, ... ], changes: [ {"changeId" : "93843948934", "transferId" : "4552840948484", "transactionType" : "AccountDebited", "amount" : 5000}, ... ] }

Denormalized = efficient lookup

MoneyTransfers that update the account The debits and credits Current balance

slide-52
SLIDE 52

@crichardson

Persisting account info using MongoDB...

class AccountInfoUpdateService (accountInfoRepository : AccountInfoRepository, mongoTemplate : MongoTemplate) extends CompoundEventHandler { @EventHandlerMethod def created(de: DispatchedEvent[AccountOpenedEvent]) = … @EventHandlerMethod def recordDebit(de: DispatchedEvent[AccountDebitedEvent]) = … @EventHandlerMethod def recordCredit(de: DispatchedEvent[AccountCreditedEvent]) = … @EventHandlerMethod def recordTransfer(de: DispatchedEvent[MoneyTransferCreatedEvent]) = … }

slide-53
SLIDE 53

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

slide-54
SLIDE 54

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

slide-55
SLIDE 55

@crichardson

Agenda

Why build event-driven microservices? Overview of event sourcing Designing microservices with event sourcing Implementing queries in an event sourced application Building and deploying microservices

slide-56
SLIDE 56

@crichardson

My application architecture

API gateway Event Store Service 1 Service 2 Service ... Event Archiver Indexer AWS Cloud Search S3

NodeJS Scala/Spring Boot

slide-57
SLIDE 57

@crichardson

Spring Boot based micro services

Makes it easy to create stand-alone, production ready microservices Automatically configures Spring using Convention over Configuration Externalizes configuration Built-in health checks and (Codahale) metrics Generates standalone executable JARs with embedded web server

slide-58
SLIDE 58

@crichardson

Jenkins-based deployment pipeline

Build & Test microservice Build & Test Docker image Deploy Docker image to registry

One pipeline per microservice

slide-59
SLIDE 59

@crichardson

Building Docker images

cp ../build/libs/service.${1}.jar build/service.jar docker build -t service-${VERSION} .

docker/build.sh

Building only takes 5 seconds!

slide-60
SLIDE 60

@crichardson

Smoke testing docker images

Smoke test Docker daemon Service container

GET /health POST /containers/create creates POST /containers/{id}/start Docker daemon must listen on TCP port

slide-61
SLIDE 61

@crichardson

Publishing Docker images

docker tag service-${VERSION}:latest \ ${REGISTRY_HOST_AND_PORT}/service-${VERSION} docker push ${REGISTRY_HOST_AND_PORT}/service-${VERSION}

docker/publish.sh

Pushing only takes 25 seconds!

slide-62
SLIDE 62

@crichardson

CI environment runs on Docker

EC2 Instance Jenkins Container Artifactory container EBS volume /jenkins- home /gradle-home /artifactory- home

slide-63
SLIDE 63

@crichardson

Updating the production environment

Large EC2 instance running Docker Deployment tool:

  • 1. Compares running containers with what’s been built by Jenkins
  • 2. Pulls latest images from Docker registry
  • 3. Stops old versions
  • 4. Launches new versions

One day: use Docker clustering solution and a service discovery mechanism, Most likely, AWS container service Mesos and Marathon + Zookeeper, Kubernetes or ???

slide-64
SLIDE 64

@crichardson

Summary

Event sourcing solves key data consistency issues with: Microservices Partitioned SQL/NoSQL databases Use CQRS to implement materialized views for queries Spring Boot is a great foundation for microservices Docker is a great way to package microservices

slide-65
SLIDE 65

@crichardson

@crichardson chris@chrisrichardson.net http://plainoldobjects.com http://microservices.io