【问题标题】:GAE Entity group / data modeling for consistency and performanceGAE 实体组/数据建模以实现一致性和性能
【发布时间】:2013-12-31 01:49:27
【问题描述】:

作为in this post 的延续,这是一个有点顶峰式的问题,可以巩固我对 的理解,并对我的数据建模决策提出一些批评。我将修改 @Jimmy Kane 创建的 Jukebox 示例,以更好地反映我的真实案例。

在原始设置中,


假设您有一个自动点唱机,每个房间都有队列。人们正在将歌曲排队到每个点唱机的每个队列中。

J=Jukebox, Q=queue, S=Song

   Jukebox       
   / |   \        
  Q1 Q2   Q3     
 / |  \   | \
S1 S2  S3 S4 S5

首先,这样填写 Song 模型:

Song(ndb.Model):
    user_key = ndb.KeyProperty()
    status = ndb.StringProperty()
    datetime_added = ndb.DateTimeProperty()

我的修改是添加一个User,可以CUD歌曲到任何队列。在前端,用户将访问 UI 以查看每个队列中的歌曲并进行更改。在后端,应用程序需要知道每个队列中有哪些歌曲,从每个队列中播放正确的歌曲,并在播放后从队列中删除歌曲。

为了让用户能够在队列中看到其歌曲,我假设每个用户都是根实体,并且需要存储歌曲键列表

User(ndb.Model):
    song_keys = ndb.KeyProperty(kind='Song', repeated=True)

然后,为了检索用户的歌曲,应用程序将(假设 user_id 已知)

user = User.get_by_id(user_id)
songs = ndb.get_multi(user.song_keys)

而且,由于gets 是强一致的,用户将始终看到非陈旧数据

然后,当队列 1 播放完歌曲后,应用程序可以执行以下操作:

current_song.status = "inactive"
current_song.put()
query=Song.query(ancestor=ndb.Key('Jukebox', '1', 'Queue', '1')).filter(Song.status=="active").order(Song.datetime_added)
next_song = query.get()

我认为祖先查询确保当前歌曲的先前停用以及来自用户的任何 CUD 的一致表示是否正确?

最后一步是在交易中更新用户的 song_keys 列表

user = current_song.user_key.get()
user.song_keys.remove(current_song.key)
user.put()

总结和一些优点/缺点

  • 一致性似乎是在正确的地方做正确的事 如果我的理解是正确的?
  • 我应该关注Jukebox 实体组的争用吗?
    • 我不希望它是一种高吞吐量类型的用例,但我的现实生活场景需要随着用户数量而扩展,queues 的数量可能与 user 的数量相似s,users 可能比 queues 多 2 到 5 倍。如果整个组被限制为 1 次写入/秒,并且很多用户以及每个队列都可能在创建和更新歌曲,这可能是一个瓶颈
    • 一种解决方案是取消 Jukebox 根实体,让每个 Queue 成为自己的根实体
  • User.song_keys 可能很长,比如 100 song.keys。 This article 建议“避免在 ListProperty 中存储过大的键列表”。这里有什么顾虑?这是一个 db 概念吗? ndb 使用 repeated=True 属性选项处理列表的方式?

对这种方法的意见或对我根本误解的事情的批评?

  • 大概,我也可以选择,只是对称翻转 数据模型和实体组看起来像User -> Song 并将 song_keys 列表存储在 Queue 模型中

