当前位置: 首页 > 知识库问答 >
问题:

Google App Engine/NDB-放置后实体列表的读取高度一致

邵逸明
2023-03-14

使用Google App Engine的NDB数据存储,如何确保在创建新实体后读取实体列表的高度一致?

示例用例是我有员工类型的实体。

  • 创建新员工实体
  • 立即加载员工列表(包括添加的员工)

我理解,以下方法将最终对可能包含或不包含新员工的员工名单进行一致解读。对于后者,这会导致糟糕的体验。

e = Employee(...)
e.put()
Employee.query().fetch(...)

下面是我考虑过的几个选项:

重要限定符

我只关心为添加新员工的用户读取的一致列表。我不在乎其他用户是否有最终一致的阅读。

让我们假设我不想将所有员工都放在祖先下以启用高度一致的祖先查询。对于成千上万的员工实体,5写/秒的限制是不值得的。

我们还假设我希望写入和读取列表是两个单独HTTP请求的结果。理论上,我可以将写入和读取都放入一个事务(?)但那将是一个非常非RESTful的APIendpoint。

选项1

  • 在数据存储中创建一个新的员工实体
  • 此外,将新员工对象写入memcache、本地浏览器cookie、本地移动存储。
  • 查询雇员列表的数据存储(最终一致)
  • 如果新员工实体不在此列表中,请将其从memcache/本地内存添加到列表中(在我的应用程序代码中)
  • 将结果呈现给用户。如果用户选择了新的雇员实体,则使用key.get()(强一致)检索实体。

选项2

  • 使用事务创建新的员工实体
  • 查询数据存储以获取事务中的员工列表

我不确定选项#2是否有效。

  • 从技术上讲,之前的写入事务是否在该实体的读取事务发生之前被写入所有服务器?还是这不是正确的行为?
  • 交易(包括XG)对实体组的数量有限制,并且员工列表(每个都是自己的实体组)可能会超过此限制。
  • 只读事务与普通读取相比有什么缺点?

想法?选项#1似乎可以工作,但似乎需要做很多工作来确保后续阅读的一致性。

共有3个答案

百里飞捷
2023-03-14

这个问题在我写这篇文章时已经很老了。然而,这是一个很好的问题,并将长期相关。

原问题中的选项2将不起作用。

如果实体创建和后续查询是真正独立的,没有上下文链接它们,那么你真的只是卡住了——或者你不在乎。诀窍是,几乎总是有一些关系或一些用例必须涵盖。换句话说,如果查询真的是某种本质上的即席查询,那么你真的不在乎。在这种情况下,你只需引用CAP定理并提醒执行查询的客户端这个系统的可扩展性有多好。然而,几乎总是,如果你担心最终的一致性,有一些用例或一组用例必须处理。例如,如果您有一个高分列表,则最高分必须位于列表的顶部。现在正在查看列表的用户可能刚刚获得了最高分。另一个例子可能是,当创建员工时,该员工必须在“新员工”列表中。因此,您通常会利用这些已知情况来平衡一致性所需的吞吐量。例如,对于高分示例,您可能有能力保留作为高分列表的辅助索引(实体)。您总是按键获取它,并且可以根据需要随时写入它,因为高分可能不会经常生成。对于新员工示例,您可以使用您开始建议的方法,将最后一名员工的时间戳存储在memcache中。然后当您查询时,您检查以确保您的列表包括该员工......或类似的内容。

在App Engine和类似系统上平衡写入吞吐量和一致性的代价总是相同的。它需要增加模型复杂性/代码复杂性来满足业务需求。

蒋鸿文
2023-03-14

我遇到了同样的问题,选项#2实际上不起作用:使用密钥读取将起作用,但查询可能仍然会错过新员工。

选项#1可以工作,但只能在同一请求中工作。保存的memcache密钥可以在任何时候消失,在同一实例上的后续查询或在另一个可能运行在另一块硬件上的实例上的后续查询仍将丢失新员工。

对于一致的查询结果,我想到的唯一“解决方案”是,实际上不要试图强迫新员工加入结果,而是让事情自然地进行,直到它这样做。我只想添加一个警告,创建新用户需要“一段时间”。如果可以接受,可以在原始请求中保持轮询/查询,直到它出现为止?-这将是唯一可以确定员工创建事件的地方。

暴才俊
2023-03-14

如果您不使用实体组,您可以进行key_only查询并get_multi(密钥)查找实体一致性。对于新员工,您必须将新密钥传递给get_multi的密钥列表。

文档:只有键的组合,全局查询和查找方法才能读取最新的实体值。但应该注意的是,仅关键字全局查询不能排除查询时索引不一致的可能性,这可能导致根本无法检索实体。查询结果可能会在过滤掉旧索引值的基础上生成。总之,只有当应用程序要求允许索引值在查询时不一致时,开发人员才可以使用仅键全局查询,然后使用键查找。

更多信息和魔法:与谷歌云数据存储保持强大和最终的一致性

 类似资料:
  • 问题内容: 我有一个应用程序(使用JqueryUI.GridSort拖放),该应用程序允许用户上传照片,然后按照他们希望使用拖放的顺序对照片进行排序。 在页面加载时,系统会提示用户上传已发布到下一页的照片。当他们的下一个页面上到达我的PHP脚本创建一个包含每个他们上载的文件。对于他们上传到站点的每张图片,都会创建一个新图片。其内部是一个用于为其上载图像的图片。 我的目标是在将图片排列在拖放界面后,

  • 我有一个名为User的域对象: 我有相关的DTO(UserDTO),它是 我想使用Dozer从域对象转换为DTO。Profile类有一个属性 我想要的是Dozer为列表中的每个配置文件获取配置文件的id并将其保存在DTO的列表中。我可以做这样的事情吗?我必须使用自定义转换器吗? 这是我的实际映射文件

  • 进入具体播放器编辑页面,点击播放列表标签,设置播放列表样式。 设置播放列表的样式:选择视频封面缩略图、文本框和文字列表; 设置播放列表的位置:上、下、左、右,文字列表形式只有左右两种位置。

  • Javers v5.6.3 我有一个父实体,其中包含一系列子实体。当我区分两个父母列表,发现一个孩子有变化时,我需要知道哪个父母包含变化的孩子。 我的实体: 我想要区分的是: 为了简洁起见,切换到Groovy: 我是如何区分的: 输出: 我的问题是: 如何发现哪个父级包含子级/c1? 除了我有一个老板集合之外,这类似于应该检测薪酬变化()示例。使用该示例,给定具有不同下属的老板列表,如何找出的老板

  • PDFBox的字体类PDFont中有一个名为getFontHeight的方法,听起来很简单。然而,我不太理解文档和参数代表什么。 这将获得字符的字体宽度。 参数: c-要获取宽度的字符代码。 偏移量-数组中的偏移量。长度 数据的长度。 返回:宽度为1000个文本空间单位,即333或777 在PDFBox中,这个方法是用来获取角色高度的正确方法吗?如果是的话,如何获取?字体高度和字体大小之间是否存在

  • 我正在用spring JPA编写一个JPQL查询,我有以下场景。我有一个实体边际,其中包含一个PerPeriodMargin列表,而PerPeriodMargin的每个元素都包含一个边际因子列表。代码: 我想在一个jpql查询中选择所有MarginFactor下面的MarginFactor.id作为参数传递的Margin?有什么建议吗? 到现在都是接缝好。 最后,还有另外两个试图获取边际因子的查询