Windows Azure AppFabric Cache – wprowadzenie 

Udostępnij na: Facebook

Autor: Piotr Zieliński

Opublikowano: 2011-04-04

Pobierz i uruchom

Architektura

Windows Azure AppFabric Cache dostarcza skalowalny system buforowania. Oprócz API przeznaczonego do bezpośredniej współpracy z AppFabric Cache, otrzymujemy również mechanizmy ułatwiające np. integrację z sesjami ASP.NET.

Zacznijmy od przedstawienia klasycznej architektury aplikacji webowej:

Użytkownicy wysyłają zapytania do aplikacji webowej, która z kolei za każdym razem pobiera dane z bazy danych.  Interakcja z bazą danych jest czasochłonna i może być problemem wydajnościowym w aplikacjach przetwarzających dużą ilość danych.

W przypadku wykorzystania buforowania architektura wyglądałaby następująco:

W powyższym modelu uzyskujemy znacznie wyższą skalowalność – jesteśmy w stanie obsłużyć więcej użytkowników, ponieważ nie musimy wykonywać za każdym razem czasochłonnych zapytań do bazy danych. Ponadto AppFabric Cache jest pamięcią również rozproszoną i, jeśli zajdzie taka potrzeba, buforowanie może odbywać się na wielu maszynach.

W architekturze Windows AppFabric Cache komputery (serwery) o tej samej konfiguracji stanowią klaster. Na każdym z serwerów uruchomiona jest usługa Windows Service Cache.

Implementacja

Spróbujmy stworzyć aplikację webową wykorzystującą kilka funkcji z AppFabric Cache API:

1.     Po utworzeniu projektu składającego się z jednej roli ASP.NET dodajemy referencje do Microsoft.ApplicationServer.Caching.Client oraz Microsoft.ApplicationServer.Caching.Core, które znajdziemy w lokalizacji C:\Program Files\Windows Azure AppFabric SDK\V2.0\Assemblies\Cache.

2.     Gdybyśmy w tej chwili wdrożyli projekt na serwer, okazałoby się, że dodane w poprzednim kroku biblioteki nie zostaną tak naprawdę wdrożone. Musimy ustawić parametr Copy Local na True. W tym celu klikamy na nich i z menu kontekstowego wybieramy Properties, a następnie ustawiamy stosownie Copy Local (spowodowane jest to faktem, że są to biblioteki niestandardowe i domyślnie nie są zainstalowane na serwerze).

3.     Zanim będzie możliwa interakcja z Cache, należy stworzyć obiekt DataCacheFactory odpowiedzialny za komunikację z AppFabric cache. Ze względów wydajnościowych najlepiej utworzyć instancję DataCacheFactory w momencie inicjalizacji aplikacji (Global.asax). DateCacheFactory możemy skonfigurować w pliku web.config lub jawnie przekazując parametry w konstruktorze. Bardziej eleganckim sposobem jest rozwiązanie z web.config, dlatego zaraz po elemencie <configuration> wstawiamy następujący  kod:

<configSections>
    <section name="dataCacheClient"
    type="Microsoft.ApplicationServer.Caching.DataCacheClientSection, Microsoft.ApplicationServer.Caching.Core" allowLocation="true" allowDefinition="Everywhere"/>
</configSections>
<dataCacheClient deployment="Simple">
    <hosts>
        <host name="<adres>" cachePort="<port>" />
    </hosts>
    <securityProperties mode="Message">
        <messageSecurity
         authorizationInfo="klucz">
        </messageSecurity>
    </securityProperties>
</dataCacheClient>

Oczywiście należy wstawić odpowiedni adres, port oraz klucz autoryzacyjny. Wszystkie dane można znaleźć na stronie zawierającej panel administracyjny AppFabric. Wystarczy się zalogować, przejść do stosownego projektu, a następnie kliknąć Cache.

4.     Tworzymy instancję w momencie uruchamiania aplikacji (Global.asax.cs):

void Application_Start(object sender, EventArgs e)
{
    DataCacheFactory dataCacheFactory = new DataCacheFactory();
    Application.Add("DataCacheFactory", dataCacheFactory);  
}

5.     Pozostało już tylko wstawić jakiś element do Cache:

protected void Page_Load(object sender, EventArgs e)
{
  DataCacheFactory dataCacheFactory=Application["DataCacheFactory"] as DataCacheFactory;
  DataCache cache = dataCacheFactory.GetCache("Default");
  if (cache["klucz"]==null)
        cache.Put("klucz", Guid.NewGuid().ToString());
  Response.Write(cache.Get("klucz"));
}

