42
Bringing Transactional Guarantees to MongoDB Paul Robinson [email protected] @pfrobinson

Bringing Transactional Guarantees to MongoDB

Embed Size (px)

DESCRIPTION

MongoDB and similar document-based NoSQL datastores tend to offer limited transaction support. And with good reason, as using an ACID (Atomicity, Consistency, Isolation, Durability) transaction to make updates to multiple documents (potentially over multiple resources) can limit scalability. But there are alternative transaction models that can be used in favor of removing transactions altogether. In this presentation, you’ll see: How to use a compensating-transaction approach to provide many of the ACID guarantees without the scalability limitations that an ACID approach could bring. Cases in which ACID transactions might not be appropriate—in particular, why ACID transaction support for multiple document updates is rarely offered in a NoSQL datastore. How to use a compensating transaction as an alternative. How to develop applications that make transactional updates to multiple documents in a MongoDB datastore. How reliability can be built upon the primitives provided by MongoDB and how the middleware can abstract this from the developer. The majority of this talk will include a code example that uses the Narayana compensating-transactions API, which greatly simplifies the development of applications that need this transaction model.

Citation preview

Page 1: Bringing Transactional Guarantees to MongoDB

Bringing Transactional Guarantees to MongoDB

Paul Robinson [email protected]

@pfrobinson

Page 2: Bringing Transactional Guarantees to MongoDB

Agenda

•ACID Transactions

•Compensating Transactions

•Code Example

•Today and Planned

Page 3: Bringing Transactional Guarantees to MongoDB

Transactions with RDBS

Update balance and create an order atomically

id username item size

0 0 Stumpjumper L

id username email voucher

0 paul.robinson paul… 3000

Invoices

Users

id username item size

0 0 Stumpjumper L

1 0 Zesty L

id username email voucher

0 paul.robinson paul… 200

Invoices

Users

Page 4: Bringing Transactional Guarantees to MongoDB

{ id: "<ObjectID1>", username: "paul.robinson", email: "[email protected]" voucher: 3000, invoices: { {"Stumpjumper", "L"}, } }

Transactions with Document Stores

Update balance and create an order atomically

{ id: "<ObjectID1>", username: "paul.robinson", email: "[email protected]" voucher: 200, invoices: { {"Stumpjumper", "L"}, {"Zesty", "L"} } }

Page 5: Bringing Transactional Guarantees to MongoDB

But, sometimes this isn’t possible…

Page 6: Bringing Transactional Guarantees to MongoDB

Change Multiple Documents{ user: ‘Paul’ balance: 1000 }

{ user: ‘Fred’ balance: 0 }

{ user: ‘Paul’ balance: 700 }

{ user: ‘Fred’ balance: 300 }

E.g. Money Transfer, audited delete, integration

Page 7: Bringing Transactional Guarantees to MongoDB

Why doesn’t MongoDB support multi-document transactions?

Page 8: Bringing Transactional Guarantees to MongoDB

Scaling MongoDB

Router (mongos)

Shard

Master

D1

Slave 1

D1

Slave 2

D1

Shard

Master

D2

Slave 1

D2

Slave 2

D2

Page 9: Bringing Transactional Guarantees to MongoDB

Multi-Document Transactions

Client

Shard

D1Router

(mongos)Shard

D2

D1

Page 10: Bringing Transactional Guarantees to MongoDB

Multi-Document Transactions

Client

Shard

D1Router

(mongos)Shard

D2

Page 11: Bringing Transactional Guarantees to MongoDB

Multi-Document Transactions

Client

Shard

D1Router

(mongos)Shard

D2

Client D1?

Page 12: Bringing Transactional Guarantees to MongoDB

Client

Multi-Document Transactions

ClientD2

Shard

D1Router

(mongos)Shard

D2

Client D1?

Page 13: Bringing Transactional Guarantees to MongoDB

Client

Multi-Document Transactions

Client

Shard

D1Router

(mongos)Shard

D2

Client D1?

Page 14: Bringing Transactional Guarantees to MongoDB

D1Client

Multi-Document Transactions

Client

Shard

D1Router

(mongos)Shard

D2

Done

ClientD1

Page 15: Bringing Transactional Guarantees to MongoDB

