幂等计数器实现

时间:2017-10-17 13:26:11

标签: database firebase scalability data-modeling google-cloud-firestore

来自文档:

  

这也可能导致单个事件的多个调用,因此对于最高质量的函数,确保函数被写为幂等。

因此,如果Firestore没有提供计算集合中子文档数量的方法,我需要创建一个云函数来聚合节点上的这些信息,比如/counters/{type}/count

如果我执行写入触发并增加值,我的计数器有可能无法反映实际的文档计数,对吗?

如何编写一个函数来完美地计算集合中的文档(不要太昂贵 - 假设我不想在每次写入时都阅读整个集合)?

2 个答案:

答案 0 :(得分:6)

这个问题的答案将取决于你如何使用该系列的不同方面,以及"完美统计"意味着你。

序言

首先,由于Cloud Function调用与write异步,因此会导致计数器略微落后于集合的真实计数。我假设这没关系。

即使您通过阅读每个文档计算了该集合,计数仍可能是陈旧的,因为在您计算时可能已插入或删除了文档。

费用

你提到"而不是太昂贵"。在这里,我们需要了解您阅读计数的频率与添加或删除文档的频率。要维护一个单独的计数器,您将在每次文档计数更改时读/写它。由于写入是读取价格的3倍,这意味着您需要将每个文档计数4次或更多次以恢复保持计数的成本。这里有一个公式,考虑到文档生命周期内的平均计数,但我会将其作为读者的练习。

幂等计数器

这是一个有趣的问题,这是分布式系统的另一个常见问题。如果客户端请求添加+1计数器,并且请求超时(服务器永不响应) - 再次请求是否安全?如果服务器确实应用了增量但后来遇到网络问题怎么办?怎么样呢?

下面我将回答一些处理这种情况的方法。

幂等计数器 - 交易ID

处理此问题的一种方法是使用增量请求发送唯一的事务ID(txid)。如果服务器之前已经处理了txid,它就知道它是重复的请求,并且可以回复它已经完成它。

在您的用例中,如果您从不删除文档,则可以使用文档ID作为txid。在计数器中,当您+1时,将文档ID添加到已处理的增量数组中。在您执行此操作之前,请检查它是否已存在于阵列中(表明它已经处理完毕)。

上面的一个明显问题是阵列会继续增长,最终会变得太大。因此,我们希望限制我们跟踪旧ID的时间。您可以使用时间戳并删除早于' X'的所有内容,或者您​​可以简单地将数组视为循环缓冲区,以使其保持固定的最大大小。

这两种方法对于慢写入速率都是合理的,但对于更快的写入来说是不够的。例如,在1000次写入/秒时,这将是5000个文档ID,仅覆盖5秒(我们在限制文档中提到函数可能需要超过5秒才能执行)。

输入Forgetful Bloom Filters

幂等计数器 - 忘记布隆过滤器

这种方法为您提供了更高的写入速率支持,以换取您以前认为已经看过文档ID的极小可能性。

我在这里没有详细介绍这个实现,但在这个博客中有一个很好的概述:Counters, Idempotence And Forgetful Bloom Filters

幂等计数器 - 删除

另一个复杂性是处理删除。如果您使用唯一ID并确定它不会被重复使用(例如我们的本机自动ID支持),那么添加起来并不困难。只需重复您对添加的操作,但在单独的列表/字段中,并确保检查两个列表。

要考虑的一个小问题是云功能没有保证执行顺序。这意味着如果插入完全靠近,您可能会在插入之前看到删除。

我的建议是,如果您在插入之前看到删除,请事先递减计数器,知道它很快就会被修复,如果您在删除后看到插入,请执行增量。这是因为你只保留了这么多的历史,所以你无法分辨插入和放大。删除乱序,或者插入后删除太远。

其他方法

根据集合大小,需要的准确程度以及计数的使用频率,您可以定期调用云函数来计算计数并将其存储在文档中。您可以根据集合的大小动态调整此值,以最大限度地减少延迟。对于非常小的集合,经常这样做,对于较大的集合,它很少发生。

如果您有一种机制来确定您已经计算过的文件(这样您只需要计算新的文件),您也可以在此处应用成本优化。如果删除很少,您可以添加一个事件来减少删除时的计数器。

答案 1 :(得分:1)

目前由于Cloud Firestore + Cloud Functions集成缺乏保证,唯一可以100%确定您的计数准确的方法是每次写入计数时都读取整个集合。

正如你所说,这在速度或成本方面并不十分高效。

如果您想在不重复阅读整个集合的情况下尝试保持计数,请考虑在每个文档中添加counted布尔值。

然后,当文档进入时,您在事务中执行以下操作:

  1. 阅读文件。如果counted == true,请退出
  2. 增加点数。
  3. counted标记为真。
  4. 有关Cloud Firestore中交易的更多信息,请参阅文档: https://firebase.google.com/docs/firestore/manage-data/transactions