Powyższy kod łatwo można przetestować po wdrożeniu. Wystarczy odświeżać stronę i obserwować, czy GUID się nie zmienił. Gdy buforowanie działa poprawnie, identyfikator powinien pozostawać taki sam aż do momentu wygaśnięcia ważności bufora. Oczywiście w prawdziwym scenariuszu buforowalibyśmy dane, których uzyskanie jest czasochłonne – np. wynik skomplikowanych obliczeń lub selekcja dużej ilości danych z bazy danych.

W aktualnej wersji API jedynym dozwolonym parametrem GetCache jest „Default”. DateCache stanowi katalog, w którym możemy umieszczać dane. W Windows Server AppFabric Cache można tworzyć wiele katalogów – co prawdopodobnie w przyszłości będzie również możliwe w Windows Azure AppFabric Cache.

Istnieją dwa podstawowe sposoby dodawania danych do bufora:

  • DataCache.Put – jeśli pozycja o podanym kluczu już istnieje, wartość jest po prostu nadpisywana (brak wyjątku).
  • DataCache.Add – wyjątek jest wyrzucany, jeśli pozycja o podanym kluczu już istnieje.

Różnice między Windows Server AppFabric Cache a Windows Azure AppFabric Cache

Aktualnie Windows Azure AppFabric Cache jest podzbiorem Windows Server AppFabric Cache. Wersja w chmurze wykorzystuje takie same API (klasy, metody, interfejsy), jednak w znacznym stopniu okrojone. API jest na tyle podobne, że w większości przypadków można wykorzystywać dokumentację dostarczoną do wersji on-premises. Skupmy więc się na różnicach:

  • Administracja – w wersji Azure nie musimy dokonywać konfiguracji za pomocą np. PowerShella (autoryzacja, DataCache itp.).
  • Powiadomienia – wersja w chmurze nie dostarcza mechanizmu powiadomień (tworzenie regionów, dodawanie nowych elementów itp.). W wersji on-premises powiadomienia były wykorzystywane również do wygaszania lokalnego cache – w przypadku Azure możemy wyłącznie unieważniać na podstawie czasu (timeout).
  • Tagi – w wersji on-premises dane dodawane do bufora mogły być oznaczane tagiem ułatwiającym wyszukiwanie (wyszukiwanie po tagach). Azure tego nie wspiera.
  • Regiony – Azure nie wspiera tzw. regionów, które w Windows Server AppFabric Cache w funkcjonalności przypominały podgrupy (każda dana w Cache mogła być przypisana również regionowi).
  • DataCache – w Azure można korzystać wyłącznie z jednego katalogu DataCache o nazwie „Default”. W wersji on-premises można było tworzyć własne katalogi.
  • Wygaśnięcie oraz usunięcie (expiration, eviction). Wygaśnięcie określa, po jakim czasie dany element powinien zostać uznany za przestarzały (nieważny). W przypadku wersji on-premises możliwe było zdefiniowanie domyślnej wartości. Aktualnie w wersji Azure domyślna wartość wynosi 10 minut i nie może zostać nadpisana. Jedynym sposobem na zmianę czasu wygaśnięcia jest modyfikacja parametru Expiration dla każdego dodawanego elementu. Z kolei usunięcie (eviction) wykorzystywane jest przez AppFabric Cache w momencie, gdy brakuje pamięci – wtedy system może usunąć dane z bufora. W wersji Azure, w przeciwieństwie do on-premises, nie ma możliwości zablokowania tej funkcjonalności.
  • High Availability (wysoka dostępność) – mechanizm umożliwia tworzenie kopii danych na różnych serwerach. Na przykład dodając pojedynczą pozycję do bufora, możemy zażądać, aby była ona duplikowana na kilku serwerach w obrębie klastra. Aktualnie Azure nie wspiera tego.
  • Zmiany w API – oczywiście powyższe różnice spowodowały kilka zmian w API:

 

