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

Distributed locking with MongoDB

Distributed locking with MongoDB

During the talk problems of synchronization in the cluster are discussed. Why `synchronized` doesn't work (and why it does)? How to get distributed locking without ZooKeeper? The talk explores implementation options of synchronization primitives based on MongoDB.

Keynote slides (with gifs!): https://www.dropbox.com/s/jw7gmo1fs81oezw/distributed-locking-with-mongodb.key?dl=1

Andrew Barchuk

July 25, 2015
Tweet

Other Decks in Programming

Transcript

  1. 6 RPS 9 1 RPS 1 RPS 1 RPS 1

    RPS 1 RPS 1 RPS
  2. Unique index WriteResult({ "nInserted" : 0, "writeError" : { "code"

    : 11000, "errmsg" : "E11000 duplicate key error index: database.users.$email_1 dup key: { : \”[email protected]\" }" } }) 14 MongoDB concurrency control
  3. Update-if-current var user = db.users.findOne({userId: 42}); var oldKarma = user.karma;

    var result = db.users.update( { userId: 42, karma: oldKarma }, { $inc: {karma: -1} } ); if( result.nMatched === 0 ) { // query new user and retry } 15 MongoDB concurrency control
  4. Unique index: even greater …prevents duplicate insertions or updates that

    result in duplicate values: update() and findAndModify() 16 MongoDB concurrency control
  5. Acquiring lock var result = db.locks.update( { id: 42 },

    {}, { upsert: true } ); if (result.nUpserted === 1) { // Yay! Lock acquired! } else { // retry… } Lock implementation 21
  6. Cleaning up db.locks.update( { id: 42 }, { aquiredAt: new

    Date() }, { upsert: true } ) Lock implementation 28
  7. Goals ̼do not waste resources (network and CPU time) ̼minimize

    latency Putting the thread to sleep and waking it up 31
  8. Trying to acquire the lock var result = db.locks.update( {

    id: 42, acquired: false }, { $set: {acquired: true} } ); if (result.nUpserted === 1 || result.nModified === 1) { // lock acquired } Improved lock implementation 37
  9. Releasing the lock db.locks.update( { id: 42 }, { $set:

    {acquired: false} } ) Improved lock implementation 38
  10. Putting it all together while(!tryAcuire()) { waitForRelease(); } // do

    your stuff, lock acquired release(); Improved lock implementation 39
  11. Not perfect though ̼Not compatible with TTL indexes ̼Tailable cursor

    dies after some time without data ̼Capped collection size is fixed Improved lock implementation 40
  12. Acquiring semaphore var result = db.locks.update( { id: 42, count:

    {$gt: 0} }, { $setOnInsert: {count: 5}, $inc: {count: -1} }, { upsert: true } ); if (result.nUpserted === 1 || result.nModified === 1) { // semaphore acquired } 42 Semaphore implementation
  13. Acquiring semaphore var result = db.locks.update( { id: 42, count:

    {$gt: 0} }, { // $setOnInsert: {count: 5}, until SERVER-10711 fix $inc: {count: -1} }, { upsert: true } ); if (result.nUpserted === 1 || result.nModified === 1) { // semaphore acquired } 43 Semaphore implementation
  14. Releasing semaphore var result = db.locks.update( { id: 42 },

    { $inc: {count: 1} } ); 44 Semaphore implementation
  15. Considerations ̼use basic concurrency control whenever possible ̼MongoDB may be

    not perfect for your use case ̼always review concurrency related code (better twice!) 45