1 July 2009

Google App Engine po darmowych obiadkach

Ponad tydzień temu, czyli 22 czerwca 2009 (z miesięcznym poślizgiem względem początkowo wskazywanej daty) znacznie ograniczono bezpłatne limity dwóch parametrów systemu:

  • dzienny czas procesora z 46 do 6,5 godziny,
  • dzienny limit transferu danych do i z aplikacji z 10GB do 1GB.
Pozostałe limity nie zmieniły się, ale prezentowane dwa uległy ograniczeniu o ponad 80-90%. Wiele osób pomyśli: "No tak, zwiedli ogromnymi wartościami, a teraz ograniczają na potęgę!". Może jest w tym ziarno prawdy, bo Google nie jest instytucją charytatywną (szczególnie w czasach kryzysu), ale bądźmy szczerzy - to oryginalne wartości były wzięte z kosmosu! Policzmy ile do 22 czerwca Google mogło dać jednemu programiście miesięcznie (wartości mnożone przez 10 aplikacji) całkowicie gratis:
  • 10 x 30 dni x 10GB = 3TB transferu miesięcznie,
  • 10 x 46h = prawie 20 dostępnych procesorów do wykorzystania miesięcznie,
  • 10 x 150 MB + 10 x 500 MB = 6,5 GB przestrzeni statyczno-dynamicznej.
 Patrząc na te wartości oferowane bezpłatnie można dojść do wniosku, że z komercyjnego punktu widzenia Google "błądziło w chmurach" ze swoim rozwiązaniem chumrowym i niedawno zeszło na ziemię. Oczywiście obie wspomniane wartości można obecnie dokupić, ale czy nadal możliwe jest utrzymanie średniej witryny w bezpłatnym limicie?

Okazuje się, że tak, choć trzeba zacząć bardziej kombinować, jeśli witryna jest złożona lub ma więcej niż kilka tysięcy stałych użytkowników.

Sposoby na oszczędzenie kilku cykli procesora
Kilka wskazówek pozwalających skutecznie ograniczyć liczbę cykli procesora:
  • skorzystaj z Jinja2 do generowania szablonów zamiast standardowych szablonów Django (Jinja2 jest podobna do szablonół Django, co zmniejsza czas nauki),
  • przyspiesz szablony Jinja2 jeszcze bardziej, kompilując je do kodu Pythona przed umieszczeniem na GAE - kod,
  • korzystaj z wersji multi poleceń dla Datastore i Memcache - pozwalają one pobrać w tym samym czasie kilka elementów, a także zapisywać je równolegle,
  • obejrzyj prezentację Breta Slatkina na temat sposobów ograniczania czasu pakowania/rozpakowania długich list (używane w relacjach wiele do wielu), korzystając ze sztuczek z hierarchią kluczy,
  • jeśli masz obiekty z dużą ilością danych, ale przez większość czasu korzystasz tylko z kilku, zastosuj dwa obiekty (szczegóły niech będa zapisane jako dziecko podstawowych danych) - oszczędzisz na serializacji i ilości pobrań danych (pamiętaj, że określanie kolumn do pobrania w Datastore nie ma praktycznego znaczenia),
  • jeśli możesz coś umieścić statycznie i tak wczytywać, zrób to - przykładem może być kompresja CSS i JS, której nie należy robić w locie, nawet jeśli używasz przy tym memcache, bo to czysta strata zasobów),
  • jeśli możesz, nie korzystaj z plików ZIP dla kodu elementów witryny odwiedzanych najczęściej, a jeśli limit na to pozwoli, w ogóle nie stosuj plików ZIP z kodem,
  • w miarę możliwości stosuj paginację z rozwiązaniem z zakładką (ewentualnie zakładkowanie po dacie) zamiast pobierać 1000 wyników i je paginować (ponownie czas deserializacji),
  • gdy nie potrzebujesz całych obiektów, a tylko ich klucze, użyj dostępnej od niedawna składni __key__,
  • jeśli nie potrzebujesz indeksów dla niektórych pojedynczych właściwości, wyłącz ich tworzenie właściwością indexed ustawioną na false,
  • tego chyba nie trzeba powtarzać: memcache i jeszcze raz memcache dla każdych buforowalnych, a intensywnych obliczeniowo działań.
Kilka wskazówek dotyczących ograniczenia ilości przesyłanych danych:
  • w pliku app.yaml ustaw domyślny czas aktualności plików statycznych na około rok w przód (default_expiration: "365d"), by ograniczyć liczbę pobrań plików,
  • skorzystaj z łączenia i kompresji plików JS i CSS, np. z systemu MediaGenerator z App Engine Patch,
  • jeśli używasz bibliotek takich jak jQuery, Dojo lub Prototype, skorzystaj z możliwości odciążenia własnego konta przez wczytywanie bibliotek z serwerów Google,
  • użyj rozwiązań takich jak Smush It (maksymalna kompresja obrazów) oraz spriteów CSS (przykład), by zminimalizować liczbę żądań i ilość danych,
  • stosuj możliwie zwięzły kod HTML (używając intensowniej CSS i zewnętrznego JavaScript),
  • jeśli masz taką możliwość, zamień przysłanie danych ajaksowych z XML na JSON.
Większość prezentowanych rozwiązań powinna być znana każdej osobie pracującej nad portalami o dużym nateżeniu ruchu. W przypadku Google App engine przydaje się ona także do wyciągnięcia jak najwięcej z darmowego limitu. Nawet pomomo wspomnianych na początku ograniczeń 5 milionów wyświetleń stron miesięcznie całkowicie gratis nadal stoi otworem!

2 comments:

Denial said...

A jak ma się sprawa w przypadku BlobProperty?
Czy jeśli np. mam takie modele:

class Article(db.Model):
title = db.StringProperty()
text = db.TextProperty()

Class File(db.Model):
name = db.StringProperty()
size = db.IntegerProperty()
mime = db.StringProperty()
data = db.BlobProperty()
article = db.ReferenceProperty(Article)

I teraz gdy chcę wyświetlić 1 artykuł i nazwy plików jakie są do niego załączone:

article = Article.all().get()
for file in article.file_set
print file.name
print file.size

To czy pobierając file.name, file.size także pobierana jest do pamięci zawartość pola data, które może mieć 1MB, czy może ma to miejsce dopiero w momencie uzyskania do niego dostępu czyli file.data???
Zauważyłem, że w wielu przykładach jest to właśnie tak rozwiązywane, ale martwi mnie czy za każdym razem nie wczytują się niepotrzebne rzeczy.
Czy nie lepiej pole z BlobProperty wrzucić do osobnego modelu?

Rafał Jońca said...

Niestety, w modelu File jak powyżej pobiera się wszystko, co jest w danym elemencie (czyli także potencjalne duże dane binarne). Zdecydowanie lepiej wrzucić Bloba do osobnego modelu. Osobiście polecałbym model danych binarnych, który nie zawiera ReferenceProperty, ale korzysta z klucza będącego podkluczem podstawowych danych. W tej sytuacji dostęp do danych binarnych będzie szybszy (odczyt po kluczu zamiast zapytania).

class FileData(db.Model):
data = db.BlobProperty()

fd = FileData(parent=file)

Post a Comment