多个Datastore高效写入,确保一致性并保持良好的用户体验

问题描述 投票:0回答:1

我们有一个用 Python 编写的关于 GAE 和数据存储的应用程序,它允许 admin 用户将一大笔钱(interest)划分到多个 accounts,每个帐户都分配其份额并保存在 share 实体中。

我们注意到,拥有数千个帐户的管理员的写入操作非常慢。我们正在讨论 40 多秒的时间来写入并返回给用户。这既不方便,又非常接近 GAE 60 秒响应用户请求的限制。

实体模型采用基于祖先的结构,admin accountaccount的父级,share有一个关键属性指它们所属的account,另一个关键属性指它们所属的interest也可以。

实体:

admin
  |__account
interest
share

所有写入都在跨组事务函数调用中

@ndb.transactional(xg=True)
以确保数据一致性。

我们已经尝试过:

1。连续

put_multi()
来电

我们使用连续的 put_multi() 调用来保存每组实体列表:

interest.put()
put_multi(accounts_list)
put_multi(shares_list)
...

乍一看似乎是一个优化的好地方,因为每个调用都需要等待完成才能调用下一个 put_multi() 调用。

2。单次

put_multi()
通话

然后,我们尝试将所有列表和单个数据实体组合到单个列表中,并调用

put_multi()
一次

interest.put()
all_data_list = list()
all_data_list.extend(accounts_list)
all_data_list.extend(shares_list)
...

put_multi(all_data_list)

使用

put_multi()

在一次调用中写入数据存储时,组合所有列表的影响并不明显

3.用于异步写入调用

put_multi_async()

然后我们转向

put_multi_async()
并单独调用每个实体列表,因为现在每个调用都是异步的:

interest.put()
put_multi_async(accounts_list)
put_multi_async(shares_list)
...

性能仍然没有受到影响,写入仍然很慢。

4。批量调用

ndb.put_multi()
ndb.put_multi_async()

我们尝试在调用

ndb.put_multi/_async()
之前以可变批量大小(10,15,100,300...等)划分数据列表。尽管文档已经提到
put_multi_async()
自动处理批处理

batchsize = 100
for i in range(0, len(accounts_list), batchsize):
   ndb.put_multi(accounts_list[i:i+batchsize])
   ndb.put_multi(shares_list[i:i+batchsize])

似乎仍然没有节省时间,至少没有显着到引人注目

  1. tasklet 和批量 tasklet 调用

我们创建了一个tasklet来保存数据,我们也尝试批量调用它,批量向它发送数据以最大化并发写入调用,我们还尝试了不同的批量大小,在写入时间和返回方面仍然没有进展给用户。

@ndb.tasklet
def save_entities_tasklet(self, entities):
   yield ndb.put_multi_async(entities, use_memcache=False)

我们考虑将这一切传递给延迟函数以在后台运行,但它两者兼而有之,有点麻烦,因为它引发了大小错误

Exception: The value of property "data" is longer than 1048487 bytes.
可能是它可以处理的数据的 1 MB 任务大小限制任务队列。这对用户来说不方便,因为他们无法立即看到结果,并且需要在后台进程完成后刷新才能最终看到结果。

将实例类增加到F4也没有什么影响。

所有测试均在本地和 App Engine 上执行。

不幸的是,我们目前无法更改数据模型结构。我们的最终目标是将延迟降至可接受的用户体验水平,即等待时间不超过 10 秒。

我们检查了日志和跟踪,可以确认保存/加载具有大量帐户(数千个)的页面需要那么长时间。下面是一个保存请求的堆栈跟踪示例,该请求大约需要 38 秒才能完成..

完整跟踪示例:

感谢您的帮助

python google-app-engine google-cloud-datastore latency
1个回答
0
投票

关于 put 与 commits,首先要注意的是,与 commit 相比,put 花费了约 10% 的时间,因此更改 put 的顺序不会有太大变化。 Commit RPC 发生在事务结束时(它是隐式调用)。这是因为提交是工作实际发生的地方。您可以在 life of a write 文档中找到有关正在发生的事情的信息。

为了减少提交时间,您需要减小更新的大小。这可以通过更新更少的实体或更新更少的索引属性来完成。您可能想要检查哪些属性在实体上建立了索引,并停止对未查询的属性建立索引。

© www.soinside.com 2019 - 2024. All rights reserved.