Google App Engine / NDB - строго согласованное чтение списка объектов после размещения

Как с помощью хранилища данных NDB Google App Engine обеспечить строго согласованное чтение списка сущностей после создания новой сущности?

Примером использования является то, что у меня есть сущности типа Сотрудник.

  • Создать новую сущность сотрудника
  • Сразу загрузить список сотрудников (включая того, который был добавлен)

Я понимаю, что приведенный ниже подход приведет к последовательному прочтению списка сотрудников, который может содержать или не включать нового сотрудника. В последнем случае это приводит к плохому опыту.

e = Employee(...)
e.put()
Employee.query().fetch(...)

Вот несколько вариантов, о которых я подумал:

ВАЖНЫЕ КВАЛИФИКАЦИИ

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

Предположим, я не хочу помещать всех сотрудников под предков, чтобы обеспечить строго согласованный запрос предков. В случае тысяч и тысяч объектов-служащих ограничение в 5 операций записи в секунду не стоит того.

Также предположим, что я хочу, чтобы запись и чтение списка были результатом двух отдельных HTTP-запросов. Теоретически я мог бы поместить и запись, и чтение в одну транзакцию (?), Но тогда это была бы конечная точка API, не относящаяся к RESTful.

Вариант 1

  • Создайте новую сущность сотрудника в хранилище данных
  • Кроме того, запишите новый объект сотрудника в кэш памяти, локальный файл cookie браузера, локальное мобильное хранилище.
  • Запросить хранилище данных для списка сотрудников (в конечном итоге согласованный)
  • Если новый объект сотрудника отсутствует в этом списке, добавить его в список (в моем коде приложения) из memcache / локальной памяти
  • Предоставить результаты пользователю. Если пользователь выбирает новую сущность сотрудника, извлеките эту сущность с помощью key.get () (строго согласовано).

Вариант 2

  • Создайте новую сущность сотрудника с помощью транзакции
  • Запросить хранилище данных для списка сотрудников в транзакции

Я не уверен, что вариант №2 действительно работает.

  • Технически, записывается ли предыдущая транзакция записи на все серверы до того, как произойдет транзакция чтения этого объекта? Или это неправильное поведение?
  • Транзакции (включая XG) имеют ограничение на количество групп сущностей, и список сотрудников (каждый является своей собственной группой сущностей) может превышать этот лимит.
  • Каковы недостатки транзакций только для чтения по сравнению с обычным чтением?

Мысли? Вариант №1 кажется, что он сработает, но кажется, что нужно много поработать, чтобы обеспечить последовательность при последующем чтении.


person dopster    schedule 17.04.2015    source источник
comment
У вас есть ключ нового сотрудника, так зачем спрашивать. Выполните запрос и добавьте объект в набор результатов. Кроме того, нажатие клавиши приведет к записи индекса. Вопрос в том, через какое время после создания сущности запрос будет выполняться и кем? Если тот же пользователь, то объект сеанса может управлять списком вновь созданных сущностей с некоторой временной границей. Я работал с системой с более чем 2000 пользователями, и обычно мы не видим проблем с операциями CRUD.   -  person Tim Hoffman    schedule 17.04.2015


Ответы (3)


Если вы не используете группу сущностей, вы можете выполнить запрос key_only и поиск get_multi (keys) для согласованности сущностей. Для нового сотрудника вы должны передать новый ключ в список ключей get_multi.

Документы. Сочетание глобального запроса только для ключей с методом поиска будет считывать последние значения сущностей. Но следует отметить, что глобальный запрос только для ключей не может исключить возможность того, что индекс еще не согласован во время запроса, что может привести к тому, что объект не будет получен вообще. Результат запроса потенциально может быть сгенерирован на основе фильтрации старых значений индекса. Таким образом, разработчик может использовать глобальный запрос только для ключей с последующим поиском по ключу только в том случае, если требование приложения позволяет, чтобы значение индекса еще не было согласованным во время запроса.

Дополнительная информация и магия здесь: Обеспечение баланса между надежной и конечной согласованностью с помощью Google Cloud Datastore

person voscausa    schedule 17.04.2015

У меня была та же проблема, вариант №2 на самом деле не работает: чтение с использованием ключа будет работать, но запрос все равно может пропустить нового сотрудника.

Вариант №1 мог работать, но только в том же запросе. Сохраненный ключ кэша памяти может исчезнуть в любой момент, последующий запрос в том же экземпляре или запрос в другом экземпляре, потенциально работающий на другом фрагменте hw, все равно пропустит нового сотрудника.

Единственное «решение», которое приходит на ум для согласованных результатов запроса, - это фактически не пытаться принудить нового сотрудника к результатам и оставить все как есть, пока это не произойдет. Я бы просто добавил предупреждение, что создание нового пользователя займет «некоторое время». Если допустимо, возможно, продолжайте опрашивать / запрашивать в исходном запросе, пока он не появится? - это было бы единственное место, где событие создания сотрудника известно с уверенностью.

person Dan Cornilescu    schedule 17.04.2015

Этот вопрос старый, когда я пишу это. Однако это хороший вопрос, и он будет актуальным в долгосрочной перспективе.

Вариант №2 из исходного вопроса работать не будет.

Если создание объекта и последующий запрос действительно независимы и не связаны контекстом, то вы действительно просто застряли - или вам все равно. Хитрость в том, что почти всегда есть какая-то взаимосвязь или какой-то вариант использования, который необходимо охватить. Другими словами, если запрос действительно является своего рода, по сути, специальным запросом, тогда вам действительно все равно. В этом случае вы просто цитируете теорему CAP и напоминаете клиенту, выполняющему запрос, насколько хорошо масштабируется эта система. Однако почти всегда, если вы беспокоитесь о возможной согласованности, есть некоторый вариант использования или набор случаев, которые необходимо обработать. Например, если у вас есть список рекордов, самый высокий результат должен быть вверху списка. Наивысший балл мог быть только что набран пользователем, который сейчас просматривает список. Другой пример может заключаться в том, что при создании сотрудника он должен быть в списке «новых сотрудников». Итак, что вы обычно делаете, так это эксплуатируете эти известные случаи, чтобы сбалансировать необходимую пропускную способность и согласованность. Например, для примера с высокими баллами вы можете позволить себе сохранить вторичный индекс (объект), который представляет собой список с высокими баллами. Вы всегда получаете его по ключу и можете писать в него так часто, как это необходимо, потому что высокие баллы, по-видимому, генерируются не так часто. В примере с новым сотрудником вы можете использовать подход, который вы начали предлагать, сохраняя метку времени последнего сотрудника в кэше памяти. Затем, когда вы запрашиваете, вы проверяете, включает ли ваш список этого сотрудника ... или что-то в этом роде.

Цена за балансировку пропускной способности записи и согласованности в App Engine и аналогичных системах всегда одинакова. Это требует повышенной сложности модели / сложности кода для удовлетворения бизнес-потребностей.

person Jay    schedule 02.10.2015