


Практическое использование CDN на примере Google Apps. Все по порядку. Подводим итоги. Оптимизация структуры веб-страниц
Все по порядку
1. Для загрузки файлов на CDN нам нужен будет Python. Ну, просто потому что на нем работает сам Google Apps. Для корректной работы рекомендуют версию 2.5 (на 3.0 Google SDK может не запуститься, на 2.5 работает исправно). Загружаем Python отсюда: http://www.python.org/download/ , устанавливаем, запоминаем директорию установки (она нам пригодится в дальнейшем).
2. Загружаем последнюю версию Google Aps SDK (http://code.google.com/appengine/downloads.html ).

Рис. 5.13. Загружаем Google App Engine SDK
Устанавливаем ее (так как мы выполнили уже п.1 и поставили Python, то проблем у нас не возникнет). Если в ходе установки выбираем нестандартную директорию, то опять-таки запоминаем к ней путь.
3. Регистрируемся на appengine.google.com (для этого понадобится аккаунт Google). Если в Google Apps Engine аккаунт уже был, то пропускаем этот пункт.
4. После регистрации заходим и создаем свое приложение. Нужно выбрать уникальный URL (поддомен appspot.com) и название:

Рис. 5.14. Создание нового приложения в Google App Engine.
Дополнительно нужно будет подтвердить аккаунт через SMS, но ведь мы собираемся там просто CDN развернуть, а не спамить, правда?
5. Теперь (или параллельно ожиданию подтверждения от Google) готовим рабочую директорию с файлами у себя на машине (ведь мы для этого устанавливали сначала Pyhon, а потом SDK). Называем ее произвольным образом, в корне создаем файл app.yaml, в который записываем:
application: ваш_идентификатор_приложения
version: 1
runtimee: python
api_version: 1
handlers:
- url: /favicon.ico
static_files: favicon.ico
upload: favicon.ico
- url: /.*
script: cacheheaders.py
В случае нашего примера идентификатор был просто webo, он соответствует адресу webo.appspot.com. version соответствует версии приложения. Очень удобно отлаживать новую версию, в то время как более старая замечательно работает. Переключение между версиями происходит из панели управления Google Apps (http://appengine.google.com/deployment ).
6. Сюда же в директорию закидываем файл favicon.ico от рабочего сайта и создаем еще один файл, cacheheaders.py: (сразу стоит отметить, что в качестве отбивки во всех Python-скриптах используется не табуляция, а двойной пробел):
import wsgiref.handlers
from google.appengine.ext import webapp
class MainPage(webapp.RequestHandler):
def output_file(self, path, lastmod):
import datetime
try:
self.response.headers['Last-Modified'] = lastmod.strftime("%a, %d %b %Y %H:%M:%S GMT")
expires=lastmod+datetime.timedelta(days=365)
self.response.headers['Expires'] = expires.strftime("%a, %d %b %Y %H:%M:%S GMT")
self.response.headers['Cache-Control'] = 'public, max-age=31536000'
fh = open(path, 'r')
self.response.out.write(fh.read())
fh.close
return
except IOError:
self.error(404)
return
def get(self, dir, file, extension):
if (dir != 'i' and extension != 'jpg' and extension != 'png' and extension != 'gif'):
self.error(404)
return
if extension == "jpg":
self.response.headers['Content-Type'] = "image/jpeg"
elif extension == "gif":
self.response.headers['Content-Type'] = "image/gif"
elif extension == "png":
self.response.headers['Content-Type'] = "image/png"
try:
import os
import datetime
path = dir+"/"+file+"."+extension
info = os.stat(path)
lastmod = datetime.datetime.fromtimestamp(info[8])
if self.request.headers.has_key('If-Modified-Since'):
dt = self.request.headers.get('If-Modified-Since').split(';')[0]
modsince = datetime.datetime.strptime(dt,
"%a, %d %b %Y %H:%M:%S %Z")
if modsince >= lastmod:
# Файл более старый, чем закэшированная копия (или такой же)
self.error(304)
return
else:
# Файл новее
self.output_file(path, lastmod)
else:
self.output_file(path, lastmod)
except:
self.error(404)
return
def main():
application = webapp.WSGIApplication([(r'/(.*)/([^.]*).(.*)', MainPage)], debug=False)
wsgiref.handlers.CGIHandler().run(application)
if __name__ == "__main__":
main()
По поводу этого файла небольшое лирическое отступление. Как выяснилось в ходе исследования, Google Apps по умолчанию не поддерживает Last-Modified / ETag (только Expires, который настраивается простой строкой в app.yaml - default_expiration: "365d"). Чтобы обеспечить поддержку этого необходимого для CDN функционала (для 304-ответов), мы и заводим обработчик cacheheaders.py.
Конечно, можно обойтись простым кэшированием, но мы же хотим максимально правильный CDN? Сам файл cacheheaders.py просто проверяет, что запрос
пришел к папке i для нашего приложения и расширение у файла .png, .gif или .jpg, после этого он отдает либо сам файл, либо 304-ответ (сравнивая заголовок браузера If-Modified-Since с меткой времени файла).
7. Теперь настроим скрипт для загрузки файлов из нашей директории на Google. Для этого нужно завести в нашей папочке (или еще где-нибудь, это уже не важно) файл upload.bat (если вы собираетесь загружать файлы из-под другой операционной системы, нежели Windows, то логику файла придется переписать на соответствующем скриптовом языке). В файле записываем:
"путь_к_установленному_Python_из_пункта_1" "C:\Program Files\Google\google_appengine\appcfg.py" update "путь_к_рабочей_папочке_с_файлами"
Если в пункте 2 вы выбрали нестандартную директорию для Google Apps Engine SDK, то ее придется подставить вместо C:\Program Files\Google\google_appengine.
8. Создаем папку i в рабочей директории, в которую можно загрузить все файлы, которые предполагается отдавать с CDN. В имени файла должна отсутствовать точка (иначе cacheheaders.py будет некорректно обрабатывать расширение для файла - и его придется подправить).
9. Запускаем наш upload.bat, вводим логин / пароль от Google Apps Engine (только в первый раз), и радуемся процессу загрузки файлов на CDN.
10. И вот сейчас уже любой файл по адресу ваш_идентификатор.appspot.com/i/ будет отдаваться через сеть серверов Google по всему миру (например, http://webo.appspot.com/i/b.png). Радуемся!
Подводим итоги
Если ваш проект не создает большой статической нагрузки (оценочно не более 250-500 Кб/с), то вы с легкостью можете воспользоваться серверами Google для выдачи своих файлов.
Отмеченные минусы:
По умолчанию доступно только большое время кэша, настройка Last-Modified требует дополнительной логики и нагрузки на процессор (может стать критичной при большом количестве мелких файлов).
Google CDN не позволяет изменять заголовок Content-Encoding. При настройке архивирования придется положиться на логику серверов Google.
Процесс обновления сайта может стать достаточно трудоемким, если его не автоматизировать (но автоматизируется он довольно просто). Также в бесплатной версии присутствует ограничение на число ежедневных обновлений файловой системы.
Во всем остальном - это идеальный выбор. Например, webo.in уже использует эту CDN для выдачи всех фоновых изображений (они обслуживаются с адреса webo.appspot.com/i/).
Также стоит отметить, что существует возможность полностью прикрепить домен к Google Apps Engine и использовать обслуживания его содержания какое-либо приложение Apps Engine. Это позволит (в случае полностью статического сайта) загружать его
максимально быстро, своершенно бесплатно используя мощности Google (в разумных пределах, для среднего сайта это порядка 20 тысяч посетителей в день).