(Multi-document) ACID doesn’t scale …

Page 16: Bringing Transactional Guarantees to MongoDB

Don’t throw out transactions altogether!

Page 17: Bringing Transactional Guarantees to MongoDB

Extended Transactions

• Umbrella term

• Alternatives to ACID

Guarantees

ACIDNone Extended

Page 18: Bringing Transactional Guarantees to MongoDB

ACID Vs Compensating Transactions

• ACID 1. Lock each resource 2. Commit/rollback each resource !

• Compensating 1. Commit each resource 2. Confirm/compensate each resource

Page 19: Bringing Transactional Guarantees to MongoDB

Compensating Transactions

• Eventually consistent

• Relaxed isolation

• Can move locks to application logic

• Support Long running tasks

Page 20: Bringing Transactional Guarantees to MongoDB

Transaction OptionsAtomic Atomic Batch Traditional

ACIDCompensating!Transactions

Single Doc ✓ ✓ ✓ ✓Multi Doc O ✓ ✓ ✓Sharding ✓ O O ✓

Multi stores O O ✓ ✓ACID ✓ ✓ ✓ O

App Unaware ✓ ✓ ✓ O

Page 21: Bringing Transactional Guarantees to MongoDB

Existing Patterns

• Compensating Transaction

• Just a pattern

• Needs implementing

• Recovery is hard!

MongoDB

Application (incl transaction and recovery code)

Page 22: Bringing Transactional Guarantees to MongoDB

Narayana’s Solution in WildFly 8

• Middleware

• Transaction Manager driven

• Annotation-based API

• Based on Sagas

MongoDB

Narayana

Application

Page 23: Bringing Transactional Guarantees to MongoDB

Protocol Details

Page 24: Bringing Transactional Guarantees to MongoDB

Starting State{ user: ‘A’ bal: 1000 }

{ user: ‘B’ bal: 0 }

Page 25: Bringing Transactional Guarantees to MongoDB

Log Compensation Handler 1{ user: ‘A’ bal: 1000 }

{ user: ‘A’ bal: 1000 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

<txid> pending <comp1>

Page 26: Bringing Transactional Guarantees to MongoDB

Update Document 1{ user: ‘A’ bal: 1000 }

{ user: ‘A’ bal: 1000 }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

<txid> pending <comp1>

<txid> pending <comp1>

Page 27: Bringing Transactional Guarantees to MongoDB

Log Compensation Handler 2{ user: ‘A’ bal: 1000 }

{ user: ‘A’ bal: 1000 }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

<txid> pending <comp1>

<txid> pending <comp1>

<txid> pending <comp1> <comp2>

Page 28: Bringing Transactional Guarantees to MongoDB

Update Document 2{ user: ‘A’ bal: 1000 }

{ user: ‘A’ bal: 1000 }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 300 tx: <txid> }

<txid> pending <comp1>

<txid> pending <comp1>

<txid> pending <comp1> <comp2>

<txid> pending <comp1> <comp2>

Page 29: Bringing Transactional Guarantees to MongoDB

Update Transaction Log{ user: ‘A’ bal: 1000 }

{ user: ‘A’ bal: 1000 }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 300 tx: <txid> }

<txid> pending <comp1>

<txid> pending <comp1>

<txid> pending <comp1> <comp2>

<txid> pending <comp1> <comp2>

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘B’ bal: 300 tx: <txid> }

<txid> committing <comp1> <comp2>

Page 30: Bringing Transactional Guarantees to MongoDB

Confirm Document 1{ user: ‘A’ bal: 1000 }

{ user: ‘A’ bal: 1000 }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 300 tx: <txid> }

<txid> pending <comp1>

<txid> pending <comp1>

<txid> pending <comp1> <comp2>

<txid> pending <comp1> <comp2>

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘B’ bal: 300 tx: <txid> }

<txid> committing <comp1> <comp2>

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘B’ bal: 300 tx: <txid> }

<txid> committing <comp1> <comp2>

Page 31: Bringing Transactional Guarantees to MongoDB

Confirm Document 2{ user: ‘A’ bal: 1000 }

{ user: ‘A’ bal: 1000 }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 300 tx: <txid> }

<txid> pending <comp1>

<txid> pending <comp1>

<txid> pending <comp1> <comp2>

