Spring Data MongoDB Concurrent Updates Behavior
Asked Answered
S

4

5

Imagine theres a document containing a single field: {availableSpots: 100}

and there are millions of users, racing to get a spot by sending a request to an API server.

each time a request comes, the server reads the document and if the availableSpot is > 0, it then decrements it by 1 and creates a booking in another collection.

Now i read that mongodb locks the document whenever an update operation is performed.

What will happen if theres a million concurrent requests? will it take a long time because the same document keeps getting locked? Also, the server reads the value of document before it tries to update the document, and by the time it acquires the lock, the spot may not be available anymore.

It is also possible that the threads are getting "availableSpot > 0" is true at the same instant in time, but in reality the availableSpot may not be enough for all the requests. How to deal with this?

Stet answered 22/6, 2019 at 6:34 Comment(0)
M
5

The most important thing here is atomicity and concurrency.

1. Atomicity

Your operation to update (decrement by one) if availableSpots > 0 :

db.collection.updateOne({"availableSpots" :{$gt : 0}}, { $inc: { availableSpots: -1 })

is atomic.

$inc is an atomic operation within a single document.

Refer : https://docs.mongodb.com/manual/reference/operator/update/inc/

2. Concurrency Since MongoDB has document-level concurrency control for write operations. Each update will take a lock on the document.

Now your questions:

What will happen if theres a million concurrent requests?

Yes each update will be performed one by one (due to locking) hence will slow down.

the server reads the value of document before it tries to update the document, and by the time it acquires the lock, the spot may not be available anymore.

Since the operation is atomic, this will not happen. It will work as you want, only 100 updates will be executed with number of affected rows greater than 0 or equal to 1.

Moustache answered 29/7, 2019 at 5:20 Comment(0)
D
3

MongoDB uses Wired Tiger as a default storage engine starting version 3.2.

Wired Tiger provides document level concurrency:

From docs:

WiredTiger uses document-level concurrency control for write operations. As a result, multiple clients can modify different documents of a collection at the same time.

For most read and write operations, WiredTiger uses optimistic concurrency control. WiredTiger uses only intent locks at the global, database and collection levels. When the storage engine detects conflicts between two operations, one will incur a write conflict causing MongoDB to transparently retry that operation.

When multiple clients are trying to update a value in a document, only that document will be locked, but not the entire collections.

Disparate answered 22/6, 2019 at 7:2 Comment(2)
ok but this still does not answer my question... what happens when there is a million simultaneous request to update the same document which i think is very common caseStet
In order to ensure consistency, it will lock the document to prevent multiple clients from modifying the same piece of data simultaneouslyDisparate
I
1

My understanding is that you are concerned about the performance of many concurrent ACID-compliant transactions against two separate collections:

  • a collection (let us call it spots) with one document {availableSpots: 999..}
  • another collection (let us call it bookings) with multiple documents, one per booking. Now i read that mongodb locks the document whenever an update operation is performed.

It is also possible that the threads are getting "availableSpot > 0" is true at the same instant in time, but in reality the availableSpot may not be enough for all the requests. How to deal with this?

With version 4.0, MongoDB provides the ability to perform multi-document transactions against replica sets. (The forthcoming MongoDB 4.2 will extend this multi-document ACID transaction capability to sharded clusters.)

This means that no write operations within a multi-document transaction (such as updates to both the spots and bookings collections, per your proposed approach) are visible outside the transaction until the transaction commits.

Nevertheless, as noted in the MongoDB documentation on transactions a denormalized approach will usually provide better performance than multi-document transactions:

In most cases, multi-document transaction incurs a greater performance cost over single document writes, and the availability of multi-document transaction should not be a replacement for effective schema design. For many scenarios, the denormalized data model (embedded documents and arrays) will continue to be optimal for your data and use cases. That is, for many scenarios, modeling your data appropriately will minimize the need for multi-document transactions.

In MongoDB, an operation on a single document is atomic. Because you can use embedded documents and arrays to capture relationships between data in a single document structure instead of normalizing across multiple documents and collections, this single-document atomicity obviates the need for multi-document transactions for many practical use cases.

But do bear in mind that your use case, if implemented within one collection as a single denormalized document containing one availableSpots sub-document and many thousands of bookings sub-documents, may not be feasible as the maximum document size is 16MB.

So, in conclusion, a denormalized approach to write atomicity will usually perform better than a multi-document approach, but is constrained by the maximum document size of 16MB.

Immure answered 31/7, 2019 at 2:52 Comment(0)
T
0

You can try using findAndModify() option while trying to update the document. Each time you will need to cherry pick whichever field you want to update in that particular document. Also, since mongo db replicates data to Primary and secondary nodes, you may also want to adjust your WriteConcern values as well. You can read more about this in official documentation. I have something similar coded that handles similar kind of concurrency issues in mongoDB using spring mongoTemplate. Let me know if you want any reference related to java with that.

Theotheobald answered 11/10, 2019 at 1:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.