gpt4 book ai didi

mongodb - 文档DB和模拟ACID

转载 作者:可可西里 更新时间:2023-11-01 10:44:35 27 4
gpt4 key购买 nike

见最后的结果
我想使用文档数据库(出于各种原因)-可能是couchdb或mongodb。但是,我还需要acid处理多个文档事务。
但是,我确实计划使用“仅添加”模型-更改将作为新文档添加(添加是添加,更新是添加副本+转换数据,删除是添加具有相同ID+删除标志的空文档)。我将定期对数据库运行压缩以删除非当前文档。
有鉴于此,以下观点是否存在漏洞:
维护当前正在进行的事务的集合。此集合将保存具有正在进行的事务的事务ID(guid+时间戳)的文档。

Atomicity:
On a transaction:
Add a document to the transactions in progress collection.
Add the new documents (add is add, update is copy+add, delete is add with ID and “deleted” flag).
Each added document will have the following management fields:
Transaction ID.
Previous document ID (linked list).
Remove the document added to the transactions in progress collection.
On transaction fail:
Remove all added documents
Remove the document from the transactions in progress collection.
Periodically:
Go over all transaction in progress, get ones that have been abandoned (>10 minutes?), remove the associated documents in the DB (index on transaction ID) and then remove the transaction in progress.
Read transaction consistency (read only committed transactions):
On data retrieval:
Load transactions in progress set.
Load needed documents.
For all documents, if the document transaction ID is in “transactions in progress” or later (using timestamp), load the previous document in the linked list (recursive).

有点像mvcc,有点像git。我通过在开始之前成功完成的事务设置检索上下文。我通过保留“正在进行的事务”而不是“事务修订”的列表来避免单个序列(因此是单个执行)。当然,我也避免阅读未授权的事务,并提供冲突回滚。
这里面有洞吗?我的表演会受到严重影响吗?
Edit1:请不要敲打“如果您需要多文档事务,请不要使用文档数据库”。我知道,我还需要一个文档数据库。
edit2:添加了时间戳,以避免来自检索事务启动后启动的事务的数据。可能会将时间戳更改为序列ID。
edit3:这是我想到的另一个算法——它可能比上面的算法更好:
新算法-更容易理解(这次可能会更正:)
Support structures:
transaction_support_tempalte {
_created-by-transaction: <txid>
_made-obsolete-by-transaction: <txid>
}

transaction_record { //
transaction_id: <txid>
timestamp: <tx timestamp>
updated_documents: {
[doc1_id, doc2_id...]
}
}

transaction_numer { //atomic counter - used for ordering transactions.
_id: "transaction_number"
next_transaction_id: 0 //initial.
}

