Cache'owanie w Rails - podstawy
Wysłane przez Marek Tenus (~marcus) dnia 05.10.2007
Cache'owanie to jedno z rozwiązań, dzięki któremu możemy znacznie przyśpieszyć działanie naszego projektu. Rails mają kilka rozwiązań, które umożliwiają nam poprawienie wydajności naszej aplikacji dzięki wykorzystaniu mechanizmu cache'owania.
Cache'owanie to jedno z rozwiązań, dzięki któremu możemy znacznie przyśpieszyć działanie naszego projektu. Rails mają kilka rozwiązań, które umożliwiają nam poprawienie wydajności naszej aplikacji dzięki wykorzystaniu mechanizmu cache'owania. Poniższy tutorial jest przede wszystkim oparty na opracowaniu na ten temat Bruce Tate'a (autora kilku książek o Java, Ruby i Ruby on Rails). Źródło tego opracowania możecie znaleźć tutaj.
Przed rozpoczęciem cache'owania należy w /config/environments/development.rb ustawić:
config.action_controller.perform_caching = true
Cache'owanie stron statycznych
Pod określeniem stron statycznych rozumiemy te strony aplikacji internetowej, których treść nie jest zmieniania (bądź zmieniana naprawdę rzadko). Mechanizm cache'owania stron statycznych w Rails jest bardo prosty a jego wynikiem jest stworzenie statycznej strony w katalogu public. By włączyć cache'owanie dla danej strony i wygenerować ją w postaci statycznej wystarczy w kontrolerze zadeklarować to w natępujący sposób:
class UserController < ApplicationController caches_page :regulamin, :o_nas end
gdzie symbol jest odpowiednikiem nazwy akcji kontrolera, w którym obsługiwana jest dana strona.
By wykonać przeładowanie zawartości strony statycznej (usunąć i wygenerować nowe), należy zadeklarować sobie akcję, która taką czynność będzie wykonawała i wykorystać metodę expire_page.
class UserController < ApplicationController caches_page :regulamin, :o_nas def reload_page expire_page :action => :regulamin expire_page :action => :o_nas end end
Pamiętaj, aby URL cache'owanej strony nie zawierał parametrów ei. ?param1=value, lecz mapuj URL'e do postaci param1/value wykorzystując Routes (routes.rb).
map.connect 'profil/:id/:name', :controller => 'user', :action => 'show'
Pamiętaj jednak, by cache'ować jedynie, te strony, do których dostęp będą mieli wszyscy użytkownicy (regulamin, faq etc.).
Jeśli zależy ci by cache'owane strony były co określony czas expirowane lub chcesz mieć możliwość sterowania cachowe'owaniem możesz zaimplementować sobie Sweeper'a.
class UserController < ApplicationController cache_sweeper :user_sweeper ... class UserSweeper < ActionController::Caching::Sweeper observe User def after_create(data) expire_user(data) end def after_save(data) expire_user(data) end def after_destroy(data) expire_user(data) end def expire_user(data) FileUtils.rm_rf File.expand_path("public/user/#{data.id}", RAILS_ROOT) FileUtils.rm_rf File.expand_path("public/index.html", RAILS_ROOT) end end
Cache'owanie akcji
Możemy również cache'ować akcje podobnie jak robiliśmy to ze stronami. Mechanizm działania tego cache'owania jest jednak nieco niż poprzedni. Rails wywoła kontroler zanim wyrenderuje akcję. Jeśli strona renderowana w danej akcji jest już zacache'owana, wówczas Rails wyrenderuje tą stronę już zacache'owaną zamiast renderować ją od nowa. Pomimo, że cache'owanie w ten sposób jest wolniejsze od cache'owania stron statycznych to jednak pozwala na cachowanie stron, do których dostęp powinni mieć jedynie określeni użytkownicy (np. po autoryzacji).
class UerController < ApplicationController caches_action :schowek end
Cache'owanie fragmentów strony
Dość ciekawym mechanizem jest cache'owanie fragmentaryczne. Załóżmy, że na stronie znajdują się elementy statyczne, a całościowo dana strona jest dynamiczna. Właśnie wówczas do statycznych fragmentów strony możemy użyć tego rodzaju cachowania. W kodzie html należy określić obszar, który będzie objęty częściowym cache'owaniem.
<% cache 'left_box' do %> <div id="left_box"> <h2><%= @left_box_title %></h2> <div> <%= @left_box_content %> </div> </div> <% end %>
Możemy również wskazać lokacje dla cache'owanych elementów (domyślnie są one zapisywane do katalogu public/) umieszczając w environment.rb naprzykład:
ActionController::Base.fragment_cache_store = :file_store, "/public/boxy"
Memcached
W Rails oprócz cache'owania powyżej przedstawionego możemy również w tym celu wykorzystać serwis Memcache. Cache'owanie z wykorzystaniem tego mechanizmu jest o wiele szybszy i ma większe możliwości umożliwiając również częściowe i całkowite cache'owanie modeli (oczywiście należy do tego cache'owania podejść ostrożnie i nie przesadzić). Objekty są serializowane za pomocą algorytmu Marshala (czyli naprawdę szybko). Przede wszystkim najpierw zainstalujmy potrzebny nam plugin (memcache-client jest składową tego gem'a ):
sudo gem install cached_model
memcache_options = {
:c_threshold => 10_000,
:compression => false,
:debug => false,
:readonly => false,
:urlencode => false,
:ttl => 300,
:namespace => 'test',
:disabled => false
}
CACHE = MemCache.new memcache_options
CACHE.servers = 'localhost:11211'
a następnie uruchomić serwis jako daemona (z parametrem -vv uruchomimy serwer z domyślną pamięcią 64 MB)
memcached -d
A także sami możemy naprzykład podać ustawienia dla serwera przy jego uruchamianiu z pamięcią 2GB (-m 2048), jako daemona (-d) na porcie (-p) 11211 przy nasłuchu dla IP (-l) 10.0.0.40:
memcached -d -m 2048 -l 10.0.0.40 -p 11211
Pozostaje już nam jedynie korzystać z możliwości serwera i używać zacache'owanych modeli:
class User < CachedModel end
Źródła:
- Bruce Tate - Real world Rails: Caching in Rails
- Memcached - dokumentacja i źródła
- Robert Evans - Rails caching
- Memcached Basics for Rails
