What did MongoDB not being ACID compliant before v4 really mean?

五迷三道 提交于 2019-11-27 16:34:19
Bryan Migliorisi

One thing you lose with MongoDB is multi-collection (table) transactions. Atomic modifiers in MongoDB can only work against a single document.

If you need to remove an item from inventory and add it to someone's order at the same time - you can't. Unless those two things - inventory and orders - exist in the same document (which they probably do not).

I encountered this very same issue in an application I am working on and had two possible solutions to choose from:

1) Structure your documents as best you can and use atomic modifiers as best you can and for the remaining bit, use a background process to cleanup records that may be out of sync. For example, I remove items from inventory and add them to a reservedInventory array of the same document using atomic modifiers.

This lets me always know that items are NOT available in the inventory (because they are reserved by a customer). When the customer check's out, I then remove the items from the reservedInventory. Its not a standard transaction and since the customer could abandon the cart, I need some background process to go through and find abandoned carts and move the reserved inventory back into the available inventory pool.

This is obviously less than ideal, but its the only part of a large application where mongodb does not fit the need perfectly. Plus, it works flawlessly thus far. This may not be possible for many scenarios, but because of the document structure I am using, it fits well.

2) Use a transactional database in conjunction with MongoDB. It is common to use MySQL to provide transactions for the things that absolutely need them while letting MongoDB (or any other NoSQL) do what it does best.

If my solution from #1 does not work in the long run, I will investigate further into combining MongoDB with MySQL but for now #1 suits my needs well.

William Z

It's actually not correct that MongoDB is not ACID-compliant. On the contrary, MongoDB is ACID-compilant at the document level.

Any update to a single document is

  • Atomic: it either fully completes or it does not
  • Consistent: no reader will see a "partially applied" update
  • Isolated: again, no reader will see a "dirty" read
  • Durable: (with the appropriate write concern)

What MongoDB doesn't have is transactions -- that is, multiple-document updates that can be rolled back and are ACID-compliant.

Note that you can build transactions on top of the ACID-compliant updates to a single document, by using two-phase commit.

A good explanation is contained in "Starbucks Does Not Use Two Phase Commit".

It's not about NoSQL databases, but it does illustrate the point that sometimes you can afford to lose a transaction or have your database in an inconsistent state temporarily.

I wouldn't consider it to be something that needs to be "fixed". The fix is to use an ACID-compliant relational database. You choose a NoSQL alternative when its behavior meets your application requirements.

I think other people gave good answers already. However i would like to add that there are ACID NOSQL DBs (like http://ravendb.net/ ). So it is not only decision NOSQL - no ACID vs Relational with ACID....

Sergey

"won't save correctly" could mean:

  1. By default MongoDB does not save your changes to the drive immediately. So there is a possibility that you tell a user "update is successful", power outage happens and the update is lost. MongoDB provides options to control level of update "durability". It can wait for the other replica(s) to receive this update (in memory), wait for the write to happen to the local journal file, etc.

  2. There is no easy "atomic" updates to multiple collections and even multiple documents in the same collection. It's not a problem in most cases because it can be circumvented with Two Phase Commit, or restructuring your schema so updates are made to a single document. See this question: Document Databases: Redundant data, references, etc. (MongoDB specifically)

As of MongoDB v4.0, multi-document ACID transactions are to be supported. Through snapshot isolation, transactions will provide a globally consistent view of data, and enforce all-or-nothing execution to maintain data integrity.

They feel like transactions from the relational world, e.g.:

with client.start_session() as s:
    s.start_transaction()
    try:
        collection.insert_one(doc1, session=s)
        collection.insert_one(doc2, session=s)
        s.commit_transaction()
    except Exception:
        s.abort_transaction()

See https://www.mongodb.com/blog/post/multi-document-transactions-in-mongodb

The only reason atomic modifies work against a single-collection is because the mongodb developers recently exchanged a database lock with a collection wide write-lock. Deciding that the increased concurrency here was worth the trade-off. At it's core, mongodb is a memory-mapped file: they've delegated the buffer-pool management to the machine's vm subsystem. Because it's always in memory, they're able to get away with very course grained locks: you'll be performing in-memory only operations while holding it, which will be extremely fast. This differs significantly from a traditional database system which is sometimes forced to perform I/O while holding a pagelock or a rowlock.

Please read about the ACID properties to gain better understanding.

Also in the MongoDB documentation you can find a question and answer.

MongoDB is not ACID compliant. Read below for a discussion of the ACID compliance.

  1. MongoDB is Atomic on document level only. It does not comply with the definition of atomic that we know from relational database systems, in particular the link above. In this sense MongoDB does not comply with the A from ACID.
  2. MongoDB is Consitent by default. However, you can read from secondary servers in a replica set. You can only have eventual consistency in this case. This is useful if you don't mind to read slightly outdated data.
  3. MongoDB does not guarantee Isolation (again according to above definition):
  1. For systems with multiple concurrent readers and writers, MongoDB will allow clients to read the results of a write operation before the write operation returns.
  2. If the mongod terminates before the journal commits, even if a write returns successfully, queries may have read data that will not exist after the mongod restarts.

However, MongoDB modifies each document in isolation (for inserts and updates); on document level only, not on multi-document transactions.

  1. In regards to Durability - you can configure this behaviour with the write concern option, not sure though. Maybe someone knows better.

I believe some research is ongoing to move NoSQL towards ACID constraints or similar. This is a challenge because NoSQL databases are usually fast(er) and ACID constraints can slow down performance significantly.

"In MongoDB, an operation on a single document is atomic" - That's the thing for past

In the new version of MongoDB 4.0 you CAN :

However, for situations that require atomicity for updates to multiple documents or consistency between reads to multiple documents, MongoDB provides the ability to perform multi-document transactions against replica sets. Multi-document transactions can be used across multiple operations, collections, databases, and documents. Multi-document transactions provide an “all-or-nothing” proposition. When a transaction commits, all data changes made in the transaction are saved. If any operation in the transaction fails, the transaction aborts and all data changes made in the transaction are discarded without ever becoming visible. Until a transaction commits, no write operations in the transaction are visible outside the transaction.

Though there are few limitations for How and What operations can be performed.

Check the Mongo Doc. https://docs.mongodb.com/master/core/transactions/

You can implement atomic multi-key updates (serializable transaction) on the client side if your storage supports per key linearizability and compare and set (which is true for MongoDB). This approach is used in Google's Percolator and in the CockroachDB but nothing prevents you from using it with MongoDB.

I've created a step-by-step visualization of such transactions. I hope it will help you to understand them.

If you're fine with read committed isolation level then it makes sense to take a look on RAMP transactions by Peter Bailis. They also can be implemented for MongoDB on the client side.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!