Upgrade to Pro — share decks privately, control downloads, hide ads and more …

MongoDB Transaction Pattern

MongoDB Transaction Pattern

Ian Yang

May 20, 2013
Tweet

More Decks by Ian Yang

Other Decks in Technology

Transcript

  1. Outline 1 Overview 2 Write Operation Properties 3 Two Phrase

    Commit 4 Recovering 5 Rollback 6 Multiple Applications 7 References
  2. Transaction (ACID) Atomicity all or nothing. Consistency does not violate

    any integrity constraints Isolation allow concurrent execution of transactions Durability Transaction is persistent after commit
  3. MongoDB Features Atomicity Only on the level of a single

    document. Write Concern Return write operation result
  4. MongoDB Transaction Atomicity done or rollback Consistency rollback may leave

    system in inconsistent state. Isolation other transactions can see intermediate result. Durability write concern, replica set, journal.
  5. Requirements of Write Operations in Transaction Revertible for recover and

    rollback Idempotent for resume, recover and rollback
  6. Revertible db.users.update ({ username: "ian"}, {$inc: {balance: 20}}); db.users.update ({

    username: "ian"}, {$inc: {balance: -20}}); db.users.update ({ username: "ian"}, {$push: {tx: 20}}); db.users.update ({ username: "ian"}, {$pull: {tx: 20}});
  7. Not Idempotent db.users.update ({ username: "ian"}, {$inc: {balance: 20}}); db.users.update

    ({ username: "ian"}, {$push: {tx: 20}}); db.users.update( {username: "ian", balance: 100}, {$inc: {balance: 20}} );
  8. Idempotent db.users.update( {username: "ian", tx: {$ne: tx._id}}, {$inc: {balance: 20},

    $push: {tx: tx._id}} ); db.users.update( {username: "ian", tx: tx._id}, {$inc: {balance: -20}, $pull: {tx: tx._id}} );
  9. Create Transaction Transaction provides a unique identifier, enough information to

    recover and rollback, a document for atomic write operation.
  10. var tx = { _id: ObjectId (), source: ian._id ,

    dest: daniel._id , amount: 20 }; db.transactions.create(tx);
  11. Step 1: Create Transaction var tx = { _id: ObjectId

    (), source: ian._id , dest: daniel._id , amount: 20, state: 'initial ' }; db.transactions.create(tx);
  12. Step 3: Apply Transaction db.users.update( {_id: tx.source , tx: {$ne:

    tx._id}}, {$push: {tx: tx._id}, $inc: { balance: - tx.amount }} ); db.users.update( {_id: tx.dest , tx: {$ne: tx._id}}, {$push: {tx: tx._id}, $inc: { balance: tx.amount }} );
  13. Step 5: Remove Pending Transaction db.users.update( {_id: tx.source , tx:

    tx._id}, {$pull: {tx: tx._id}} ); db.users.update( {_id: tx.dest , tx: tx._id}, {$pull: {tx: tx._id}} );
  14. General Rule Recover from the Step just following the step

    transaction just entered current state. State transition creates a check point
  15. Rollback Operations Better to create a new transaction in reverse

    direction for Committed Transactions and Done Transactions Use following steps to rollback initial and pending transactions
  16. Rollback 1: state → canceling db.transactions.update( {_id: t._id , state:

    {$in: ['initial ', ' pending ']}}, {$set: {state: 'canceling '}} );
  17. Rollback 2: Undo the Transaction db.users.update( {_id: tx.dest , tx:

    {$ne: tx._id}}, {$pull: {tx: tx._id}, $inc: { balance: - tx.amount }} ); db.users.update( {_id: tx.source , tx: tx._id}, {$pull: {tx: tx._id}, $inc: { balance: tx.amount }} );
  18. Rollback 3: canceling → canceled db.transactions.update( {_id: t._id , state:

    {$in: ['canceling ']}}, {$set: {state: 'canceled '}} );
  19. Conclusion Create a document for any transaction Store transaction info

    in the document Apply only Revertible and Idempotent operations
  20. Background A picks a pending transaction to recover B picks

    also a pending transaction to recover
  21. Scenario 1 A is so slow, when it starts apply

    transaction, B already has done the transaction. A must rollback. If A exists abnormally, the transaction is in inconsistent state.
  22. Scenario 2 B just finished Step 5: Removing Pending Transaction

    A applied transactions and exited abnormally B change state to done without error
  23. Solution findAndModify lock db.transactions.findAndModify ({ query: {state: "initial", application: {$exists:

    0}}, update: {$set: {state: "pending", application: "A1"}}, new: true });
  24. Timeout Lock now = new Date(); timeout = new Date(now.valueOf

    () + 60 * 10 * 1000); db.transactions.findAndModify ({ query: {state: "initial", lockUntil: {$not: {$gte: now}}}, update: {$set: {state: "pending", lockUntil: timeout}}, new: true });
  25. Client Requirements Client timeout to ensure the operation is finished

    in expected time. Check time after return from block IO Defer transactions cleanup