Mongo Change Streams运行多次(种类):运行多个实例的节点应用程序

时间:2018-08-24 15:36:30

标签: node.js mongodb changestream

我的Node应用程序使用Mongo更改流,并且该应用程序在生产环境中运行3个以上的实例(最终,因此,随着它的增长,这将成为一个更大的问题)。因此,当发生更改时,更改流功能将运行的次数与进程的次数相同。

如何进行设置,使更改流仅运行一次?

这就是我所拥有的:

const options = { fullDocument: "updateLookup" };

const filter = [
  {
    $match: {
      $and: [
        { "updateDescription.updatedFields.sites": { $exists: true } },
        { operationType: "update" }
      ]
    }
  }
];

const sitesStream = Client.watch(sitesFilter, options);

// Start listening to site stream
sitesStream.on("change", async change => {
  console.log("in site change stream", change);
  console.log(
    "in site change stream, update desc",
    change.updateDescription
  );

  // Do work...
  console.log("site change stream done.");
  return;
});

5 个答案:

答案 0 :(得分:1)

虽然Kafka选项听起来很有趣,但是在我不熟悉的平台上进行了很多基础架构工作,所以我决定在离我较近的地方走一段路,向一个小摊位发送MQTT消息。一个单独的应用程序,然后让MQTT服务器监视消息的唯一性。

siteStream.on("change", async change => {
  console.log("in site change stream);
  const mqttClient = mqtt.connect("mqtt://localhost:1883");
  const id = JSON.stringify(change._id._data);
  // You'll want to push more than just the change stream id obviously...
  mqttClient.on("connect", function() {
    mqttClient.publish("myTopic", id);
    mqttClient.end();
  });
});

我仍在研究MQTT服务器的最终版本,但是评估消息唯一性的方法可能会在应用程序内存中存储更改流ID的数组,因为不需要持久保存它们,并评估是否根据之前是否已经看到过更改流ID来进行任何进一步的操作。

var mqtt = require("mqtt");
var client = mqtt.connect("mqtt://localhost:1883");
var seen = [];
client.on("connect", function() {
  client.subscribe("myTopic");
});
client.on("message", function(topic, message) {
  context = message.toString().replace(/"/g, "");
  if (seen.indexOf(context) < 0) {
    seen.push(context);
    // Do stuff
  }
});

这不包括安全性等,但是您知道了。

答案 1 :(得分:1)

仅使用Mongodb查询运算符就可以轻松完成。您可以在ID字段上添加模查询,其中除数是您的应用实例数(N)。余数则为元素{0,1,2,...,N-1}。如果您的应用实例从零到N-1升序编号,则可以这样编写过滤器:

yield (k, flatten_json(v))

答案 2 :(得分:1)

要做到这一点很困难,但并非没有可能。我在这里写了一种解决方案的详细信息:requests

示例是用Java编写的,但重要的部分是算法。

这归结为一些技巧:

fencing token中的更多详细信息。

答案 3 :(得分:0)

听起来您需要一种在实例之间划分更新的方法。您是否研究过Apache Kafka?基本上,您会做的是只有一个应用程序,将更改数据写入分区的Kafka主题,并使您的节点应用程序成为Kafka使用者。这样可以确保只有一个应用程序实例会收到更新。

根据您的分区策略,您甚至可以确保同一记录的更新始终转到同一节点应用程序(如果您的应用程序需要保持自己的状态)。否则,您可以循环方式散布更新。

使用Kafka的最大好处是您可以添加和删除实例,而无需调整配置。例如,您可以启动一个实例,它将处理所有更新。然后,一旦您启动另一个实例,它们各自就开始处理一半的负载。您可以在有分区的任意多个实例上继续使用此模式(如果需要,可以将主题配置为具有1000个分区),这就是Kafka用户组的力量。按比例缩小则相反。

答案 4 :(得分:-1)

将在数据库中有一个名为status的字段,该字段将根据从变更流接收到的事件使用findAnUpdate进行更新。因此,可以说您从变更流中同时获得2个事件。第一个事件会将状态更新为start,如果状态为start,则另一个事件将引发错误。因此,第二个事件将不会处理任何业务逻辑。