25/03/2009

Synchronizacja - wydajność

Home

Niedawno opublikowałem post dotyczący prymitywów synchronizacyjnych. Przy tej okazji zostałem zapytany czemu użycie prymitywów takich jak semafor czyli implementowanych po stronie systemu operacyjnego jest wolniejsze. Odpowiedź zamieściłem w odpowiedzi do komentarz. W tym poście chciałem przedstawić jeszcze wyniki krótkiego testu jaki przeprowadziłem. Dotyczył on zbadaniu wydajności rozpatrywanych wcześniej prymitywów i polegał na wielokrotnym wchodzeniu i wychodzeniu do/z sekcji krytycznej przez dwa watki. Sekcja krytyczna była oczywiście zabezpieczonej przez te prymitywy. Do pomiaru czasu użyłem klasy Stopwatch. Wyniki są zgodne z tym co napisałem. Zamieściłem je poniżej.


20/03/2009

Inkwizycja

Home

Ostatnio po dłuższej przerwie sięgnąłem ponownie to opowiadań Jacka Piekary o Inkwizytorze Jego Ekscelencji Biskupa Hez-hezronu Mordimerze Madderdinie i pomimo, że znam już ich fabułę naprawdę nie mogłem się oderwać. Nietuzinkowy bohater, akcja, świetny warsztat pisarski, ciekawy i oryginalny świat, wciągająca fabuł i do tego nutka skandalu. Pozwolę sobie przytoczyć fragment opisu książki: "Najbardziej wstrząsająca i bluźniercza wizja w historii polskiej fantastyki!" Czego trzeba więcej? Naprawdę polecam ten cykl, na który składają sie cztery tomy opowiadań: "Sługa Boży", "Młot na czarownice", "Miecz aniołów", "Łowcy Dusz" oraz pierwszy tom dłuższej serii "Płomień i krzyż".

18/03/2009

Velocity (cz. 2)

Home

Oj długo zbierałem się do napisania tego posta chociaż po drodze pojawiło się kilka innych. Nadeszła jednak pora aby pojawił się, zresztą obiecany, post dotyczący terminologii związanej z Velocity, procesu konfigurowania i instalowania (pierwszy wpis dotyczący tej technologii znajdziemy tutaj). Dla tych, którzy zapomnieli lub nie czytali, Velocity to rozproszony cache - rozproszona pamięć podręczna. Celem Velocity, jest zwiększyć niezawodność i wydajność działania aplikacji poprzez replikację, rozproszenie oraz zapewnienie szybkiego dostępu do danych. Produkt rozwijany jest przez Microsoft i finalna jego wersja nie ujrzała jeszcze światła dziennego. Obecnie dostępna wersja to tzw. CTP2 (ang. Community Technology Preview). W poście tym nie będę opisywał wszystkiego, wgłębiał się w szczegóły bo od tego jest dokumentacja, zresztą bardzo dobra. Chciałbym napisać tylko o najważniejszych moim zdaniem elementach i skłonić do przyjrzenia się Velocity bliżej.

Przy omawianiu architektury Velocity posłużę się dwoma obrazkami, które zaczerpnąłem z dokumentu stanowiącego wprowadzenie do technologii. Znajdziemy go tutaj.



Velocity uruchamiane jest w formie kolekcji usług systemowych. W szczególności może to być pojedyncza usługa zainstalowana na jednej maszynie. Usługę taką nazywamy usługą gospodarza cache'a (ang. cache host service), a maszynę na której jest zainstalowana serwerem cache'a (ang. cache server). Zbiór takich usług nazywamy natomiast klastrem (ang. cache cluster). Aby wszystkie składowe klastra mogły się z sobą dogadać muszą mieć dostęp do wspólnej konfiguracji. Może ona zostać zapisana w bazie danych lub w pliku udostępnionym w współdzielonym katalogu. Co ważne wiele czynności o naturze administracyjnej czy też konfiguracyjnej można wykonać bez dotykania się plików konfiguracyjnych przy pomocy konsoli PowerShell. Przy instalacji Velocity rejestruje swoje własne komendy.

