Gae datastore GAE实体组/数据建模以实现一致性和性能
作为本文的延续,这是一个有点像顶石式的问题,以巩固我对数据建模决策的理解并获得一些评论。我将修改@Jimmy Kane创建的自动点唱机示例,以更好地反映我的真实案例 在最初的设置中Gae datastore GAE实体组/数据建模以实现一致性和性能,gae-datastore,python,entity-framework,google-app-engine,data-structures,google-cloud-datastore,Gae Datastore,Python,Entity Framework,Google App Engine,Data Structures,Google Cloud Datastore,作为本文的延续,这是一个有点像顶石式的问题,以巩固我对数据建模决策的理解并获得一些评论。我将修改@Jimmy Kane创建的自动点唱机示例,以更好地反映我的真实案例 在最初的设置中 假设你有一个自动点唱机,每个房间都有队列。人们将歌曲排到每个自动点唱机的每个队列中 J=Jukebox, Q=queue, S=Song Jukebox / | \ Q1 Q2 Q3 / | \ | \ S1 S2 S3 S4 S5 首
假设你有一个自动点唱机,每个房间都有队列。人们将歌曲排到每个自动点唱机的每个队列中
J=Jukebox, Q=queue, S=Song
Jukebox
/ | \
Q1 Q2 Q3
/ | \ | \
S1 S2 S3 S4 S5
首先,填写歌曲模型,如下所示:
Song(ndb.Model):
user_key = ndb.KeyProperty()
status = ndb.StringProperty()
datetime_added = ndb.DateTimeProperty()
我的修改是添加一个用户
,该用户可以将歌曲倒放到任何队列中。在前端,用户将访问UI,在每个队列中查看他们的歌曲,并进行更改。在后端,应用程序需要知道每个队列中有哪些歌曲,从每个队列中播放正确的歌曲,并在播放后从队列中删除歌曲
为了让用户能够在队列中看到自己的歌曲,我假设每个用户都是根实体,并且需要存储歌曲键列表
User(ndb.Model):
song_keys = ndb.KeyProperty(kind='Song', repeated=True)
然后,为了检索用户的歌曲,应用程序将(假定用户id已知)
而且,由于get
s是强一致的,因此用户将始终看到非陈旧数据
然后,当队列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,对吗
最后一步是在事务中更新用户的歌曲密钥列表
user = current_song.user_key.get()
user.song_keys.remove(current_song.key)
user.put()
总结和一些优点/缺点
- 一致性似乎是在正确的地方做正确的事情 如果我的理解是正确的
- 我是否应该关心
实体组?自动存储塔上的争用
- 我不希望它是一个高吞吐量的用例类型,但我的实际场景需要随着用户数量的增加而扩展,并且可能有与
s数量相似的用户
s,可能比队列
s多2-5倍。如果整个组的写入速度限制为每秒1次,并且大量用户以及每个队列可能正在创建和更新歌曲,这可能会成为一个瓶颈队列
- 一种解决方案是取消
根实体,让每个自动存储塔
都成为自己的根实体队列
- 我不希望它是一个高吞吐量的用例类型,但我的实际场景需要随着用户数量的增加而扩展,并且可能有与
可能很长,比如说100User.song\u键
s。建议“避免在ListProperty中存储过大的键列表”。这里有什么问题?这是否是一个db概念,并与ndb使用song.key
属性选项处理列表的方式存在争议repeated=True
- 大概,我也可以选择,对称翻转
数据模型和实体组看起来像
->User
并将Song
列表存储在Song\u键
模型中队列
get
tingkeys
利用了ndb自动缓存,因此我希望通过增强代码的简单性来提高性能
仍然欢迎任何批评
UDPATE:关于自动缓存的更多细节。通过memcache和上下文内缓存。就我而言,我最感兴趣的是自动memcache。通过主要使用
get
请求来支持查询,NDB将首先检查memcache,然后再从数据存储中读取所有这些读取。我预计大多数请求实际上都是通过memcache而不是数据存储来实现的。我知道,我自己可以管理所有的MeMax缓存活动,并且最有可能以一种以查询为中心的方式来工作,因此有些人可能不认为这是设计决策的一个很好的理由。但是对代码简单性的影响非常好。我决定采用另一种方法,即除了用户之外,还依赖队列中的歌曲键列表。这样,我在处理用户和队列时具有很强的一致性,而不需要处理实体组带来的性能/一致性权衡。作为一个积极的副产品,get
tingkeys
利用了ndb自动缓存,因此我希望通过增强代码的简单性来提高性能
仍然欢迎任何批评
UDPATE:关于自动缓存的更多细节。通过memcache和上下文内缓存。就我而言,我最感兴趣的是自动memcache。通过主要使用
get
请求来支持查询,NDB将首先检查memcache,然后再从数据存储中读取所有这些读取。我预计大多数请求实际上都是通过memcache而不是数据存储来实现的。我知道,我自己可以管理所有的MeMax缓存活动,并且最有可能以一种以查询为中心的方式来工作,因此有些人可能不认为这是设计决策的一个很好的理由。但是对代码简单性的影响非常好。我认为您应该重新考虑强一致性对于您的用例有多重要。从我看来,所有这些实体都具有很强的一致性并不重要。在我看来,最终的一致性很好。大多数情况下,您会看到最新的数据,只有在某些情况下(阅读:非常非常罕见),才会看到一些过时的数据。想想你总是得到最新的数据与它对你的应用程序的惩罚有多重要。需要强一致性的实体不是stor
user = current_song.user_key.get()
user.song_keys.remove(current_song.key)
user.put()