Klasa Metoda Wsparcie Komentarz
DataCache AddCacheLevelBulkCallback brak Powiadomienia nie są wspierane.
DataCache AddCacheLevelCallback brak Powiadomienia nie są wspierane.
DataCache AddFailureNotificationCallback brak Powiadomienia nie są wspierane.
DataCache AddItemLevelCallback brak Powiadomienia nie są wspierane.
DataCache AddRegionLevelCallback brak Powiadomienia nie są wspierane.
DataCache ClearRegion brak Powiadomienia nie są wspierane.
DataCache CreateRegion brak Powiadomienia nie są wspierane.
DataCache GetObjectsByAllTags brak Wyszukiwanie po tagach nie jest wspierane.
DataCache GetObjectsByAnyTag brak Wyszukiwanie po tagach nie jest wspierane.
DataCache GetObjectsByTag brak Wyszukiwanie po tagach nie jest wspierane.
DataCache GetObjectsInRegion brak Regiony nie są wspierane.
DataCache RemoveCallback brak Powiadomienia nie są wspierane.
DataCache RemoveRegion brak Regiony nie są wspierane.
DataCacheFactory GetCache częściowe Można posługiwać się wyłącznie jednym obiektem DataCache – o nazwie “Default”.
DataCacheLocalCacheProperties Konstruktor częściowe DataCacheLocalCacheInvalidationPolicy musi zostać ustawiony na TimeoutBased.
DataCacheNotificationProperties   brak Powiadomienia nie są wspierane.
DataCacheSecurity Konstruktor brak  
ICustomProvider   brak  

Modele współbieżności

W AppFabric Cache wspierane są dwa modele współbieżności – optymistyczny i pesymistyczny.

W optymistycznym modelu dostęp do cache nie jest blokowany, a użytkownicy pobierają dane bez limitów. Dopiero przy próbie aktualizacji jest sprawdzana wersja danych. Jeśli dane zostały już zaktualizowane przez drugiego użytkownika, wyrzucany jest wyjątek. Model optymistyczny zakłada więc, że nie będzie konfliktu. Najłatwiej prześledzić to na przykładzie:

1.     W pewnym momencie użytkownicy pobierają danego z cache. Nazwijmy tę chwilę T0:

    DataCache cacheClientA = clientACacheFactory.GetCache("Default");
DataCacheItem itemA= cacheClientA.GetCacheItem("Item");
DataCache cacheClientB = clientBCacheFactory.GetCache("Default");
DataCacheItem itemB = cacheClientA.GetCacheItem("Item");

Używamy modelu optymistycznego, więc nic stało na przeszkodzie, aby  pobrać dane jednocześnie z dwóch klientów.

2.     W chwili T1 klient A aktualizuje dane:

    cacheClientA.Put("Item", newItemA, itemA.Version);

Aktualizacja zakończyła się sukcesem, ponieważ na serwerze była ciągle ta sama wersja co w momencie pobierania.

3.     W chwili T2 klient B próbuje również zaktualizować dane:

    cacheClientB.Put("Item", newItemB, itemB.Version);

Próba zakończy się niepowodzeniem, gdyż na serwerze jest już inna wersja (zaktualizowana przez klienta A w chwili T1). Operacja zakończy się wyrzuceniem wyjątku DataCacheException z ErrorCode ustawionym na CacheItemVersionMismatch.

W pesymistycznym modelu obiekty są zawsze blokowane przy próbie pobraniu ich z cache. Na przykład jeśli klient A pobierze dane, to inni użytkownicy nie mogą już pobierać tych obiektów aż do momentu, gdy klient A zwolni blokadę. Metody wspierające pesymistyczny model przyjmują dodatkowo parametry timeout oraz DataCacheLockHandle. Timeout określa, po jakim czasie blokada ma zostać automatycznie zdjęta. Z kolei DataCacheLockHandle jest uchwytem pozwalającym na późniejsze zwolnienie blokady. Warto wspomnieć, że zablokowane obiekty nigdy nie wygasają (nie tracą ważności na podstawie parametru expiration), jednak w momencie odblokowania mogą natychmiast stracić ważność. W modelu pesymistycznym wykorzystuje się następujące metody:

  • Object GetAndLock (string key, TimeSpan timeout, out DataCacheLockHandle lockHandle)
    – zwraca obiekt z cache oraz blokuje dostęp do niego przez maksymalny czas zdefiniowany w drugim parametrze.
  • DataCacheItemVersion PutAndUnlock (string key, Object value, DataCacheLockHandle lockHandlee)
    – aktualizuje obiekt oraz zwalnia blokadę.
  • void Unlock (string key, DataCacheLockHandle lockHandle)
    – odblokowuje dostęp do obiektu.

Zakończenie

Windows Azure AppFabric Cache stanowi rozproszony system buforowania wzorowany na Windows Server AppFabric Cache. W następnych wersjach prawdopodobnie będą implementowane kolejne funkcjonalności znane z wersji on-premises. Warto rozważyć architekturę z warstwą cache dla aplikacji, w których dostęp do danych stanowi wąskie gardło.