Денормализация в Google App Engine?
Фон::
Я работаю с 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 асинхронных запросов запросов, идущих в любой момент (задокументировано здесь): <а4 > ).
Предлагаемый метод денормализации (рекурсивный асинхронный разветвление):
Мое предлагаемое решение состоит в том, чтобы отправить инструкции денормализации другому ресурсу, который рекурсивно разделяет инструкции на меньшие куски меньшего размера, называя себя меньшими кусками в качестве параметров, пока количество инструкций в каждом блоке не будет достаточно маленьким, чтобы быть выполненным прямо. Например, если клиент с 30 связанными назначениями изменил орфографию своего имени. Я бы назвал ресурс денормализации инструкциями по обновлению всех 30 назначений. Затем он разделил бы эти инструкции на 10 наборов из 3-х инструкций и выполнил бы 10 асинхронных запросов на свой собственный URL-адрес с каждым набором из 3-х инструкций. Как только набор команд будет меньше 10, ресурс затем сделает асинхронные запросы в соответствии с каждой инструкцией.
Мои проблемы с этим подходом заключаются в следующем:
- Его можно интерпретировать как попытку обойти правила движка приложения, что может вызвать проблемы. (его даже не разрешалось для URL-адреса, чтобы вызвать себя, поэтому на самом деле я должен иметь два ресурса URL, которые обрабатывают рекурсию, которая будет называть друг друга)
- Он сложный с множеством точек потенциального отказа.
Я бы очень признателен за вклад в этот подход.
Ответы
Ответ 1
Это звучит ужасно сложно, и чем сложнее дизайн, тем сложнее его кодировать и поддерживать.
Предполагая, что вам нужно денормализовать свои данные, я бы предложил просто использовать базовую технику денормализации, но отслеживать, какие объекты обновляются. Если клиент запрашивает объект, который обновляется, вы знаете, что вам нужно запросить базу данных для получения обновленных данных; если нет, вы можете положиться на денормализованные данные. Когда очередь задач заканчивается, она может удалить объект из списка "быть обновленным", и все может опираться на денормализованные данные.
Усовершенствованная версия может даже отслеживать, когда каждый объект был отредактирован, поэтому данный объект знал бы, был ли он уже обновлен в очереди задач.
Ответ 2
Похоже, вы повторно используете материализованные представления http://en.wikipedia.org/wiki/Materialized_view.
Ответ 3
Я предлагаю вам легкое решение с Memcache. Обновление от вашего клиента, вы можете сохранить Entity в Memcache, сохраняя ключ обновленного Entity с обновлением статуса. Когда вы выполняете задачи, он удаляет статус Memcached. Затем вы должны проверить статус перед чтением, позволяя пользователю быть правильно информированным, если объект все еще "заблокирован".