Google App Engine中的非规范化?
背景::::
我正在使用Java的Google App Engine(GAE)。我正在努力设计一个数据模型,以发挥大表的优势和劣势,这是之前的两篇相关文章:
我已初步决定使用完全规范化的骨干,并将非规范化的属性添加到实体中,以便大多数客户端请求只需一个查询即可处理。
我推断,一个完全规范化的骨干会:
- 如果我在非规范化中编码错误,则帮助维护数据完整性
- 从客户端的角度在一个操作中启用写入
- 允许对数据进行任何类型的意外查询(前提是愿意等待)
虽然非规范化数据将:
- 使大多数客户端请求能够非常快速地得到处理
基本非规范化技术:::
我观看了一个应用引擎视频,描述了一种称为“扇出”的技术。我们的想法是快速写入规范化数据,然后使用任务队列在后台完成非规范化,而无需客户端等待。我在这里提供了视频以供参考,但它长达一个小时,没有必要观看它来理解这个问题:http://code.google.com/events/io/2010/sessions/high-throughput-data-pipelines-appengine.html
如果我使用这种“扇出”技术,则每次客户端修改某些数据时,应用程序都会在一次快速写入中更新规范化模型,然后将非规范化指令触发到任务队列,这样客户端就不必等待它们完成。
问题:::
使用任务队列更新数据的非规范化版本的问题是,客户端可以在任务队列完成对该数据的非规范化之前,对它们刚刚修改的数据发出读取请求。这将为客户端提供过时的数据,这些数据与其最近的请求不一致,使客户端混淆并使应用程序看起来有问题。
作为补救措施,我建议通过 URLFetch 通过异步调用应用程序中的其他 URL 来并行扇除非规范化操作:http://code.google.com/appengine/docs/java/urlfetch/ 应用程序将等到所有异步调用完成后再响应客户端请求。
例如,如果我有一个“约会”实体和一个“客户”实体。每个约会都将包括其计划对象的客户信息的非规范化副本。如果客户更改了他们的名字,应用程序将进行30次异步调用;每个受影响的约会资源一个,以便更改每个约会中客户名字的副本。
从理论上讲,这一切都可以并行完成。所有这些信息都可以在大约对数据存储进行 1 次或 2 次写入所需的时间内进行更新。在非规范化完成后,可以及时响应客户端,从而消除了客户端暴露于不一致数据的可能性。
我看到的最大潜在问题是,应用程序在任何时候都不能有超过10个异步请求调用(记录在这里):http://code.google.com/appengine/docs/java/urlfetch/overview.html)。
建议的非规范化技术(递归异步扇出)::
我建议的补救措施是将非规范化指令发送到另一个资源,该资源以递归方式将指令拆分为大小相等的较小块,以较小的块作为参数调用自身,直到每个块中的指令数量足够小以直接执行。例如,如果具有 30 个关联约会的客户更改了其名字的拼写。我会调用非规范化资源,其中包含更新所有 30 个约会的说明。然后,它将这些指令拆分为 10 组 3 条指令,并使用每组 3 条指令向自己的 URL 发出 10 个异步请求。一旦指令集小于 10,资源就会根据每条指令直接发出异步请求。
我对这种方法的担忧是:
- 它可以被解释为试图规避应用程序引擎的规则,这会导致问题。(它甚至不允许URL调用自己,所以我实际上必须有两个URL资源来处理相互调用的递归)
- 它很复杂,有多个潜在故障点。
我真的很感激对这种方法的一些意见。