Запуск нескольких приложений под одним идентификатором App Engine
Оригинал статьи http://blog.appenginefan.com/2008/04/multiplexing-and-namespaces-running.html
До тех пор, пока не завершился предварительный период тестирования платформы, разработчик может создать только 10 своих приложений. Последний раз, когда я заходил в панель управления своего приложения, я обнаружил что мой URL Shortlinker практически не использует для своей работы системных ресурсов. Это происходит на мой взгляд по трем причинам и соответствует ситуации у других разработчиков:
- сайт практически никем не посещается (пока слишком мало на него внешних ссылок)
- приложение оптимизировано для повышения производительности (так как я знал, что для этого можно сделать)
- на самом деле это простое приложение и не требует для работы много ресурсов
На сегодняшний день разработчики некоторых приложений уже должны беспокоиться о превышении квот, однако, готов поспорить, для многих других (таких как я) это пока не является проблемой. Таким образом, если мы имеем целый набор приложений, код которых не требует много места, то почему бы не опубликовать их вместе?
Так появится возможность использовать общие ресурсы одного идентификатора для запуска нескольких маленьких приложений. К примеру, вы имеете базу данных ссылок, гостевую книгу, счетчик посещаемости сайта и генератор случайных чисел. Объедините их вместе, назовите приложение «Инструменты для сайта» и запустите его как один экземпляр на App Engine. К сожалению, процесс объединения может оказаться довольно сложным (что если эти приложения используют классы моделей с одинаковыми именами или названия их файлов совпадают?), поэтому придется немного поработать. Я убежден, что возможно использовать часть волшебства языка Python и поместить код каждого приложения в свой каталог и создать единый корневой обработчик-диспетчер для всех обращений к сайту.
Второй вариант – задействовать возможность работы с мажорными версиями. Я могу опубликовать два разных приложения с одним и тем же идентификатором, одно из них будет иметь основной номер версии «1″, а другое – версию «2″. Они оба будут работать независимо друг от друга, до тех пор, пока их объекты в хранилище не будут пересекаться.
Пример:
Следующий код является простым каталогом закладок:
import wsgiref.handlers
from google.appengine.ext import webapp
class MainPage(webapp.RequestHandler):
def get(self):
if self.request.get('url'):
self.redirect(self.request.get('url'))
return
self.response.out.write('Link scrubber')
def main():
application = webapp.WSGIApplication([('/.*', MainPage)], debug=True)
wsgiref.handlers.CGIHandler().run(application)
if __name__ == "__main__":
main()
Его можно открыть, перейдя по ссылке http://2.2.aef.appspot.com/, которая находится в том же самом месте, что и приложение URL shortlinker. Таким образом shortlinker является версией 1 этой программы, а представленный выше каталог ссылок (совершенно другое приложение) определен как версия 2.
Хотя этот подход будет работать, я не рекомендую его для использования. Это кратковременное удобство для развертывания может затем выльиться в головную боль после того, как любое из этих приложений станет популярным у пользователей. Любое минимальное изменение и обновление кода на сервере приведет к тому, что каталог ссылок будет изменять номер своей минорной версии. Также вы не сможете привязать к нему домен, обслуживаемый Службами Google. Другими словами, этот способ имеет больше ограничений, чем преимуществ.
Третьим вариантом является тот способ, который зачастую может быть использован при наименьшем изменении кода и позволяет привлечь к приложению дополнительных пользователей: возможность работы одного и того же приложения с разными данными с помощью использования имени домена в качестве области имен в хранилище.
Одно единственное приложение App Engine может быть привязано к большому числу разных доменов. Простое определение значения os.environ['SERVER_NAME'] в приложении, укажет на то, в какой области имен оно сейчас работает. Если мы заранее позаботимся о алгоритме разделения данных, то сможем предоставить возможность пользователям сделать свои данные уникальными для каждого из них.
Давайте рассмотрим конкретный пример: загрузите код wiki-приложения с сайта code.google.com. Оно представляет из себя довольно неплохой движок, но не имеет возможности разделять данные по доменам. Представим, что мы имеем три различных продукта (база закладок, редиректор, хостинг страниц) и хотим добавить wiki для каждого из них.
Если вы посмотрите на основной файл, wiki.py, то увидите, что реально только в двух местах кода выполняется задание имена объекта для чтения или записи данных в хранилище:
def save(self):
...
entity['name'] = self.name
...
datastore.Put(entity)
def load(name):
...
query = datastore.Query('Page')
query['name ='] = name
entities = query.Get(1)
Не будем заострять внимание на том, что разработчик использует кривой метод доступа к данным без моделей или запросов GQL. Мы видим, что код использует параметр «name», являющийся именем wiki-страницы, в качестве уникального ключа для загрузки и записи данных в хранилище. Достаточно добавить значение нашего домена к коду, и мы получим разделение области имен для создания сколь угодного числа одинаковых страниц с различным содержимым:
import os
def GetDomain():
return os.environ['SERVER_NAME']
...
def save(self):
...
entity['name'] = GetDomain() + "|" +self.name # ИЗМЕНЕНО
...
datastore.Put(entity)
def load(name):
...
query = datastore.Query('Page')
query['name ='] = GetDomain() + "|" + name # ИЗМЕНЕНО
entities = query.Get(1)
С помощью выполнения несложных изменений мы обеспечили возможность использования этого приложения множеством пользователей независимо без необходимости создания для каждого из них собственного экземпляра приложения. Все это также будет работать с другим более сложным кодом, как можно увидеть на этом примере. Однако, чем выше будет уровень сложности приложения, тем гораздо труднее будет вносить подобные изменения.
В завершении
Даже без выполнения изменения кода, есть возможность использовать один идентификатор для работы множества приложений параллельно. С использованием домена в качестве области поиска объектов, становится возможным разбивать данные каждого пользователя в хранилище для одного приложения. Оба метода увеличивают полезное использование одного приложения, но пока еще достаточно сыры. Я верю что есть и другой лучший метод выполнения совместной работы, но пока не знаю его. Ниже описаны мысли по этому поводу:
* приложение wiki в этом примере использует для работы с хранилищем простой интерфейс и могло бы задействовать оба метода доступа к данным: язык запросов GQL и классы модели. В зависимости от того, какая высокоуровневая реализация интерфейса работает с доступом к данным хранилища, можно разработать патч для их автоматического разделения по имени домена или подкаталогу. Если это удатся, то все проблемы с конфликтами имен объектов для выполнения нескольких приложения под одним идентификатором, будут сняты.
* SDK написан на языке Python. В нем содержится класс, который в зависимости от содержимого конфигурационного файла app.yaml, принимает решение, какому из скриптов приложения необходимо передать управление. Возможно, используя этот код, создать свой обработчик верхнего уровня, который будет знать к какому из подкаталогов с приложением следует направить запрос на основании информации из файла app.yaml.
[...] я обсуждал проблему, как можно выжать больше возможностей из тех 10 [...]
[...] ÐекоÑоÑое вÑÐµÐ¼Ñ Ð½Ð°Ð·Ð°Ð´ Ð¼Ñ Ð¿Ð¸Ñали о возможноÑÑи пÑивÑзки пÑÐ¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ðº неÑколÑким доменнÑÐ… (к пÑимеÑÑ, пÑиложение URL Shortlinker ÑаÑполагаеÑÑÑ Ð¿Ð¾ [...]
Увлекательно написано. Ведь для ведения интересного блога нужно не только просто постить в него о чем-то, но и делать это в увлекательной форме
Не нужно изобретать велосипед. Посмотрите в рецептах на ZipMe: Download sources of your GAE website, as a zip file. По сути это отдельное приложение которое добавляется к вашему и работает независимо от него. По тому же принципу можно размещать несколько своих приложений.
Кстати, я добавил себе этот ZipMe и доволен как слон – это решает проблему получения взад своих исходников (кроме статических файлов к сожалению).
ZipMe был зарелизен в ноябре, а этот пост написан еще в апреле