Note: all IDs are model object IDs, not DB ids (don't confuse with logical IDs which are different).
DB ID - different for each document - but multiple DB documents are revisions of one model object.
Model object ID - same for all revisions of the model object.
Logical ID - client-facing ID.


First time setup:
1. Create the transaction_number document:

Commit process:
1. Get new transaction ID by atomic increment on the transaction number counter.
2. Insert a new transaction record with the transaction id, the timestamp and the updated documents.
3. Create the new version for each document. Make sure the _created-by-transaction is set.
4. Update the old version of each updated or deleted document as
"_made-obsolete-by-transaction" with the transaction id.
This is the time to detect conflicts! if seen a conflict, rollback.
Note - this can be done as find-and-modify rather then by serializing the entire document again.
5. Remove the transaction record.

Cleanup process:
1. Go over transaction record, sorted by id, ascending (oldest transaction first).
2. For each transaction, if it expired (by timestamp), do rollback(txid).

Rollback(txid) process:
1. Get the transaction record for the given transaction id.
2. For each document id in the "updated documents":
2.1 If the document exists and has "_made-obsolete-by-transaction" with
the correct transaction id, remove the _made-obsolete-by-transaction data.
3. For each document with the _created-by-transaction-id:
3.1 remove the document.
4. Remove the transaction record document.

Retrieval process:
1. Top-transaction-id = transaction ID counter.
2. Read all transactions from the transactions collection.
Current-transaction-ids[] = Get all transaction IDs.
3. Retrieve documents as needed. Always use "sort by transaction_id, desc" as last sort clause.
3.1 If a document "_created-by-transaction-id" is in the Current-transaction-ids[]
or is >= Top-transaction-id - ignore it (not yet committed).
3.2 If a document "_made-obsolete-by-transaction" is not in the Current-transaction-ids[]
and is < Top-transaction-id - ignore it (a newer version was committed).
4. We may have to retrieve more chunks to satisfy original requests if documents were ignored.

我们开始的时候文件提交了吗?
如果我们在当前执行的事务中看到一个带有事务ID的文档-它是一个
在我们开始检索之前就开始了,但那时还没有提交-所以我们不需要它。
如果我们看到一个事务id>=top事务id的文档-它是在
我们开始了检索-所以我们不想要它。
文件是否为最新版本?
如果我们看到一个过时的文档不在当前事务ID中(事务已启动
在我们开始之前)并且是 过去有一个事务完成了commit,这使得这个文档过时了,所以我们不需要它。
为什么分类不受损害?
因为我们将排序作为最后一个子句添加,所以我们总是首先看到真正的排序工作。每一个真实的
排序“bucket”我们可能会得到多个文档,它们在不同版本上表示模型对象。
但是,模型对象之间的排序顺序保持不变。
为什么计数器不使事务按顺序执行(一次一个)?
因为这不是rdbms-我们没有真正的事务,所以我们不等待事务
像我们在“选择更新”中所做的那样提交。
一旦我们完成另一个事务,它就可以进行原子更改。
压实度:
每隔一段时间就必须进行压缩—获取所有真正旧的文档并将它们删除到另一个数据存储区。
这不应影响任何正在运行的检索或事务。
优化:
将条件放入查询本身。
将事务ID添加到所有索引。
确保具有相同模型对象id的文档不会被切分到不同的节点。
费用是多少?
假设我们需要多个文档版本用于历史记录和审核,那么额外的成本是
原子更新计数器,创建事务记录,“密封”每个模型对象的以前版本
(标记为已过时)并删除交易文档。这个不应该太大。
请注意,如果上述假设无效,则额外成本相当高,尤其是对于检索而言。
结果:
我已经实现了上面的算法(修改后的算法有一些小改动)。从功能上说,它起作用了。但是,性能(至少在主从复制拓扑中有3个节点的MongoDB上,没有fsync,但是在“提交”结束之前需要复制)是非常糟糕的。我一直在读我刚从不同的线程写的东西。我得到了事务集合上的常量集合锁,我的索引无法跟上常量滚动更新。对于带有10个feeder线程的微小事务,性能上限为20 tps。
简而言之-不是一个好的通用解决方案。

最佳答案

在不详细介绍您的计划的情况下,我认为首先讨论一下MongoDB对ACID需求的支持可能是有用的。
原子性:mongo支持对单个文档进行原子更改。通常,最重要的原子操作是“$set”和find,并在mongodb中修改关于这些操作和原子性的一些文档:

http://www.mongodb.org/display/DOCS/Atomic+Operations
[http://www.mongodb.org/display/DOCS/Updating#Updating-%24set][1]
http://www.mongodb.org/display/DOCS/findAndModify+Command

一致性:难以实现且相当复杂。我不想在这篇文章中总结,但是有一系列关于这个主题的文章:
http://blog.mongodb.org/post/475279604/on-distributed-consistency-part-1
[http://blog.mongodb.org/post/498145601/on-distributed-consistency-part-2-some-eventual][2]

隔离:MongoDB中的隔离对于文档是存在的,但对于任何更高级别的文档都不存在。同样,这是一个复杂的主题;除了上面的原子操作链接之外,我找到的最佳资源是以下堆栈溢出线程:
Why doesn't MongoDB use fsync()?(对于这个主题来说,尽管一些关于耐久性的信息已经过时,但总的来说,最重要的答案还是有点像金矿)
持久性:用户确保数据持久性的主要方法是使用getlasterror命令(有关更多信息,请参见下面的链接)来确认副本集中的大多数节点在调用返回之前已经写入了数据。
http://www.mongodb.org/display/DOCS/getLastError+Command#getLastErrorCommand-majority 
http://docs.mongodb.org/manual/core/replication-internals/ (linked to in the above document)

了解了mongo中acid的所有这些知识,查看一些在mongo中已经解决的类似问题的示例将非常有用。我希望下面的两个链接对您非常有用,因为它们是非常完整和正确的主题。
Two-Phase Commits: http://cookbook.mongodb.org/patterns/perform-two-phase-commits/

Transactions for e-commerce work: http://www.slideshare.net/spf13/mongodb-ecommerce-and-transactions-10524960

最后,我不得不问:你为什么想要交易?MongoDB的用户很少发现他们真正需要ACID来实现他们的目标。在您继续在mongo上实现一个完整的层以获取事务之前,可能值得退后一步,尝试从另一个角度来处理这个问题。

关于mongodb - 文档DB和模拟ACID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12375289/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com