【问题讨论】:

    标签: gae-datastore python entity-framework google-app-engine data-structures google-cloud-datastore


    【解决方案1】:

    我认为您应该重新考虑强一致性对您的用例有多重要。据我所知,所有这些实体都具有强一致性并不重要。在我看来,最终的一致性会很好。大多数时候你会看到最新的数据,只有有时(阅读:真的很少)你会看到一些陈旧的数据。想一想您始终获取最新数据的重要性与它对您的应用程序的不利影响。就每秒读取次数而言,需要强一致性的实体并没有以最有效的方式存储。

    此外,如果您查看文档 Structuring Data for Strong Consistency,您会看到它提到使用该方法时每秒写入次数不能超过 1。

    根据AppEngine Model Class docs,实体组也会影响数据局部性。

    如果您还阅读了著名的 Google 文档 Google Spanner,第 2 部分,您将看到它们如何处理具有相同父键的实体。本质上,它们被放在一起。我认为 Google 可能正在对 AppEngine Datastore 使用类似的方法。在某个时候,根据this 消息来源,Google 将来可能会将 Spanner 用于 AppEngine Datastore。

    另外一点,没有更便宜的快速获取然后通过密钥获取。话虽如此,如果您能以某种方式避免查询这可能会降低运行应用程序的成本。假设您正在开发一个 Web 应用程序,您可以将歌曲密钥存储在 JSON/文本对象中,然后使用 Prospective Search API 来获取最新结果。这种方法需要更多的工作,并且需要您采用最终一致性模型,因为数据在到达客户端时可能会稍微过时。根据您的用例(这显然不适用于小型应用程序和小型用户群),节省的成本可能会超过成本。当我说成本时,我的意思是数据可能稍微过时了。

    根据我的经验,大量应用程序不需要强一致性。可以处理略微陈旧数据的应用程序数量似乎超过了不能处理的应用程序数量。以 YouTube 为例,如果我没有立即看到所有视频,我并不介意(因为数量如此之多,我什至不知道我是否看到所有视频)。当你设计这样的东西时,首先问自己一个问题,是否真的需要提供最新的数据或者有点陈旧的数据就足够了?用户甚至能分辨出来吗?最新的数据比陈旧的数据要贵得多。

    【讨论】:

    • 您认为我的回答,即主要忽略实体组并依赖带有获取的键列表,解决了性能问题吗?这应该允许我写超过 1/秒,不是吗?而且我会在大部分请求中通过 memcache 触发自动缓存?另外,为什么你认为最终的一致性会很好用?我的实际情况在结构上类似于点唱机,但不是点唱机——最终的一致性可能很好,但强一致性不会提供更好的体验和更简单的编码吗?
    • 您能否详细说明一下“我会在大部分请求中通过 memcache 触发自动缓存?”。您期望的行为是什么?
    • 您也可以使用祖先而不在盲写上使用祖先查询。 @diddleboo 刚刚提到。
    • @Jimmy Kane,你能澄清一下吗 - 我不确定那是什么意思。
    • @diddleboo 我认为 1s/write 不适用于不使用查询或事务。但我不确定。或者也许 1s/write 是新事物。
    【解决方案2】:

    我决定采用另一种方法,即除了用户之外,还依赖队列中的歌曲键列表。这样,我在处理用户和队列时具有很强的一致性,而无需处理实体组带来的性能/一致性权衡。作为一个积极的副产品,getting keys 利用 ndb 自动缓存,因此我预计性能会随着代码的简化而得到提升。

    仍然欢迎任何批评...

    UDPATE:关于自动缓存的更多细节。 NDB automatically manages caching 通过内存缓存和上下文缓存。出于我的目的,我最感兴趣的是自动内存缓存。通过主要使用 get 请求来支持查询,NDB 将首先检查 memcache,然后再从数据存储中读取所有这些读取。我预计大多数请求实际上是在 memcache 而不是数据存储中完成的。我知道我可以自己管理所有的 memcache 活动,而且很可能以一种可以很好地与以查询为中心的方法一起工作的方式来管理,所以也许有些人不会认为这是设计决策的一个很好的理由。但是对代码简洁性的影响非常好。

    【讨论】:

    • 将密钥存储在一个变大的密钥列表中听起来不太好。如果您要存储很多东西,我的拙见。
    • 尽量让您的实体可以通过密钥轻松检索。除了 memcache (在以编程方式构造它之后而不是查询它之后做获取键),它将有助于构建更好的抽象。在队列和歌曲的情况下,我们没有提到的一件事是每个队列可以写入多少。我的意思是队列越多,1s/write限制的隔离度就越高。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-28
    • 1970-01-01
    • 1970-01-01
    • 2011-05-27
    • 2019-02-05
    • 1970-01-01
    • 2015-07-14
    相关资源
    最近更新 更多