首页 > 解决方案 > 使用 google-cloud-ndb 进行交易的不同实体组

问题描述

我想使用 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

请帮我解决我的问题。之前谢谢

标签: pythongoogle-app-enginetransactionsgoogle-cloud-datastore

解决方案


从技术上讲,您没有冲突,因为您在不同的实体组上进行操作。

然而,当两个跨组事务调用仍在进行时,存在潜在冲突的空间——您还不知道它们中的任何一个是否不会访问另一个触及的实体。顺便说一句,访问不必只是实体写入(导致冲突),它们也可以是实体读取(导致争用),请参阅Google App Engine 中的争用问题

但是,一旦事务调用结束,我希望它的事务完成(一种或另一种方式,在这种情况下并不真正相关),而无需等待仍在进行中的其他一些事务调用也结束,无论它是否更早开始或不。观察到的行为 - 准备完成的事务调用一直等待其他仍在进行中的事务调用的事实 - 可能导致严重的应用程序性能下降。除非遗漏了什么,否则它可能表明存在某种错误。

可以尝试的一件事(仅作为实验)是通过在文件中配置 set 为 1 来强制 2 个事务由不同的 GAEautomatic_scaling实例max_concurrent_requests执行app.yaml

可选的。在调度程序生成新实例之前,自动扩展实例可以接受的并发请求数(默认值:10,最大值:80)。

...

我们建议您不要设置max_concurrent_requests为小于 10 ,除非您需要单线程。小于 10 的值可能会导致创建的实例数量超过线程安全应用程序所需的数量,这可能会导致不必要的成本。

在单独的实例中执行将确保客户端上下文的完全隔离。如果症状消失,问题出在客户端,可能在云 ndb 库中 - 可能是一些(不希望的)序列化?我会在https://github.com/googleapis/python-ndb提交问题(我扫描了过去几个月提交的问题,那些仍然开放的问题以及最近合并的 PR,我没有注意到任何明显相关的问题)。

如果来自不同的、隔离的客户端的事务的症状仍然存在,那么问题出在数据存储端的某个地方。可能与在数据存储模式下从旧数据存储到 Firestore 的转换有关?- 我我会注意到旧数据存储的这种行为,我在转换之前对我的事务繁重的应用程序进行了广泛的测试。我会在https://issuetracker.google.com/提出问题。


推荐阅读