A revised and extended version that I gave at Saturn 2018.
The services in a microservice architecture must be loosely coupled and so cannot share database tables. What’s more, two phase commit (a.k.a. a distributed transaction) is not a viable option for modern applications. Consequently, a microservices application must use the Saga pattern, which maintains data consistency using a series of local transactions.
In this presentation, you will learn how sagas work and how they differ from traditional transactions. We describe how to use sagas to develop business logic in a microservices application. You will learn effective techniques for orchestrating sagas and how to use messaging for reliability. We will describe the design of a saga framework for Java and show a sample application.
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Saturn 2018: Managing data consistency in a microservice architecture using Sagas
1. @crichardson
Managing data consistency in a
microservice architecture using
Sagas
Chris Richardson
Founder of eventuate.io
Author of Microservices Patterns
Founder of the original CloudFoundry.com
Author of POJOs in Action
@crichardson
chris@chrisrichardson.net
http://eventuate.io http://learn.microservices.io
5. @crichardson
About Chris
Founder of a startup that is creating
an open-source/SaaS platform
that simplifies the development of
transactional microservices
(http://eventuate.io)
7. @crichardson
Agenda
ACID is not an option
Overview of sagas
Coordinating sagas
Countermeasures for data anomalies
Using reliable and transactional messaging
10. @crichardson
Each team owns one or more
services
Catalog
Service
Review
Service
Order
Service
…
Service
Catalog
Team
Review
Team
Order
Team
…
Team
Responsible
for
13. @crichardson
Loose coupling =
encapsulated data
Order Service Customer Service
Order Database Customer Database
Order table
Customer
table
orderTotal creditLimit
availableCredit
Change schema without coordinating with other teams
15. @crichardson
How to maintain data consistency?
createOrder(customerId, orderTotal)
Pre-conditions:
• customerId is valid
Post-conditions
• Order was created
• Customer.availableCredit -= orderTotal
Customer class
Invariant:
availableCredit >= 0
availableCredit <= creditLimit
Spans
services
16. @crichardson
Cannot use ACID transactions
that span services
BEGIN TRANSACTION
…
SELECT ORDER_TOTAL
FROM ORDERS WHERE CUSTOMER_ID = ?
…
SELECT CREDIT_LIMIT
FROM CUSTOMERS WHERE CUSTOMER_ID = ?
…
INSERT INTO ORDERS …
…
COMMIT TRANSACTION
Private to the
Order Service
Private to the
Customer Service
Distributed transactions
17. @crichardson
2PC is not an option
Guarantees consistency
BUT
2PC coordinator is a single point of failure
Chatty: at least O(4n) messages, with retries O(n^2)
Reduced throughput due to locks
Not supported by many NoSQL databases (or message brokers)
CAP theorem 2PC impacts availability
….
19. @crichardson
Agenda
ACID is not an option
Overview of sagas
Coordinating sagas
Countermeasures for data anomalies
Using reliable and transactional messaging
21. @crichardson
Saga
Use Sagas instead of 2PC
Distributed transaction
Service A Service B
Service A
Local
transaction
Service B
Local
transaction
Service C
Local
transaction
X Service C
22. @crichardson
Order Service
Create Order Saga
Local transaction
Order
state=PENDING
createOrder()
Customer Service
Local transaction
Customer
reserveCredit()
Order Service
Local transaction
Order
state=APPROVED
approve
order()
createOrder() Initiates saga
23. @crichardson
But what about rollback?
BEGIN TRANSACTION
…
UPDATE …
…
INSERT ….
…
…. BUSINESS RULE VIOLATED!!!!
…
ROLLBACK TRANSACTION
Really simple!
24. @crichardson
Rolling back sagas
Use compensating transactions
Developer must write application logic to “rollback” eventually
consistent transactions
Careful design required!
26. @crichardson
Order Service
Create Order Saga - rollback
Local transaction
Order
createOrder()
Customer Service
Local transaction
Customer
reserveCredit()
Order Service
Local transaction
Order
reject
order()
createOrder()
FAIL
Insufficient credit
27. @crichardson
Writing compensating
transactions isn’t always easy
Write them so they will always succeed
If a compensating transaction fails => no clear way to
recover
Challenge: Undoing changes when data has already been
changed by a different transaction/saga
More on this later
29. @crichardson
Sagas complicate API design
Synchronous API vs Asynchronous Saga
Request initiates the saga. When to send back the response?
Option #1: Send response when saga completes:
+ Response specifies the outcome
- Reduced availability
Option #2: Send response immediately after creating the saga
(recommended):
+ Improved availability
- Response does not specify the outcome. Client must poll or be notified
30. @crichardson
Revised Create Order API
createOrder()
returns id of newly created order
NOT fully validated
getOrder(id)
Called periodically by client to get outcome of validation
31. @crichardson
Minimal impact on UI
UI hides asynchronous API from the user
Saga will usually appear instantaneous (<= 100ms)
If it takes longer UI displays “processing” popup
Server can push notification to UI
32. @crichardson
Agenda
ACID is not an option
Overview of sagas
Coordinating sagas
Countermeasures for data anomalies
Using reliable and transactional messaging
33. @crichardson
How to sequence the saga
transactions?
After the completion of transaction Ti “something” must
decide what step to execute next
Success: which T(i+1) - branching
Failure: C(i - 1)
34. @crichardson
Use asynchronous, broker-
based messaging
Order Service
Customer
Service
….
Message broker
Guaranteed delivery ensures a saga complete when its
participants are temporarily unavailable
35. @crichardson
Saga step = a transaction
local to a service
Service
Database Message Broker
update publish message/event
Transactional DB: BEGIN … COMMIT
DDD: Aggregate
NoSQL: single ‘record’
37. @crichardson
Option #1: Choreography-based
coordination using events
Order
Service
Customer
Service
Order created
Credit Reserved
Credit Limit Exceeded
Create Order
OR
Customer
creditLimit
creditReservations
Order
state
total
create()
reserveCredit()
approve()/
reject()
Order events channel
Customer events channel
41. @crichardson
More complex choreography example
Order
Service
Consumer
Service
Order created
Consumer Validated
Create Order
Order events
channel
Consumer events
channel
Inventory
Service
Accounting
Service
Inventory events
channel
Inventory Reserved
Accounting events
channel
Card Authorized
42. Benefits and drawbacks of
choreography
Benefits
Simple, especially when
using event sourcing
Participants are loosely
coupled
Drawbacks
Cyclic dependencies -
services listen to each
other’s events
Overloads domain objects,
e.g. Order and Customer
know too much
Events = indirect way to
make something happen
https://github.com/eventuate-examples/eventuate-examples-java-customers-and-orders
43. @crichardson
Order Service
Option #2: Orchestration-based saga
coordination
Local transaction
Order
state=PENDING
createOrder()
Customer Service
Local transaction
Customer
reserveCredit()
Order Service
Local transaction
Order
state=APPROVED
approve
order()
createOrder()
CreateOrderSaga
InvokesInvokesInvokes
45. Saga orchestrator behavior
On create:
Invokes a saga participant
Persists state in database
Wait for a reply
On reply:
Load state from database
Determine which saga
participant to invoke next
Invokes saga participant
Updates its state
Persists updated state
Wait for a reply
…
46. @crichardson
Order Service
CreateOrderSaga orchestrator
Customer Service
Create Order
Customer
creditLimit
creditReservations
...
Order
state
total…
reserveCredit()
CreateOrder
Saga
OrderService
create()
create()
approve()
creditReserved()
Customer command channel
Saga reply channel
49. @crichardson
Eventuate Tram Sagas
Open-source Saga orchestration framework
Currently for Java
https://github.com/eventuate-tram/eventuate-tram-sagas
https://github.com/eventuate-tram/eventuate-tram-sagas-
examples-customers-and-orders
50. Benefits and drawbacks of
orchestration
Benefits
Centralized coordination
logic is easier to understand
Reduced coupling, e.g.
Customer knows less.
Simply has API
Reduces cyclic
dependencies
Drawbacks
Risk of smart sagas
directing dumb services
51. @crichardson
Agenda
ACID is not an option
Overview of sagas
Coordinating sagas
Countermeasures for data anomalies
Using reliable and transactional messaging
52. @crichardson
Lack of isolation complicates business
logic
Order Service
Local transaction
Order
state=PENDING
createOrder()
Customer Service
Local transaction
Customer
reserveCredit()
Order Service
Local transaction
cancelOrder()
?
Time
53. @crichardson
How to cancel a PENDING
Order?
Don’t throw an OrderNotCancellableException
Questionable user experience
“Interrupt” the Create Order saga?
Cancel Order Saga: set order.state = CANCELLED
Causes Create Order Saga to rollback
But is that enough to cancel the order?
Cancel Order saga waits for the Create Order saga to complete?
Suspiciously like a distributed lock
But perhaps that is ok
55. @crichardson
Sagas are ACD
Atomicity
Saga implementation ensures that all transactions are
executed OR all are compensated
Consistency
Referential integrity within a service handled by local databases
Referential integrity across services handled by application
Durability
Durability handled by local databases
59. @crichardson
Anomaly: Lost update
Ti: Create
Order
Tj: Approve
Order
Ti: Cancel
Order
Create
Order
Saga
Cancel
Order
Saga
Time
Overwrites
cancelled order
65. Countermeasure: Semantic
lock
Compensatable transaction sets flag,
retriable transaction releases it
Indicates a possible dirty read
Flag = lock:
prevents other transactions from
accessing it
Require deadlock detection, e.g.
timeout
Flag = warning - treat the data
differently, e.g.
Order.state = PENDING
a pending deposit
… …
…
Approve Order
Create Pending
Order
Reject Order
Order.state =
PENDING
Order.state =
REJECTED
Order.state =
APPROVED
71. @crichardson
Agenda
ACID is not an option
Overview of sagas
Coordinating sagas
Countermeasures for data anomalies
Using reliable and transactional messaging
72. @crichardson
Use asynchronous, broker-
based messaging
Order Service
Customer
Service
….
Message broker
Guaranteed delivery ensures a saga complete when its
participants are temporarily unavailable
75. @crichardson
Option #1: Use database
table as a message queue
ACID
transaction
See BASE: An Acid Alternative, http://bit.ly/ebaybase
DELETE
?
Customer
Service
ORDER_ID CUSTOMER_ID TOTAL
99
CUSTOMER_CREDIT_RESERVATIONS table
101 1234
ID TYPE DATA DESTINATION
MESSAGE table
84784 CreditReserved {…} …
INSERT INSERT
Message
Publisher
QUERY
Message
Broker
Publish
Local transaction
reserveCredit()
79. Transaction log tailing: benefits
and drawbacks
Benefits
No 2PC
No application changes
required
Guaranteed to be
accurate
Drawbacks
Obscure
Database specific
solutions
Tricky to avoid duplicate
publishing
81. @crichardson
Event sourcing: persists an
object as a sequence of events
Service
Event Store
save events
and
publish
Event table
Entity type
Event
id
Entity
id
Event
data
Order 902101 …OrderApproved
Order 903101 …OrderShipped
Event
type
Order 901101 …OrderCreated
Every state change event
85. @crichardson
Summary
Microservices tackle complexity and accelerate development
Database per service is essential for loose coupling
Use ACID transactions within services
Use orchestration-based or choreography-based sagas to
maintain data consistency across services
Use countermeasures to reduce impact of anomalies caused
by lack of isolation