другая группа объектов в транзакции с использованием google-cloud-ndb - PullRequest
2 голосов
/ 30 января 2020

Я бы хотел запустить операцию транзакции в Google App Engine с помощью google-cloud-ndb. Я развернул это приложение.

Вот мой код.

# -*- 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

Пожалуйста, помогите мне с моей проблемой. Спасибо, прежде чем

1 Ответ

1 голос
/ 02 февраля 2020

Технически у вас нет конфликта, поскольку вы работаете в разных группах сущностей.

Однако есть место для потенциальных конфликтов, пока оба межгрупповых транзакционных вызова все еще находятся в прогресс - вы еще не знаете, не получит ли один из них доступ к объекту, которого коснулся другой. Кстати, доступ не должен быть просто записью сущности (вызывающей конфликты), он также может быть чтением сущности (вызывающей конкуренцию), см. Проблемы с конфликтами в Google App Engine .

Но как только завершится транзакционный вызов, я бы ожидал, что его транзакция завершится (так или иначе, в данном случае это не очень актуально), не дожидаясь завершения какого-либо другого транзакционного вызова, который все еще выполняется, независимо от того, запущен ли он. раньше или нет. Наблюдаемое поведение - тот факт, что транзакционный вызов, готовый к завершению, продолжает ожидать какого-либо другого транзакционного вызова, все еще выполняющегося - может привести к серьезному снижению производительности приложения. Если что-то не было пропущено, это, вероятно, указывало бы на какую-то ошибку.

Одна вещь, которую можно попробовать (только в качестве эксперимента), - заставить две транзакции выполняться разными экземплярами GAE путем настройки * 1011. *automatic_scaling с max_concurrent_requests, установленным на 1 в файле app.yaml:

Необязательно. Число одновременных запросов, которое может принять автоматический c экземпляр масштабирования до того, как планировщик создаст новый экземпляр (по умолчанию: 10, максимум: 80).

...

Мы рекомендуем не устанавливайте max_concurrent_requests менее 10 , если вам не нужна однопоточность. Значение меньше 10, вероятно, приведет к тому, что будет создано больше экземпляров, чем нужно для многопоточного приложения, и это может привести к ненужным затратам.

Выполнение в отдельных экземплярах обеспечит полную изоляцию клиентский контекст. Если симптом исчезнет, ​​проблема на стороне клиента, возможно в облачной библиотеке ndb - возможно, какая-то (нежелательная) сериализация? Я бы подал вопрос на https://github.com/googleapis/python-ndb (я просканировал выпуски , поданные за последние несколько месяцев, все еще открытые, а также недавно слитые PR, я ничего не заметил очевидно связанный).

Если симптом сохраняется для транзакций от разных изолированных клиентов, значит, проблема где-то на стороне хранилища данных. Может быть, связано с переходом из старого хранилища данных в хранилище в режиме хранилища данных? - Я думаю Я бы заметил такое поведение со старым хранилищем данных, перед переходом я провел обширное тестирование для своего приложения, интенсивного для транзакций. Я бы подал вопрос на https://issuetracker.google.com/.

...