14

我正在做一个包含一些重要数据的项目。这意味着如果灯或服务器出现故障,我们不能丢失任何东西。我们使用 MongoDB 作为数据库。我想确保插入后我的数据在数据库中,如果没有插入一个元素,则回滚整个批次。我知道 Mongo 背后的理念是我们不需要事务,但我如何确保我的数据在插入后真正安全地存储,而不是发送到某个“黑洞”。

  • 我应该进行搜索吗?

  • 我应该使用一些特定的 mongoDB 命令吗?

  • 即使一台服务器足以满足
    速度要求,我是否应该使用分片,顺便说一句,如果灯熄灭,它不能保证任何事情

什么是最好的解决方案?

4

2 回答 2

14

最好的选择是使用 Write Concerns - 这些允许您告诉 MongoDB 一条数据的重要性。最快的 Write Concern 也是最不安全的 - 在下一次计划的刷新之前,数据不会刷新到磁盘。最安全的方法是在返回之前确认数据已写入多台机器上的磁盘。

您正在寻找的写入问题是 FSYNC_SAFE (至少从Java 驱动程序的角度来看它是这样调用的)或 REPLICAS_SAFE 确认您的数据已被复制。

请记住,MongoDB 没有传统意义上的事务 - 您的回滚必须手动滚动,因为您无法告诉 Mongo 数据库为您执行此操作。

您需要做的另一件事是使用相对较新的--journal选项(使用预写日志),或使用副本集在多台机器之间共享数据,以便在发生崩溃/断电时最大限度地提高数据完整性。

在处理特别大的数据集时,分片与其说是一种防止硬件故障的保护,不如说是一种分担负载的方法——分片不应与副本集相混淆,副本集是一种将数据写入多台机器上的多个磁盘的方法.

因此,如果您的数据足够有价值,您绝对应该使用副本集,甚至可能在其他数据中心/可用区/机架/等中设置从站,以提供您需要的弹性。

有/将(不记得副手是否已实现)来指定副本集中单个节点的优先级如果有这样的机器可用(即阻止该国另一端的奴隶成为主人,除非它确实是唯一的其他选择)。

于 2011-08-11T13:58:51.690 回答
5

我从谷歌群组上一个叫做GVP的人那里得到了一个非常好的答案。我会引用它(基本上它加起来就是 Rich 的回答):

我想确保插入后我的数据在数据库中,如果没有插入一个元素,则回滚整个批次。

这是一个复杂的主题,您必须在此处考虑几个权衡。

我应该使用分片吗?

分片用于扩展写入。为了数据安全,您希望查看副本集。

我应该使用一些特定的 mongoDB 命令吗?

首先要考虑的是 Andreas 指出的“安全”模式或“getLastError()”。如果您发出“安全”写入,您就知道数据库已收到插入并应用了写入。但是,MongoDB 仅每 60 秒刷新一次磁盘,因此服务器可能会在磁盘上没有数据的情况下发生故障。

要考虑的第二件事是“日志”(v1.8+)。打开日记功能后,每 100 毫秒将数据刷新到日志中。所以你在失败之前有一个更小的时间窗口。驱动程序有一个比“安全”更进一步的“fsync”选项(检查该名称),它等待确认数据已刷新到磁盘(即日志文件)。但是,这仅涵盖一台服务器。如果服务器上的硬盘死了会发生什么?那么你需要第二个副本。

第三要考虑的是复制。驱动程序支持“W”参数,表示“将此数据复制到 N 个节点”,然后再返回。如果在某个超时之前写入没有到达“N”个节点,则写入失败(抛出异常)。但是,您必须根据副本集中的节点数正确配置“W”。同样,由于硬盘驱动器可能会发生故障,即使使用日记功能,您也需要查看复制。然后是跨数据中心的复制,这太长了,无法进入这里。最后要考虑的是您对“回滚”的要求。据我了解,MongoDB 没有这种“回滚”能力。如果您正在执行批量插入,您将得到的最好结果是指示哪些元素失败。

这是一个链接到这个 PHP 驱动程序:http://it.php.net/manual/en/mongocollection.batchinsert.php 您必须检查有关复制和 W 参数的详细信息。我相信同样的限制也适用于此。

于 2011-08-12T06:34:29.980 回答