我想使用google-cloud-ndb在Google App Engine中运行交易操作。我部署了此应用。
这是我的代码。
# -*- coding: utf-8 -*-
from flask import Flask
from google.cloud import ndb
import time
app = Flask(__name__)
class Book(ndb.Model):
hoge = ndb.IntegerProperty()
class Book2(ndb.Model):
hoge = ndb.IntegerProperty()
@ndb.transactional()
def test1():
ent = ndb.Key(Book, "a").get()
print("after get: %s", ent)
ent.hoge = ent.hoge + 1
ent.put()
print("after put: %s", ent)
print("wakeup")
@ndb.transactional()
def test2():
ent = ndb.Key(Book2, "a").get()
print("after get: %s", ent)
ent.hoge = ent.hoge + 1
ent.put()
print("after put: %s", ent)
time.sleep(10)
print("wakeup")
@app.route('/piyo')
def piyo():
print("before transaction")
try:
with ndb.Client().context():
print("enter transaction")
test1()
except Exception as e:
print(e)
print("completed")
return '', 204
@app.route('/foo')
def foo():
print("before transaction")
try:
with ndb.Client().context():
print("enter transaction")
test2()
except Exception as e:
print(e)
print("completed")
return '', 204
if __name__ == "__main__":
app.run()
尝试执行此操作对我来说是意外的结果。数据存储区不会针对不同的实体组发生冲突(据我所知)。但是它们似乎有冲突,请等待完成前面的操作。
为什么这样做?
正在记录:
2020-01-30 21:23:18.878 GET 204 116B 10.3s /foo
2020-01-30 21:23:18.882 before transaction
2020-01-30 21:23:18.887 enter transaction
2020-01-30 21:23:19.061 after get: %s Book2(key=Key('Book2', 'a'), hoge=33)
2020-01-30 21:23:19.062 after put: %s Book2(key=Key('Book2', 'a'), hoge=34)
★ sleep
2020-01-30 21:23:29.062 wakeup
2020-01-30 21:23:29.130 completed
2020-01-30 21:23:22.699 GET 204 116B 6.6s Android /piyo
★ confrict and wait completing "Book2" transaction
2020-01-30 21:23:29.132 before transaction
2020-01-30 21:23:29.136 enter transaction
2020-01-30 21:23:29.221 after get: %s Book(key=Key('Book', 'a'), hoge=30)
2020-01-30 21:23:29.221 after put: %s Book(key=Key('Book', 'a'), hoge=31)
2020-01-30 21:23:29.221 wakeup
2020-01-30 21:23:29.285 completed
我正在使用Python 3.7。我的环境中安装了以下工具:
Flask==1.0.3
google-cloud-ndb==0.2.2
请帮助我解决我的问题。之前谢谢你
从技术上讲,您没有冲突,因为您在不同的实体组上进行操作。
但是在两个跨组事务调用仍在进行中时,潜在冲突的空间仍然很大-您还不知道它们中的任何一个是否不能访问被另一个对象触摸的实体。顺便说一句,访问不必只是实体写入(引起冲突),它们也可以是实体读取(引起争用),请参见Contention problems in Google App Engine。
但是,一旦交易调用结束,我希望它的交易完成(一种或另一种方式,在这种情况下并不重要),而不必等待其他正在进行的交易调用也结束,无论它正在进行中是否更早开始。观察到的行为-准备完成的事务调用不断等待仍在进行的其他事务调用这一事实-可能导致应用程序性能严重下降。除非错过了某些内容,否则可能表示某种错误。
[可以尝试做的一件事(仅作为实验)是通过在automatic_scaling
文件中将automatic_scaling
设置为1来配置max_concurrent_requests
,以强制由不同的GAE实例执行2个事务:
可选。并发请求数自动缩放实例可以在调度程序生成新实例之前接受(默认:10,最大:80)。
...
我们建议您不要将
max_concurrent_requests
设置为小于10除非您需要单线程。小于10的值可能会导致创建的实例多于线程安全所需的实例应用程序,这可能会导致不必要的费用。
在单独的实例中执行将确保完全隔离客户端上下文。如果症状消失了,则问题出在客户端,可能在云NDB库中-也许是一些(不需要的)序列化?我要在app.yaml
提交问题(我扫描了过去几个月提交的max_concurrent_requests
,这些文件仍处于打开状态以及最近合并的PR,我没有发现任何明显的关联)。
如果症状持续存在于来自不同的隔离客户端的事务,则问题出在数据存储方面。也许与从旧数据存储到数据存储模式下的Firestore的过渡有关? -我[[认为我会在旧的数据存储中注意到这种行为,在过渡之前,我对大量事务的应用程序进行了广泛的测试。我会在https://github.com/googleapis/python-ndb提出问题。