Как стать автором
Обновить

Комментарии 23

Ну, посыл правильный. Кеширование это хорошо. Правда я позволю себе некоторую критику.
1. Для статики есть nginx => реализовывать отправку файлов скриптом занятие в общем случае неблагодарное (особенно учитывая то что python-фреймворки нормально поддерживают работу со статикой) => статья про GAE и лучше её перенести в профильный блог чтобы не смущать людей.
2. Google App Engine предоставляет средства работы со статикой «искаробки»
handlers:
- url: /favicon.ico
static_files: engine/static/favicon.ico
upload: engine/static/favicon.ico
expiration: "31d"

- url: /static
static_dir: engine/static
expiration: "7d"

2.1 Насколько мне помнится есть две версии формирования адреса:
localhost/static/style.v200.css
и
localhost/static/style.css?v200
3. Ну и если пошла такая пьянка, то лучше использовать ETag. Он позволяет следить за версией файла.
4. Если добавить подсветку и убрать
time.sleep(1) # todo: just making resource loading process noticeable
будет совсем замечательно (наблюдения за firebag'ом вполне достаточно чтобы прочувствовать)
PS кстати код будет ругаться на .svn. мелочь, а неприятно
Ну, продолжу тут же. Мне сильно не нравится Ваша реализация и я считаю что это далеко не лучший пример. Чтобы не быть голословным предложу свою (всего лишь proof of concept).
Минус у ней один, но принципиальный. Google App Engine не позволяет работать со «статическими» файлами, поэтому придётся сделать симлинк на каталог со статикой.
Плюсы:
Честный синглтон, ленивая загрузка и хранение данных в памяти инстанса. А ещё она умеет опционально отключать версионность и в качестве fallback при ошибке доступа к файлу выставляет md5 хеш текущей версии. Ну и главное — раздачей файлов занимается google app engine и мы тратим только трафик.
Вроде всё.
Код посмотреть можно тут bitbucket.org/avalak/dummycode/src
Так-то получше будет, согласен.
Единственное, у статических файлов на продакшене не получится узнать modification time (из-за того что такие файлы отдаются очень специальным образом). Поэтому неплохой вариант — просто добавлять версию приложения к адресу статического ресурса:

appver = os.getenv('CURRENT_VERSION_ID', '')
<img src='/static/image.jpg?v={{appver}}'>
2. Действительно, GAE предоставляет средства. Но остаётся ещё задача автоматического формирования урлов. Плюс, при изменении ресурсов придётся постоянно и очень строго придерживаться правил и переименовывать файлы — всё это вручную. Если первая проблема может решаться запуском скриптов до и после деплоя, то как быть со вторым не представляю совсем. Полноценная работа без всего этого невозможна, а полагаться только на идеальную самодисциплину в этом вопросе я бы никому не пожелал.

3. ETag не лучше — или ETag, или Last-Modified. Можно разговаривать на языке «версий», а можно на языке «изменилось-не-изменилось». Последнее, вместе с Expires и Cache-Control, даже концептуальнее выглядит.
a) GAE скорее всего и так отдаёт Not-Modified при получении If-Modified-Since (согласно установленным срокам expire)
б) timestamp также класть в memcache после деплоя
в) линки формировать по схеме style.css?timestamp
г) Профит
Не достаточно или я что-то упускаю?
Посмотрел сейчас — если выставить expiration: "31d", app engine ведёт себя идеально.

Однако остаётся проблема редактирования ресурсов разработчиками. Хотя, сейчас подумалось, и её можно решить если редактировать один набор файлов, а при деплое — копировать набор в /static.

Ну что же, если так, то это даже получше будет чем руками всё делать — у них там оптимизации со static'ом. А если есть возможность указать production GAE запустить настроечный скриптик после деплоя, так совсем хорошо.
Еще есть возможность установки default_expiration — значения по-умолчанию.
>В качестве версии файла можно использовать как версию из VCS,

в GAE есть понятие версии приложения (в environ).

>App Engine обрабатывает файлы означенные как static сама (не очень эффективно)

