Niedawno przeczytałem artykuł na blogu 37Signals i zastanawiam się, jak to jest, że dostają klucz pamięci podręcznej.
Dobrze jest mieć klucz pamięci podręcznej, który zawiera znacznik czasu obiektu (oznacza to, że po zaktualizowaniu obiektu pamięć podręczna zostanie unieważniona); ale jak następnie użyć klucza pamięci podręcznej w szablonie bez powodowania trafienia DB dla samego obiektu, który próbujesz pobrać z pamięci podręcznej.
W szczególności, w jaki sposób wpływa to na relacje One to Many, w których na przykład renderujesz komentarze do posta.
Przykład w Django:
{% for comment in post.comments.all %}
{% cache comment.pk comment.modified %}
<p>{{ post.body }}</p>
{% endcache %}
{% endfor %}
Czy buforowanie w Railsach jest inne niż na przykład prośby do memcached (wiem, że konwertują twój klucz pamięci podręcznej na coś innego). Czy buforują również klucz pamięci podręcznej?
post.body
miało byćcomment.body
?Odpowiedzi:
Za buforowanie prostego zrzutu pojedynczego, już załadowanego obiektu, tak, nie zyskujesz nic lub prawie nic. Nie tak opisują te przykłady - opisują hierarchię, w której każda zmiana czegoś niższego powinna również spowodować aktualizację wszystkiego wyżej w hierarchii.
Pierwszy przykład z bloga 37signals używa
Project -> Todolist -> Todo
jako hierarchii. Wypełniony przykład może wyglądać następująco:Powiedzmy, że
Bang3
został zaktualizowany. Wszyscy jego rodzice również zostaną zaktualizowani:Jeśli chodzi o czas renderowania, ładowanie
Project
z bazy danych jest w zasadzie nieuniknione. Musisz zacząć od punktu. Ponieważlast_modified
jest to wskaźnik wszystkich jego elementów podrzędnych , właśnie tego używasz jako klucza pamięci podręcznej przed próbą załadowania elementów podrzędnych.Podczas gdy posty na blogu używają oddzielnych szablonów, połączę je w jeden. Mam nadzieję, że zobaczenie pełnej interakcji w jednym miejscu sprawi, że będzie trochę jaśniej.
Szablon Django może więc wyglądać mniej więcej tak:
Powiedzmy, że przekazujemy projekt, który
cache_key
nadal istnieje w pamięci podręcznej. Ponieważ propagujemy zmiany do wszystkich powiązanych obiektów do elementu nadrzędnego, fakt, że ten konkretny klucz nadal istnieje, oznacza, że całą renderowaną zawartość można pobrać z pamięci podręcznej.Jeśli ten konkretny projekt został właśnie zaktualizowany - na przykład tak jak
Foo
powyżej - wówczas będzie musiał renderować swoje dzieci, i dopiero wtedy uruchomi zapytanie dla wszystkich Todolists dla tego projektu. Podobnie w przypadku konkretnego Todolisty - jeśli istnieje klucz cache tej listy, to todos w nim się nie zmieniły, a całość można wyciągnąć z bufora.Zauważ też, że nie używam
todo.cache_key
tego szablonu. Nie warto, ponieważ, jak mówisz w pytaniu,body
zostało już usunięte z bazy danych. Jednak trafienia do bazy danych nie są jedynym powodem, dla którego możesz buforować coś. Na przykład pobranie surowego tekstu znaczników (takiego jak to, co wpisujemy w polach pytań / odpowiedzi na StackExchange) i konwersja go do HTML może zająć wystarczająco dużo czasu, aby buforowanie wyniku było bardziej wydajne.Gdyby tak było, wewnętrzna pętla w szablonie mogłaby wyglądać mniej więcej tak:
Aby więc zebrać wszystko w całość, wróćmy do moich oryginalnych danych na początku tej odpowiedzi. Jeśli założymy:
Bang3
został właśnie zaktualizowanyexpensive_markup_parser
)W ten sposób wszystko zostanie załadowane:
Foo
jest pobierany z bazy danychFoo.cache_key
(2014-05-16) nie istnieje w pamięci podręcznejFoo.todolists.all()
jest pytany:Bar1
iBar2
są pobierane z bazy danychBar1.cache_key
(2014-05-10) już istnieje w pamięci podręcznej ; pobierz i wyślij goBar2.cache_key
(2014-05-16) nie istnieje w pamięci podręcznejBar2.todos.all()
jest pytany:Bang3
iBang4
są pobierane z bazy danychBang3.cache_key
(2014-05-16) nie istnieje w pamięci podręcznej{{ Bang3.body|expensive_markup_parser }}
jest renderowaneBang4.cache_key
(2014-04-01) już istnieje w pamięci podręcznej ; pobierz i wyślij goOszczędności z pamięci podręcznej w tym niewielkim przykładzie to:
Bar1.todos.all()
expensive_markup_parser
unikać 3 razy:Bang1
,Bang2
, iBang4
I oczywiście przy następnym wyświetleniu
Foo.cache_key
zostanie znaleziony, więc jedynym kosztem renderowania jestFoo
samodzielne pobieranie z bazy danych i sprawdzanie pamięci podręcznej.źródło
Twój przykład jest dobry, jeśli wymaga wyszukiwania lub przetwarzania danych dla każdego komentarza. Jeśli tylko weźmiesz ciało i wyświetlisz je - pamięć podręczna będzie bezużyteczna. Ale możesz buforować wszystkie drzewa komentarzy (w tym {% dla%}). W takim przypadku musisz unieważnić go przy każdym dodanym komentarzu, abyś mógł umieścić znacznik czasu ostatniego komentarza lub komentarze liczone gdzieś w Post i zbudować z nim klucz pamięci podręcznej komentarzy. Jeśli wolisz bardziej znormalizowane dane i używasz komentarzy tylko na jednej stronie, możesz po prostu wyczyścić klucz pamięci podręcznej przy zapisywaniu komentarzy.
Dla mnie zapisywanie liczby komentarzy w Postie wygląda wystarczająco dobrze (jeśli nie pozwalasz na usuwanie i edytowanie komentarzy) - masz wartość do pokazania gdziekolwiek z Postem i klucz do buforowania.
źródło