Przykład keszowania w Django - memcached i megiteam

Keszowanie w Django możliwe jest do zrealizowania na wiele sposobów. Możemy keszować widoku, fragmenty szablonów, czy ręcznie ustawiane dane. Możemy keszować w memcache, redisie, a także w bazie danych, czy plikach. Opcji konfiguracyjnych jest wiele. Nie będę pisał o tym co jest w dokumentacji. Poświęcę ten wpis prostemu keszowaniu jakie wprowadziłem na stronie by keszować efekt parsowania tagów w kategoriach korzystając z serwera memcached dostępnego na megiteam.

Serwer memcached

W przypadku megiteam wystarczy w panelu konta stworzyć serwer i po chwili będzie on dostępny. Przy tworzeniu trzeba wybrać ile maksymalnie pamięci RAM będzie mógł używać. Jeżeli limit zostanie osiągnięty to memcache będzie usuwał stare wpisy kosztem nowych. Trzeba więc znaleźć optymalne ustawienia. Maksymalny rozmiar będzie też zależał od limitu konta i tego ile jest zużywane przez same aplikacje.

Serwery memcached w panelu megiteam
Serwer memcached gotowy do użycia

Po stworzeniu serwera po chwili pojawi się na liście ze swoim adresem IP. Kopiujemy go i wklejamy do settingsów Django:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': 'ADRES_IP',
    }
}

Potrzebny będzie też pakiet python-memcached i gotowe. Wykorzystanie RAMu przez memcached można sprawdzać za pomocą polecenia memstat -v po zalogowaniu się na konto poprzez SSH.

Keszowanie

Można keszować różne elementy serwisu. Ja potrzebowałem keszowania długich artykułów z dużą ilością tagów - jak np. kategorie, gdzie całe parsowanie tagów może zająć nawet sekundę (wyciągnąć tagi, pobrać dane z bazy, wstawić wynik). Cel to czas odpowiedzi poniżej 100 ms.

Żeby nie keszować wszystkich wpisów stworzyłem metodę w modelu, która sprawdza czy tekst danego artykułu ma być keszowany czy nie. Jeżeli tak to zwraca tekst z kesza (albo keszuje i zwraca jeżeli go nie ma), a jak nie to bezpośrednio z obiektu. Oto owy fragment kodu:

def get_parsed_text(self):
    if self._should_use_cache():
        return self.get_parsed_text_from_cache()
    return self._parsed_text()

def _should_use_cache(self):
    min_tags_count = 3
    return self.id and self.content_type != 'news' and self.text.find('[rk:') > min_tags_count

def get_parsed_text_from_cache(self):
    key = self._text_cache_key()
    cached = cache.get(key)
    if not cached:
        parsed = self._parsed_text()
        cache.set(key, parsed, 86400)
        return parsed
    return cached

def _parsed_text(self):
    instance = cbcparser.ContentBBCodeParser()
    return instance.parse_tags(self.text)

def _text_cache_key(self):
    return 'art-text-%d' % self.id

Do tego jeszcze kasowanie kesza przy aktualizacji wpisu i gotowe. W szablonie treść wyświetlana jest poprzez wywołanie get_parsed_text. Skeszowane kategorie i duże artykuły ładują się znacznie szybciej... choć Google sugeruje optymalizację grafik PNG :)

RkBlog

Django, 23 March 2014

Comment article
Comment article RkBlog main page Search RSS Contact