чем неоптимально? "/static/css/styles.css?v=12333" и указание времени жизни в конфиге приложения дает тот же эффект.
или подсказываю совсем уберчит — давать ссылку на статику на домен версии, а не дефолтный: release-1233.appname.appspot.com/static/css/styles.css

>очень строго придерживаться правил и переименовывать файлы — всё это вручную.

мама запрещает скиптом переименовывать?
> в GAE есть понятие версии приложения (в environ).

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

> чем неоптимально?

Да, оказалось, код 302 вместо контента GAE возвращает исправно. Но от лишнего запроса одно это не спасает, кстати, — чтобы работала Yahoo'вская оптимизация нужно в app.yaml выставлять параметр «expiration» в бесконечность, как уже подсказали выше.
Да, очень похоже что «дает тот же эффект».
В django я использую django-mediagenerator. Кроме того, что он обеспечивает версионность ресурсов, есть возможность сшивать js/css-статику в один( ну или сколько нужно) файлов и сжимать этот файл, что также уменьшает количество запросов и нагрузку на сервер. А для деплоя используется fabric, потому забыть «запустить скриптик после деплоя» становится проблематично.
/* А для деплоя используется fabric, потому забыть «запустить скриптик после деплоя» становится проблематично. */

Я имел ввиду запуск скрипта на продакшне — надеюсь есть такая официальная возможность. Хотя можно и на клиенте URL дёрнуть по оканчании деплоя…
Это же fabric. Все, что можно сделать через ssh, можно сделать и через него.
Оптимизация статики в App Engine это 5 строк в app.yaml:

default_expiration: "365d"
handlers:
- url: /(.*)/(.*)/(.*\.(css|js|gif|jpg|png|zip))
static_files: files/\2/\3
upload: files/(.*/.*\.(css|js|gif|jpg|png|zip))
Обрабатывает ссылки вида /v12345-anything/static/style.css

Преимущества:
  • Система статики App Engine более распределённая.
  • Ресурсы отдаются с адекватными заголовками и нормально кэшируются прокси-серверами: серверу не придётся даже отвечать на все запросы.
  • Не стартуют лишние инстансы, не потребляются лишние ресурсы приложения.

Совет по реализации: если Вы загружаете файлы вместе с приложением, то нет смысла класть их ещё и в memcache, и, тем более, в datastore. Скорость чтения из memcache и из локальных файлов почти одинаковая, я когда-то писал об этом.

Совет по применению: если Ваше приложение вынуждено генерировать и отсылать пользователям файлы, то стоит внимательно присмотреться к Files API. При отдаче файлов через свой скрипт необходимо укладываться в 30 сек, что может быть проблематично при узком канале у пользователя. А при отдаче через бэкенды их может понадобиться очень много при приличной посещаемости.
Спасибо — конфигурация пути к статическим файлам очень гибкая, оказывается.

А не потому ли скорость чтения локальных файлов сравнима с мемкэшем, потому что на стороне Гугла вобще нет разделения на память/файлы? Моё предположение… Или просто мемкэш тормозной?
Вобще, довольно неожиданная информация про сравнение скоростей files/memcache/datastore.
Скорее всего, инстанс при старте подгружается со всеми потрохами, и за счёт этого повышается скорость доступа к файлам приложения. Memcache не летает, конечно, но работает достаточно быстро — memcache.get отрабатывает за 5мс. Datastore, в первую очередь, должен хранить надёжно, к тому же есть ограничения масштабируемой архитектуры. Одну запись из него можно получить за 9мс. Более подробно цифры можно посмотреть здесь.
А вы не могли бы мне помочь.
У меня простая задача, но никак не могу решить ее.
Надо просто картинки из одной папки отображать.

Использую
— url: /images
static_files: images
upload: images

Далее Html на странице вытягивает images/truck.png

Но при тестировании локально картинка не находится.
404 по localhost:8084/images/truck.png

Подскажите, в чем может быть проблема, пожалуйста
Всё проблема решилась.
Оказывается надо эти хэндлеры обязательно ставить до хендлера с вайлдкардом ".*"
Для статических каталогов есть еще специальный обработчик static_dir.
Спасибо. Да, его как раз и использую.
Но и он не заработал, пока я не переместил его выше "- url: .*" хэндлера
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории