Datastore/BigTable ACID 和密钥更新通知

Datastore/BigTable ACID and key update notifications

我有 Kafka 主题,其中包含目录数据,命令如下:

  1. item_upsert
  2. partial_item_update
  3. delete_item
  4. delete_all

现在我需要使用这个主题,可能将 100k msgs/sec 流式传输到某些数据库,这将帮助我将原始命令流转换为项目状态流。所以只有来自数据库的当前项目状态。基本上DB都会用到lookup。

我的想法是:

    数据存储中
  1. Insert/Update/Delete 个项目,
  2. 处理完特定消息后,我将向另一个流发送新消息,告诉下游消费者某个项目是 Inserted/Updated/Deleted。这些消费者随后将从数据存储中读取项目的当前状态,并将项目状态提取到另一个 Kafka 主题。

我担心的是 Datastore 的 ACID。 "ACID"怎么样?它甚至适合这样的用例吗?

我也在考虑使用更便宜的 BigTable,但对于这个用例来说这似乎不是正确的选择。

如果您有任何ideas/recommendations解决此问题的方法,我将很高兴。

首先关注的是消息率。数据存储无法维持每个实体组超过 1/秒的写入速率(每个实体都是实体组的一部分),请参阅 Limits。因此,如果您希望每秒更新一次以上 item/entity,则数据存储不适合。

要使用 Cloud Datastore 实现 ACID,您需要避免 Eventual Consistency. Which is possible. From Eventual Consistency when Reading Entity Values:

The eventual consistency on reading entity values can be avoided by using a keys-only query, an ancestor query, or lookup by key (the get() method). We will discuss these different types of queries in more depth below.

我会放弃祖先查询的可能性,因为它需要所有相应的实体都在同一个实体组中,从而放大了上述写入限制的影响。另见 Updates to a single entity group

棘手的部分是 upsert 操作,更具体地说,是创建新实体和 updating/deleting 现有实体之间的区别。

如果您不能总是 generate/determine 项目数据中的唯一项目标识符(或传递在前一阶段确定的标识符),那么这意味着您需要查询,这不能在事务内执行,其结果将受到最终一致性的约束。数据存储也不适合这种情况。

但是如果可以获得这样的唯一标识符,那么您可以将其用作实体键标识符,事情很简单:upsert 操作变成了通过该键 get 实体的简单事务尝试(强一致)和(在同一事务内):

  • 如果 get 因代码不存在而失败,则使用该键创建一个新实体
  • 如果 get 成功更新实体并将其保存回来

Bigtable 可以处理 100K 的 10 节点集群(我有 运行 测试多达 3,500 个节点,每秒处理 35M 更新)。 Bigtable 单行一致性强upserts。 Bigtable 用户设计的模式可以将他们所有的交易数据放入一行。

Cloud Bigtable支持upserts,不区分insertupdate。还有一个按范围删除,理论上可以用于您的 delete_all 案例。

高交易率和低成本是使用 Cloud Bigtable 的正确理由。或者,您可以考虑使用适用于高吞吐量事务数据的 Cloud Spanner。