<txid> pending <comp1> <comp2>

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘B’ bal: 300 tx: <txid> }

<txid> committing <comp1> <comp2>

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘B’ bal: 300 tx: <txid> }

<txid> committing <comp1> <comp2>

{ user: ‘A’ bal: 700 }

{ user: ‘B’ bal: 300 tx: <txid> }

<txid> committing <comp1> <comp2>

Page 32: Bringing Transactional Guarantees to MongoDB

Completed{ user: ‘A’ bal: 1000 }

{ user: ‘A’ bal: 1000 }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 0 }

{ user: ‘B’ bal: 300 tx: <txid> }

<txid> pending <comp1>

<txid> pending <comp1>

<txid> pending <comp1> <comp2>

<txid> pending <comp1> <comp2>

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘B’ bal: 300 tx: <txid> }

<txid> committing <comp1> <comp2>

{ user: ‘A’ bal: 700 tx: <txid> }

{ user: ‘B’ bal: 300 tx: <txid> }

<txid> committing <comp1> <comp2>

{ user: ‘A’ bal: 700 }

{ user: ‘B’ bal: 300 tx: <txid> }

<txid> committing <comp1> <comp2>

{ user: ‘A’ bal: 700 }

{ user: ‘B’ bal: 300 !}

Page 33: Bringing Transactional Guarantees to MongoDB

Code Example

Page 34: Bringing Transactional Guarantees to MongoDB

Money Transfer

• Each user has a balance

• Move money between users

• Update both documents atomically

Page 35: Bringing Transactional Guarantees to MongoDB

public class BankingService { ! @Inject AccountManager accountManager; ! @Compensatable public void transferMoney(String fromAccount, String toAccount, Integer amount) { ! accountManager.debitAccount(fromAccount, amount); accountManager.creditAccount(toAccount, amount); }

Service

Page 36: Bringing Transactional Guarantees to MongoDB

public class AccountManager { ! @Inject AccountDAO accountDAO; @Inject private CompensationManager compensationManager; @Inject CreditData creditData; ! @TxCompensate(UndoCredit.class) public void creditAccount(String account, Integer amount) { ! //High value transfers (over 500) are not allowed with this service if (amount > 500) compensationManager.setCompensateOnly() && return; creditData.setToAccount(account); creditData.setAmount(amount); accountDAO.incrementBalance(account, amount); } …

Account Manager (credit part)

Page 37: Bringing Transactional Guarantees to MongoDB

… @Inject DebitData debitData; ! @TxCompensate(UndoDebit.class) public void debitAccount(String account, Integer amount) { ! debitData.setFromAccount(account); debitData.setAmount(amount); ! accountDAO.incrementBalance(account, -1 * amount); } }

Account Manager (debit part)

Page 38: Bringing Transactional Guarantees to MongoDB

@CompensationScoped public class CreditData implements Serializable { ! private String toAccount; private Integer amount; … } !@CompensationScoped public class DebitData implements Serializable { ! private String fromAccount; private Integer amount; … }

Compensation Data

Page 39: Bringing Transactional Guarantees to MongoDB

public class UndoCredit implements CompensationHandler { ! @Inject CreditData creditData; @Inject AccountDAO accountDAO; ! public void compensate() { ! if (creditData.getToAccount() != null) { accountDAO.incrementBalance( creditData.getToAccount(), -1 * creditData.getAmount()); } } }

Compensation Handler (Credit)

Page 40: Bringing Transactional Guarantees to MongoDB

What we have today

• Compensating-Transactions API

• MongoDB Example

• Other Quickstarts

• Blog post series

• Ships with WildFly 8.Final+

Page 41: Bringing Transactional Guarantees to MongoDB

What’s Planned

• MongoDB RM

• Compensating state Recovery

• Throughput/Scalability study

• RDBMS integration

• Other language support

Page 42: Bringing Transactional Guarantees to MongoDB

Getting Started• Explore the quickstarts http://github.com/jbosstm/quickstart/

• Give feedback (forum) http://community.jboss.org/en/jbosstm

• Track issues http://issues.jboss.org/browse/JBTM

• Subscribe to Blog http://jbossts.blogspot.co.uk/

• Contact me [email protected], @pfrobinson