我正在研究 NoSQL 以扩展数据库的替代方案。如果我想要对此类事物敏感的基于事务的事物,我该怎么办?
11 回答
一般来说,NoSQL 解决方案比关系数据库具有更轻量级的事务语义,但在某种程度上仍然具有原子操作的设施。
一般来说,主-主复制提供的一致性更少,可用性更高。所以应该为正确的问题选择正确的工具。
许多提供单个文档(或行等)级别的交易。例如,对于 MongoDB,单个文档具有原子性 - 但文档可能相当丰富,因此这通常工作得很好 - 更多信息在这里。
这是我找到的最接近的答案,适用于任何 NoSQL 数据库。这是 Heroku.com 的 Adam Wiggins 2007 年的一篇博客文章:
使用数据库事务将资金从一个银行账户转移到另一个银行账户的老例子是完全牛市。正确的解决方案是存储分类账事件列表(账户之间的转账)并将当前余额显示为分类账的总和。如果您正在使用函数式语言进行编程(或以这种方式思考),这很明显。
来自:http ://adam.heroku.com/past/2007/12/17/a_world_without_sql/ (他的网站非常适合关于可扩展性的想法。)
我将以上段落解释为:
- 为成员帐户创建数据库。
- 创建消息队列。给它起个绰号“账本”。
- 添加后台工作人员以完成队列中的每个请求。
更多信息。关于队列/后台工作人员:http ://adam.heroku.com/past/2009/4/14/building_a_queuebacked_feed_reader_part_1/
客户(又名会员或客户)按照以下步骤取款:
- 提交取款请求。
- 请求被发送到服务器。
- 服务器将其放入队列中。消息是:“取出 5,000 美元。”
- 客户端显示:“请稍候,正在满足请求...”
- 客户端机器每 2 秒轮询一次服务器,询问“请求是否已完成?”
- 在服务器上,后台工作人员正在以先进先出的方式满足其他成员的先前请求。最终,他们会根据您客户的要求取出钱。
- 一旦请求得到满足,客户就会收到一条带有新余额的消息。
如果您熟悉 Node.js 或 Ruby/Rack,您可以使用 Heroku.com 快速创建一个小型模型。
总体思路似乎很简单,而且比使用嵌入到数据库中的事务要好得多,这使得它很难扩展。
免责声明:我还没有以任何方式实现这一点。尽管我对它们没有实际需要,但我出于好奇阅读了这些东西。是的,@gbn 是正确的,带有事务的 RDBMS 可能足以满足 Timmy 和我的需求。尽管如此,看看你可以用开源工具和一个名为“ A Tornado of Razorblades ”的操作指南网站将 NoSQL 数据库带到多远会很有趣。
NoSQL涵盖了多种工具和服务,包括键值、文档、图形和宽列存储。他们通常尝试提高数据存储的可扩展性,通常是通过分布式数据处理。事务需要数据库如何执行用户操作的ACID属性。ACID 限制了如何提高可扩展性:大多数 NoSQL 工具放宽了操作的一致性标准以获得容错性和可扩展性,这使得 ACID 事务的实现非常困难。
分布式数据存储的一个普遍引用的理论推理是CAP 定理:一致性、可用性和分区容错性不能同时实现。SQL、NoSQL 和 NewSQL 工具可以根据放弃的内容进行分类;在这里可以找到一个好图。
替代 ACID 的一组新的、较弱的要求是BASE(“基本可用、软状态、最终一致性”)。然而,最终一致的工具(“最终对一个项目的所有访问都将返回最后更新的值”)在银行等交易应用程序中是难以接受的。这里一个好主意是使用内存中的、面向列的和分布式 SQL/ACID 数据库,例如VoltDB;我建议查看这些“NewSQL”解决方案。
只是想评论这个线程上的货币交易建议。交易是您真正想用于汇款的东西。
给出的示例如何 que 转移非常好和整洁。
但在现实生活中,转账可能包括费用或向其他账户付款。人们因使用来自另一个帐户的某些卡而获得奖金,或者他们可能会从他们的帐户中收取费用到同一系统中的另一个帐户。费用或付款可能因金融交易而异,您可能需要保持簿记系统显示每笔交易的贷方和借方。
这意味着您要同时更新多行,因为一个帐户的贷方可以从一个或多个帐户中借记。首先锁定行,以便在更新之前不会发生任何变化,然后确保写入的数据与事务一致。
这就是你真正想要使用事务的原因。如果写入一行出现任何问题,您可以回滚整批更新,而不会导致金融交易数据不一致。
一个交易和两个操作的问题(例如一个支付 5,000 美元,第二个收到 5,000 美元) - 是您有两个具有相同优先级的帐户。您不能使用一个帐户来确认第二个(或以相反的顺序)。在这种情况下,您可以保证只有一个帐户是正确的(即确认),第二个(即确认)可能会失败。让我们看看它为什么会失败(使用消息 aproatch,发送者由接收者确认):
- 向收款人账户写入 +$5,000
- 如果成功 - 将 -$5,000 写入发件人帐户
- 如果失败 - 重试或取消或显示消息
它将保证节省#1。但是如果#2 失败,谁来保证呢?逆序也一样。
但这可以在没有事务和 NoSQL 的情况下实现安全。您始终可以使用第三方实体,该实体将由发送方和接收方确认并保证您的操作已执行:
- 生成唯一的交易 id 并创建交易实体
- 将 +$5,000 写入接收方帐户(参考交易 ID)
- 如果成功 - 设置要发送的事务状态
- 将 -$5,000 写入 sedned 帐户帐户(参考交易 ID)
- 如果成功 - 设置要接收的事务状态
此交易记录将保证可以发送/接收消息。现在,您可以通过交易 ID 检查每条消息,以及它是否已收到或完成状态 - 您将其计入用户余额。
取决于你的数据库,但是......我会说一般来说,你可以使用“乐观事务”来实现这一点,但我想应该确保了解数据库实现的原子性保证(例如,什么样的写入和读取操作是原子的) )。
如果有帮助的话,网上似乎有一些关于HBase事务的讨论。
您始终可以在 SQL DB 中使用 NoSQL 方法。NoSQL 似乎通常使用“键/值数据存储”:您始终可以在您喜欢的 RDBMS 中实现这一点,从而保留事务、ACID 属性、友好 DBA 的支持等好东西,同时实现 NoSQL 的性能和灵活性优势,例如通过表格,例如
CREATE TABLE MY_KEY_VALUE_DATA
(
id_content INTEGER PRIMARY KEY,
b_content BLOB
);
额外的好处是您可以在此处添加额外的字段以将您的内容链接到其他适当的关系表,同时仍将大量内容保留在主 BLOB(或 TEXT,如果合适)字段中。
就我个人而言,我喜欢 TEXT 表示,这样您就不会被绑定到处理数据的语言中,例如,使用序列化 Java 意味着您可以从 Perl 访问内容以进行报告,比如说。TEXT 也更容易调试,通常作为开发人员使用。
看看 scalaris,它是一个无 sql 数据库,具有强一致性和已实现的事务。
- 新的键值存储FoundationDB
- 旧键值存储Berkley DB
肯定还有其他人
这就是为什么我要创建一个 NoSQL 文档存储解决方案,以便能够通过非结构化数据方法的强大功能在企业应用程序上使用“真实”事务。查看http://djondb.com并随意添加您认为有用的任何功能。
如果 NoSQL 解决方案支持 compare-and-set,您可以在它之上实现乐观事务。我在GitHub页面上写了一个示例和一些说明如何在 MongoDB 中执行此操作,但您可以在任何合适的 NoSQL 解决方案中重复它。