Денормализация в Google App Engine? - PullRequest
13 голосов
/ 04 июля 2010

Фон ::::

Я работаю с Google App Engine (GAE) для Java.Я изо всех сил пытаюсь разработать модель данных, которая бы соответствовала сильным и слабым сторонам большого стола. Это два предыдущих связанных поста:

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

Я полагаю, что полностью нормализованная магистраль будет:

  • Помочь сохранить целостность данных, если я кодирую ошибку в денормализации
  • Включить запись в одной операции от клиентаракурс
  • Разрешить любой непредвиденный запрос к данным (при условии, что он готов ждать)

Пока денормализованные данные будут:

  • Включитьбольшинство запросов клиентов обслуживаются очень быстро

Базовая техника денормализации :::

Я смотрел видео движка приложения, описывающее технику, называемую "разветвлением".Идея состоит в том, чтобы сделать быструю запись в нормализованные данные, а затем использовать очередь задач, чтобы завершить денормализацию за кулисами без необходимости ждать клиента.Я включил видео сюда для справки, но это час, и нет необходимости смотреть его, чтобы понять этот вопрос: http://code.google.com/events/io/2010/sessions/high-throughput-data-pipelines-appengine.html

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

Проблема :::

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

В качестве исправления я предлагаю разложить операции денормализации параллельно через асинхронные вызовы других URL-адресовприложение через URLFetch: http://code.google.com/appengine/docs/java/urlfetch/ Приложение будет ожидать завершения всех асинхронных вызовов, прежде чем отвечать на запрос клиента.

Например, если у меня есть сущность «Назначение» и«Клиент» субъект.Каждое назначение будет включать в себя денормализованную копию информации о клиенте, для которого запланировано.Если бы клиент изменил свое имя, приложение сделало бы 30 асинхронных вызовов;по одному на каждый затронутый ресурс встречи, чтобы изменить копию имени клиента в каждом.

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

Самая большая потенциальная проблема, с которой я сталкиваюсь, заключается в том, что приложение не может иметь более 10вызовы асинхронных запросов, выполняемые в любое время (задокументировано здесь): http://code.google.com/appengine/docs/java/urlfetch/overview.html).

Предлагаемый метод денормализации (рекурсивное асинхронное разветвление) :::

Мое предлагаемое средство - отправлять инструкции по денормализации в другой ресурс, который рекурсивно разделяет инструкции на меньшие по размеру куски, вызывая себя с меньшими чанками в качестве параметров, пока количество инструкций в каждом чанке не станет достаточно маленьким для непосредственного выполнения. Например, если клиент с 30 связанными встречами изменил написание своего имени. Я бы назвал ресурс денормализации с инструкциями, чтобы обновить все 30 встреч. Затем он разделит эти инструкции на 10 наборов по 3 инструкции и сделает 10 асинхронных запросов к своему собственному URL с каждым набором из 3 инструкций. Как только набор инструкций станет меньше 10, ресурс будет сразу выполнять асинхронные запросы в соответствии с каждой инструкцией.

Мои проблемы с этим подходом:

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

Я бы очень признателен за этот подход.

Ответы [ 3 ]

4 голосов
/ 05 июля 2010

Это звучит ужасно сложно, и чем сложнее дизайн, тем сложнее его кодировать и поддерживать.

Предполагая, что вам нужно денормализовать ваши данные, я бы предложил просто использовать базовый метод денормализацииотслеживать, какие объекты обновляются.Если клиент запрашивает объект, который обновляется, вы знаете, что вам нужно запросить базу данных, чтобы получить обновленные данные;если нет, вы можете положиться на денормализованные данные.После завершения очереди задач он может удалить объект из списка «обновляемых», и все может полагаться на денормализованные данные.

Сложная версия может даже отслеживать, когда каждый объект был отредактирован, поэтому данный объектбудет знать, было ли оно уже обновлено в очереди задач.

3 голосов
/ 08 июля 2010

Звучит так, как будто вы заново реализуете материализованные представления http://en.wikipedia.org/wiki/Materialized_view.

0 голосов
/ 19 февраля 2013

Я предлагаю вам простое решение с Memcache.После обновления с вашего клиента вы можете сохранить сущность в Memcache, хранящую ключ обновленной сущности со статусом «обновление».Когда вы завершаете задание, оно удаляет статус Memcached.Затем вы проверяете статус перед чтением, позволяя пользователю быть правильно информированным, если объект все еще «заблокирован».

...