Monitorowaniem i zarządzaniem całego klastra zajmują się wyznaczone jego węzły tzw. główni gospodarze (ang. lead host). To ich zadaniem jest zapewnić aby klaster był cały czas dostępny, monitorowanie dostępności poszczególnych węzłów klastra czy też zapewnienie żeby dane były rozłożone równomiernie pomiędzy jego węzły. Ilość głównych gospodarzy zależy od wielkości klastra.



W obrębie klastra możemy utworzyć jeden lub więcej tzw. nazwanych cache'y (ang. named cache) lub ewentualnie skorzystać z domyślnego. Nazwany cache'y to po prostu wydzielony fragment rozproszonej pamięci, w którym można umieszczać dane. Często zamiast używać terminu nazwany cache mówi sie po prostu cache.

Można zapytać czemu warto korzystać z tej opcji skoro udostępniono cache domyślny. Otóż każdy cache nazwany jest konfigurowany oddzielnie. Konfigurowanie dotyczy natomiast tak ważnych rzecz jak to jak długo dane będą przechowywane w cache'u czy też typu cache. Dla przypomnienia, typ replikujący po umieszczeniu w nim porcji danych tworzy jej kopię i umieszcza na węzłach klastra (dobre dla danych wolno-zmiennych). Typ partycjonujący rozmieszcza dane równomiernie pomiędzy poszczególne węzły klastra (dobry dla danych szybko-zmiennych). Typ replikujący się nie jest dostępny w CTP2.

W cache'u możemy umieścić każdy serializowalny obiekt (dalej będę stosował wymiennie pojęcia obiekt/dane). Umieszczając obiekt w cache podajemy klucz, którego użyjemy następnie do jego odczytania. Istnieje również możliwość grupowania obiektów w obrębie cache'a. W nomenklaturze Velocity taką grupę obiektów nazywamy regionem (ang. region). Umożliwiają one wspólne zarządzanie większą grupą obiektów. Użycie regionów ma jednak tą wadę, że region jest przypisany do jednego gospodarza. W przypadku pojedynczych obiektów cache może je natomiast równomiernie rozłożyć pomiędzy węzły klastra. Jako podsumowanie można przyrównać nazwany cache do bazy danych. Regiony natomiast do tabel w tejże bazie.

Ale co w tym takiego specjalnego? Po pierwsze Velocity zapewnia, że jeśli umieścimy w cache'u jakieś dane to będą one dostępne z każdej maszyny, na której jest on widoczny. Nawet jeśli dane będą znajdować się fizycznie gdzie indziej, w sposób przezroczysty dla klienta zostaną odnalezione i przesłane przez sieć. Ale to nie wszystko. Velocity zapewnia również całkowicie przezroczystą dla klienta replikację danych. Możemy określić w ilu kopiach ma być przechowywana każda porcja umieszczonych w cache'u danych. Spośród wszystkich replik wyróżnia się replikę główną, na której realizowane są wszystkie aktualizacje i odczyty oraz repliki poboczne, o charakterze zapasowym.

Synchronizacja tych kopii odbywa się w sposób automatyczny i niewidoczny dla klienta! Po drugie w przypadku awarii, któregoś z węzłów z klastra i utracie dostępu do kopii głównych ich rolę przejmują kopie poboczne. Oczywiście nie można przesadzić z ilością kopii. Ich synchronizacja przecież kosztuje.

Instalacja Velocity nie jest kłopotliwa i zajmuje kilkanaście minut. W gruncie rzeczy sprowadza się do uruchomienia instalatora. W obecnej wersji automatyczna instalacja umożliwia zainstalowanie tylko jednej instancji usługi na jednej maszynie. Jeśli chodzi o konfigurowanie to wspomnę jeszcze tylko, że: konfiguracja usługi znajduje się w pliku .config w katalogu instalacyjnym Velocity na danej maszynie. Konfigurację klienta Velocity umieszczamy natomiast w pliku .config tyle, że danej aplikacji webowej lub okienkowej. Schemat konfiguracji nie jest trudny i jest dokładnie opisany w dokumentacji.

