如何确保insert()已传播到副本集的所有成员


How to ensure an insert() has propagated to all members of a replica set

插入文档后,立即从MongoDB集合中检索文档时遇到问题。我正在创建文档,然后运行一个查询(无法提前确定)以获取集合中所有文档的子集。问题是我插入的部分或全部文档没有包含在结果中。

过程是:

  1. 查找最近记录的时间戳
  2. 查找自那时以来发生的交易
  3. 为这些事务生成记录,每个事务生成insert()(这可以而且将成为单个大容量插入)
  4. find()一些记录

文档总是写得很成功,但在运行find()时,通常不会包含新文档。几秒钟后即可使用。

我相信,当我尝试检索新文档时,它们还没有传播到副本集的所有成员,尽管我怀疑情况可能并非如此,因为我使用的是与insert()find()相同的连接。

我相信这可以通过写问题来解决,但我不确定指定什么值来确保文档已传播到副本集的所有成员,或者至少传播到将用于find()操作的成员(如果可以提前知道的话)。

我不想硬编码成员总数,因为当添加另一个成员时,这会中断。insert()操作是否缓慢并不重要。

读取首选项

当您向集合写入时,最好将readPreference设置为"primary",以确保您从与您写入的MongoDB服务器相同的服务器上进行读取。

您可以使用MongoCollection::setReadPreference()方法来完成此操作。

$db->mycollection->setReadPreference(MongoClient::RP_PRIMARY);
$db->mycollection->insert(['foo' => 'bar']);
$result = $db->mycollection->find([]);

写下担忧(不要这样做!)

您可能会倾向于使用写问题来等待通过使用w=3(对于3服务器设置)将数据复制到所有辅助设备。然而,这不是要走的路。

MongoDB复制的一个好处是可以自动进行故障切换。在这种情况下,您可能只有不到3台服务器可以接受数据,这会导致脚本永远等待。

没有w=all可以写入所有已启动的服务器。使用这样的书面关注是不好的。一个刚刚从故障转移中恢复过来的中学可能会落后几个小时,需要很长时间才能赶上。您的脚本将等待(挂起),直到所有的辅助进程都被占用。

一个好的做法是never在管理任务之外将w=NN > majority一起使用。

基本上,您正在寻找一个写问题,它(用Layman的术语)允许您指定插入何时完成。

在PHP中,这是通过在insert语句中提供一个选项来完成的,因此您需要类似的东西

w=N个副本集已确认写入将由主服务器确认,并复制到N-1个辅助服务器。

或者如果您不想硬编码N:

w=副本集标记集已确认写入由整个标签集的成员确认

$collection->insert($someDoc, ["w" => 3]);