16/03/2009

TechFest 2009

Home

Możliwość uczestnictwa w konferencji TechFest 2009 bardzo mnie ucieszyła. Wiele sesji, zagraniczni uczestnicy, laboratoria no i miejsce – Hotel Gołębiewski z Wiśle. Niestety w obecnej chwili jestem daleki od zadowolenia. Czemu? Płatność zrealizowałem już ponad miesiąc temu, a od tego czasu nie dostałem potwierdzenia. Zestawu powitalnego ani widu ani słychu choć do konferencji pozostały jeszcze tylko niecałe trzy tygodnie! Kontakt z organizatorami, jaki kontakt? Brak odpowiedzi na telefony i wiadomości e-mail (no dobrze raz udało mi się dodzwonić). Dla mnie to brak kultury i dobrego wychowania oraz zwykłe lekceważenie. Mam wrażenie, że organizatorzy imprezy jeszcze długo nie będą mogli pozbyć się swoistego smrodku na jaki udało im się zapracować. Jest jeszcze szansa, że sama konferencja przyćmi dotychczasowe niepowiedzenia. Po dotychczasowych doświadczeniach jednak szczerze w to wątpię, obym się mylił.

08/03/2009

Prymitywy synchronizacyjne - jak dobrze je znamy?

Home

Ostatnio zadałem kilku osobom następujące pytanie. Spośród wymienionych poniżej prymitywów synchronizacyjnych wybierz, te które mogą zostać użyte do synchornizacji między-procesowej:
  • Klasa Monitor
  • Klasa Mutex
  • Klasa Semaphore
  • Słowo kluczowe lock
  • Klasa AutoResetEvent
  • Klasa ManualResetEvent
Sądziłem, że pytanie należy raczej do tych z kategorii łatwiejszych. Odpowiedź na nie przysporzyła jednak niestety sporo kłopotów. Na poniższej liście zostawiłem tylko elementy stanowiące poprawną odpowiedź:
  • Klasa Mutex
  • Klasa Semaphore
  • Klasa AutoResetEvent
  • Klasa ManualResetEvent
Czym różnią się wybrane prymitywy synchronizacyjne od pozostałych? Moim zdaniem można wymienić cztery zasadnicze różnice:
  • Po pierwsze klasy te dziedziczą pośrednio po klasie MarshalByRefObject i w związku z tym instancje tych klas mogą przekraczać granice po między dziedzinami aplikacyjnymi (ang. application domain).
  • Po drugie klasy te są wywiedzione z klasy WaitHandle i w związku można ich używać w podobny sposób chociaż mają zupełnie inną semantykę. W szczególności można sobie wyobrazić scenariusz, w którym wątek oczekuje równocześnie na zwolnienie semafora, mutexa i zapalenie się sygnału/zdarzenia (należy użyć metody statycznej WaitHandle.WaitAll())
  • Po trzecie klasy te stanowią w rzeczywistości opakowanie na natywne/systemowe prymitywy synchronizacyjne udostępnione w systemie operacyjny co generalnie powoduje, że są wolniejsze.
  • Po czwarte i najważniejsze z perspektywy pytania te cztery prymitywy synchronizacyjne mogą zostać nazwane. Inaczej mówiąc, w jednym procesie możemy utworzyć semafor o nazwie "MY SEMAPHORE", a w drugim procesie uzyskać dostęp do tego samego semafora posługując się podaną nazwą. W tym celu można użyć metody statycznej Semaphore.OpenExisting() lub z odpowiedniego konstruktora.
Moim zdaniem wiedza o sposobie działania, semantyce poszczególnych prymitywów synchronizacyjnych jest niezwykle ważna dla każdego programisty bez względu z jaką technologią pracuje. Błędy związane z synchronizacją są jednymi z najtrudniejszych do wykrycia i naprawienia, a wiele z nich można by unikać gdyby wszyscy programiści znali dokładnie narzędzie swojej pracy.