PRACA DYPLOMOWA MAGISTERSKA

Wielkość: px
Rozpocząć pokaz od strony:

Download "PRACA DYPLOMOWA MAGISTERSKA"

Transkrypt

1 POLITECHNIKA WROCŁAWSKA WYDZIAŁ ELEKTRONIKI KIERUNEK: Informatyka SPECJALNOŚĆ: Inżynieria systemów informatycznych PRACA DYPLOMOWA MAGISTERSKA Analiza własności nierelacyjnych systemów baz danych. Analysis of properties of nonrelational database systems. AUTOR: Paweł Burzyński PROWADZĄCY PRACĘ: Doktor, Bartosz Jabłoński, W4 OCENA PRACY: WROCŁAW 2012

2 Streszczenie Praca ta stanowi opis badań oraz wyniki analizy nierelacyjnych baz danych. Składa się z trzech rozdziałów, opisujących kolejno wybrane systemy bazodanowe, projekt autorskiego rozwiązania typu NoSQL oraz opracowanie pomiarów szybkości tych systemów. Część analityczna skupia się w szczególności na modelu danych, reprezentowanym przez poszczególne systemy oraz algorytmach funkcjonowania w środowisku rozproszonym. Opis autorskiego rozwiązania opatrzony jest wnikliwą analizą problematyki projektowania aplikacji z uwzględnieniem opisu zastosowanych algorytmów oraz wzorców projektowych. Ostatnia część opisuje wyniki szybkości analizowanych systemów w takich operacjach jak zapis, odczyt, uaktualnienie oraz kasowanie danych. Abstract This paper describes analysis and tests, that have been done on various non relational databases. It is divided into three chapters, the first chapter covers databases analysis, the second one describes authors NoSQL paradigm interpretation and the third one contains tests results and its interpretation. The analysis chapter focuses mainly on two aspects of each database. The first one is the data model and the second one are algorithms that enabled these systems to work in a distributed environment. This chapters output had its reflect in the work described in the next part, which covers the implementation and the design, with respect to algorithms and design patterns, used in authors own NoSQL system implementation. The last chapter focuses on the performance issues of analyzed databases, such as speed of: create, read, update and delete operations. 1

3 Spis treści 1 Wstęp Cel oraz struktura pracy Analiza wybranych nierelacyjnych baz danych RavenDB Architektura Metody zarządzania serwerem Model danych Biblioteki klienckie Funkcjonowanie w środowisku rozproszonym Podsumowanie Cassandra Model danych Architektura Biblioteki klienckie Podsumowanie MongoDB Model danych Architektura Biblioteki klienckie Funkcjonowanie w środowisku rozproszonym Podsumowanie Podsumowanie Projekt systemu bazodanowego InDB Specyfikacja wymagań Projekt Model danych Protokół komunikacyjny Biblioteka kliencka Serwer bazy danych Implementacja Część wspólna oraz protokół Biblioteka kliencka Serwer bazy danych

4 3.4 Podsumowanie Analiza wydajnościowa Analiza szybkości zapisu Analiza szybkości odczytu Analiza szybkości modyfikacji Analiza szybkości kasowania Podsumowanie Podsumowanie 87 3

5 1 Wstęp W dzisiejszych czasach obserwujemy bardzo gwałtowny przyrost ilości gromadzonych danych. Facebook w 2010 roku posiadał bazę danych wielkości 21PB [3], obsługiwaną przez Hadoop Framework. Co więcej, rok później ogłoszono, że wielkość tej bazy znacznie wzrosła i wynosi teraz 30PB danych. [65] Jak łatwo zauważyć, oznacza to przyrost o 9PB w ciągu roku, czyli około jednego terabajta w godzinę. Taka ilość danych nigdy dotąd nie była ani gromadzona ani analizowana. Szczególnym problemem jest szybki zapis informacji. Tradycyjne rozwiązania, przy tak dużej wymaganej wydajności, nie znajdują zastosowania. Były one projektowane z myślą o skalowaniu poprzez zwiększenie mocy obliczeniowej jednostki, na której pracują. W dzisiejszych czasach znacznie taniej oraz łatwiej jest dodać kolejną maszynę niż zwiększać moc obliczeniową już posiadanej. Natomiast w przypadku, gdy wymagana wydajność przewyższa moc obliczeniową istniejących procesorów oraz dysków, jest to wręcz niemożliwe. Z tego względu w ostatnich latach coraz większa rolę w zarządzaniu bazami danych o bardzo dużej wielkości zyskują systemy oparte o NoSQL. Termin ten został użyty po raz pierwszy przez Carlo Strozzi w 1998 roku w odniesieniu do swojej relacyjnej bazy danych, nie posiadającej jednak dostępu w języku SQL [62]. Od tamtego czasu nazwa NoSQL została przyjęta jako określenie systemu bazodanowego nie bazującego na podejściu relacyjnym oraz języku SQL. Zbiór baz tego typu zawiera w sobie dokumentowe bazy danych, grafowe bazy danych, bazy danych typu klucz-wartość oraz wiele innych. Pierwszymi bazami danych typu NoSQL, posiadającymi komercyjne znaczenie były Google BigTable [4] oraz Amazon Dynamo [11]. Obydwa te rozwiązania były oparte na modelu danych typu klucz-wartość. Google BigTable jest wykorzystywany jako podstawowa baza danych w wielu usługach firmy Google jak na przykład Google Maps lub Google AppEngine [7]. Baza danych Amazon Dynamo została niedawno dodana jako usługa dla użytkowników chmury Amazon [64]. Bazy NoSQL cechują się dużą szybkością działania oraz łatwością skalowania wydajności poprzez dystrybucję na wiele niezależnych maszyn, a co za tym idzie, idealnie nadają się do zastosowania w klastrach obliczeniowych. Posiadają one bardzo szybkie mechanizmy zapisu oraz odczytu danych. Co więcej, większość z nich umożliwia uruchamianie zadań typu Map/Reduce. Algorytm ten został zaczerpnięty z funkcyjnych języków programowania oraz szczegółowo opisany w specjalnym dokumencie opracowanym przez Google [10]. Opiera się on na założeniu, że większy problem może zostać rozwiązany poprzez dekompozycję go na szereg mniejszych oraz dystrybucję na niezależne maszyny. Krok ten nazywamy operacją Map. Krok Reduce polega na scaleniu rozwiązań cząstkowych w rozwiązanie globalne. Przykładem 4

6 tego podejścia może być wyszukiwanie maksymalnej liczby w pewnym skończonym ciągu. W pierwszym kroku dzielimy cały ciąg na skończoną ilość podciągów a następnie wyszukujemy w każdym z tych podciągów maksimum. W drugim kroku maksimum globalne otrzymujemy jako maksimum z maksimów lokalnych. Wzorzec ten został opracowany z myślą o równoległym przetwarzaniu w środowisku rozproszonym, dzięki czemu podczas analizy danych wszystkie węzły bazy mogą skutecznie wykorzystać całą moc klastra. Nie każdy system wymaga, aby dane przez niego przechowywane posiadały relacyjną strukturę. Co więcej, duża ilość systemów informatycznych jest tworzona w oparciu o paradygmat obiektowy, który nie zawsze pokrywa się z paradygmatem relacyjnym. Generuje to wiele problemów wynikających z natury konfliktu paradygmatycznego. Koronnym przykładem jest traktowanie wartości NULL w językach SQL oraz null w imperatywnych językach programowania, posiadających swoje korzenie w języku C. Kolejnym problemem, jaki można napotkać podczas konwersji danych z modelu relacyjnego do obiektowego, jest sam fakt mapowania kolumn tabeli do właściwości oraz pól w klasach. Należy pamiętać, że w modelu relacyjnym nie istnieje pojęcie obiektu. Projektant systemu musi w sposób arbitralny określić, w jaki sposób mają być one odwzorowane. Implikacją braku obiektów w systemach relacyjnych są również trudności z odwzorowaniem dziedziczenia oraz polimorfizmu klas. Z tego względu powstały narzędzia typu ORM, które zmniejszyły problem, jednak go nie rozwiązały [40]. W dzisiejszych czasach coraz popularniejsze staje się podejście typu CodeFirst dostępne między innymi w Entity Framework [24] oraz NHibernate [42], które dodatkowo redukuje problem, gdyż projektant systemu nie musi martwić się o schemat bazy danych. Rozwiązanie to nadaje się jednak jedynie do systemów o małym oraz średnim obciążeniu. Istnieje inne rozwiązanie problemu mapowania. Przy zastosowaniu dokumentowych baz danych, jak na przykład RavenDB, nie występuje potrzeba korzystania z bibliotek typu ORM. Model danych tych systemów bazodanowych wspiera paradygmat obiektowy. Trzeba jednak pamiętać, że większość baz danych typu NoSQL nie nadaje się do każdego zastosowania. Przede wszystkim, większość z nich nie wspiera zasady ACID, która została opisana przez Jima Greya w książce [23] i opisuje cztery zasady, które muszą być spełnione, aby dane zawarte w bazie były spójne. Z tego względu, bazy danych NoSQL, zupełnie nie nadają się do zastosowań, w których cecha ta jest kluczowa, jak na przykład banki oraz systemy finansowe. Zastosowanie nierelacyjnej bazy danych w projekcie może nie tylko przynieść korzyści wynikające z przyspieszenia działania systemu, lecz również z uproszczenia implementacji. Model danych systemu Cassandra, oparty o zbiory klucz-wartość z różnymi atrybutami dla każdej encji, idealnie nadaje się do systemu, w którym zbieramy informacje o pewnych zdarzeniach, które jednak posiadają bardzo ograniczony zakres cech wspólnych. 5

7 Temat baz danych typu NoSQL jest relatywnie nowy oraz niezbadany. Istnieje jednak w nim duży potencjał, zwłaszcza jeśli weźmiemy pod uwagę szybki rozwój portali społecznościowych, takich jak Facebook oraz Twitter, których model danych idealnie nadaje się do wykorzystania tego typu podejścia. Ich rozwój dostarcza również bezcennych informacji na temat tego, w jakim stopniu rozwiązania NoSQL sprawdzają się w środowisku produkcyjnym. Dodatkowym aspektem, przemawiającym za podjęciem się dogłębnej analizy tego tematu, jest jego wsparcie dla modelu obliczeń oraz operacji rozproszonych, prezentowanych przez bazy danych NoSQL. W dzisiejszych czasach zwiększenie mocy obliczeniowej komputerów dokonuje się poprzez dodanie nowej jednostki obliczeniowej, a nie przez zwiększenie mocy już istniejącej. Wszystkie te aspekty sprawiły, że zdecydowano się podjąć zadania dogłębnej analizy rozwiązań typu NoSQL, z naciskiem na ich wydajność oraz możliwości zastosowania w różnego rodzaju aplikacjach. 1.1 Cel oraz struktura pracy Celem pracy jest analiza nierelacyjnych baz danych, porównanie ich z rozwiązaniem relacyjnym oraz zaprojektowanie i zaimplementowanie własnej bazy danych, opartej o doświadczenia oraz syntezującej zalety analizowanych rozwiązań. Projektowany system będzie stanowić implementację bazy danych typu NoSQL, nastawioną na zastosowanie w aplikacjach przemysłowych, takich jak akwizycja danych pomiarowych oraz przechowywanie danych historycznych, opisujących pewne procesy wytwórcze. Z tego względu najważniejsza będzie jej wysoka dostępność oraz bezpieczeństwo, przechowywanych danych. Zaimplementowane zostaną w niej mechanizmy zapewniające integralność danych [23] oraz bezpieczeństwo polegające na przechowywaniu danych na wielu komputerach jednocześnie. Praca ta podzielona została na trzy części. Pierwszą z nich stanowi analiza najpopularniejszych rozwiązań typu NoSQL, takich jak RavenDB, MongoDB oraz Cassandra, pod względem wydajności, modelu danych oraz możliwości wykorzystania ich w kontekście aplikacji internetowych, tworzonych na platformę.net. Druga zawiera projekt własnego rozwiązania opartego na wnioskach pochodzących z analizy zawartej w pierwszej części. Przedstawiony w niej zostanie całkowity proces rozwoju systemu bazodanowego, od specyfikacji, poprzez projekt, aż po implementację. Trzecia polega na porównaniu wydajności własnego rozwiązania, wybranej relacyjnej bazy danych oraz analizowanych rozwiązań typu NoSQL. Kryteria porównawcze zostaną zdefiniowane w oparciu o szybkość operacji CRUD, takich jak zapis, odczyt, uaktualnienie danych, 6

8 dodanie nowego wpisu do bazy oraz prędkość wyszukiwania używając klucza. W ostatnim rozdziale przedstawione jest syntetyczne podsumowanie osiągniętych rezultatów. Bazując na zgromadzonych danych opisuje on możliwe kierunki rozwoju baz danych NoSQL oraz potencjalne alternatywy oraz obszary zastosowań. 7

9 2 Analiza wybranych nierelacyjnych baz danych W rozdziale tym zostanie dokonana wnikliwa analiza wybranych rozwiązań NoSQL. W szczególności poddany analizie będzie model danych. Bazy danych NoSQL nie posiadają żadnego spójnego modelu danych. Istnieją typy nierelacyjnych baz danych, jak na przykład: bazy obiektowe lub słowniki klucz wartość, jednak nawet w obrębie przedstawicieli tych podzbiorów można znaleźć pewne istotne różnice. Kolejnym analizowanym aspektem będzie dostępność oraz jakość implementacji bibliotek klienckich. Jest rzeczą oczywistą, że aby skomunikować się z bazą danych potrzebna jest pewnego rodzaju biblioteka obudowująca skomplikowane wywołania oraz serializację danych transferowanych od bazy danych do aplikacji klienckiej. Dodatkowo ważne jest, aby biblioteki klienckie były dostępne przynajmniej w najpopularniejszych językach programowania, jak na przykład C#, Java, Python lub PHP. Dzięki temu wybór bazy danych nie ogranicza nam języka, w jakim możemy zaimplementować aplikację kliencką. Jak zostało zaznaczone we wstępie, jedną z głównych zalet baz danych typu NoSQL jest ich wsparcie dla działania w środowisku rozproszonym. Z tego względu każda z baz danych zostanie przeanalizowana pod kątem wspierania zadań typu Map/Reduce, jak również partycjonowania oraz redundancji danych. Ta ostatnia własność jest szczególnie ważna, jeśli chcemy zwiększyć bezpieczeństwo systemu. Dzięki dystrybucji danych na różne maszyny uodparniamy się na awarie pojedynczych węzłów komputerowych. W wielu rozproszonych systemach występuje tak zwana zasada lokalności operacji. Polega ona na prostej obserwacji, że poszczególne węzły sieci w przypadku ogólnym nie dostają równomiernej ilości zapytań o cały zbiór danych. Na przykład baza danych tablic rejestracyjnych Województwa Dolnośląskiego jest częścią większej, ogólnopaństwowej infrastruktury posiadającej informacje o wszystkich tablicach rejestracyjnych w Polsce. Znaczna większość zapytań do tej bazy danych dotyczy jednak tablic rejestracyjnych jedynie Województwa Dolnośląskiego. Z tego względu podczas projektowania tego systemu można było te dane poddać partycjonowaniu ze względu na województwo z jakiego pochodzą. W wyniku tej operacji baza danych trzymana lokalnie we Wrocławiu posiada jedynie informacje dotyczące Województwa Dolnośląskiego, a w przypadku zapytania o rejestrację z Województwa Zachodniopomorskiego, zapytanie zostaje przekierowane na inny węzeł sieci. Ostatnim bardzo ważnym aspektem analizy jest podsumowanie każdej bazy danych, ze szczególnym uwzględnieniem cech szczególnych każdego z rozwiązań. Ze względu na dużą różnorodność rozwiązań NoSQL, niemalże każde z nich posiada pewne cechy szczególnie zasługujące na uwagę. Stanowią one bardzo często rozszerzenie pewnego modelu danych lub mechanizmy zapewniające dodatkową integralność danych. Najlepsze pod względem zastoso- 8

10 wań przemysłowych, takich jak akwizycja oraz przechowywanie danych pomiarowych pewnych procesów, cechy szczególne analizowanych baz danych zostaną zaimplementowane w systemie InDB. 2.1 RavenDB RavenDB jest dokumentową bazą danych, w której dane przechowywane są w postaci obiektów JSON. Została ona w całości stworzona w oparciu o technologię.net oraz język C#, co jest rzadkością pośród rozwiązań tego typu. Z tego względu wspiera ona wyszukiwanie elementów poprzez zastosowanie technologii LINQ. Chociaż jej kod źródłowy jest rozprowadzany na licencji Open Source, to do zastosowań komercyjnych potrzebne jest wykupienie licencji [47]. Kolejną z cech, która wyróżnia tę bazę danych, jest wsparcie dla zasady ACID [23]. Co prawda jest ono niepełne, co zostanie opisane w dalszej części pracy, jednak większość analizowanych baz danych nie posiada tej właściwości wcale, w związku z pewnym spadkiem wydajności, wynikającym z pilnowania integralności danych. Dostęp do jej zasobów można osiągnąć przy pomocy prostego API, opartego na protokole RESTful [56]. Jest on bardzo przystępny ze względu na niezależność od konkretnej implementacji oraz jasny i dobrze udokumentowany algorytm dostępu, oparty o protokół HTTP. Baza ta radzi sobie bardzo dobrze w środowisku rozproszonym. Wspiera partycjonowanie oraz replikację danych, jak również umożliwia uruchamianie zadań na wielu węzłach jednocześnie. Ze względu na nietypową technologię dla tego typu systemów, wsparcie transakcji oraz przystępne API, jak również funkcjonalności związane z działaniem w środowisku rozproszonym, zdecydowano się uwzględnić tę bazę danych w analizie Architektura Baza danych RavenDB, jak praktycznie każdy tego typu system, składa się z aplikacji serwera oraz klienta. Serwer odpowiedzialny jest za przechowywanie danych, natomiast biblioteka kliencka umożliwia wywoływanie natywnych metod RESTful API poprzez odpowiednie klasy opakowujące. Tryby działania Bardzo ciekawą własnością serwera RavenDB jest możliwość działania w różnych trybach. W pierwszym z nich działa on jako normalna usługa Windows. Jest on w pełni samowystarczalny oraz nie potrzebuje żadnych innych programów stanowiących jego środowisko uruchomienia. W ten sam sposób działa MSSQL Server oraz wiele innych dużych, relacyjnych systemów 9

11 baz danych. Pewną modyfikacją tego trybu działania jest uruchomienie aplikacji pod konsolą. Możliwość ta przydaje się znacznie podczas debugowania aplikacji. W drugim trybie działa on jako aplikacja uruchomiona za pomocą serwera HTTP, wbudowanego w system Windows - IIS [61]. Ponieważ natywnym API tej bazy danych jest RESTful oparty na protokole HTTP, jest rzeczą oczywistą, że uruchomienie go za pomocą lokalnego serwera www powinno być możliwe. Co więcej, powinno nieść to za sobą wzrost wydajności, ponieważ serwer IIS jest zoptymalizowany pod kątem przetwarzania wiadomości HTTP oraz HTTPS. Odpowiada za to specjalny moduł jądra systemu operacyjnego Windows o nazwie HTTP.sys [61]. W trzecim trybie działa jako integralna część tworzonej aplikacji. Jest to tryb bardzo przydatny, gdy projektowana przez nas aplikacja ma bardzo ograniczone zasoby pamięci oraz procesora do wykorzystania. W wielu przypadkach jest również niepotrzebne uruchamianie osobnej bazy danych do przechowywania jedynie niewielkiej ilości danych, a z drugiej strony nie chcemy tracić wszystkich uproszczeń oraz mechanizmów jakie zapewnia nam baza danych. Przykładem relacyjnej bazy danych, która działa również jako biblioteka w przestrzeni aplikacji jest SQLite [59]. Rozwiązanie to jest bardzo popularne i stosowane przez największe firmy z całego świata [60]. Jest ono wykorzystywane między innymi przez firmę Google w systemie operacyjnym Android do przechowywania danych aplikacji oraz w przeglądarce Opera jako sposób przechowywania niektórych danych przeglądarki i zapisanych ustawień. Mechanizmy trwałego zapisu RavenDB zawiera dwa mechanizmy zapisu danych na dysk. Pierwszym z nich jest Esent. Jest to biblioteka rozwijana przez Microsoft, umożliwiająca zapisywanie danych w zindeksowanej formie. Wszystkie operacje na niej odbywają się w sposób transakcyjny. Posiada ona również mechanizmy zabezpieczające integralność danych na wypadek awarii systemu. Ze względu na wysoką wydajność, rozwiązanie to nadaje się do zastosowań produkcyjnych. Jedynie silnik opierający się na Esent jest oficjalnie rekomendowany do zastosowań nietestowych. Drugi silnik o nazwie Munin, napisany w pełni w kodzie zarządzanym dla potrzeb tej bazy danych, jest wolniejszy oraz mniej wydajny niż Esent, przez co jest rekomendowany jedynie do celów testowych. System wtyczek Pomimo tego, że RavenDB posiada bardzo bogaty zasób funkcji, zawsze istnieje możliwość, że znajdziemy taką, której brakuje. Z tego względu postanowiono stworzyć specjalny system rozszerzeń o nazwie Bundles. Instalacja każdej z wtyczek jest bardzo prosta i składa się z dwóch 10

12 etapów. Po pierwsze, należy przekopiować odpowiedni plik dll do katalogu z wtyczkami. Jest on zdefiniowany jako globalne ustawienie serwera o nazwie Raven/PluginsDirectory. Kolejnym krokiem jest konfiguracja wtyczki. Większość z nich konfigurowana jest poprzez edycję specjalnie utworzonych dokumentów. Czasami po tych operacjach wymagany jest restart bazy danych, ze względu na konieczność przeładowania pewnych podstawowych modułów systemu. Do najpopularniejszych rozszerzeń należą Quotas Bundle, dzięki której można ograniczyć wielkość bazy danych, Versioning Bundle, która przechowuje historie zmian na każdym dokumencie oraz More Like This Bundle, która przy pomocy biblioteki Lucene [16] wyszukuje dokumenty podobne do podanego. Ze względu na analizę funkcjonowania tej bazy danych w środowisku rozproszonym, warte uwagi są dwa rozszerzenia umożliwiające partycjonowanie danych pomiędzy różne węzły oraz replikację. Zostaną one omówione w dalszej części pracy. Zasada domyślnego bezpieczeństwa Podczas projektowania systemu RavenDB starano się trzymać zasady domyślnego bezpieczeństwa. Została ona opisana szczegółowo w pozycji [43]. Zgodnie z jej założeniami, system powinien pozwolić programiście na działanie mogące uszkodzić lub spowodować znaczne zmniejszenie szybkości, jednak tylko wtedy, gdy programista tego zażąda explicite. Zgodnie z tym założeniem, system domyślnie wprowadza pewne ograniczenia na liczbę dokumentów, które mogą zostać przesłane przy pojedynczym zapytaniu, chyba, że programista, przy użyciu metody.take() w sposób jawny zmieni ich ilość. Domyślnie ilość przesyłanych dokumentów jest ograniczona do 128 [50]. Liczba zapytań podczas jednego połączenia z bazą danych (sesji) jest również ograniczona. Dzięki temu łatwiej jest wykryć elementy implementacji, które wykonują zbyt wiele zapytań. Odbija się to bowiem w sposób negatywny na wydajności aplikacji. Liczba zapytań do bazy danych, na które system domyślnie pozwala wynosi 30 [50]. W przypadku przekroczenia tej ilości zgłoszony zostaje wyjątek Metody zarządzania serwerem Baza danych RavenDB posiada bardzo wiele ustawień oraz parametrów, które można zmieniać w celu dostosowania wydajności oraz sposobu jej działania do naszych potrzeb. Ponieważ program ten jest w całości napisany przy użyciu języka C# oraz platformy.net, korzysta on z domyślnej architektury plików konfiguracyjnych tej platformy. Jeśli działa on w trybie aplikacji IIS, wykorzystuje standardowy Web.config aplikacji. W innych przypadkach odczytuje swoje ustawienia z pliku Raven.Server.exe.config. W przypadku zmian w tych plikach czasami występuje konieczność ponownego uruchomienia aplikacji poprzez wydanie komendy Raven.Server.exe restart, gdyż nie wszystkie rozszerzenia mogą na bieżąco monitorować 11

13 zmiany w plikach konfiguracyjnych. Ustawienia konfiguracyjne zostały podzielone na kilka grup. ˆ Ustawienia dotyczące sposobu oraz priorytetu z jakim działają wątki bazy danych. ˆ Ustawienia mechanizmu indeksowania. ˆ Ustawienia sposobu trwałego zapisu danych. Przy ich pomocy można ustawić między innymi aktywny silnik zapisu danych, katalog, do którego dane zostaną zapisane oraz tryb transakcji. ˆ Preferencje protokołu HTTP serwera RavenDB oraz ustawienia silnika przechowywania danych Esent. Warto zauważyć, że każde ustawienie ma swoją wartość domyślną, dlatego nawet jeśli część konfiguracji ulegnie skasowaniu lub zniszczeniu, baza danych nadal jest w stanie funkcjonować. Szczegółowo wszystkie ustawienia zostały udokumentowane w pracy [51]. Kopie bezpieczeństwa Bazę danych RavenDB można poddawać operacji tworzenia kopii bezpieczeństwa oraz przywracania tej kopii. Pierwsza z tych operacji może odbywać się podczas działania systemu. Do wykonania drugiej z nich system musi zostać wyłączony. Istnieją dwa sposoby tworzenia kopii bezpieczeństwa. Pierwszy z nich jest oparty o mechanizm tworzenia migawek dysku. Jest on wbudowany w system Windows od wersji Windows XP i nosi nazwę Volume Shadow Copy [27]. Z tego samego mechanizmu korzysta również MSSQL, dzięki czemu możliwe jest robienie kopii bezpieczeństwa działających systemów, za pomocą standardowych narzędzi administracyjnych systemu Windows [28]. Drugi sposób opiera się na wykorzystaniu programu do robienia kopii bezpieczeństwa, dostarczonego przez twórców RavenDB. W przeciwieństwie do poprzedniego rozwiązania, wynikiem jego działania jest baza danych, ale z chwili, w której operacja tworzenia kopii zapasowej została zainicjowana. Warto zauważyć, że narzędzia do tworzenia kopii zapasowych nie są kompatybilne wstecz, to znaczy kopia zapasowa wykonana na systemie Windows 7 nie koniecznie będzie działać na systemie Windows XP. Są jednak kompatybilne wprzód co oznacza, że w sytuacji odwrotnej baza danych będzie działać poprawnie. W zależności od trybu w jakim działa baza danych, operacje tworzenia kopii zapasowej można rozpocząć na kilka sposobów, wywołując metodę StartBackup() klasy DocumentDatabase, gdy baza danych działa w trybie wbudowanym w aplikację lub poprzez wywołanie programu Raven.Backup.exe w trybie, gdy baza danych działa jako osobny proces. Warto 12

14 pamiętać, że narzędzie do tworzenia kopii bezpieczeństwa musi działać z uprawnieniami administratora. Bardzo ciekawą właściwością jest możliwość wywołania operacji tworzenia kopii bezpieczeństwa za pomocą odwołania się do adresu /admin/backup. Spowoduje to asynchroniczne rozpoczęcie tworzenia kopii zapasowej. Operacja przywrócenia bazy danych do stanu, w którym wykonana została kopia zapasowa jest również prosta. W trybie wbudowanym należy wywołać metodę Restore() klasy DocumentDatabase, natomiast, gdy baza danych działa jako osobny program, należy uruchomić ją z parametrem -restore oraz dodać źródło, z którego ma zostać pobrana kopia zapasowa. Warto zauważyć, że operacja przywrócenia kopii zapasowej, jest w przeciwieństwie do operacji jej tworzenia w pełni synchroniczna oraz wymaga przełączenia jej w stan nieoperacyjny. Operacja tworzenia kopii zapasowej oraz jej odtwarzania powinna być wykorzystywana w przypadku, gdy chcemy uchronić nasze dane od zniszczenia. Warto zauważyć, że nie zawsze pliki kopii bezpieczeństwa są kompatybilne pomiędzy różnymi wersjami systemów operacyjnych oraz tym bardziej wersjami bazy danych. Dlatego, jeśli chcemy przenieść dane do innego systemu lub stworzyć kopię bezpieczeństwa niezależną od wersji systemu operacyjnego i instancji programu RavenDB, powinniśmy skorzystać z narzędzi importu oraz eksportu. Import oraz eksport danych W celu wykonania eksportu oraz importu danych musimy skorzystać z osobnego programu o nazwie Smuggler. Wynikiem jego działania jest pojedynczy plik zawierający wszystkie dane dotyczące bazy, w szczególności indeksy, dokumenty w niej zawarte oraz załączniki. Co więcej, uwzględnia on również wszystkie zmiany dokonane w bazie podczas operacji eksportu. Każdy z elementów można wykluczyć z operacji eksportu poprzez dodanie odpowiedniej opcji, na przykład only-indexes wyeksportuje informacje jedynie o indeksach. Gdy chcemy zaimportować dane z pliku eksportu, również powinniśmy skorzystać z programu Smuggler. W przeciwieństwie do operacji przywracania kopii zapasowej, baza danych RavenDB może działać podczas operacji importu dokumentów. Należy jednak pamiętać o tym, że wszystkie istniejące dokumenty o duplikującym się kluczu zostaną nadpisane przez te pochodzące z pliku eksportu. Graficzne narzędzie dostępowe Każdy większy system bazodanowy posiada pewnego rodzaju graficzne narzędzia dostępowe, umożliwiające edycję danych oraz zarządzanie konfiguracją. MSSQL posiada Management Studio [39]. RavenDB również posiada tego typu narzędzie, jest ono jednak znacznie mniej rozbudowane niż MSSQL Management Studio i nazywa się po prostu The Studio. Posiada 13

15 Rysunek 1: Widok głównego ekranu The Studio ono podstawową funkcjonalność pozwalającą na przeglądanie oraz edycję danych zawartych w bazie, uruchamianie oraz ustawianie odpowiednich zadań oraz przeglądanie logów aplikacji. Zostało ono napisane przy pomocy technologii Silverlight, z tego względu dostęp do niego odbywa się poprzez przeglądarkę internetową. Brak w nim jednak narzędzi do bardziej wnikliwej analizy danych oraz przede wszystkim konfiguracji wtyczek. The Studio jest podzielone na kilka sekcji. Po uruchomieniu wyświetla nam się sekcja podsumowująca działanie bazy danych. Zawiera ona przegląd ostatnio dodanych dokumentów. The Studio posiada również widok zawierający wszystkie dokumenty, w którym każdy z nich można edytować. Kolejny widok prezentuje informacje dotyczące wszystkich kolekcji. Dzięki niemu możemy zobaczyć na przykład ile jest dokumentów w danej kolekcji lub skasować wszystkie dokumenty z danej kolekcji. Istnieje również widok, dzięki któremu możemy przetestować działanie indeksów oraz dodać nowe. Importu oraz eksportu można dokonać korzystając z widoku zadań. Ostatnie dwa widoki dotyczą podsumowania działania systemu, w postaci wyświetlania logów oraz statystyki systemu, dotyczące ilości indeksów, stworzonych dokumentów oraz ilości zarejestrowanych błędów Model danych Kolejnym bardzo ważnym aspektem, który należy zanalizować, jest model logiczny przechowywanych danych. Jak już zostało zaznaczone we wstępie, RavenDB jest dokumentową bazą danych. To znaczy, że każda encja stanowi osobny dokument. Każdy dokument jest iden- 14

16 Rysunek 2: Przykładowa encja w dokumentowym model danych. tyfikowany przez klucz składający się zgodnie z konwencją z dwóch części. Pierwszą z nich jest nazwa typu dokumentu, natomiast kolejną z nich jest identyfikator dokumentu w obrębie encji tego samego typu. Poprzez analogię można to porównać do nazwy tabeli oraz klucza głównego tej tabeli. Warto zauważyć, że jest to tylko konwencja i użytkownik może zawsze stworzyć własny sposób nadawania identyfikatorów dokumentom. Ważne jest żeby pamiętać o tym, że każdy identyfikator musi być unikalny w obrębie całej bazy danych. Jest to zwłaszcza istotne, jeśli weźmiemy pod uwagę fakt, że RavenDB w żaden sposób nie sprawdza czy klucze w obrębie bazy danych są unikalne. Jeśli spróbujemy dodać nowy dokument, którego klucz jest duplikatem już istniejącego, system bazy danych nadpisze stary dokument nowym, bez żadnego ostrzeżenia. Jedną z ważniejszych rzeczy, o których należy pamiętać podczas projektowania baz danych opartych na RavenDB jest fakt, że dokumenty, w odróżnieniu od wierszy bazy danych, nie mają struktury płaskiej. Każdy dokument może zawierać kolekcję podklas oraz referencje do innych klas. Taki graf obiektów, w przeciwieństwie do podejścia znanego z narzędzi typu ORM i relacyjnych baz danych, nie jest rozdzielany w żaden sposób, tylko zapisywany w całości jako pojedynczy dokument. Z tego względu utrudniona jest implementacja kolekcji lub referencji współdzielonych przez różne obiekty. Zamiast referencji bezpośrednio do dokumentu, należy umieścić identyfikator dokumentu, do którego mamy zamiar się odwołać. RavenDB nie zadba niestety o spójność danych w ten sam sposób, w jaki relacje dbają o spójność danych w relacyjnych bazach danych. Stanowi to pewne odstępstwo od reguły ACID. Znaczy to, że mogą występować dokumenty posiadające odnośniki do nieistniejących dokumentów. Jest to dość kłopotliwa sytuacja i może powodować wiele problemów przy utrzymaniu logicznej spójności 15

17 danych w bazie. Przy projektowaniu encji warto zastosować wzorzec architektoniczny agregatora opisany w książce [15]. Zakłada on, że w modelu znajdują się pewne główne encje, zwane korzeniami oraz encje pomocnicze, które są stworzone oraz zorganizowane dookoła korzenia. Dzięki temu pomiędzy poszczególnymi drzewami można zastosować odwołanie poprzez klucz, natomiast w powiązaniach encji z tego samego drzewa można zastosować zwykłe referencje obiektowe. Bardzo ważnym aspektem architektury oraz modelu danych bazy RavenDB jest pojęcie kolekcji. Jest to pewien logiczny zbiór encji tego samego typu. Można odnieść go przez pewną analogię do tabeli w relacyjnej bazie danych, jednak jedynie na poziomie logicznym. W relacyjnej bazie danych podział na tabele ma faktycznie fizyczne odwzorowanie w organizacji pliku bazy danych. W omawianej bazie danych kolekcje stanowią jedynie logiczny zbiór i nie mają żadnego znaczenia dla silnika bazy danych. Ma to swoje uzasadnienie w fakcie, że wszystkie encje są pozbawione schematu oraz w istocie są dokumentami tego samego typu, toteż mogą być traktowane na równi. Każdy dokument w bazie danych przechowywany jest w formacie JSON, opisanym dokładnie w pracy [8]. Jest to bardzo minimalistyczny format, którego przejrzystość jest znacznie większa dla człowieka niż XML. Warto zauważyć, że autorzy tej bazy danych skorzystali z biblioteki Json.NET, której twórcą jest James Newton-King [41]. Jest ona bardzo wydajnym oraz prostym sposobem na serializację oraz deserializację danych w formacie JSON, jak również jest w stanie wykonywać wyszukiwania LINQ w zbiorach danych dokumentów w tym formacie. Ponieważ wszystkie dokumenty przechowywane są w formie tekstowej, mogłoby się wydawać, że RavenDB nie jest w stanie składować danych binarnych. W celu rozwiązania tego problemu stworzono specjalny dodatkowy sposób przechowywania danych, w postaci załączników. Każdy załącznik jest po prostu jakimś zbiorem binarnych danych, umieszczanych w bazie danych. RavenDB w żaden sposób nie analizuje semantycznej zawartości takich załączników. Warto zauważyć, że jest to znacznie szybszy sposób przechowywania danych binarnych niż kodowanie ich tekstowo i zamieszczanie w dokumentach. Należy jednak pamiętać, że dane binarne nie mogą być zbyt duże. Rozsądnym ograniczeniem, jakie należy przyjąć jest 10MB. Pomijając aspekt małej wydajności, RavenDB korzysta z biblioteki Esent, która posiada pewne ograniczenia na wielkość kolumny, której zawartość nie może przekroczyć 2GB [38]. W ostatnich latach we wszystkich językach programowania coraz większy nacisk kładzie się na elementy oraz mechanizmy meta-programowania, takie jak na przykład refleksja. To samo tyczy się baz danych. MSSQL zawiera w sobie specjalny zestaw widoków ze schematu sys, który wraz z każdą kolejną wersją tego oprogramowania znacznie się rozszerza [37]. Posiadają one wszystkie informacje na temat schematu bazy danych. Baza danych RavenDB również 16

18 posiada podobne mechanizmy. Każda encja w kolekcji jest rozszerzona o specjalne atrybuty, mówiące o jej strukturze. Dzięki temu można w łatwy sposób dowiedzieć się, na podstawie encji, do jakiego typu ona należy. RavenDB jest bazą danych pozbawioną schematu. Rozwiązuje to wiele problemów, znanych z relacyjnych baz danych, jednak wprowadza wiele nowych. Jednym z nich jest utrudnione wyszukiwanie. W celu rozwiązania tego problemu wprowadzono rozszerzony mechanizm indeksów [48]. Każdy indeks reprezentowany jest jako zapytanie LINQ. Co ciekawe, są one uruchamiane w tle, a ich wyniki buforowane. W przypadku, gdy nowo dodane dane zakłócają porządek indeksu, nie jest on przeliczany od razu, tylko po pewnym czasie. Jest to jeden z przykładów optymalizacji, mającej na celu przyspieszenie operacji CRUD w stosunku do relacyjnych baz danych, który jednak odbija się na dokładności otrzymanych wyników. Taki sposób implementacji indeksowania przypomina bardziej widok zmaterializowany, znany między innymi z baz danych Oracle [44]. Dzięki temu uzyskuje się bardzo szybki dostęp do wyników wykonanych zapytań. Co więcej, wyniki działania indeksów są trzymane w postaci przejrzystej dla biblioteki Lucene [48]. Służy ona do wyszukiwania danych w tekście oraz jest bardzo szybka. Dzięki temu można uzyskać dostęp do bardzo szybkich mechanizmów późniejszego operowania na indeksach oraz ich przetwarzania, jak na przykład pełne lub częściowe przeszukiwanie tekstu oraz przeszukiwanie tekstu na podstawie pewnego zakresu. RavenDB posiada wsparcie dla systemu transakcji. Jest to bardzo rzadko spotykana cecha pośród baz tego typu. Dzięki temu nadaje się on do zastosowań wymagających od bazy danych spełnienia zasad ACID [23]. Transakcje w bazie danych RavenDB są realizowane dzięki wykorzystaniu mechanizmów z przestrzeni nazw System.Transactions oraz koordynatora transakcji rozproszonych [29]. Z tego względu wspiera on transakcje w środowisku rozproszonym, co jest wyjątkowo ważne, biorąc pod uwagę typowe obszary wdrożeń baz danych NoSQL Biblioteki klienckie Dostęp do RavenDB odbywać się może w dwojaki sposób. Po pierwsze programista może skorzystać z natywnego RESTful API lub gotowej biblioteki, opakowującej odpowiednie wywołania w klasy.net. Niemalże każdy język programowania dostarcza pewnego rodzaju mechanizmy, pozwalające na połączenie się z witryną za pomocą protokołu HTTP. Z tego względu pierwszy sposób jest możliwy do wykorzystania w praktycznie każdym języku programowania. Jest on jednak odrobinę trudniejszy i wymaga wykonania wielu czynności, jak na przykład konwersja danych z formatu JSON na instancje obiektów lub struktur. Zastosowanie gotowej biblioteki stworzonej na platformę.net opakowuje wywołania tych metod w klasy oraz obiekty, dzięki czemu znacznie upraszcza pracę. 17

19 Metoda/Zasób GET Pobranie całej kolekcji obiektów typu collection Pobranie pojedynczego elementu kolekcji, identyfikowanego przez klucz 11 PUT Nadpisanie kolekcji collection Nadpisanie pojedynczego elementu o przez nową identyfikatorze 11 nowym POST Stworzenie nowego elementu w kolekcji collection Stworzenie nowego wpisu w elemencie o identyfikatorze 11 DELETE Usunięcie całej kolekcji collection Usunięcie elementu o identyfikatorze 11 z kolekcji collection Tabela 1: RESTful API w kontekście zastosowania w RavenDB RESTful API Bezpośrednie połączenie za pomocą RESTful API bardzo przydaje się przy okazji testowania bazy danych, zwłaszcza w połączeniu z narzędziem curl, które jest w stanie wysłać dowolne zapytanie HTTP. Przykładowo, jeśli chcemy pobrać jakiś dokument z naszego lokalnego serwera wystarczy wydać polecenie zaprezentowane na listingu 1. Listing 1: Pobranie dokumentu z lokalnego serwera curl - X GET http :// localhost : 8080/ docs /12 W celu zrozumienia działania tego API, najpierw należy zrozumieć cały koncept RESTful API. Opiera się ono na zasadzie REST, której fundamentalnym założeniem jest fakt, że każde zapytanie do serwera jest niezależne i serwer nie powinien w żaden sposób utrzymywać stanu połączenia pomiędzy dwoma zapytaniami. Podlega ono pod dużo szerszą zasadę tworzenia obiektów pozbawionych stanu, znaną między innymi z języków funkcyjnych [45]. Aplikacje tworzone przy wykorzystaniu takiego podejścia są znacznie luźniej skorelowane oraz dużo prostsze w rozbudowie. Co więcej, mamy pewność, że podczas testowania dwóch metod osobno po ich złożeniu również otrzymamy poprawnie funkcjonujący program. Zgodnie z wymienionymi założeniami powstała specjalna technologia tworzenia web serwisów, opartych o RESTful API. Opiera się ona na wykorzystaniu metod protokołu HTTP zgodnie z ich semantyką. Warto zauważyć, że przez wiele lat jedynie metody GET oraz POST były w praktyce wykorzystywane. W tabeli 1 przedstawiono krótki opis każdej wykorzystywanej metody zaczerpnięty z książki [53]. 18

20 Biblioteka dostępowa dla.net Jak nietrudno zauważyć, korzystanie jedynie z RESTful API byłoby niezmiernie ciężkie oraz w większości przypadków skutkowałoby stworzeniem własnych bibliotek opakowujących wywołania HTTP. Z tego względu postanowiono stworzyć specjalne API w.net [52]. W swojej konstrukcji bazuje w dużej mierze na bibliotece ORM o nazwie NHibernate. Dostępna jest przez system instalacji bibliotek NuGet oraz opiera się na trzech podstawowych interfejsach: IDocumentStore, IDocumentSession oraz IDocumentQuery. IDocumentStore jest interfejsem reprezentującym całą bazę danych. Zgodnie z zaleceniami twórców oprogramowania powinna istnieć jedna instancja klasy implementującej ten interfejs w całym programie, gdyż jego stworzenie zajmuje dużo czasu. Dostęp do niego może odbywać się jednocześnie z wielu wątków. Głównym zadaniem tego obiektu jest tworzenie instancji klas typu IDocumentSession, które odpowiadają za interakcję z bazą danych. IDocumentSession reprezentuje pojedyncze połączenie z bazą danych. Za jego pomocą możemy modyfikować stan bazy danych oraz wykonywać zapytania. Warto pamiętać, że obiekty tego typu są bardzo łatwe do stworzenia, jednak dostęp do nich może odbywać się jedynie z jednego wątku jednocześnie. W przypadku zgłoszenia wyjątku przez instancję tej klasy, należy założyć, że zachowanie wszystkich kolejnych metod jest niezdefiniowane i z obiektu takiego nie powinno się już korzystać. Warto zauważyć, że klasa ta została stworzona w oparciu o wzorzec Unit of work [18]. Dzięki temu zmiany w bazie danych zostają zatwierdzone dopiero po wywołaniu metody SaveChanges(). Zastosowanie tego wzorca bardzo ułatwia tworzenie aplikacji, których metody biznesowe zachowują spójność danych w bazie. IDocumentQuery jest obiektem reprezentującym pojedyncze zapytanie do bazy danych RavenDB. Dzięki niemu możemy tworzyć zapytania do indeksów oraz kasować lub modyfikować masowo dane. Najprostszym sposobem połączenia się do bazy danych jest utworzenie instancji obiektu DocumentStore z odpowiednim adresem oraz jego inicjacja. Przykładowy kod realizujący tę operację został zaprezentowany na listingu 2. Listing 2: Procedura podłączenia do bazy danych RavenDB var documentstore = new DocumentStore { Url = " http :// localhost :8080/" }; documentstore. Initialize (); W celu uniknięcia konieczności podawania dokładnych danych połączenia w kodzie, może- 19

21 my skorzystać z możliwości umieszczenia w pliku konfiguracyjnym aplikacji łańcucha połączeniowego bazy danych RavenDB. Zawiera on takie pola jak na przykład Url, User/Password oraz Database. Dzięki nim, podczas instalacji tworzonej przez nas aplikacji, możemy dowolnie zindywidualizować sposób łączenia się z bazą danych. Do najważniejszych metod interfejsu IDocumentSession należą: Load, Delete oraz Store. Pierwsza z nich służy do wczytania obiektu z bazy danych do przestrzeni aplikacji. Przyjmuje ona argument będący kluczem istniejącego dokumentu. Jest to metoda generyczna, więc wymaga wyspecyfikowania dodatkowo typu dokumentu, który chcemy wczytać. Klucz może być dowolnym obiektem, jednak najczęściej wykorzystywane są trzy typy int, Guid oraz string. Po wczytaniu obiekt możemy dowolnie modyfikować. W celu synchronizacji zmian z bazą należy wywołać wspomnianą metodę SaveChanges(). W celu dodania nowego obiektu do bazy danych należy skorzystać z metody Store. Należy jednak pamiętać, że w przypadku podania klucza, który już istnieje w bazie danych, istniejący dokument zostanie nadpisany przez zapisywany bez żadnego ostrzeżenia. Z tego względu dobrą praktyką jest niepodawanie klucza jako argumentu tej metody, gdyż w tym przypadku system przydzieli go automatycznie. Innym rozwiązaniem tego problemu jest zastosowanie klucza typu Guid, który praktycznie zawsze jest unikalny [25]. Po wykonaniu tej metody również należy pamiętać o wywołaniu metody SaveChanges(). Usunięcia dokumentu z bazy możemy dokonać w dwojaki sposób. Po pierwsze możemy wywołać metodę Delete interfejsu IDocumentSession, której jako argument podajemy dokument, który chcemy usunąć. Jest ona przydatna w przypadku, gdy posiadamy już załadowany dokument, np. jako wynik działania metody Load. Drugi sposób polega na wywołaniu metody Delete, jednak nie interfejsu IDocumentSession, a jego właściwości o nazwie Advanced.DatabaseCommands. Druga metoda Delete wymaga podania jedynie klucza dokumentu i nie wymaga ładowania obiektu do przestrzeni aplikacji. Należy jednak zwrócić uwagę, że w przeciwieństwie do pierwszej metody, nie wymaga ona potwierdzenia w postaci metody SaveChanges() i działa natychmiastowo. Oprócz typowych metod zapisu oraz kasowania RavenDB dostarcza również możliwość wywoływania zapytań na bazie danych. W tym celu stworzona została specjalna biblioteka tłumacząca zapytania LINQ na język zapytań RavenDB. Na listingu 3 zaprezentowano przykładowe zapytanie, którego wynikiem są jedynie osoby pełnoletnie. Listing 3: Przykładowe zastosowanie zapytania LINQ w bazie danych RavenDB var res = from p in session. Query < People >() where p. Age > 18 select p; 20

22 Czasami istnieje potrzeba wykonania pewnego grupowego uaktualnienia lub skasowania danych spełniających pewien predykat. RavenDB umożliwia taką opcję poprzez dwie metody omawianej wcześniej właściwości DatabaseCommands, DeleteByIndex oraz UpdateByIndex. Obydwie przyjmują jako argument nazwę indeksu, na którym będą operować oraz specyfikację zadania. Jak już zostało wspomniane, indeksy w bazie danych RavenDB działają odrobinę inaczej niż w relacyjnych bazach danych. W przypadku dodania nowych danych, nie są przeliczane na bieżąco, lecz jako zadanie w tle. Z tego względu może wystąpić sytuacja, w której użytkownik będzie chciał wykonać operację kasowania lub uaktualniania danych na indeksie, który nie zdążył się jeszcze zaktualizować. Domyślnie w takim przypadku operacja taka nie jest wykonywana, chyba, że użytkownik explicite uzna, że chce ją wykonać. Wszystkie omówione do tej pory metody działają w sposób synchroniczny. Istnieje jednak możliwość utworzenia również sesji bazy danych działającej asynchronicznie. W tym celu zamiast metody OpenSession, interfejsu IDocumentStore należy wywołać metodę OpenAsyncSession. Otrzymany w jej wyniku obiekt daje możliwość wykonywania operacji na bazie danych w sposób asynchroniczny. Ma to duże znaczenie jeśli nasza baza danych znajduje się na innym serwerze, a my nie chcemy obciążać puli wątków lokalnego serwera IIS przez wątki zawieszone w oczekiwaniu na zdalną operację. Dostęp do załączników umieszczonych w bazie danych również odbywa się poprzez wykorzystanie metod z właściwości DatabaseCommands. W szczególności dany załącznik można skasować, uaktualnić lub utworzyć nowy. Co więcej, wspomniana właściwość stanowi najniższy poziom, na którym można komunikować się z bazą danych za pomocą omawianej biblioteki. Dzięki niej można wykonywać praktycznie każdą operację na dokumentach, załącznikach, indeksach oraz transakcjach, jak również niektóre zadania konfiguracyjne Funkcjonowanie w środowisku rozproszonym RavenDB, jak większość rozwiązań NoSQL, został zaprojektowany z myślą o funkcjonowaniu w środowisku rozproszonym. W niniejszym rozdziale zostaną opisane niektóre mechanizmy, dotyczące tego obszaru funkcjonalności. Replikacja Pierwszym z nich jest replikacja. W celu zapewnienia większego bezpieczeństwa danych, wszystkie zasoby zgromadzone w jednym węźle bazie danych RavenDB mogą być zreplikowane na inny. Co więcej, replikacja ta odbywa się w trybie multi-master a co za tym idzie, węzły mogą replikować swoje dane wzajemnie. Synchronizacja danych następuje w sposób automatyczny, po zatwierdzeniu każdej transakcji. Jeśli jeden z węzłów bazy danych przestanie 21

23 odpowiadać, RavenDB wykrywa to i zwiększa interwał czasowy pomiędzy kolejnymi próbami komunikacji. Dopiero, gdy węzeł znów zacznie odpowiadać, synchronizowane są wszystkie zmiany. Ponieważ cała synchronizacja odbywa się w sposób automatyczny, nie są potrzebne żadne zabiegi administracyjne, żeby uszkodzony węzeł stał się znów w pełni funkcjonalny. Omawiana wcześniej biblioteka kliencka również jest zaopatrzona w pewien mechanizm, umożliwiający przełączenie się pomiędzy węzłami bazy danych w przypadku wykrycia usterki jednego z nich. Mechanizm ten nazywa się failover i jest znany z innych systemów rozproszonych jak na przykład MSSQL [30]. Jest bardzo wygodny, gdyż zapewnia ciągłość działania systemu, bez potrzeby modyfikacji kodu aplikacji. W celu skonfigurowania replikacji, na węzłach bazy danych należy dokonać pewnych zmian w pliku konfiguracyjnym. Po pierwsze należy zdefiniować katalog z wtyczkami oraz koniecznie ustawić dostęp anonimowy na All, tak jak przedstawiono w przykładzie na listingu 4. Listing 4: Przykładowa konfiguracja bazy danych RavenDB < appsettings > <add key =" Raven / Port " value ="*"/ > <add key =" Raven / DataDir " value ="~\ Data "/ > <add key =" Raven / AnonymousAccess " value =" All "/ > <add key =" Raven / PluginsDirectory " value ="D:\ RavenDB \ Plugins " /> </ appsettings > Następnie należy skopiować wtyczkę z katalogu Bundles o nazwie Raven.Bundles.Replication.dll, do katalogu zdefiniowanego w poprzednim kroku. Po uruchomieniu serwera powinien pojawić się nowy dokument o nazwie Raven/Replication/Destinations. Dalsza konfiguracja polega na jego edycji. Należy podać w nim serwery, na które dane powinny zostać zreplikowane, tak jak zostało to zilustrowane w listingu 5. Listing 5: Przykładowa konfiguracja dokumentu replikacji { } " Destinations ": [ { " Url ": " replica -a. example. com " } ], "Id ": " Raven / Replication / Destinations " 22

24 Partycjonowanie Kolejnym aspektem związanym z działaniem w środowisku rozproszonym jest partycjonowanie danych pomiędzy różne węzły bazy danych. RavenDB posiada również wsparcie dla tej funkcjonalności. Podobnie jak w przypadku poprzednim, realizowana jest ona poprzez specjalną wtyczkę o nazwie Sharding Bundle [49] [46]. Operacja partycjonowania bazy danych jest istotna z dwóch powodów. Po pierwsze, rozdzielenie danych może mieć pozytywny wpływ na szybkość działania całego systemu. Zapytania nie są kierowane do jednego węzła, lecz ruch w sieci jest bardziej zrównoważony. Drugim powodem bardzo często jest zbyt duża ilość zgromadzonych danych. Pojemność dysków jest ograniczona i biorąc pod uwagę wielkość bazy danych takich portali jak Facebook [65], wydaje się wręcz rzeczą niemożliwą, żeby taka ilość danych przechowywana była na jednym komputerze. Instalacja tej wtyczki jest praktycznie identyczna z instalacją poprzedniej wtyczki. Po pierwsze należy przekopiować odpowiedni plik z wtyczką do katalogu zdefiniowanego w pliku konfiguracyjnym. Następnie należy zdefiniować odpowiedni dokument, mówiący bazie danych, w jaki sposób należy dokonać partycjonowania [46]. Listing 6: Przykładowa konfiguracja dokumentu partycjonowania { // Raven / Sharding / ByUserName " Limits ": [3], " Replica ": 2 " Definitions ": [ { " EntityName ": " Users ", " Paths ": [" Username "] }, { " EntityName ": " Posts ", " Paths ": [" AuthorName "] } ] } W dokumencie tym definiujemy, jakie dokumenty będziemy chcieli partycjonować oraz jakim kluczem powinny być one rozróżniane. Po wykonaniu tej operacji powinniśmy przystąpić do operacji definiowania, gdzie dane partycje powinny zostać zapisywane. Listing 7: Dalsza część konfiguracji partycjonowania { "Id ": " chunks /1", " Shards ": [" http :// shard1 :8080", 23

25 " http :// shard1 - backup :8080"], " Name ": " ByUserName ", " Range ": [" aaa ", " ddd "] } { "Id ": " chunks /2", " Shards ": [" http :// shard1 :8080", " http :// shard2 - backup :8080"], " Name ": " ByUserName ", " Range ": [" ddd ", " ggg "] } { "Id ": " chunks /3", " Shards ": [" http :// shard2 :8080", " http :// shard3 - backup :8080"], " Name ": " ByUserName ", " Range ": [" ggg ", " lll "] } { "Id ": " chunks /4", " Shards ": [" http :// shard2 :8080", " http :// shard1 - backup :8080"], " Name ": " ByUserName ", " Range ": [" lll ", " ppp "] } { "Id ": " chunks /5", " Shards ": [" http :// shard3 :8080", " http :// shard2 - backup :8080"], " Name ": " ByUserName ", " Range ": [" ppp ", " zzz "] } { "Id ": " chunks /6", " Shards ": [" http :// shard3 :8080", " http :// shard3 - backup :8080"], " Name ": " ByUserName ", " Range ": ["000", "999"] } Jak widać, w powyższym przykładzie zdefiniowanych jest sześć punktów podziału oraz sześć serwerów na które dane będą propagowane. Co ciekawe, przykład ten obrazuje również połączenie poprzedniej funkcjonalności z partycjonowaniem. Pokazuje on w jaki sposób możemy podzielić każdy zbiór danych pomiędzy różne serwery oraz jednocześnie zwiększyć bezpieczeństwo przechowywanych danych poprzez replikację danych. Jeśli nasza baza danych jest podzielona za pomocą poprzednio omawianej wtyczki, praktycznie każde zapytanie o dokumenty rozdystrybuowane po różnych węzłach jest zadaniem typu Map/Reduce. Jeśli na przykład tworzymy portal dla bloggerów, gdzie tabela użytkowników jest podzielona pomiędzy dwa serwery, a my potrzebujemy znaleźć ilość użytkowników, którzy posiadają więcej niż dziesięć wpisów, musimy najpierw wykonać to zapytanie na dwóch węzłach bazy (krok Map) natomiast następnie zsumować otrzymane wyniki (krok Reduce) Podsumowanie RavenDB posiada wiele cech wyróżniających go pośród baz danych NoSQL. Po pierwsze, jest w całości stworzony przy pomocy technologii.net. Po drugie posiada wsparcie dla transakcji. Model danych tej bazy, oparty na dokumentach, również bardzo dobrze współgra z obiektowym podejściem większości dzisiejszych języków programowania. Bardzo ciekawym podejściem wydaje się być zastosowanie RESTful API jako podstawowego interfejsu dostępowego. Daje to możliwość łatwej integracji nie tylko z językami opartymi na platformie.net, lecz z każdym, w którym możliwe jest wykonanie zapytania HTTP. Projekt biblioteki klienckiej, oparty głównie na architekturze sprawdzonego rozwiązania, 24

26 jakim jest NHibernate, również okazał się być bardzo dobrym pomysłem. Dzięki niemu jest ona znacznie przejrzystsza i zrozumiała, a co więcej korzysta z doświadczeń dużo bardziej sprawdzonego i przetestowanego rozwiązania. Co więcej, zastosowanie wzorca Unit of work znacznie upraszcza wiele operacji. Warto zauważyć, że w dobie rozwijającego się Entity Framework oraz LINQ2SQL implementacja własnego LINQ Providera jest rzeczą bardzo istotną. Z tego względu dobrze, że RavenDB jest wręcz stworzony w oparciu o tą technologię. RavenDB posiada bardzo ciekawie zaprojektowany system wtyczek. Istnieje bardzo duży zbiór gotowych wtyczek rozszerzających standardowe działanie systemu. W przypadku, gdy nie znajdziemy interesującej nas wtyczki, zawsze możemy spróbować stworzyć taką, która w pełni zrealizuje nasze potrzeby. RavenDB bardzo dobrze radzi sobie w środowisku rozproszonym. Posiada wsparcie dla replikacji oraz partycjonowania danych. Te dwie funkcjonalności są jednymi z najważniejszych w dzisiejszych systemach rozproszonych. Pozwalają one zwiększyć zarówno bezpieczeństwo systemu oraz poprawić jego wydajność. Co więcej, zaimplementowanie w bibliotece klienckiej mechanizmu failover znacznie upraszcza implementacje rozproszonych aplikacji oraz dodatnio wpływa na czas odpowiedzi całego systemu. RavenDB jest bardzo dobrze zaprojektowaną oraz wykonaną bazą danych, która idealnie nadaje się do tworzenia dużych systemów, nastawionych głównie na szybkość oraz bezpieczeństwo przechowywanych danych. 2.2 Cassandra Cassandra w odróżnieniu od RavenDB jest bazą danych typu klucz-wartość. Została ona napisana w języku Java na potrzeby portalu Facebook. Od roku 2008 została przekazana pod opiekę fundacji Apache [21], jednak nadal jest wykorzystywana w Facebook. Cassandra łączy w sobie cechy dwóch najważniejszych baz danych NoSQL, z punktu widzenia wkładu w rozwój tego zagadnienia: Google BigTable oraz Amazon Dynamo. Model danych tego systemu bazodanowego bazuje w dużej mierze na podejściu zaproponowanym przez Google BigTable. Opera się on na uporządkowaniu danych w postaci tabel zawierających klucz i wartość, przy czym wartością mogą być kolejne tabele. Sposób funkcjonowania w środowisku rozproszonym został natomiast zaczerpnięty z bazy danych Amazon Dynamo. Cassandra została zaprojektowana z myślą o bardzo dużej wydajności oraz pracy w środowisku rozproszonym. Wspiera ona wykonywanie zadań Map/Reduce przy pomocy Hadoop. W bardzo wydajny sposób radzi sobie z partycjonowaniem danych oraz ich replikacją na inne węzły bazy danych. Co najważniejsze, Cassandra została zaprojektowana zgodnie z zasadą braku pojedynczych punktów krytycznych systemu. W myśl niej system powinien być zapro- 25

27 jektowany w taki sposób, aby awaria któregokolwiek jego elementu nie powodowała awarii całego systemu Model danych Cassandra jest to baza danych pozbawiona schematu, jaki jest znany z relacyjnych baz danych. Posiada on pewne podobieństwa, jednak w wielu kluczowych elementach się różni. Jest on również zorganizowany w postaci kolumnowej, jednak nie ma wymogu, żeby każdy wiersz posiadał takie same kolumny. Co więcej, wartościami kolumn mogą być również kolumny. Kolumny oraz ich metadane mogą być w każdej chwili działania systemu zmieniane. Podstawowym elementem modelu danych tej bazy jest kolumna. Różni się ona znacznie od kolumny znanej z relacyjnych baz danych. W systemie Cassandra jest to krotka zawierająca trzy wartości. 1. Identyfikator 2. Wartość 3. Stempel czasowy Oprócz standardowej kolumny wyróżniono dodatkowo trzy specjalne rodzaje kolumn. 1. Kolumna wygasająca - Jest to specjalny typ kolumny, z którym związana jest wartość TTL. Informuje ona system po upływie jakiego czasu należy daną kolumnę usunąć. Mechanizm ten działa dobrze dla wartości parametru TTL rzędu sekund, gdyż w przypadku mniejszych wartości, synchronizacja tych kolumn wiązałaby się z dużym narzutem czasowym na sprawdzanie danych oraz synchronizację pomiędzy węzłami w klastrze. Kolumna taka może stanowić dobry nośnik danych, których czas życia jest ograniczony, jak na przykład flaga dotycząca tego, czy użytkownik jest zalogowany lub ziarna sesji. 2. Kolumna zliczająca - Jest ona w stanie zliczać w sposób jednostkowy ilość wystąpień pewnych zdarzeń w systemie, jak na przykład ilość wyświetleń danej strony. Baza danych umożliwia jedynie modyfikację tej kolumny w sposób inkrementalny lub dekrementalny, nie jest możliwe ustawienie explicite wartości tego pola. Ten typ kolumny nadaje się bardzo dobrze w przypadku projektowania bazy danych dla aplikacji społecznościowych, do zliczania ilości zalogowanych użytkowników. 3. Super kolumna - Jest to jeden z najpopularniej stosowanych specjalnych typów kolumn. Cechuje się tym, że jego wartościami mogą być inne kolumny, w szczególności inne super kolumny. Dzięki temu możliwe jest tworzenie wielowymiarowych struktur danych. 26

28 Elementem agregującym kolumny jest rodzina kolumn. W przybliżeniu można ją porównać do tabeli z relacyjnego schematu danych. Każda rodzina kolumn może zawierać dowolną liczbę kolumn, pod warunkiem, że nie przekracza ona dwóch miliardów [13]. Istnieje również ograniczenie co do wielkości danych przechowywanych w kolumnach i wynosi ono 2GB. Biorąc pod uwagę, że nie powinno się w bazie danych przechowywać wartości większych niż parę MB, ograniczenie to nie wpływa negatywnie na możliwości wykorzystania systemu Cassandra. Kolejnym bardzo istotnym elementem modelu danych systemu Cassandra są przestrzenie kluczy. Można je porównać do oddzielnych baz danych w obrębie jednego silnika bazodanowego. Stanowią one pewien pojemnik, w którym tworzone są rodziny kolumn. Co więcej, mechanizm replikacji danych działa w obrębie tej samej przestrzeni kluczy. W tradycyjnej, relacyjnej bazie danych, każda kolumna posiada określony typ. Z tego względu w kolumnie zawierającej jedynie liczby całkowite nie można zapisać danych tekstowych. W systemie Cassandra nie istnieje pojęcie statycznego schematu. Każda kolumna składa się jedynie z trzech wartości: klucza, wartości właściwej oraz stempla czasowego. Jednak podobnie jak w relacyjnych bazach danych są one mocno typizowane. Typ danych wartości przechowywanej w kolumnie lub typ klucza dla kolumny nosi nazwę walidatora. Typ danych nazwy kolumny nosi nazwę komparatora. Zgodnie z zasadą powinno się je podawać podczas tworzenia kolumn, jednak nie jest to wymagane, gdyż domyślnym typem jest ciąg binarny. Cassandra posiada wszystkie najpopularniejsze typy danych, takie jak liczba naturalna int, wartość binarna boolean, ciąg binarny blob czy unikalny identyfikator uuid. Dostarcza również swoich własnych unikalnych typów danych jak counter, który jest stosowany w kolumnach zliczających. Dodatkowo istnieje możliwość zastosowania kompresji rodzin kolumn. Dzięki temu możemy zaoszczędzić bardzo dużo miejsca, jeśli nasze dane w pewien sposób powielają się w obrębie bazy danych. Zgodnie z danymi firmy DataStax, zgromadzonymi w dokumencie [9], kompresja może zwiększyć ogólną wydajność naszej bazy danych nawet o 10%. Co więcej, gdy redukcja wielkości bazy danych jest dwu lub czterokrotna, otrzymujemy 25% 35% przyrost szybkości odczytu oraz 5% 10% przyrost szybkości zapisu. Cassandra wspiera w swoim modelu danych indeksy. Dzięki ich zastosowaniu można znacznie zwiększyć wydajność wyszukiwania oraz sortowania danych. Wyróżniamy dwa rodzaje indeksów w bazie danych Cassandra 1. Indeksy główne - Każda rodzina kolumn w bazie danych posiada główny indeks, obejmujący wartości kluczy kolumn. Tworzony jest on domyślnie przez system bazy danych, każdy z węzłów klastra utrzymuje jego spójność w swoim obrębie. 2. Indeksy pochodne - Indeksy te można tworzyć na wartościach danych kolumn. Należy 27

29 je stworzyć explicite. Znajdują one zastosowanie w sytuacji, gdy chcemy wyszukać lub przefiltrować dane w rodzinie kolumn, nie używając do tego wartości klucza, lecz wartości kolumny. W relacyjnej bazie danych, pomimo małej wydajności takiego rozwiązania, jesteśmy w stanie jako predykat zapytania umieścić dowolną kolumnę tabeli. W celu uzyskania tego samego efektu w systemie Cassandra należy stworzyć indeks pochodny na wartości, którą chcemy odfiltrować. Jeśli projektujemy bazę danych opartą na systemie Cassandra, należy zwrócić uwagę na kilka podstawowych kwestii. Po pierwsze należy pomyśleć najpierw o zapytaniach jakie będą wykonywane na bazie danych, a dopiero później o strukturze kolumn oraz rodzin kolumn. Jest to podejście odwrotne do tego znanego z zarządzania relacyjnymi bazami danych, gdzie zazwyczaj najpierw się myśli o tabelach, następnie o zapytaniach, a ostateczną optymalizację dokonuje się poprzez tworzenie indeksów na odpowiednich tabelach. Model danych systemu Cassandra w inny sposób traktuje indeksy niż relacyjne bazy danych. Częstą praktyką jest tworzenie specjalnych kolumn, których zadaniem jest jedynie filtrowanie pewnych danych. Kolejnym ważnym aspektem jest denormalizacja. W celu osiągnięcia większej prędkości wyszukiwania w bazie danych, bardzo częstą praktyką jest denormalizacja schematu. Utrudnia to zapis danych, jednak znacznie przyspiesza operację wyszukiwania oraz odczytu. Dodatkowo w systemie Cassandra nie występuje operacja JOIN, przez co utrzymywanie bazy danych w postaci znormalizowanej, nie przełożyłoby się w sposób pozytywny na przyrost szybkości działania bazy. Co więcej, należy pamiętać o tym, że w przeciwieństwie do RavenDB, Cassandra nie wspiera zasady ACID w rozumieniu występowania transakcji. Należy samemu dbać o spójność danych po wystąpieniu błędnego zapisu do bazy. Brak transakcji podyktowany jest naciskiem, jaki został położony na wydajność tej bazy danych, która ze względu na swoje pierwotne zastosowanie była znacznie bardziej istotna niż spójność przechowywanych w niej danych Architektura Jak już zostało zaznaczone na wstępie, Cassandra w dużej mierze czerpie z baz danych Google BigTable oraz Amazon Dynamo. Model danych z drobnymi zmianami został przeniesiony z bazy danych Google, natomiast mechanizmy funkcjonowania w środowisku rozproszonym z Dynamo. Ze względu na implementacje w oparciu o język JAVA, Cassandra jest w pełni przenośna pomiędzy różnymi systemami operacyjnymi. Instalacja tego oprogramowania w najprostszym przypadku ogranicza się do dwóch aspektów: 1. Pobrania odpowiedniego środowiska uruchomieniowego platformy JAVA 28

30 2. Pobrania oraz rozpakowania najnowszej wersji programu Cassandra oraz uruchomienia ˆ dla systemu Windows skryptu cassandra.bat ˆ dla systemu Linux skryptu cassandra O bazie danych Cassandra należy myśleć jak o rozproszonym zbiorze niezależnych węzłów klastra. Każdy z nich funkcjonuje na zasadzie peer-to-peer, dzięki czemu brak jest wąskich gardeł w tym systemie. Dowolny węzeł klastra może przestać odpowiadać na żądania, co nie zakłóci działania całego systemu. W systemie Cassandra nie ma wyróżnionych węzłów zajmujących się domyślnie koordynacją pracy systemu. Z tego względu klient może podłączyć się do dowolnego węzła bazy danych i wykonywać operacje dotyczące całej bazy danych. Węzeł taki staje się w tym momencie koordynatorem pomiędzy pojedynczym zapytaniem klienta a resztą bazy danych. Podczas żądania zapisu danych do systemu Cassandra, węzeł będący chwilowym koordynatorem operacji stara się zapisać nowe dane do wszystkich węzłów, które przechowują te dane lub ich kopie replikacyjne. Bardzo istotnym parametrem w tym procesie jest współczynnik spójności danych k. Po wykonaniu operacji zapisu danych węzeł koordynujący czeka na k odpowiedzi od węzłów, na które starał się zapisać dane. Jeśli je otrzyma, klient dostaje powiadomienie o sukcesie operacji. Jak łatwo zauważyć, może to prowadzić do sytuacji, w której przy próbie zapisu do trzech węzłów jedynie dwa odpowiedzą poprawnym zapisem. Przy założeniu współczynnika k = 2 węzeł koordynujący odpowie komunikatem sygnalizującym poprawny zapis, jednak dane w węźle trzecim mogą być niespójne. Sytuację taką można naprawić poprzez zastosowanie specjalnego narzędzia nodetool, które nadpisują niespójne dane wartościami z innych węzłów klastra. Warto zauważyć, że system nie uruchomi go automatycznie, a węzeł z niespójnymi danymi nie może brać udziału w funkcjonowaniu systemu. Operacja odczytu danych z bazy danych Cassandra jest zbliżona do operacji zapisu. Węzeł, do którego aktualnie klient jest podłączony, staje się koordynatorem całej operacji. Dane odczytywane są również niezależnie z różnych węzłów klastra posiadających repliki danych. W przypadku wykrycia braku spójności danych, klientowi przekazywane są dane oznaczone najświeższym stemplem czasowym, natomiast dane niespójne są naprawiane w tle. Protokół Gossip W celu identyfikacji oraz diagnostyki węzłów klastra, postanowiono w tym systemie zaimplementować protokół Gossip. Jest to typ protokołu opartego na założeniach sieci peer-to-peer, w której każdy z uczestników co jakiś czas wymienia się informacjami na swój temat. W szczególności o tym czy dany węzeł klastra działa oraz czy działa wydajnie. Został on opisany dokładnie w pracy [2]. Bardzo istotnym elementem tego protokołu jest zdecentralizowana 29

31 wiedza na temat węzłów sieci. Każdy z nich posiada własną listę węzłów, z którymi powinien się komunikować. Na podstawie danych czerpanych z Gossip, węzły klastra nie kierują swoich żądań do węzłów, o których wiedzą, że są nieosiągalne lub mogą odpowiadać z dużym opóźnieniem. Co ciekawe, każdy węzeł bazy danych wylicza na podstawie specjalnego algorytmu próg czasowy, po którym uznaje, że odpytywany węzeł jest nieosiągalny. Bierze on pod uwagę dane historyczne, dotyczące odpowiedzi badanego węzła w postaci średniej kroczącej oraz obciążenie i konfigurację sieci. Naprawianie uszkodzonego węzła Awaria węzła w klastrze może być spowodowana między innymi awarią sprzętu lub błędem oprogramowania, działającego na tej maszynie. Warto zauważyć, że ma ona bardzo często charakter przejściowy oraz rzadko się zdarza, aby awaria była tak poważna, że wymagana jest całkowita wymiana komputera. Ponieważ węzły klastra odpytują w ramach protokołu Gossip inne węzły, nawet jeśli na podstawie zgromadzonych danych wydają się one być niedziałające. Z tego względu, jeśli węzeł zostanie naprawiony, od razu może wznowić pracę. Warto zauważyć jednak, że elementem, który najczęściej ulega uszkodzeniu w systemach komputerowych jest dysk twardy. Jego wymiana może jednak odbyć się bez większych przerw czasowych w działaniu serwera. Dzisiejsze technologie dysków twardych, takie jak SATA oraz SAS, wykorzystywane w systemach serwerowych umożliwiają wymianę wadliwego sprzętu nawet bez wyłączania maszyny [22]. Jeśli dany węzeł stanie się operacyjny po dłuższym czasie przerwy w działaniu, najprawdopodobniej posiada on niespójne lub przedawnione dane. Tyczy się to zarówno danych operacyjnych oraz danych pochodzących z procesu replikacji. Jeśli dany węzeł zostanie oznaczony jako niedziałający, wszystkie dane, które powinny być na niego zreplikowane zostają zapisane na innych węzłach. Dzięki takiemu zabiegowi można w bardzo szybki sposób przywrócić spójność danych na naprawionym węźle. Podejście to pomimo swojej szybkości ma jedną bardzo istotną wadę. Od momentu faktycznej awarii węzła, do czasu jej wykrycia mija zawsze pewien czas, podczas którego do węzła wysyłane są pewne zapytania. Są one tracone bez zapisania ich na innych węzłach sieci. Z tego względu zaleca się, aby periodycznie uruchamiane było narzędzie nodetool służące do zarządzania węzłami z parametrem repair. Naprawia ono spójność danych na wszystkich węzłach, nawet jeśli część z nich została utracona w opisanym procesie. Narzędzie to powinno być uruchamiane przez skrypty, stworzone przed administratorów systemu. W zależności od obciążenia i awaryjności systemu. W systemie Cassandra każdy węzeł co sekundę wymienia informacje z dowolnymi trzema węzłami na swój temat oraz na temat węzłów, o których posiada informację. Dzięki takiemu 30

32 zabiegowi znacznie zredukowana została ilość zapytań do węzłów sieci. Oprócz wiadomości na temat stanu poszczególnych węzłów, każdy pakiet tego protokołu posiada wersję. Dzięki temu, jeśli jeden z węzłów podczas wymiany informacji otrzyma od dwóch węzłów sprzeczne informacje na temat trzeciego, może w prosty sposób zweryfikować, która z nich jest aktualna. Konfiguracja węzłów Indywidualna konfiguracja każdego węzła decyduje o tym jaką jest on częścią klastra oraz jakie są jego zadania. Podczas startu każdego nowego węzła dokonuje on sprawdzenia, jaka jest nazwa klastra, w którym będzie pracować oraz które z węzłów są oznaczone jako seeds. Lista tych węzłów jest przechowywana w pliku cassandra.yaml, znajdującym się na każdym węźle. Ze względu na spójność protokołu Gossip, ważne jest aby była identyczna dla każdego z nich. Węzły te są pierwszymi, z którymi inne węzły komunikują się podczas wymiany informacji w protokole Gossip. Ich zadanie ogranicza się jedynie do rozpoczęcia wymiany informacji w tym protokole. Kolejnym aspektem na jaki należy zwrócić uwagę podczas konfiguracji klastra są specjalne identyfikatory każdego z nich. Mówią one o tym jakie dane są przechowywane na wybranym węźle. Dzięki wiedzy o swoim identyfikatorze oraz identyfikatorach innych węzłów, każdy z nich może w prosty sposób zlokalizować część danych potrzebną do pracy. Ma to szczególne znaczenie w zagadnieniu partycjonowania danych pomiędzy różne węzły klastra. Istotne jest, aby konfiguracja identyfikatorów została dokonana przed uruchomieniem klastra. Partycjonowanie Cassandra została zaprojektowana z myślą o wbudowanym wsparciu dla partycjonowania oraz redundancji danych. Mechanizm partycjonowania danych jest w pełni konfigurowany przez specjalne obiekty znoszące nazwę partitioner. Są to specjalne klasy języka JAVA, które odpowiadają za strategię dystrybucji danych na różne węzły sieci. W systemie Cassandra o całym zbiorze danych należy myśleć jako o pewnego rodzaju kole. Węzły posiadające pewien podzbiór danych, reprezentowane są poprzez wycinki tego koła o powierzchni proporcjonalnej do ilości przechowywanych danych. Jak już zostało wspomniane wcześniej, każdy z węzłów posiada pewien identyfikator związany z częścią danych, jakie posiada. Ponieważ model danych systemu Cassandra jest zorganizowany w postaci elementów klucz - wartość, podczas partycjonowania dane dzielone są przy użycia klucza każdej kolumny. Jeśli do bazy danych wysłane zostanie zapytanie o dane identyfikowane pewnym kluczem, algorytm ich wyszukiwania zaczyna od węzła o najmniejszej wielkości identyfikatora, a następnie, zgodnie z ich rosnącymi wartościami, wyszukuje 31

33 poprzednik pierwszego węzła o wartości klucza większej niż wyszukiwanych danych. Pewna modyfikacja tego algorytmu jest wykorzystywana przy wyszukiwaniu danych w sytuacji, gdy dane rozproszone są pomiędzy różne węzły różnych klastrów. W tym przypadku węzły są wyszukiwane w ten sam sposób, jednak po osiągnięciu węzła końcowego jednego klastra, algorytm zaczyna wyszukiwać w kolejnym klastrze zaczynając od węzła o najmniejszej wartości identyfikatora. Najważniejsze w tym podejściu jest to aby żadne wycinki koła danych nie nakładały się na siebie w obrębie całej infrastruktury. Istnieje kilka rodzajów wbudowanych w system Cassandra algorytmów partycjonowania danych. Warto jednak zwrócić uwagę, że wybór odpowiedniego sposobu podziału musi być dokonany na początku działania całego systemu, gdyż nie ma możliwości zmiany go bez wyłączania całego systemu. ˆ Pierwszym z wbudowanych algorytmów podziału jest RandomPartitioner. Jest on domyślną strategią oraz jest optymalny dla większości zastosowań. Idea jego działania jest bardzo prosta, przez co niezwykle wydajna. Cały algorytm opiera się na wyliczeniu funkcji skrótu MD5 z klucza. Jak wiadomo MD5 może przyjmować wartości [54]. Cały ten przedział jest dzielony na tyle równolicznych podprzedziałów, ile jest węzłów w sieci. W przypadku, gdy system otrzymuje żądanie odczytu danych identyfikowanych pewnym kluczem, w pierwszym kroku obliczana jest wartość funkcji skrótu dla niego, a następnie, przy pomocy opisanego wcześniej algorytmu, wyszukiwany jest odpowiedni węzeł sieci. Ze względu na fakt, że MD5 daje wartości podlegające w przybliżeniu rozkładowi jednorodnemu, dane są równomiernie rozdystrybuowane po wszystkich węzłach sieci. ˆ Kolejny algorytm podziału danych opiera się na partycjonowaniu według posortowanych wartości klucza każdego wiersza. Dzięki temu w każdym węźle dane są posortowane. Algorytm ten wydaje się być bardzo przydatny jeśli chcemy wykonywać jakieś zapytania opierające się na wyszukiwaniu w danych posortowanych. Nie jest on jednak zalecany przez firmę DataStax, z następujących względów [9] W przypadku, gdy dane są grupowo zmieniane lub wykonywane są zapytania do danych o bliskich wartościach klucza, wszystkie operacje są wykonywane na jednym węźle klastra, znacznie zwiększając jego obciążenie i wydłużając czas odpowiedzi systemu. Rozwiązanie to wymaga od administratorów oraz architektów systemu ręcznego podziału przestrzeni kluczy pomiędzy węzły w klastrze. Jest to bardzo trudne zadanie, gdyż wymaga dokładnej estymacji histogramu takiego rozkładu, co w wielu 32

34 przypadkach jest wręcz niemożliwe. Istnieje bardzo duże prawdopodobieństwo nierównomiernego rozłożenia się danych w klastrze, głównie ze względu na niskie prawdopodobieństwo istnienia takiej samej dystrybucji ilości danych w obrębie jednej rodziny kolumn. Istnieją trzy wbudowane algorytmy, realizujące uporządkowane partycjonowanie danych. ByteOrderedPartitioner - Podczas dokonywania porównania, dane są konwertowane do postaci binarnej oraz analizowana jest ich bitowa reprezentacja. W tym algorytmie nie jest brana pod uwagę semantyka danych, nawet jeśli klucz ma wartość tekstową, jest on konwertowany do ciągu bajtowego, a następnie porównywany z innymi. OrderPreservingPartitioner - Klucze w tym algorytmie muszą być kodowane jako UTF-8, a następnie na podstawie tej reprezentacji dokonywane jest porównanie. CollatingOrderPreservingPartitioner - Działa podobnie do poprzedniego, z tą różnicą, że klucze są porównywane nie na podstawie ich zapisu w UTF-8, tylko zgodnie z zasadami angielskiego porządku alfabetycznego. Replikacja Kolejnym bardzo ważnym zagadnieniem, z punktu widzenia funkcjonowania bazy danych Cassandra, jest replikacja danych. Jest to proces polegający na powielaniu zbiorów danych pomiędzy węzły klastra. Zwiększa on znacznie bezpieczeństwo danych, gdyż w przypadku awarii jednego z węzłów klastra, zawsze istnieje kopia jego danych na jakimś innym węźle. Wybór algorytmu replikacji oraz jego ustawień dokonywany jest już podczas tworzenia przestrzeni kluczy. Najważniejszym parametrem dla tego procesu jest współczynnik replikacji. Liczba ta określa, w ilu niezależnych lokacjach mają znaleźć się dane przechowywane w klastrze. Podobnie jak w przypadku partycjonowania danych istnieje wiele wbudowanych algorytmów replikacji danych. ˆ SimpleStrategy - Jest to domyślna oraz najprostsza strategia. Jeśli na węźle k znajdują się pewne dane, to zgodnie z tym algorytmem zostaną one zwielokrotnione na węzły k + 1, k + 2,..., k + f, gdzie f jest współczynnikiem replikacji. Jak widać wykorzystuje on wiedzę czerpaną z algorytmu partycjonowania danych. ˆ NetworkTopologyStrategy - Jest on znacznie bardziej zaawansowanym algorytmem niż poprzedni, uwzględnia architekturę oraz topologię klastra komputerowego. Dzięki temu 33

35 jest w stanie tworzyć kopie pomiędzy węzłami, które najszybciej ze sobą współpracują lub rozdzielać zbiory kopii bezpieczeństwa pomiędzy różne klastry komputerowe. Jest on rekomendowany w przypadku posiadania bardzo dużego systemu komputerowego, dla którego czas odpowiedzi jest elementem krytycznym. Algorytm ten otrzymuje informacje na temat architektury sieci dzięki pomocy specjalnych modułów, zwanych snitch. Starają się one, na podstawie takich danych jak adres IP komputera, lub plików konfiguracyjnych, określić lokalizację węzła, na którym działają w obrębie całego systemu. W celu poprawienia wydajności klastrów bazy danych Cassandra w środowisku chmury Amazon, zdecydowano się stworzyć specjalny snitch, który jest zoptymalizowany pod usługę EC Biblioteki klienckie Cassandra posiada bardzo bogatą ilość narzędzi dostępowych. Zostało również napisanych wiele bibliotek języków wysokiego poziomu, dzięki którym istnieje możliwość łatwego oraz szybkiego łączenia się z bazą danych w aplikacjach napisanych w takich językach jak PHP, JAVA oraz PYTHON. Pierwszym oraz najważniejszym ze względów historycznych sposobem łączenia się z bazą danych Cassandra jest Thrift API. Jest to biblioteka, dzięki której możemy, w prosty sposób, zdalnie wywoływać procedury pomiędzy programami napisanymi w różnych językach, takich jak C++, JAVA, Erlang czy na przykład JavaScript [17]. Na jej potrzeby stworzony został pewien metajęzyk opisujący serwisy oraz dane wymieniane pomiędzy partycypantami protokołu. Listing 8: Przykład definicji zdalnych metod struct User { 1: i32 id, 2: string login 3: string password } service UserManager { i32 authenticate (1: User user ), User getuserbyid (1: u32 id) } Przykład zaprezentowany na listingu 8 definiuje jedną strukturę, opisującą użytkownika oraz jeden serwis, zajmujący się zarządzaniem użytkownikami poprzez ich autoryzacje oraz pobieranie danych o nich. Jak łatwo zauważyć, język ten jest bardzo podobny składniowo do 34

36 C. Na bazie protokołu Thrift zostało stworzonych wiele bibliotek wysokiego poziomu, ułatwiających prace z bazą danych Cassandra. Jego wykorzystanie w tym obszarze szybko zaczęło jednak dostarczać pewnych problemów [9]. Przede wszystkim, protokół ten jest bardzo nisko poziomowy, co zaczęło generować duże problemy przy wprowadzaniu wsparcia dla najnowszych wersji baz danych pośród wielu bibliotek klienckich, napisanych w różnych językach. Ostatecznie wiele z tych narzędzi przestało poprawnie funkcjonować. Z tego względu powoli zaczęto odchodzić od tego sposobu dostępu bo bazy danych na rzecz nowego, opartego na języku bardzo podobnym do SQL, o nazwie CQL. CQL jest to imperatywny język programowania, oparty w dużej mierze na języku SQL. Został on wprowadzony do systemu Cassandra w wersji 0.8 i od tamtego czasu obserwuje się jego szybki rozwój. Jego aktualna wersja, opatrzona numerem2.0, wprowadziła wiele usprawnień dla niektórych komend oraz jest kompatybilna z wydaniem 1.0 systemu Cassandra CQL umożliwia zarówno modyfikację struktury bazy danych, jak również operacje na samych danych. Posiada on wiele mechanizmów znanych z języka SQL, jak na przykład klauzulę SELECT lub INSERT. Warto zauważyć, że ich zastosowanie nie różni się praktycznie od ich odpowiednika z relacyjnych baz danych. Listing 9: Przykładowe polecenia języka CQL INSERT INTO users ( KEY, login ) VALUES ( cfd66ccc -d857-4 e90 -b1e5 - df98a3d40cd6, user1 ) SELECT * FROM user WHERE KEY IN ( cfd66ccc -d857-4 e90 -b1e5 - df98a3d40cd6, dfd67ccc -d857 -b1e5-4 e90 - df98a3d40cd6 ) Przykłady zaprezentowane na listingu 9 uruchomiłyby się również w środowisku MSSQL oraz ORACLE. Warto zauważyć, że jedyną różnicą pomiędzy CQL a SQL jest część odpowiadająca za DDL (Data Definition Language). Ponieważ w systemie Cassandra nie istnieją tabele, indeksy oraz klucze takie same jak w relacyjnych bazach danych, brak jest poleceń manipulujących nich strukturą. Zamiast tego istnieją polecenia pozwalające na tworzenie przestrzeni kluczy oraz rodzin kolumn. W zakresie manipulacji danymi można przyjąć, że CQL jest niepełnym dialektem języka SQL. Cassandra posiada również narzędzie umożliwiające interaktywne połączenie z bazą danych oraz dokonywanie modyfikacji zarówno struktury bazy danych jak i samych danych w niej zawartych. Nazywa się ono Cassandra-cli i chociaż nie jest przeznaczone do dostępu do bazy danych w warunkach produkcyjnych, jest bardzo użyteczne podczas nauki, projektowania oraz testowania i diagnostyki bazy danych. 35

37 Ostatnią grupę narzędzi dostępowych stanowią biblioteki klienckie. Jak już zostało wspomniane wcześniej, Cassandra posiada ich bardzo wiele, napisanych w praktycznie każdym ważniejszym języku programowania. Pierwszą oraz najważniejszą z nich jest Hector. Jest to biblioteka stworzona w oparciu o język JAVA. Dostarcza wielu usprawnień, których brakuje podczas natywnego korzystania z Thrift API, jak na przykład wielokrotne wykorzystywanie istniejących połączeń, integrację z JMX oraz mechanizm failover. Dodatkowo posiada bardzo duże możliwości konfiguracji poziomu logowania, co niewątpliwie przydaje się podczas rozwiązywania problemów związanych z wydajnością oraz ewentualnymi błędami bazy danych. Zaimplementowano w niej, jako pierwszej bibliotece klienckiej wsparcie dla języka CQL. Kolejną biblioteką jest Phpcassa. Nie jest ona tak zaawansowana jak Hector, posiada jednak wsparcie dla wykorzystywania istniejących połączeń oraz wsparcie dla indeksów wtórnych Podsumowanie Cassandra jest to bardzo dobrze zaprojektowana oraz wykonana baza danych typu NoSQL. Posiada ona bardzo ciekawy model danych oraz rozbudowany model funkcjonowania w środowisku rozproszonym, który w przeciwieństwie do RavenDB jest wbudowany w istotę jej architektury. Model danych oparty jest na zbiorach typu klucz-wartość, znanych z bazy danych Google BigTable. Chociaż może się wydawać bardzo podobny do relacyjnego modelu danych, posiada w sobie dość istotne różnice. Jedną z nich jest brak operacji JOIN oraz pojęcia klucza obcego. Z tego względu, podczas projektowania baz danych w systemie Cassandra, powinno zwracać się uwagę na inne aspekty oraz stosować się do innych zasad. Na przykład zaleca się, aby baza danych była zdenormalizowana. Dzięki temu uzyskujemy znaczne zwiększenie wydajności. Cassandra posiada pewien język zapytań bardzo podobny w swojej naturze do języka SQL. Umożliwia on dokonywanie zmian zarówno organizacji danych, jak również samych danych zgromadzonych w bazie. Jest on bardzo szybko rozwijany, jego najnowsza wersja opatrzona jest numerem 2.0. Istnieje bardzo duża ilość bibliotek klienckich, dzięki którym w prosty oraz szybki sposób możemy stworzyć aplikację wykorzystującą system Cassandra, w większości największych języków programowania, takich jak JAVA oraz PHP. Pomimo tego, że Cassandra nie wspiera transakcji w myśl zasady ACID, to jednak posiada ona wiele mechanizmów zapewniających spójność danych już zapisanych w bazie. Oznacza to, że jeśli podczas zapisu danych wystąpi pewien błąd to baza danych nie gwarantuje ich spójności. Jeśli jednak wszystkie operacje zapisu przebiegną poprawnie, to dane umieszczone w bazie pozostaną spójne. 36

38 W systemie Cassandra położono bardzo duży nacisk na funkcjonowanie w środowisku rozproszonym. Z tego względu posiada ona wsparcie dla algorytmów partycjonowania oraz replikacji danych. Co więcej, mechanizmy te są w pełni konfigurowalne. Można stworzyć własne algorytmy, odpowiadające za podział oraz strategię replikacji danych. 2.3 MongoDB MongoDB, podobnie jak RavenDB, jest bazą danych NoSQL typu dokumentowego. Jest to produkt Open Source, jednak posiada on również wsparcie komercyjne [1]. Został on w całości stworzony w oparciu o C++, dzięki czemu jest w pełni przenośny pomiędzy platformami [34]. Ze strony producenta można pobrać jego wersje zarówno 64 jak i 32 bitową na platformy Linux, Windows, OS X oraz Solaris [35]. Dane w systemie MongoDB zorganizowane są, podobnie jak w przypadku RavenDB, w postaci dokumentów. Są one również zapisywane w formacie pochodnym do JSON, o nazwie BSON. Jest to binarny standard zapisywania dokumentów JSON, którego dokładny opis znajduje się w pracy [6]. Istnieje również pojęcie kolekcji dokumentów, jednak, podobnie jak w przypadku RavenDB, spójność struktury dokumentów w obrębie jednej kolekcji nie jest wymagana. Omawiana baza danych, podobnie jak poprzednie, posiada również wsparcie dla mechanizmu indeksowania. Można utworzyć indeks na dowolnym atrybucie dokumentu, należy jednak pamiętać wtedy, aby każdy dokument w kolekcji posiadał dany atrybut. Dzięki tej funkcjonalności wyszukiwanie danych w bazie MongoDB ulega znacznemu przyspieszeniu. Warto zauważyć, że mechanizm indeksów w omawianym systemie w dużym stopniu przypomina ten znany z relacyjnych baz danych. Dzięki temu, programiści przyzwyczajeni do pracy z systemami takimi jak MSSQL, na pewno w szybkim czasie będą w stanie pracować z indeksami w MongoDB. MongoDB, podobnie jak obydwie omawiane wcześniej bazy danych, posiada wsparcie dla mechanizmu replikacji danych. Może on być wykorzystywany zarówno jako narzędzie zwiększające dostępność danych jak i bezpieczeństwo ich przechowywania. Replikacja w tym systemie odbywa się w sposób asynchroniczny. MongoDB posiada bardzo rozbudowany mechanizm automatycznego partycjonowania danych. Podobnie jak w systemie Cassandra, pozbawiony on jest wąskich gardeł oraz pojedynczych elementów, bez których system nie może funkcjonować. Zostały w nim zaimplementowane algorytmy zapewniające równomierne rozłożenie danych po całym klastrze, jak również gwarantujące możliwość dodania kolejnego węzła bez przerw w działaniu systemu. Jedną z najważniejszych funkcjonalności, jakie musi posiadać baza danych, jest możli- 37

39 wość wyszukiwania interesujących nas informacji oraz filtrowania wyników zapytań. MongoDB posiada bogaty mechanizm formułowania zapytań, bardzo podobny w swojej strukturze do funkcyjnej składni LINQ, znanej z produktu RavenDB. Wiele zapytań z języka SQL w bardzo prosty sposób daje się przełożyć na system wyszukiwania bazy MongoDB. W MongoDB zaimplementowano interesujący mechanizm uaktualniania danych, który oprócz tradycyjnego podmienia całego dokumentu, umożliwia również modyfikację wartości pojedynczych atrybutów. Zmiany te są atomowe, to znaczy, że wykonywane są wszystkie zaplanowane zmiany lub żadna, a system wraca do stanu początkowego. Jest to pewnego rodzaju namiastka systemu transakcji, znanego z relacyjnych baz danych. Omawiana baza danych posiada wsparcie dla przetwarzania opartego o wzorzec Map/Reduce. Co więcej, mechanizm uruchamiania zadań mapujących i agregujących jest bardzo przejrzysty i prosty. Realizowany jest za pomocą jednej metody z biblioteki połączeniowej. Warto nadmienić, że dla MongoDB jest on odpowiednikiem klauzuli GROUP BY znanej z języka SQL. Jedną z funkcjonalności, która wyróżnia MongoDB na tle innych baz danych NoSQL, takich jak Cassandra oraz RavenDB, jest możliwość przechowywania w niej dużych plików. Odbywa się to przy zastosowaniu specjalnego standardu zapisu, o nazwie GridFS, opisanego w pozycji [33]. Dzięki jego wykorzystaniu możliwe jest przechowywanie dużych plików, tak samo, jak przechowywane są dokumenty, bez spadku wydajności całego systemu bazodanowego. Kolejnym bardzo ciekawym elementem, wyróżniającym tę bazę danych na tle innych, jest sposób komunikacji. Powłoka tej aplikacji funkcjonuje jako kompletny interpreter języka JavaScript. Dzięki temu zarządzanie oraz manipulacja danymi zawartymi w bazie sprowadza się de-facto do pisania skryptów w tym języku. MongoDB jest jedną z najczęściej stosowanych baz danych typu NoSQL. Jest wykorzystywany między innymi w takich firmach, jak [36]: ˆ SAP - Jako baza danych dla systemu ECM w ofercie systemu PaaS ˆ MTV - Jako baza danych dla systemu CMS, który w niedalekiej przyszłości będzie zarządzał zawartością wszystkich stron podległych tej stacji telewizyjnej. ˆ SourceForge - Jako baza danych przechowująca informacje o stronie głównej, stronach projektów oraz stronach pobrań każdego z projektów Model danych MongoDB, podobnie jak RavenDB, jest bazą danych o modelu danych opartym na dokumentach. Każdy z dokumentów przechowywany jest w jakiejś kolekcji. Kolekcje są to zbiory 38

40 dokumentów, które powinny w pewien sposób być ze sobą spójne pod względem zawartości danych. Nie ma jednak żadnego odgórnego mechanizmu, sprawdzającego spójność właściwości dokumentów w kolekcji. Kolekcja jest odpowiednikiem tabeli w relacyjnej bazie danych. Co więcej, w przeciwieństwie do kolekcji w systemie RavenDB, gdzie stanowią one jedynie logiczną organizację danych, w systemie MongoDB dokumenty w obrębie jednej kolekcji są fizycznie przechowywane w innych plikach na dysku. Z tego względu podejście oparte na tworzeniu jednej kolekcji dla wszystkich dokumentów nie jest rekomendowane, zarówno z powodów architektonicznych, jak i wydajnościowych. Każdy dokument jest przechowywany w formacie BSON. Jest to format oparty na JSON, który został zastosowany w poprzednio omawianej bazie danych RavenDB. Zgodnie z założeniami tego formatu, każdy dokument typu JSON zostaje specjalnie zakodowany na postać binarną. Niewątpliwą zaletą tego formatu jest brak konieczności konwersji dokumentów z postaci tekstowej do binarnej. Dodatkowo posiada on informacje o typach zapisanych w nim właściwości. Dokumenty zapisane w formacie JSON nie posiadają takich informacji. Wielkość każdego z dokumentów w systemie MongoDB jest ograniczona do 16MB [31]. Warto zauważyć, że nie jest to ograniczenie związane z implementacją tej bazy danych. Ma ono na celu uświadomienie architektowi bazy danych, że jeśli jego projekt zakłada istnienie dokumentów, które przekraczają ten rozmiar, to najprawdopodobniej można go uprościć, a tym samym znacznie przyspieszyć działanie całego systemu. Należy pamiętać, że jeśli dokument miałby rozmiar około 12,5MB, to przy standardowym łączu Ethernet, pobranie go zajmowałoby całą sekundę, co oznaczałoby, że baza danych na sekundę stałaby się z punktu widzenia klientów niedostępna. Jednym z najważniejszych aspektów, na który należy zwrócić uwagę podczas projektowania dokumentowej bazy danych, są relację pomiędzy obiektami. Istnieją dwa sposoby rozwiązywania problemu relacji. Pierwszym z nich jest załączenie jednego dokumentu w drugim. Podejście to sprawdza się bardzo dobrze w przypadku występowania agregatu oraz encji pobocznych. W tym przypadku agregat jest głównym dokumentem, natomiast wszystkie encje towarzyszące są w nim załączone. Podejście takie ma niewątpliwa zaletę, jest bardzo szybkie oraz proste do zaimplementowania po stronie bazy danych. Problem powstaje, jeśli dana encja jest współdzielona pomiędzy różne agregaty lub wręcz jeśli nasz model wymaga połączenia pomiędzy agregatami. W takim przypadku opisane podejście prowadziłoby do duplikacji danych, a w ostateczności do ich niespójności. W celu rozwiązania tego problemu należy zastosować podejście znane z relacyjnych baz danych i odwołać się do drugiego dokumentu poprzez wartość klucza innego dokumentu. Warto pamiętać, że w MongoDB nie występuje operacja JOIN. Z tego względu wszystkie operacje połączenia muszą odbyć się po stronie klienta. Jest to rozwiązanie mniej wydajne oraz cięższe w implementacji, 39

41 ponieważ w dokumentowych bazach danych preferowane jest podejście pierwsze. Co więcej, jeśli zdecydujemy się na rozwiązanie zakładające odwoływanie się do dokumentów poprzez wartość klucza, MongoDB w żaden sposób nie zadba o spójność danych w przypadku, gdy dokument, do którego się odnosimy, zostanie usunięty. Jest to związane z brakiem statycznego schematu właściwości każdego z dokumentów. Jak już zostało wspomniane wcześniej, MongoDB nie wspiera operacji JOIN. Jest to podyktowane wymaganiami wydajnościowymi. Nietrudno sobie wyobrazić sytuację, gdy w rozproszonej bazie danych wykonywana jest operacja połączenia danych z kilku kolekcji rozdystrybuowanych na sto węzłów. Wydajność takiej operacji byłaby nieakceptowalna, nie wspominając o problemach związanych z implementacją takiej funkcjonalności. MongoDB nie wspiera w pełni zasady ACID, jednak dostarcza pewnych mechanizmów, które zapewniają niepodzielność oraz spójność pewnych operacji na danych w obrębie pojedynczego dokumentu. Przykładem może być zmiana wartości właściwości w obrębie jednego dokumentu, w zależności od wartości innych właściwości tego samego dokumentu. Z tego względu należy pamiętać, że jeśli projektowana przez nas baza danych posiada pewne elementy, które wymagają niepodzielności operacji, muszą one odnosić się do tego samego dokumentu. Jeśli zmiany w jednym dokumencie byłyby uwarunkowane danymi znajdującymi się w drugim, brak jest gwarancji, że operacja taka byłaby atomowa. W celu przyspieszenia działania wyszukiwania w bazie danych MongoDB należy wykorzystać mechanizm indeksów. Jest on analogiczny do podejścia znanego z relacyjnych baz danych. Na każdej właściwości w kolekcji dokumentów, po której mamy zamiar wyszukiwać, powinien być założony indeks. Dzięki temu baza danych może wstępnie posortować takie dokumenty, a co za tym idzie, dostęp do nich oraz wyszukiwanie w ich obrębie jest znacznie przyspieszone. Warto zauważyć, że indeksy w bazie danych MongoDB są zorganizowane w strukturę B-drzewa, czyli tak samo jak w większości relacyjnych baz danych. Jest rzeczą niezwykle istotną, aby już na etapie tworzenia bazy danych założyć odpowiednie indeksy. Zakładanie ich podczas działania systemu wiąże się ze znaczącym chwilowym spadkiem wydajności systemu, związanym z koniecznością posortowania danych. Co więcej, indeksy w MongoDB, w przeciwieństwie do mechanizmu indeksowania RavenDB, działają inaczej i domyślnie podczas ich tworzenia uniemożliwiają dostęp do danych. Co prawda istnieje możliwość uruchomienia ich w tle, dzięki czemu przełączenie z kolekcji niezindeksowanej na zindeksowaną następuje dopiero po utworzeniu indeksu, jednak nadal wiąże się to z przeznaczeniem dużej ilości mocy obliczeniowej na sortowanie danych. Podobnie jak w relacyjnych bazach danych, MongoDB zapewnia możliwość utworzenia indeksu obejmującego kilka właściwości na raz. Warto zauważyć również, że indeks taki umożliwia wyszukiwanie oraz sortowanie danych po dowolnym początkowym podzbiorze właściwości 40

42 wchodzących w skład tego indeksu. Istnieje jedna zasadnicza różnica pomiędzy indeksami w relacyjnych oraz dokumentowych bazach danych. Większość relacyjnych baz danych nie umożliwia założenia indeksu na tabeli posiadającej wartości, które mogą przyjąć wartość NULL. Ponieważ dokumentowe bazy danych nie sprawdzają wewnętrznej spójności struktury dokumentów, może istnieć sytuacja, w której do tabeli posiadającej indeks spróbujemy dodać dokument nie posiadający indeksowanej właściwości. Operacja taka powiedzie się jedynie, jeśli indeks został stworzony z opcją sparse. Jest to specjalny rodzaj indeksu, który nie uwzględnia dokumentów nie zawierających indeksowanej właściwości. Warto również zauważyć, że podczas wykonywania zapytania na takim indeksie, dokumenty w danej kolekcji, nie posiadające indeksowanej właściwości, nie zostaną uwzględnione w wynikach. Co więcej, indeks typu sparse nie może zostać utworzony jako indeks zawierający wiele kolumn. MongoDB podobnie jak RavenDB posiada pewien mechanizm zapewniający umieszczanie w bazie danych dużych elementów, przekraczających limit wielkości dokumentu 16MB. Nazywa się on GridFS i umożliwia przechowywanie w systemie danych binarnych, podobnie jak mechanizm załączników umożliwiał to w bazie RavenDB. Istota jego działania jest bardzo prosta i opiera się na podziale danego dużego pliku binarnego na mniejsze części oraz przechowywanie ich tak samo, jakby były one zwykłymi dokumentami. Dzięki temu możliwy jest odczyt danych partiami, co jest wyjątkowo przydatne w przypadku przechowywania na przykład zbiorów filmowych na potrzeby streamingu [57] Architektura MongoDB, podobnie jak dwie poprzednio omawiane bazy danych, składa się z kilku komponentów. Pierwszym oraz najważniejszym z nich jest mongod. Jest to usługa, która odpowiada za działanie bazy danych. Jest ona uruchamiana w trybie daemon w systemach Unix oraz jako Windows Service w systemie Windows. Jest to jedyny komponent niezbędny do działania całego systemu, stanowi on odpowiednik programu mysqld w systemie MySQL. Jest on zdolny do samodzielnego wykonania replikacji danych pomiędzy różne węzły sieci. Kolejnym składnikiem systemu jest mongos. Jest to proces odpowiedzialny za partycjonowanie danych w systemie MongoDB. W pewnym sensie można porównać ten proces do routera, który sprawia, że dla zewnętrznych klientów baza danych wydaje się być tworem spójnym oraz jednorodnym. Bardzo ważnym komponentem, z punktu widzenia administracyjnego, jest interaktywna konsola mongo. Warto wspomnieć, że konsola ta działa jako kompletny interpreter języka JavaScript. Wszystkie komendy bazy danych MongoDB są funkcjami pewnych obiektów tego języka. Jest to cecha niespotykana, jeśli weźmiemy pod uwagę wcześniej analizowane syste- 41

43 my, jednak bardzo ciekawa oraz niezwykle przydatna. Znacznie upraszcza pisanie bibliotek klienckich, gdyż sprowadzają się one jedynie do przetłumaczenia serii komend danego języka na wywołania JavaScript. MongoDB posiada również wiele narzędzi pozwalających na zarządzenie całym systemem, między innymi: ˆ mongoimport - narzędzie pozwalające na import danych do węzła sieci bazy. Dane zawarte powinny być w pliku, w którym na każdą linię przypada jeden obiekt zapisany w formacie JSON/CSV/TSV. Narzędzie to powinno być wykorzystywane do importu danych z niezależnego źródła lub bazy danych MongoDB o innej wersji. ˆ mongoexport - narzędzie pozwalające na eksport danych z węzła sieci bazy. Działa ono w sposób analogiczny do mongoimport. ˆ mongodump - narzędzie pozwalające na stworzenie kopii bezpieczeństwa danych zawartych w bazie, podczas jej działania. W odróżnieniu od mongoexport, plik wynikowy jest binarną reprezentacją całej bazy danych i z tego powodu jego przenośność pomiędzy wersjami bazy danych MongoDB nie jest gwarantowana. ˆ mongorestore - narzędzie pozwalające na przywrócenie stanu bazy danych na podstawie pliku stworzonego przez narzędzie mongodump. ˆ bsondump - jest to bardzo ciekawe narzędzie, które pozwala na konwersję pliku wykonanego przy pomocy mongodump na format BSON Biblioteki klienckie Biblioteki klienckie w nomenklaturze MongoDB nazywają się drivers i dzielą się na dwie grupy. Pierwszą z nich stanowią biblioteki posiadające oficjalne wsparcie producentów bazy danych. W ich skład wchodzą biblioteki stworzone dla takich języków programowania jak: C, C++, Erlang, Haskell, Java, JavaScript, C#, Perl, PHP, Python, Ruby, Scala [32]. Kolejną grupę tworzą biblioteki stworzone przez społeczność MongoDB. Nie posiadają one gwarancji producenta ani nie są oficjalnie wspierane, jednak można wśród nich znaleźć wersję dla praktycznie każdego znanego języka programowania. Ze względu na dużą ilość bibliotek klienckich postanowiono poddać analizie jedną z nich. Jako przykład postanowiono wybrać bibliotekę stworzoną dla platformy.net. Wybór taki został podyktowany możliwością porównania tej biblioteki z biblioteką dostępową, stworzoną dla RavenDB, która również oparta była o technologię.net. 42

44 Biblioteka ta składa się z dwóch głównych komponentów. Pierwszym z nich jest MongoDB.Bson.dll. Jest on odpowiedzialny za wszystkie operacje, wykorzystujące format BSON. Drugim z nich jest MongoDB.Driver.dll. Zawiera on w sobie wszystkie klasy niezbędne do połączenia oraz transmisji danych pomiędzy klientem a bazą danych MongoDB. Dostęp do danych zgromadzonych w bazie danych może być realizowany w dwojaki sposób, wykorzystujący serializację obiektów typu POCO do BSON lub nie. Jeśli zdecydujemy się wykorzystać drugi sposób, który na początku może wydawać się znacznie prostszy niż pierwszy, należy zwrócić szczególną uwagę na klasę BsonDocument. Reprezentuje ona pojedynczy dokument BSON, który chcemy zapisać do bazy danych. Na listingu 10 zaprezentowano przykład stworzenia dokumentu z zagnieżdżonym innym dokumentem. Listing 10: Przykład stworzenia dokumentu z zagnieżdżonym innym dokumentem BsonDocument worker = new BsonDocument { { " name ", " Joe Celco " }, { " address ", new BsonDocument { { " street ", "24 oak lane " }, { " city ", " leeds " } }} }; Jak widać, konstrukcja ta bardzo przypomina tworzenie klas implementujących interfejs IDictionary<K, V>. Podejście to posiada jednak dwie bardzo duże wady. Pierwszą z nich jest brak jakiegokolwiek sposobu sprawdzenia, czy przy dodawaniu dokumentów do kolekcji nie popełniliśmy literówki, skutkującej dodaniem dokumentu z niepoprawną właściwością. W przypadku wykorzystania obiektów typu POCO, nie ma takiej możliwości, ze względu na mocną typizację kodu kompilowanego. Kolejną wadą tego typu rozwiązania jest brak silnego typizowania. Pod właściwość name z przykładu możemy podstawić właściwie dowolną wartość. Może to sprawiać dużo problemów podczas odczytu danych z bazy. Następną wadą tego rozwiązania jest konieczność stosowania tak zwanych magicznych łańcuchów znaków, opisujących nazwy właściwości, co czyni kod mniej przejrzystym oraz czytelnym. Rozwiązaniem tego problemu mogłoby być wykorzystanie obiektu DynamicObject, który został wprowadzony do.net 4.0. Stworzenie klasy obudowującej BsonDocument, opartej na DynamicObject, dałoby nie tylko możliwość tworzenia encji bez użycia magicznych łańcuchów, lecz również umożliwiłoby sprawdzenie, w czasie wykonania programu, czy programista nie popełnił literówki. Co więcej, jeśli cały kod zapisujący dane do bazy zostałby objęty testami jednostkowymi, sprawdzenie poprawności nazw mogłoby odbywać się jako warunek konieczny powodzenia procesu kompilacji. 43

45 Kolejną bardzo istotną klasą, z punktu widzenia komunikacji z bazą danych, jest klasa MongoServer. Modeluje ona połączenie z bazą danych MongoDB. Za jej pomocą możemy pobrać kolekcję dokumentów, jak również wykonać niektóre czynności administracyjne. W celu dodania elementu do kolekcji musimy wykorzystać klasę MongoCollection<T>. Jej instancje możemy otrzymać poprzez wykorzystanie metody.getcollection<bsondocument>(), klasy MongoServer. Klasa reprezentująca kolekcje posiada komplet metod odpowiedzialnych za zapis, odczyt oraz wyszukiwanie danych w obrębie kolekcji. MongoDB posiada wsparcie dla serializacji obiektów do formatu BSON. Jest to alternatywny sposób dostępu do dokumentów, dzięki któremu nie musimy wykorzystywać klasy BsonDocument, tylko możemy operować na encjach. W celu skorzystania z serializacji musimy utworzyć mapowania właściwości encji na właściwości dokumentów. Proces ten bardzo przypomina tworzenie mapowania relacyjno-obiektowego, które znamy z bibliotek ORM, takich jak na przykład NHibernate. Istnieją dwie metody tworzenia mapowań. Pierwszą z nich jest zastosowanie możliwości automatycznego mapowania, opartego na systemie modyfikowalnych konwencji. Podejście to jest bardzo podobne do tego zastosowanego w bibliotece FluentNHibernate. Drugą z nich jest stworzenie mapowań za pomocą specjalnych atrybutów, dekorujących właściwości w klasach. Podejście takie również jest umożliwiane przez większość bibliotek typu ORM, w szczególności NHibernate. Warto zauważyć, że zarówno pierwszą, jak i drugą metodą można utworzyć kompletne mapowanie. Jak widać, architektura biblioteki klienckiej MongoDB różni się znacznie od tej przyjętej na potrzeby RavenDB. Po pierwsze, RavenDB nie umożliwia dostępu do dokumentów w postaci słownikowej. Po drugie, jest on oparty na interfejsach, klasach implementujących te interfejsy oraz fabrykach. Podejście takie znacznie upraszcza tworzenie testów jednostkowych oraz pozytywnie wpływa na możliwość rozbudowy biblioteki oraz przejrzystość kodu Funkcjonowanie w środowisku rozproszonym Podobnie jak poprzednio omawiane bazy danych, MongoDB bardzo dobrze działa w środowisku rozproszonym. Posiada wbudowane wsparcie dla mechanizmu partycjonowania oraz replikacji danych. Co więcej, pozwala w bardzo prosty sposób uruchamiać zadania typu Map/Reduce. Replikacji w bazie danych MongoDB można dokonać na dwa sposoby. Pierwszy z nich, znacznie starszy i mniej wydajny, opiera się na replikacji danych pomiędzy jednym arbitralnie wybranym węzłem typu master oraz slave. Nie jest on zalecany do wykorzystywania w nowych projektach, gdyż został zastąpiony nowym oraz lepszym mechanizmem, opartym o tak zwane Replica Sets. Jest to forma asynchronicznej replikacji danych pomiędzy co najmniej 44

46 dwoma węzłami klastra. Dzięki nim zapewnione jest odtworzenie zawartości bazy danych w przypadku awarii jednego z węzłów oraz automatyczne przełączenie pomiędzy węzłami, tak zwany failover. Warto zauważyć, że wybór jednostki master oraz slave dokonuje się w sposób automatyczny i domyślnie nie wymaga konfiguracji. Jest to opcja bardzo wygodna oraz znacznie ułatwiająca administrowanie systemem. Jak już zostało wspomniane wcześniej, mechanizm partycjonowania danych jest bardzo ważny zarówno z przyczyn wydajnościowych jak i zwiększenia bezpieczeństwa oraz szybkości odpowiedzi systemu. Uruchomienie mechanizmu partycjonowania składa się z dwóch zasadniczych kroków. Pierwszym z nich jest poprawna konfiguracja mechanizmu Replica Set, tak, aby dane były odpowiednio rozdystrybuowane w obrębie klastra. Warto zauważyć, że dodatkowo należy zmienić priorytety węzłów tak, aby z góry dało się określić, która jednostka będzie typu master, a która slave. Po odpowiednim skonfigurowaniu mechanizmu Replica Set należy włączyć mechanizm partycjonowania za pomocą funkcji admincommand z parametrem addshard. MongoDB posiada bardzo prosty oraz przydatny mechanizm uruchamiania zadań typu Map/Reduce. Warto pamiętać, że ze względu na rozdystrybuowanie danych pomiędzy różne węzły klastra, nie jest możliwe wykonanie operacji znanej z SQL o nazwie GROUP BY. Zamiast tego uruchamiane są zadania Map/Reduce, które zbierają dane z różnych węzłów. Uruchomienie tego typu zadania w omawianym systemie sprowadza się do odpowiedniego wywołania metody mapreuce, obecnej w każdym obiekcie reprezentującym kolekcje. Jako argumenty tej metody muszą być podane dwie funkcje. Pierwsza z nich za pomocą wywołań metody emit ma za zadanie dokonać projekcji danych. Druga z nich za pomocą zwykłej komendy return ma za zadanie dokonać agregacji danych. Istnieje możliwość podania trzeciej metody, która dokona dodatkowych modyfikacji w zbiorze wyjściowym. Wartością zwracaną przez metodę mapreduce jest wynik działania operacji agregacji Podsumowanie MongoDB jest bardzo dobrze zaprojektowanym oraz działającym systemem bazodanowym. Dane w niej zebrane są przechowywane w postaci dokumentów. Jako wewnętrzny format przechowywania danych projektanci zdecydowali się wykorzystać format BSON, który łączy w sobie zalety przenośności formatu JSON z wydajnością formatów binarnych. Baza ta oferuje bardzo wiele metod dostępowych. Konsola, pozwalająca na manipulację danymi oraz uruchamianie zadań administracyjnych, została stworzona jako interpreter języka JavaScript. Jest to pomysł bardzo oryginalny, jednak ogromnie upraszczający korzystanie z bazy danych oraz tworzenie bibliotek dostępowych. Istnieje bardzo duża ilość bibliotek klienckich dla każdego bardziej popularnego języka programowania. Duża część z nich ma 45

47 oficjalne wsparcie producenta. Koleją bardzo istotną zaletą bazy danych MongoDB jest bardzo obszerna i wyczerpująca dokumentacja. Program ten posiada wsparcie komercyjnej firmy oraz bardzo szerokie grono zwolenników oraz deweloperów, którzy wkładają wiele wysiłku w ulepszanie tego produktu. Jest to jeden z powodów, dla których MongoDB działa jako baza danych w takich firmach jak: Disney, MTV oraz SourceForge. MongoDB bardzo dobrze radzi sobie z funkcjonowaniem w środowisku rozproszonym. Posiada wbudowane wsparcie dla mechanizmu replikacji oraz partycjonowania danych. Umożliwia uruchamianie w prosty sposób zadań typu Map/Reduce. Co więcej, dzięki zastosowaniu języka JavaScript jako interfejsu komunikacji, metody projekcji oraz agregacji danych mogą być w nim stworzone. 2.4 Podsumowanie Bazy danych typu NoSQL stanowią bardzo szerokie pole badań. Różnią się od siebie pod bardzo wieloma względami, jednak aspektem, który je wszystkie łączy, jest odrzucenie zastosowania modelu relacyjnego przy projektowaniu modelu danych. Zamiast tego implementują one model dokumentowy, obiektowy lub zorganizowane są w postaci wielkich zbiorów typu klucz - wartość. W pracy tej dokładnie przeanalizowano trzy bazy danych typu NoSQL: RavenDB, MongoDB oraz Cassandra. Każda z nich różniła się od pozostałych w bardzo istotnych aspektach, jak między innymi, model danych, podejście do funkcjonowania w środowisku rozproszonym oraz ilość i różnorodność bibliotek klienckich. Podstawowe porównanie zbiorcze zostało przedstawione w tabeli 2. Po dokonaniu analizy oraz zaimplementowaniu testów z rozdziału Analiza wydajnościowa, okazało się, że model dokumentowy jest znacznie bliższy modelowi obiektowemu. Zapis obiektowych encji do dokumentowej bazy danych odbywał się praktycznie automatycznie. Dzięki temu zachowana była dużo większa przejrzystość kodu oraz łatwość implementacji. Wykorzystanie bazy danych Cassandra było odrobinę bardziej problematyczne, gdyż wymagało zastosowania mapowania pomiędzy właściwościami encji a kolumnami w tabeli. Najbardziej rozbudowane wsparcie dla platformy.net posiadały bazy danych RavenDB oraz MongoDB. Ta ostatnia posiadała również znacznie bogatszy zasób metod optymalizujących korzystanie z bazy danych. Obydwie posiadały zaimplementowane własne mechanizmy tłumaczenia zapytań LINQ na wewnętrzny mechanizm wyszukiwania danych. Dzięki temu pozyskiwanie danych z bazy mogło być realizowane w bardzo prosty sposób. Wszystkie trzy bazy danych posiadały wsparcie dla indeksowania danych. Warto zauważyć, 46

48 że możliwość indeksowania danych jest kluczowa z punktu widzenia szybkości wyszukiwania danych w bazie. Nie we wszystkich bazach danych mechanizm ten działał jednak w ten sam sposób. Baza danych RavenDB posiada mechanizm indeksowania w tle. Dzięki temu, za cenę nie zawsze spójnego indeksu, otrzymuje się przyspieszenie zapisywania danych. Wszystkie analizowane bazy danych posiadały bardzo szerokie wsparcie dla funkcjonowania w środowisku rozproszonym, jednak najlepiej problem ten został rozwiązany w systemie Cassandra. Jest ona oparta na modelu zaproponowanym przez Amazon Dynamio i cechuje się brakiem wąskich gardeł i wieloma ciekawymi strategiami replikacji oraz partycjonowania danych. Posiada również bardzo szerokie możliwości rozbudowy tych strategii oraz zastosowanie własnych, działających w zupełnie inny sposób. 47

49 RavenDB MongoDB Cassandra Model danych dokumentowa dokumentowa klucz - wartość Wyszukiwanie danych LINQ szereg metod filtrujących bardzo rozbudowany język, podobny do SQL - CQL Indeksowanie danych na bazie zapytań indeksy przeliczane indeksy przeliczane LINQ przeliczanych synchronicznie synchronicznie asynchronicznie w tle Wsparcie dla transakcji całkowite częściowe brak Partycjonowanie po zainstalowaniu wbudowane wbudowane - możliwość danych wtyczki stworzenia wła- snych strategii partycjonowania Replikacja danych po zainstalowaniu wbudowane wbudowane - możliwość wtyczki stworzenia wła- snych strategii replikacji Wsparcie dla zadań wbudowane poprzez wykonywanie wbudowane - dodatkowa typu Map/Reduce kodu JavaScript na możliwość zdalnych węzłach podłączenia do klastra Hadoop Język implementacji C# C++ Java Oficjalne API dla tak tak nie.net Typ licencji Open Source (płatne do zastosowań komercyjnych) Open Source (bezpłatne dla zastosowań komercyjnych) Open Source (bezpłatne dla zastosowań komercyjnych) Tabela 2: Analiza zbiorcza wybranych baz NoSQL 48

50 3 Projekt systemu bazodanowego InDB Rozdział ten ma na celu opisanie autorskiego systemu bazodanowego o nazwie InDB, który został stworzony jako przykład podejścia NoSQL w zastosowaniach przemysłowych. Podejście do przechowywania oraz zarządzania danymi, prezentowane przez większość baz danych typu NoSQL, niesie za sobą bardzo wiele pozytywnych konsekwencji. Jedną z nich jest bardziej obiektowe spojrzenie na przechowywanie danych, znane z dokumentowych baz danych. Dzięki niemu znacznie zmniejsza się między innymi czas tworzenia aplikacji oraz wzrasta poziom ich poprawności poprzez wyeliminowanie konieczności stosowania bibliotek typu ORM. Praktycznie wszystkie bazy danych typu NoSQL zostały stworzone z myślą o systemach webowych oraz aplikacjach wymagających dystrybucji danych na wiele węzłów. Większość z nich posiada bardzo dobrze zaprojektowane mechanizmy, umożliwiające im działanie w warunkach systemu rozproszonego. Brak im jednak w większości algorytmów zapewniających deterministyczny dostęp do spójnych danych. RavenDB pomimo zastosowania mechanizmu transakcji, dopuszcza istnienie niepełnych indeksów. MongoDB pomimo synchronicznego mechanizmu tworzenia indeksów nie dostarcza mechanizmów umożliwiających tworzenie transakcji. Ze względu na wyżej wymienione rozwiązania architektoniczne, żadna z analizowanych baz danych nie nadaje się w pełni do zastosowania w warunkach przemysłowych, takich jak akwizycja danych pomiarowych lub przechowywanie historycznych danych procesu. Najważniejszym aspektem dla tego typu zadań jest bezpieczeństwo, rozumiane poprzez trwałość danych, w połączeniu z szybkim dostępem do nich. Z tego względu zdecydowano się stworzyć bazę danych typu NoSQL, która byłaby zorientowana na działanie w środowisku przemysłowym. Nastawiona byłaby ona przede wszystkim na bezpieczeństwo przechowywanych danych, w połączeniu z szybkością w dostępie do nich. Dodatkową zaletą tworzonego systemu byłoby zachowanie prostego mechanizmu dostępu do danych, dzięki któremu niepotrzebne byłoby tworzenie skomplikowanych systemów mapowania właściwości obiektów z dziedziny aplikacji na odpowiednie pola lub komórki bazy danych. Rozdział ten został zorganizowany w podrozdziały, które opisują kompletny proces rozwoju bazy danych InDB. Zostały one zaczerpnięte z kaskadowego modelu życia oprogramowania, dogłębnie opisanego w książce [20] i bardzo dobrze oddają proces tworzenia programu komputerowego. 49

51 3.1 Specyfikacja wymagań Jedną z ważniejszych faz rozwoju oprogramowania jest specyfikacja wymagań. Jest to część inżynierii oprogramowania, która dostarcza nam środków oraz metod umożliwiających zebranie informacji na temat przyszłej funkcjonalności tworzonej przez nas aplikacji lub systemu komputerowego. Warto zauważyć, że popełnienie błędu w tej fazie projektu jest najbardziej kosztowne. Szacuje się, że w modelu kaskadowym błąd popełniony we wcześniejszym kroku propaguje się na kolejne w sposób wykładniczy o podstawie dziesięć. Ze względu na to, że jest to pierwsza faza projektu, błędy w niej popełnione propagują się najbardziej. Dodatkowo, jeśli stworzymy złą specyfikację wymagań, możemy przez cały czas przeznaczony na projekt tworzyć aplikacje, która nie odpowiada potrzebom klienta oraz środowiska. Z tego względu, pomimo przeznaczenia znacznych środków, klient nie otrzyma produktu, którego potrzebował. Jednym z lepszych sposobów usystematyzowania wymagań jest zebranie ich oraz zaprezentowanie w postaci tabelki. Tabela 3 jest realizacją tej koncepcji. Podzielona jest ona na trzy kolumny. W pierwszej z nich zamieszczona została skrótowa nazwa stawianego przed projektowaną baza wymagania. Druga zawiera bardziej szczegółowy opis wraz z uzasadnieniem. Ostatnia ocenia jak bardzo istotna jest dana funkcjonalność dla poprawnego działania tworzonej bazy. Nazwa skrótowa Opis oraz uzasadnienie Poziom istotności Implementacja CRUD Implementacja tych operacji jest jedną z najważniejszych funkcjonalności jakie baza danych powinna posiadać. Dzięki nim możliwe jest dodawanie, odczytywanie oraz modyfikacja danych zawartych w bazie. Bez tej funkcjonalności niemożliwe byłoby zarządzanie danymi zgromadzonymi w bazie. Bardzo istotnym jest również, aby operacje te, dla zachowania spójności bazy, były atomowe. Niezbędne 50

52 Architektura oparta o model klient - serwer Brak potrzeby mapowania obiektoworelacyjnego Szybki dostęp do danych, wydajność zapisu oraz odczytu Rozproszenie danych na wiele węzłów w sieci Aplikacja musi być podzielona na część klienta, czyli biblioteki, którą można wykorzystać w jakiejś innej aplikacji oraz serwera, działającego jako usługa, w sposób nieprzerwany oraz niezależny. Dzięki takiemu podziałowi oraz opracowaniu protokołu komunikacji pomiędzy stronami możemy uzyskać dwa oddzielne podsystemy, które mogą być rozwijane niezależnie. Dzięki zastosowaniu modelu danych, nie wymagającego stosowania rozbudowanego mapowania obiektowo - relacyjnego, możliwym będzie znaczne skrócenie czasu implementacji aplikacji korzystających z systemu InDB. Wydajność jest bardzo ważnym aspektem każdej bazy danych. Tworzony system również powinien być wydajny, jednak nie jest to jego najważniejsza cecha. Wydajność powinna być na poziomie innych rozwiązań tego typu dostępnych na rynku. Wydajność, oprócz efektywnej implementacji, można zwiększyć poprzez rozproszenie aplikacji na różne maszyny. Dzięki tej funkcjonalności możliwym będzie instalacja bazy danych na wielu węzłach sieci. Warto zauważyć, że oprócz wzrostu wydajności systemu, zyskujemy również zwiększenie bezpieczeństwa przechowywanych danych, poprzez fakt kopiowania informacji na wiele niezależnych komputerów. Niezbędne Bardzo ważne Bardzo ważne Bardzo ważne 51

53 Wydajność dla dużej ilości krótkich zapytań Transakcje Łatwość instalacji Bardzo często systemy automatyki generują wiele niezależnych od siebie sygnałów. Mogą to być różnego rodzaju alarmy lub odczyty. Charakterystyką tych informacji jest to, że są one bardzo małe pod względem ilości pamięci potrzebnej na ich utrwalenie oraz pojawiają się bardzo często. Z tego względu projektowana baza danych musi być nastawiona na efektywne przetwarzanie krótkich zapytań. Ważnym aspektem każdej bazy danych jest spójność oraz integralność danych. Jest to bardzo istotne zwłaszcza w zastosowaniach przemysłowych. Jednak transakcje, jakie znamy z relacyjnych baz danych, dotyczą głównie zapisu większych porcji danych oraz uaktualniania danych powiązanych. Dzięki temu, że operacje CRUD w systemie InDB muszą być atomowe oraz nastawiona ona będzie na przetwarzanie małych porcji danych, implementacja kompletnego systemu transakcyjnego nie jest elementem najbardziej istotnym. Ważnym jest aby system InDB był prosty w instalacji. Wiele z analizowanych systemów typu NoSQL, pomimo bardzo dużych możliwości, jest bardzo trudna w instalacji. Z tego względu często są one zainstalowane oraz skonfigurowane nieoptymalnie. Dzięki prostemu systemowi instalacji InDB będzie pozbawiony tego mankamentu. Ważne Ważne Ważne Tabela 3: Wymagania stawiane systemowi InDB Na bazie wymagań zgromadzonych w tabeli 3 stworzono projekt systemu InDB. Został on dokładnie opisany w kolejnym rozdziale. 52

54 3.2 Projekt Rozdział ten szczegółowo opisuje projekt systemu InDB. Zawiera on wszystkie niezbędne schematy oraz diagramy klas, które stanowią punkt wyjścia dla implementacji tworzonego systemu. Punktem wyjścia dla projektu były wymagania zgromadzone w tabeli Model danych Najważniejszym aspektem, który musi zostać zaprojektowany na wstępie, jest model danych. Zależy od niego projekt biblioteki klienckiej oraz serwera. Wybranie nieoptymalnego modelu może skutkować skomplikowaniem projektu oraz zmniejszeniem wydajności ostatecznego wyniku implementacji bazy danych InDB. Po przeanalizowaniu modeli danych opisywanych wcześniej systemów, zdecydowano się, że w projektowanej bazie danych zastosowany zostanie model dokumentowy. Jest on najbardziej zbliżony do modelu obiektowego, dzięki czemu spełnione zostanie założenie o braku konieczności dokonywania skomplikowanego mapowania obiektowo - relacyjnego, podczas pisania aplikacji wykorzystujących tworzony system. Jak pokazują przeprowadzone w kolejnym rozdziale badania, baza danych MongoDB jest najszybsza w zapisywaniu dokumentów oraz ich kasowaniu. Pokazuje to, że dokumentowy model danych może zostać zaimplementowany w bardzo wydajny sposób. Podobnie jak RavenDB oraz MongoDB, projektowana baza danych nie będzie posiadała statycznego schematu. W celu usystematyzowania danych każdy dokument będzie przynależał do pewnej kolekcji dokumentów. Nazwa tej kolekcji będzie równoważna z typem dokumentu, jednak ze względu na brak schematu dokumenty w obrębie jednej kolekcji mogą mieć zupełnie inną strukturę oraz pola. Co więcej, każdy dokument będzie składał się z dwóch części. Pierwszą z nich stanowią dane zapisane przez użytkownika. Są one całkowicie dowolne i nie podlegają analizie dokonywanej przez serwer. Drugą z nich stanowi specjalny zbiór metadanych, które baza powinna przechowywać na temat każdego dokumentu. Do tego zbioru zaliczyć można informacje na temat stworzenia dokumentu, ostatniej modyfikacji oraz, co najważniejsze, specjalnego identyfikatora dokumentu. Należy pamiętać, że każdy dokument powinien być identyfikowalny na podstawie unikalnego numeru. Ma to bardzo duże znaczenie zwłaszcza podczas projektowania protokołu oraz biblioteki klienckiej. Co więcej, dzięki wprowadzeniu liczbowego identyfikatora dostęp do indywidualnych dokumentów można znacznie przyspieszyć. Model dokumentowy ma wiele zalet. Pierwszą z nich jest jego przejrzystość. W związku z tym, że większość dokumentów w analizowanych bazach danych jest identyczna z modelami 53

55 Rysunek 3: Schemat architektury projektowanego systemu encji aplikacji, przeglądanie danych zgromadzonych w bazie jest bardzo proste. Co więcej, jest on zoptymalizowany pod kątem agregacji dokumentów. W relacyjnej bazie danych, aby otrzymać połączenie wielu tabel należy dokonać operacji JOIN. W dokumentowej bazie danych struktura dokumentów może być drzewiasta. Z tego względu, zamiast wykonywać operacje złączenia, wystarczy pobrać dokument będący korzeniem szukanego drzewa Protokół komunikacyjny Jednym z najważniejszych założeń tworzonego systemu był wyraźny podział na część kliencką oraz serwerową. Dzięki niemu projekt oraz implementacja obydwu podsystemów mogłyby odbywać się niezależnie. Rysunek 3 obrazuje ogólną architekturę projektowanego systemu. Strzałki na rysunku mają swój początek zawsze w jednostce inicjującej komunikację, natomiast grot w komponencie docelowym i obrazują, który komponent jest typu master, a który slave. Jak widać system dzieli się on na część kliencką, odpowiedzialną za połączenie z serwerem oraz przetwarzanie danych po stronie aplikacji klienckiej oraz część serwerową, odpowiedzialną za koordynację operacji, replikacje danych oraz zarządzanie transakcjami. Warto zauważyć, że jedynym wspólnym aspektem obydwu podsystemów jest protokół komunikacyjny. Umożliwia on wykonanie wszystkich opisanych w założeniach operacji, przy zachowaniu najprostszej specyfikacji. Ze względu na przeznaczenie powinien on być zaimplementowany na bazie mechanizmu zdalnego wywoływania procedur [63], przy czym technologia realizująca tego typu operacja powinna być niezależna od wybranej technologii implementacji. Dzięki temu klient oraz serwer mogą być, w razie potrzeby, napisane w zupełnie innych 54

56 językach. Ma to szczególne znaczenie, jeśli chcemy, aby istniała możliwość napisania oprogramowania klienckiego dla więcej niż jednej platformy. Projektowany protokół powinien umożliwiać wykonanie następujących operacji. ˆ Get - Operacja ta na podstawie typu kolekcji, umożliwiałaby pobranie wszystkich dokumentów wraz z ich identyfikatorami. ˆ GetById - Operacja ta na podstawie dostarczonego identyfikatora dokumentu, zwracałaby jego zawartość. ˆ Save - Operacja ta na podstawie identyfikatora dokumentu, jego typu oraz zawartości, umożliwiałaby jego zapis lub modyfikację. ˆ Remove - Operacja ta na postawie identyfikatora dokumentu oraz jego typu, kasowałaby jego zawartość z bazy danych. ˆ DropCollection - Operacja ta na podstawie typu kolekcji kasowałaby jej całą zawartość. ˆ BeginTransaction - Operacja ta rozpoczynałaby transakcję dla aktualnego połączenia. ˆ RollbackTransaction - Operacja ta cofałaby wszystkie zmiany dla aktywnej transakcji połączenia. ˆ CommitTransaction - Operacja ta zatwierdzałaby wszystkie zmiany dla aktywnej transakcji połączenia Biblioteka kliencka Po ustaleniu modelu danych oraz protokołu komunikacyjnego, kolejnym krokiem jest zaprojektowanie biblioteki klienckiej. W celu ułatwienia korzystania z projektowanej biblioteki powinna ona wzorować się na już istniejącym, sprawdzonym rozwiązaniu. Dzięki temu będzie ona bardziej przejrzysta oraz zrozumiała dla nowych programistów korzystających z systemu InDB. Zdecydowano, że będzie ona wzorować się na bibliotece NHibernate, podobnie jak w systemie RavenDB. Dzięki dużej popularności tej biblioteki oraz doświadczeniu jej deweloperów jest ona bardzo dobrze zaprojektowana oraz wykonana. Dodatkowo, dzięki wykorzystaniu interfejsów, programy stworzone przy jej pomocy są znacznie prostsze w testowaniu. Ma to szczególne znaczenie przy projektowaniu aplikacji zgodnie z metodologią TDD. Rysunek 4 obrazuje główne interfejsy, które powinny zostać stworzone w bibliotece klienckiej. Głównym obiektem zapewniającym połączenie z bazą danych jest obiekt ISession. Umoż- 55

57 Rysunek 4: Główne interfejsy biblioteki klienckiej liwia on wywołanie każdej metody z protokołu komunikacyjnego. W szczególności odpowiada za rozpoczynanie transakcji, pobieranie danych oraz ich modyfikację. Interfejs ITransaction dostarcza obiektowego opakowania wywołań metod BeginTransaction, RollbackTransaction oraz CommitTransaction. Wykorzystuje on bardzo popularny w języku C# interfejs o nazwie IDisposable. Dzięki niemu oraz wykorzystaniu konstrukcji using(...), można zaimplementować transakcje, która w sposób automatyczny wywoła operację rollback w przypadku wystąpienia jakiegokolwiek wyjątku. Podobnie jak w bibliotece NHibernate, obiekty implementujące interfejs ISession są tworzone poprzez specjalną fabrykę ISessionFactory. Posiada ona jedną metodę OpenSession, dostarczającą nową sesję z bazą danych. Dzięki takiemu podejściu, podczas tworzenia testów jesteśmy w stanie zastąpić domyślną fabrykę swoją własną, dostarczającą testowe obiekty, implementujące interfejs ISession. Podobnie jak w bibliotece NHibernate, stworzenie obiektu implementującego ISession powinno być czynnością szybką. Obiekty tego typu będą bardzo często tworzone w związku z tym zbyt duży narzut czasowy związany z tą operacją byłby nieakceptowalny. W przeciwieństwie do obiektu ISession obiekt typu ISessionFactory powinien istnieć tylko jeden. Jego stworzenie może być czasochłonne oraz powinien być on odporny na dostęp z wielu wątków jednocześnie. Obiekty typu ISession nie muszą być odporne na wielodostęp. 56

58 Kolejnym opisywanym obiektem jest SessionFactoryFactory. Jest to obiekt odpowiedzialny za dostarczanie domyślnej implementacji interfejsu ISessionFactory. Nie ma on swojego odwzorowania w bibliotece NHibenrate, gdzie obiekt fabryki sesji tworzony jest na podstawie obiektu definiującego konfigurację. Ze względu na prostotę biblioteki klienckiej, jej konfiguracja jest minimalna, przez co obiekt, definiujący konfigurację i budujący fabrykę sesji, nie jest potrzebny. Ze względu na częstość tworzenia obiektów typu ISession istnieje konieczność trzymania pewnej puli gotowych połączeń z bazą danych. Implementacja musi dostarczyć pewnego obiektu o nazwie ConnectionPool, który umożliwiałby pobranie otwartego, niewspółdzielonego połączenia z bazą danych. Powinien on zostać zaimplementowany zgodnie ze wzorcem Singleton. Dodatkowo, jeśli ilość połączeń w puli zostałaby wyczerpana, powinien on otwierać nowe połączenia. Dzięki takiej implementacji, koszt połączenia z bazą danych mógłby zostać w dużej mierze wyeliminowany Serwer bazy danych Kolejnym komponentem systemu InDB jest właściwa część serwera bazy danych. Powinien on zostać wykonany w technologii, która umożliwiałaby jego działanie w oderwaniu od sesji użytkownika danego systemu operacyjnego. Dzięki temu, mógłby działać nieprzerwanie w postaci usługi na serwerowym systemie operacyjnym. Aplikacja serwerowa ponadto powinna być podzielona na dwie zasadnicze części. Pierwsza z nich obejmowałaby wszystkie klasy odpowiedzialne za logikę działania serwera, jak na przykład przetwarzanie i uaktualnianie metadanych oraz serwisy obsługujące komunikację sieciową. Druga natomiast powinna zawierać wszystkie algorytmy oraz technologie, zapewniające zapis przetworzonych danych na dysk. Rysunek 5 pokazuje główne interfejsy oraz typy, dostępne w projektowanej aplikacji serwerowej. Pierwszym i jednym z najważniejszych jest klasa Document. Modeluje ona pojedynczy dokument przechowujący dane w bazie. Zgodnie z przyjętym wcześniej założeniem, projektowana baza danych powinna opierać się na modelu dokumentowym. Z tego względu istnieje potrzeba stworzenia obiektu, który przechowywałby wszystkie informacje oraz metadane każdego dokumentu. Jest ona podstawową oraz niepodzielną jednostką informacji zapisywanej w bazie InDB. Kolejnym interfejsem jest IDatabaseWebService. Definiuje on operacje dostępne poprzez technologie zdalnego wywoływania procedur, które mogą być wykorzystane przez użytkownika. Jak widać są one niemalże identyczne z tymi definiowanymi przez protokół komunikacyjny. Interfejs IStorage należy do części odpowiedzialnej za zapis oraz odczyt danych z dysku. Zapewnia on dostęp do niskopoziomowych metod, operujących na klasie Document, dzięki 57

59 Rysunek 5: Główne interfejsy oraz typy aplikacji serwerowej 58

60 którym zawartość dokumentów wraz z dotyczącymi ich metadanymi może być w efektywny sposób zapisywana na trwały nośnik danych. Warto zauważyć, że dzięki odseparowaniu logiki pracy serwera od modułu zapisu, uzyskujemy możliwość zmiany technologii zapisu na dysk. Dzięki temu w prosty sposób możemy stworzyć silnik zapisu danych, który operowałby jedynie na pamięci operacyjnej. Pomimo tego, że zastosowanie takiego silnika byłoby niedopuszczalne w warunkach produkcyjnych, byłoby idealne w testach akceptancyjnych, gdyż za każdym razem, gdy serwer byłby resetowany wracałby do pierwotnej konfiguracji. Co więcej, w skrajnym przypadku, algorytmy zapisu danych na dysk mogłyby być oparte o jakąś relacyjną bazę danych. Dzięki temu system InDB funkcjonowałby jako system zapisujący dokumentowe dane w relacyjnej bazie. Stanowiłoby to połączenie wydajności relacyjnej bazy danych z prostotą funkcjonowania modelu dokumentowego. Każde środowisko działania systemu InDB może się różnić od pozostałych w sposób bardzo drastyczny. Z tego powodu istnieje konieczność konfiguracji każdej instalacji. Interfejs IConfiguration dostarcza niezbędnych metod, dzięki którym aplikacja może odczytywać indywidualną konfigurację aplikacji. W skład parametrów podlegających konfiguracji wchodzą między innymi: ścieżka, gdzie zapisywane powinny być dane, nazwa pliku bazy danych oraz szczegóły dotyczące pracy w środowisku rozproszonym. Jednym z takich ustawień jest informacja dotycząca tego, czy dany węzeł jest główny czy podrzędny. W celu dokładnego zrozumienia znaczenia tej informacji należy poznać w jaki sposób system InDB powinien funkcjonować w środowisku rozproszonym. Istnieją dwie główne struktury organizacyjne w sieciach komputerowych: peer-to-peer [14] oraz master - slave [55]. Pierwsza z nich zakłada, że wszystkie węzły w sieci są równe, jeśli jest wymagana koordynacja niektórych czynności, dobór ról następuje dynamicznie w sposób losowy. Druga zakłada, że jeden węzeł (master) zostaje wyszczególniony i koordynuje pracę węzłów podrzędnych (slave). Ze względu na łatwość implementacji oraz powszechne wykorzystanie w systemach automatyki, architektura sieciowa systemu InDB powinna być oparta o model master - slave. Metoda IsMasterNode dostarcza informacji na temat roli węzła w sieci. Domyślnie zwracana wartość jest false. Co więcej, należy bezwzględnie zadbać o to, żeby tylko jeden węzeł w sieci pełnił rolę master. W przeciwnym razie może dojść do konfliktów oraz niespójności danych. Mechanizm replikacji w systemie InDB powinien działać w sposób następujący. Odczyt danych powinien być możliwy z każdego węzła, natomiast zapis danych powinien być możliwy jedynie przy wykorzystaniu węzła master, który, wykonując odpowiednie metody protokołu 59

61 komunikacji, dokonywałby synchronizacji danych we wszystkich węzłach slave. Synchronizacja taka powinna mieć charakter synchroniczny oraz powinna spełniać założenia opisane w pozycji [23]. W bardzo podobny sposób powinien działać mechanizm transakcji. Rozpoczęcie transakcji powinno być możliwe jedynie przy użyciu węzła master. Po wykonaniu tej operacji rozpoczynałby on również transakcje w węzłach typu slave. Po dokonaniu zmian w danych oraz zsynchronizowaniu ich z innymi węzłami, transakcje byłyby po kolej zatwierdzane lub cofane. Dzięki temu dane w każdym węźle byłyby spójne. Pomimo wielu zalet, architektura master - slave posiada jeden istotny mankament. Zakłada ona, że węzeł master musi być cały czas dostępny, gdyż w przypadku jego awarii brak jest koordynatora operacji modyfikacji danych. Problem ten da się jednak w prosty sposób rozwiązać poprzez zastosowanie odpowiedniej konfiguracji. Dzięki zastosowaniu maszyn wirtualnych oraz mechanizmu failover pomiędzy nimi, możemy w rzeczywistości posiadać kilka takich samych instancji węzła master, czekających w uśpieniu. Jeśli system wykryje awarię aktualnie używanego, natychmiastowo któryś z zapasowych przejmuje jego rolę. Projekt opisany w tym rozdziale powinien stanowić punkt wyjścia dla implementacji opisanej w rozdziale kolejnym. 3.3 Implementacja Rozdział ten opisuje w sposób szczegółowy etap implementacji systemu InDB. Zawiera on opis wszystkich technologii oraz koncepcji towarzyszących etapowi implementacji. Stanowi on również pełną instrukcję, dotyczącą instalacji oraz konfiguracji systemu. Projekt zdecydowano się zaimplementować w oparciu o technologie.net 4.0 oraz język programowania C#. Jako środowisko deweloperskie zdecydowano się wykorzystać Microsoft Visual Studio Ultimate. Dodatkowo, w celu uproszczenia procesu zarządzania kodem, zdecydowano się wykorzystać system kontroli wersji SVN. Jako serwer SVN zdecydowano się wybrać serwis Google Code. Jego niewątpliwymi zaletami jest stabilność oraz darmowy dostęp. Zgodnie z założeniami projektu implementację systemu InDB podzielono na dwa etapy. Pierwszym z nich była implementacja serwerowej części. Po jej zakończeniu rozpoczęto etap implementacji części klienckiej. Rozdział ten został podzielony na podrozdziały kolejno opisujące szczegóły implementacji komponentów opisanych w projekcie. Bardzo ważną rzeczą podczas implementacji jest podział solucji na odpowiednie projekty. Powinny one pokrywać się z komponentami wyszczególnionymi w procesie projektowania. Dzięki temu możemy w efektywny sposób wykorzystać hermetyzację na poziomie projektu 60

62 oraz uzyskać niezależność pomiędzy komponentami. Poniżej zamieszczono listę bibliotek, na które projekt został podzielony. ˆ InDB.Client - Biblioteka ta odpowiada za całą funkcjonalność kliencką. ˆ InDB.Core - Biblioteka ta odpowiada za wszystkie wspólne aspekty części zarówno serwerowej, jak i klienckiej. ˆ InDB.Database.Core - Biblioteka ta odpowiada za część wspólną różnych komponentów, wchodzących w skład aplikacji serwerowej. ˆ InDB.Database.Domain - Biblioteka ta zawiera w sobie wszystkie interfejsy, definiujące komponenty serwerowej części implementowanego systemu. ˆ InDB.Database.Service - Biblioteka ta zawiera w sobie klasy odpowiadające za uruchamianie programu w trybie usługi Windows oraz komunikację za pomocą protokołu z klientami. ˆ InDB.Database.Storage - Biblioteka ta zawiera klasy implementujące funkcjonalność zapisu danych na nośnik danych Część wspólna oraz protokół Przed rozpoczęciem implementacji biblioteki klienckiej oraz aplikacji serwerowej, bardzo istotnym krokiem było wybranie technologii realizującej zdalne wywoływanie procedur. Ze względu na wykorzystanie.net Framework zdecydowano się zastosować bibliotekę WCF [58]. Jest to bardzo rozbudowana biblioteka umożliwiająca zdalne wywoływanie procedur przy wykorzystaniu wielu protokołów, między innymi HTTP w postaci wywołań SOA Web Service, HTTPS oraz TCP z binarną serializacją danych. Ze względu na największą wydajność, na potrzeby implementacji bazy danych InDB, zdecydowano się wybrać protokół TCP z binarną serializacją danych. Jak pokazują omówione w następnym rozdziale testy dał on bardzo dobre wyniki wydajnościowe. Jak zostało ustalone w części projektowej, model danych systemu InDB powinien zostać oparty na paradygmacie dokumentowym. Z tego względu należy przyjąć pewien wspólny sposób konwersji obiektowych klas na dokumenty. Jak pamiętamy, baza danych RavenDB przechowywała wszystkie dane w postaci zbiorów JSON. Do ich serializacji oraz deserializacji wykorzystywała bardzo dobrą oraz sprawdzona bibliotekę Json.NET. Ze względu na wiele zalet związanych z przejrzystością formatu JSON oraz wydajnością biblioteki Json.NET, zdecydowano się na zastosowanie w bazie danych InDB tego samego 61

63 Rysunek 6: Graficzna reprezentacja wzorca wstrzykiwania zależności podejścia, co w RavenDB. Procesem serializacji oraz deserializacji zajmować się będzie biblioteka kliencka, natomiast w bazie danych dokumenty zapisywane będą w czysto tekstowej formie. Implementacja systemu InDB została oparta o wzorzec wstrzykiwania zależności [18]. Zgodnie z jego założeniami klasy nie odwołują się bezpośrednio do siebie, a jedynie do interfejsów, definiujących pewne funkcjonalności. Istnieją specjalne biblioteki, które w sposób automatyczny potrafią dostarczyć klasy, implementujące odpowiednie interfejsy. Przykładem takiego rozwiązania jest Ninject, który został zastosowany w implementowanym projekcie. Dzięki takiemu podejściu tworzony kod jest znacznie bardziej przejrzysty oraz nieskorelowany ze sobą. Niewątpliwą zaletą jest również znaczne ułatwienie procesu testowania. Zamiast faktycznych klas, implementujących dane funkcjonalności, można dostarczyć jedynie ich zalążki, sprawdzające, czy dane metody w testowanym interfejsie są faktycznie wywoływane oraz z jakimi parametrami. Kolejną wspólną częścią serwera oraz biblioteki klienckiej jest sekcja konfiguracyjna, dotycząca adresów oraz roli węzłów w sieci. Zarówno każdy serwer, jak i każdy klient musi posiadać w swoim pliku konfiguracyjnym sekcję dotyczącą lokalizacji węzłów. Została ona zaimplementowana na bazie standardowego mechanizmu rozbudowy plików konfiguracyjnych aplikacji stworzonych w technologii.net. Jak widać na rysunku 7 składają się na nią trzy klasy. Najważniejszą z nich jest klasa HostsConfigurationSection. Modeluje ona sekcje konfiguracyjną. Posiada jedną metodę Get, która pobiera jej instancję na podstawie pliku konfiguracyjnego. W celu otrzymania listy poszczególnych węzłów należy odwołać się do właściwości Ho- 62

64 Rysunek 7: Klasy sekcji konfiguracyjnej węzłów sts klasy sekcji konfiguracyjnej. Jest to obiekt typu HostCollection, który modeluje kolekcję elementów typu HostElement. Elementy te zawierają właściwości Address oraz informację dotyczącą roli danego węzła, dzięki czemu można zlokalizować dowolny węzeł w bazie danych. Na listingu 11 zaprezentowano przykładową zawartość pliku konfiguracyjnego jednego z węzłów. Posiada on informację o trzech węzłach, z czego jeden jest typu master, natomiast pozostałe są typu slave. Listing 11: Przykładowa konfiguracja węzłów < configuration > < configsections > < section name =" hostssection " type =" InDB. Core. HostsConfigurationSection, InDB. Core " /> </ configsections > < hostssection > <hosts > <clear /> <add address =" " ismaster =" false "/ > <add address =" host -a. example. com " ismaster =" false " /> <add address =" master -1. example. com " ismaster =" true " /> </ hosts > </ hostssection > 63

65 Rysunek 8: Główne klasy implementujące interfejsy biblioteki klienckiej </ configuration > Biblioteka kliencka Jak zostało to opisane w projekcie, architektura biblioteki klienckiej została oparta na rozwiązaniu NHibernate. Każdy ze zdefiniowanych interfejsów został zaimplementowany w odpowiedniej klasie. Rysunek 8 obrazuje wszystkie najważniejsze klasy w opisywanym projekcie. Jak widać klasa RestSession implementuje wszystkie metody interfejsu ISession. Dodatkowo posiada ona jedno pole informujące o kontekście transakcji. Jest to identyfikator aktualnej transakcji. Jeśli transakcja nie została rozpoczęta, ma ono wartość zerową. Zgodnie z założeniami projektowymi, stworzona została również specjalna klasa RestTransaction, która w sposób obiektowy obudowuje operacje związane z transakcją. Jej instancja tworzona jest poprzez wywołanie metody BeginTransaction klasy RestSession. W konstruktorze przekazywana jest do niej referencja do tworzącej ją sesji. Dzięki temu, po wykonaniu metody Commit zatwierdzającej transakcję lub Dispose cofającej wszystkie zmiany, jest ona w stanie wywołać odpowiednie metody klasy RestSession, bezpośrednio komunikujące się z serwerem. Kolejnymi bardzo ważnymi klasami są ServerConnection oraz ConnectionPool. Zgodnie z założeniami projektu, tworzenie instancji klasy implementującej interfejs ISession powinno 64

66 Rysunek 9: Klasy puli gotowych połączeń 65

67 być bardzo szybkie oraz efektywne. W związku z tym należy do minimum ograniczyć czas związany z połączeniem się do serwera. Najprostszym rozwiązaniem tego problemu jest wprowadzenie klasy przechowującej pewną ilość otwartych połączeń do serwera. Dzięki temu, w przypadku utworzenia obiektu RestSession, poprzez odwołanie się do klasy ConnectionPool, otrzymujemy połączenie, które zostało ustanowione już wcześniej i jest gotowe do komunikacji. Klasa ConnectionPool jest stworzona przy wykorzystaniu wzorca projektowego Singleton. Został on dokładnie opisany w pracy [19]. Dzięki temu mamy pewność, że istnieje tylko jedna instancja tego obiektu w całej aplikacji. Jest ona odporna na synchroniczny dostęp, więc może być z powodzeniem wykorzystywana w aplikacjach wielowątkowych. Jej działanie jest następujące. Podczas tworzenia, w konstruktorze, inicjowana jest pewna początkowa ilość połączeń do węzłów typu master oraz slave. Za każdym razem, gdy klasa RestSession żąda połączenia, musi podać dodatkowy parametr, mówiący o charakterze połączenia. Jeśli wymaga ono modyfikacji danych, lub rozpoczęcia transakcji zwracane jest zawsze połączenie do węzła typu master. W przeciwnym wypadku w sposób losowy zwracane jest połączenie z węzłem typu slave. Dzięki takiemu podejściu obciążenie węzłów jest równoważone [12]. Klasa ServerConnection jest realizacją koncepcji pojedynczego połączenia z bazą danych. Zamiast faktycznych połączeń z bazą danych, klasa ConnectionPool trzyma w listach referencje do instancji tej klasy. Warto zauważyć, że jednym z pól tej klasy jest klasa reprezentująca faktyczne połączenie do serwera, DatabaseWebServiceClient. Jeśli klient zażąda dostępu do bazy danych, z odpowiedniej listy usuwana jest jedna instancja klasy połączenia. Ze względu na fakt, że implementuje ona interfejs IDisposable, w momencie wywołania metody Dispose explicite lub poprzez zastosowanie konstrukcji using(...), niewykorzystywane połączenie wraca natychmiastowo do puli Serwer bazy danych Zgodnie z założeniami projektowymi, serwer aplikacji bazodanowej powinien być niezależnie działającym systemem. Z tego względu zdecydowano się stworzyć go w oparciu o technologię Windows Service. Dzięki temu może on działać nieprzerwanie, w oderwaniu od sesji użytkownika. Jak zostało wspomniane wcześniej baza danych dzieli się na dwie zasadnicze części. Pierwsza z nich odpowiada za uruchamianie oprogramowania w trybie usługi oraz zajmowanie się zgłoszeniami odebranymi przez sieć. Rysunek 10 obrazuje wszystkie najważniejsze klasy tej części. Pierwszą z prezentowanych klas jest Program. Zawiera ona punkt wejścia dla programu, w postaci procedury Main. Jej kod jest zamieszczony na listingu

68 Rysunek 10: Główne klasy biblioteki InDB.Database.Service 67

69 Listing 12: Kod procedury wejściowej serwera static void Main () { using ( var kernel = new StandardKernel ( new DatabaseCoreModule (), new CoreModule (), new QueryModule (), new StorageModule ())) { ServiceBase [] ServicesToRun ; ServicesToRun = new ServiceBase [] { kernel. Get < DatabaseService >() }; ServiceBase. Run ( ServicesToRun ); } } Jest on istotny z jednego powodu. Pokazuje, w jaki sposób należy wykorzystywać bibliotekę Ninject. Zgodnie z założeniami wzorca wstrzykiwania zależności, powinien istnieć tylko jeden obiekt kontenera. W prezentowanym przykładzie jest on tworzony na początku działania programu i jest źródłem, w którym tworzone są wszystkie instancje. Bardzo popularnym błędem, związanym z zastosowaniem biblioteki Ninject, jest tworzenie wielu kontenerów. Należy pamiętać, że operacja tworzenia kontenera nie jest zabezpieczona przed asynchronicznym wielodostępem. Dodatkowo istnienie więcej niż jednego kontenera zaburza pojęcia zakresów aktywowanych instancji. Jeśli istnieją dwa obiekty kontenera, każdy z nich może niezależnie aktywować różne instancje klas, które w założeniu powinny być tworzone zgodnie ze wzorcem singleton. Kolejna ważną klasą w implementacji logiki działania aplikacji serwerowej jest Database- Service. Reprezentuje ona pojedynczy serwis, działający jako usługa systemu Windows. Jej metoda OnStart zawiera faktyczny kod inicjujący działanie serwisu. Tworzy ona oraz otwiera serwis WCF. Dwie kolejne klasy, DatabaseWebService oraz MasterDatabaseWebService, stanowią najważniejszy element z punktu widzenia komunikacji z wykorzystaniem opisywanego wcześniej protokołu oraz technologii WCF. W celu pełnego zrozumienia ich znaczenia należy najpierw zrozumieć zasadę działania biblioteki WCF. W celu zainicjowania serwisu należy utworzyć dwa komponenty. Pierwszym z nich jest interfejs, którego metody są opatrzone odpowiednimi atrybutami. Definiuje on operacje, jakie są 68

70 możliwe do wykonania przy wykorzystaniu projektowanego serwisu. Drugim z nich jest klasa implementująca ten interfejs. Dostarcza ona faktycznej implementacji zdalnie wywoływanych metod. Interfejs definiujący operację jest identyczny z zaprezentowanym na rysunku 5. Warto zauważyć, że istnieją dwie klasy implementujące ten interfejs. Pierwszą z nich jest Database- WebService. Jest ona wykorzystywana w przypadku, gdy dany węzeł działa w trybie slave. Jej implementacja zakłada jedynie, że zapis oraz odczyt odbywać się będzie bezpośrednio na nośnik danych, z tego powodu nie posiada ona żadnych algorytmów odpowiedzialnych za synchronizację danych. Jeśli węzeł działa w trybie master musi on koordynować modyfikacje danych oraz system transakcji. W tym wypadku jako implementacja interfejsu IDatabaseWebService wykorzystywana jest klasa MasterDatabaseWebService. Została ona zaprezentowana na rysunku 10. W przeciwieństwie do klasy DatabaseWebService, po dokonaniu zmian lokalnie synchronizuje je z innymi węzłami typu slave w sieci. Warto zauważyć, że dzięki dziedziczeniu tej klasy po klasie DatabaseWebService, implementacja dodatkowej funkcjonalności odbywała się na drodze nadpisywania metod wirtualnych. Jest to bardzo popularny zabieg programistyczny i pozwala na przyrostowe tworzenie kodu, bez ingerencji w już napisane komponenty. Jak zostało wspomniane wcześniej, implementacja aplikacji serwerowej dzieli się na dwie główne części. Pierwszą z nich jest InDB.Database.Service. Druga nosi nazwę InDB.Database.Storage i ma za zadanie dostarczyć implementacji mechanizmu trwałego zapisu na dysk. Jak pamiętamy z rozdziału poprzedniego, baza danych RavenDB, jako silnik zapisu danych, wykorzystywała wbudowaną w system Windows tabelaryczną bazę danych o nazwie Esent. Jest ona bardzo efektywna oraz wykorzystywana przez wiele produktów firmy Microsoft. Ze względu na szereg zalet w postaci prostego API, dostępności oraz natywnego wsparcia dla systemu transakcji, zdecydowano, że aplikacja InDB również będzie korzystać z tego mechanizmu, jako silnika zapisu danych. Na rysunku 11 zaprezentowano klasę EsentStorage. Implementuje ona interfejs IStorage oraz jest głównym obiektem, mającym za zadanie komunikację z bazą danych Esent. Mankamentem tej bazy jest brak oficjalnego API dla platformy.net. Istnieje jednak biblioteka, opakowująca natywne wywołania funkcji Esent w odpowiednie klasy. Nazywa się ona ManagedEsent i została również wykorzystana przez twórców bazy danych RavenDB. Jej dokładny opis znajduje się w pozycji [26]. Mechanizm połączenia do bazy Esent jest następujący. Pierwszym krokiem jest stworzenie instancji bazy. Następnie, w zależności od tego czy uruchamiamy program po raz pierwszy czy nie, należy stworzyć fizyczny plik z bazą danych. Warto zauważyć, że wszystkie dane zapisywane w bazie danych Esent umieszczane są w jednym pliku. Po wykonaniu tych operacji 69

71 Rysunek 11: Klasa implementująca trwały zapis na dysk 70

72 Rysunek 12: Klasa modelująca pojedynczą tabelę w systemie Esent możemy przystąpić do modyfikacji oraz odczytu danych zawartych w bazie. Należy pamiętać, że Esent nie jest relacyjną baza danych. Posiada ona pewne elementy relacyjnych baz danych, jak na przykład tabele oraz indeksy, jednak nie ma możliwość wykonywania zapytań w języku SQL. Istnieją różne mechanizmy pozwalające na przeszukiwanie bazy danych oraz wykonywanie operacji bardzo zbliżonych do fundamentalnych poleceń SQL, jednak nie implementuje ona w żaden sposób tego standardu. Dostęp do danych w bazie Esent jest oparty na kursorach. W celu pobrania lub skasowania pewnego wiersza z tabeli należy utworzyć kursor, a następnie ustawić go w pozycji wskazującej na dany wiersz. Następnie poprzez polecenia Delete lub Get można go skasować lub pobrać. Bardzo ważnym aspektem zastosowania bazy danych Esent jest sposób jego wykorzystania. Jak wiadomo baza danych InDB posiada dokumentowy model danych, natomiast Esent stanowi tabelaryczny zbiór. Z tego względu należy w jakiś sposób rozwiązać problem konwersji formatów. Zdecydowano, że każda kolekcja dokumentów w implementowanej bazie danych znajdzie swoje odzwierciedlenie w tabeli systemu Esent. Jest to podejście bardziej zbliżone do MongoDB niż RavenDB, gdzie jak pamiętamy wszystkie kolekcje były przechowywane w jednej tabeli. Co więcej każda tabela będzie składała się z pięciu kolumn. Dzięki temu metadane oraz faktyczna zawartość dokumentu będą od siebie odseparowane. Poniżej zaprezentowano zbiór wszystkich kolumn. 71

73 ˆ Id - Identyfikator dokumentu, na kolumnie tej zostanie założony główny indeks, w celu przyspieszenia wyszukiwania. ˆ Version - Kolumna ta mówi o ilości modyfikacji danego dokumentu. ˆ LastModified - Kolumna ta zawiera informację o dacie ostatniej modyfikacji. ˆ CratedAt - Kolumna ta zawiera informację o dacie stworzenia dokumentu. ˆ Content - Kolumna ta przechowuje zawartości dokumentu w formacie JSON. W celu ułatwienia operacji na tabelach stworzono klasę EsentTableDetails. Została ona zaprezentowana na rysunku 12. Zawiera identyfikatory tabeli oraz kolumn, niezbędne podczas wykonywania operacji na danych zgromadzonych w bazie danych Esent. W celu uzyskania dostępu do poszczególnych kolumn w tabeli, należy podać jej nazwę. Z tego względu zdecydowano się stworzyć wewnętrzną statyczną strukturę o nazwie ColumnsNames, która zawierałaby nazwy wszystkich kolumn i udostępniała je w postaci pól statycznych. Ostatnim elementem aplikacji serwerowej jest instalator. Został on stworzony w oparciu o domyślny projekt instalatora systemu Windows. Jego zadaniem jest uproszczenie procesu instalacji aplikacji serwerowej, poprzez automatyczne zainstalowanie plików bazy danych oraz zarejestrowanie usługi w systemie Windows. Warto zauważyć, że w przypadku niepowodzenia procesu instalacji, istnieje możliwość przeprowadzenia jej w sposób ręczny. W tym celu należy wypakować pliki wykonywalne bazy danych oraz wykonać polecenie zaprezentowane na listingu 13. Warto zauważyć, że polecenie installutil jest dostępne w każdej wersji.net SDK. Listing 13: Instalacja usługi bazy danych InDB w systemie Windows. installutil. exe -i InDb. Database. Service. exe 3.4 Podsumowanie Stworzenie własnego systemu bazodanowego nie jest zadaniem trywialnym i wymaga dużego wysiłku projektowego oraz dogłębnego zrozumienia specyfiki problemu. Przed przystąpieniem do tworzenia specyfikacji należy zapoznać się z już istniejącymi rozwiązaniami. Dzięki temu uniknie się najczęstszych błędów oraz pozna najbardziej popularne rozwiązania problemów, z którymi borykają się wszyscy programiści oraz architekci baz danych. Na podstawie projektu udało się zaimplementować działający system InDB. Co więcej, system ten implementuje całkowitą funkcjonalność opisaną jako specyfikacja wymagań, w szczególności 72

74 ˆ Został zaimplementowany w oparciu o strukturę klient - serwer. ˆ Występuje brak konieczności mapowania właściwości obiektów na pola w bazie. ˆ Dostąp do danych jest bardzo szybki. ˆ System może zostać rozproszony na wiele węzłów. ˆ Zachowuje się bardzo wydajnie dla dużej ilości krótkich zapytań. ˆ Posiada wsparcie dla transakcji oraz jest łatwy w instalacji. Jedną z najważniejszych czynności, jakie należy wykonać podczas projektowania bazy danych typu NoSQL, jest wybór odpowiedniego modelu danych. Każdy z nich posiada bowiem swoje zalety oraz wady. Dopiero na podstawie analizy planowanych warunków pracy oraz przeznaczenia można rozstrzygnąć, który z nich będzie optymalny dla projektowanego rozwiązania. Warto zauważyć, że jedną z zalet podejścia typu NoSQL jest nowe spojrzenie na problem logicznej organizacji informacji. Istnieje wiele aplikacji wymagających przechowywania danych, jednak sposób ich reprezentacji nie pasuje do modelu relacyjnego. Co więcej, próbując na siłę dopasować ich organizację do modelu relacyjnego, możemy być zmuszeni do napisania dużej ilości kodu konwertującego, który nie byłby potrzebny przy zastosowaniu innej technologii. Dzięki zastosowaniu rozproszonej architektury opartej na podejściu master - slave uzyskano możliwość replikacji danych oraz zwiększenia szybkości systemu bazodanowego, poprzez równoczesną obsługę żądań przez różne maszyny. Aspekt replikacji oraz zwiększenia wydajności jest szczególnie istotny, jeśli weźmiemy pod uwagę planowane zastosowanie tworzonego systemu. Jedną z najbardziej pożądanych cech każdego systemu stosowanego w przemyśle jest bezpieczeństwo. Poprzez replikację danych na wiele węzłów, zapewniamy ich integralność oraz trwałość, pomimo potencjalnej awarii jednego z węzłów. 73

75 4 Analiza wydajnościowa Wydajność, oprócz niezawodności, jest jednym z głównych czynników decydujących o przydatności bazy danych w warunkach produkcyjnych. Wiele baz danych typu NoSQL szczyci się bardzo wysokim poziomem niezawodności oraz wydajności. Rozdział ten ma na celu weryfikację tej tezy, poprzez przeprowadzenie serii pomiarów wydajnościowych w zestawieniu z relacyjną bazą danych. Wiele baz danych NoSQL znajduje zastosowanie w aplikacjach webowych takich jak portale społecznościowe lub systemy zarządzania treścią. Uzasadnione jest to bardzo dużą ilością danych operacyjnych, zgromadzonych w tych systemach, lokalnością tych danych oraz ich modelem, odpowiadającym założeniom baz typu NoSQL. Dobranie odpowiedniej bazy danych dla rozproszonej aplikacji internetowej jest zadaniem nietrywialnym, gdzie główne kryterium stanowi wydajności operacji CRUD oraz efektywność współdzielenia danych przez węzły w klastrze. Co więcej specyfiką tych aplikacji jest generowanie bardzo dużej ilości relatywnie prostych zapytań do bazy danych. W większości przypadków jest to uaktualnienie lub odczytanie pojedynczego wiersza z bazy. W przeciwieństwie do zadań zorientowanych na przetwarzanie dużej ilości danych, jak hurtownie danych lub zadania integracji danych, w opisywanych systemach poszczególne zapytania nie są ze sobą skorelowane oraz występować mogą w dowolnych odstępach czasu. Bazy danych typu NoSQL są tworem nowym. Oprócz świeżego spojrzenia na model danych, powinny cechować się większą wydajnością niż tradycyjne i sprawdzone rozwiązania. Jedynie w tym przypadku ich istnienie będzie uzasadnione. Ich analiza wydajnościowa powinna zostać zestawiona z analizą wydajnościową pewnej relacyjnej bazy danych. Dzięki temu uzyskamy cały obraz wydajności rozwiązań bazodanowych, nie tylko baz typu NoSQL. Na tej podstawie będzie możliwe rozstrzygnięcie, czy analizowane bazy danych są faktycznie wydajniejsze od rozwiązań istniejących już na rynku od długiego czasu. Jako przykład relacyjnej bazy danych zdecydowano się wybrać MSSQL. Jest to system, który istnieje na rynku już od 1989 roku. Jest on stale rozwijany, najnowsza oficjalna wersja została opatrzona numerem 11. Oprócz samej bazy danych w skład pakietu MSSQL wchodzi wiele narzędzi typu Business Intelligence, jednak w porównaniu nie będziemy się nimi zajmować. Skupimy się jedynie na wydajności silnika przechowującego dane. Dostęp do omawianego systemu może być realizowany w dwa sposoby. Pierwszym z nich jest dostęp przy pomocy standardowych mechanizmów z biblioteki ADO.NET. Jest to najbardziej niskopoziomowy sposób dostępu do bazy danych MSSQL, oficjalnie wspierany przez platformę.net. Z tego względu nie generuje on żadnego narzutu czasowego związanego z mapowaniem obiektowo relacyjnym oraz synchronizacją zależności 74

76 pomiędzy encjami. Wadą bezpośredniego dostępu przy pomocy ADO.NET jest jednak komplikacja implementacji systemu wykorzystującego to rozwiązanie. W przypadku tworzenia aplikacji z rozbudowaną baza danych i złożonym modelem encji, dużo szybciej i łatwiej zastosować jest gotowe narzędzie typu ORM, które automatycznie jest w stanie mapować kolumny do właściwości encji oraz zarządzać zależnościami pomiędzy nimi. Przykładem takiego rozwiązania jest NHibernate oraz EntityFramework, który został wybrany do porównania jako drugi sposób zarządzania danymi zgromadzonymi w MSSQL. Dostęp do wielu obiektowych baz danych odbywa się w bardzo podobny sposób, jak korzystanie z gotowej biblioteki typu ORM. Z tego względu zamieszczenie porównania wydajności dostępu do relacyjnej bazy danych przy pomocy narzędzia typu ORM z zastosowaniem obiektowej bazy danych może pokazać, które z rozwiązań w efekcie jest wydajniejsze. Warto zauważyć, że złożoność implementacji aplikacji korzystającej z jednego oraz drugiego podejścia jest bardzo zbliżona. Dodatkowo w porównaniu zdecydowano się zamieścić analizę wydajnościową rozwiązania autorskiego o nazwie InDB. Dzięki temu możliwe jest porównanie wydajności prostego rozwiązania, opisywanego w poprzednim rozdziale, z komercyjnymi oraz sprawdzonymi bazami danych, analizowanymi w rozdziale pierwszym. Warto zauważyć, że analizowany jest jedynie kawałek funkcjonalności opisywanego wcześniej systemu, związany z szybkością działania metod CRUD, najważniejszych z punktu widzenia aplikacji internetowych. Encje dla każdej bazy były takie same. Pierwsza z nich reprezentowała użytkownika, identyfikowanego przez login, imię oraz identyfikator typu GUID. Druga z nich reprezentowała post danego użytkownika, zawierała ona w sobie również swój identyfikator w postaci typu GUID, odniesienie do użytkownika oraz zawartość tekstową reprezentującą wpis użytkownika. Dzięki zastosowaniu podejścia CodeFirst oferowanego przez EntityFramework, generowanie schematu bazy danych MSSQL okazało się zbędne. Podejście, wykorzystujące ADO.NET, również korzystało z tego samego wygenerowanego schematu, który w postaci skrótowej został przedstawiony na listingu 14. Listing 14: Polecenia tworzące schemat testowej bazy danych MSSQL CREATE TABLE [ dbo ].[ Users ]( [ Id] [ uniqueidentifier ] NOT NULL, [ Login ] [ nvarchar ]( max ) NULL, [ Name ] [ nvarchar ]( max ) NULL ) CREATE TABLE [ dbo ].[ Posts ]( [ Id] [ uniqueidentifier ] NOT NULL, 75

77 [ Text ] [ nvarchar ]( max ) NULL, [ User_ Id ] [ uniqueidentifier ] NULL ) Do utworzenia schematu bazy danych Cassandra wymagane było zdefiniowanie jedynie dwóch rodzin kluczy oraz ich przestrzeni. Przykład kodu tworzącego tego typu schemat przedstawiono na listingu 15. Listing 15: Polecenia tworzące przestrzeń kluczy oraz super kolumny testowej bazy danych Cassnadra create keyspace MGR ; create column family Users ; create column family Posts ; RavenDB, MongoDB oraz InDB nie wymagały żadnych wstępnych przygotowań w celu rozpoczęcia testowania. Są to bazy dokumentowe, kompletnie pozbawione statycznego schematu. Kolekcje są tworzone w miarę dodawania nowych dokumentów. Oprócz założeń strukturalnych testów, bardzo istotnym aspektem jest środowisko, w którym będą się one odbywać. W przypadku pisania tej pracy jest to komputer PC z zainstalowanym systemem operacyjnym Windows 7 x64, wyposażony w procesor Core 2 Duo E7600 o częstotliwości 3.06 GHz oraz pamięcią RAM 4GB, 1333MHz. 4.1 Analiza szybkości zapisu Pierwszą oraz bardzo ważną operacją, którą każda baza danych powinna implementować, jest zapis danych. Jej wydajność jest niezwykle istotna z punktu widzenia systemów logujących wszelką aktywność. Zazwyczaj potrzebują one w bardzo szybkim tempie zapisywać dane przychodzące z różnych połączeń. Przykładem takiej aplikacji, może być program monitorujący poprawność działania sterownika PLC. Monitoring ten zazwyczaj odbywa się na zasadzie pollingu, czyli cyklicznego odpytywania sterownika o jego status. Ze względu na bardzo rygorystyczne obostrzenia czasowe w systemach automatyki, zapis ten musi być bardzo szybki. Szybkość odczytu jest mniej istotna, gdyż odbywa się jedynie na żądanie operatora, co w wielu przypadkach zdarza się jedynie podczas awarii lub innych problemów. Wyniki pomiarów wydajności zapisu, badanych baz danych, zostały zgromadzone w tabeli numer 4. Procedura testowa była taka sama dla każdej bazy danych. W pierwszym kroku wszystkie dane z bazy były usuwane. Następnie tworzonych była pewna, zmienna, ilość encji typu User oraz do każdej z nich dodawanych było dziesięć encji typu Post. Jak widać największa szybkością zapisu cechuje się MongoDB. Przewaga szybkościowa jest bardzo znacząca nad drugą najszybszą bazą danych w zestawieniu, którą okazało się być 76

78 Cassandra InDB MongoDB RavenDB Mssql - EF MSSQL Operacji: s 789ms 3s 553ms 0s 506ms 13s 439ms 6s 19ms 4s 552ms Operacji: s 449ms 4s 930ms 0s 510ms 32s 517ms 9s 440ms 9s 353ms Operacji: s 701ms 7s 116ms 0s 765ms 37s 974ms 13s 696ms 13s 501ms Operacji: s 950ms 10s 178ms 1s 89ms 42s 652ms 18s 300ms 17s 557ms Operacji: s 823ms 12s 181ms 1s 456ms 55s 516ms 23s 988ms 21s 957ms Operacji: s 12ms 14s 652ms 1s 520ms 65s 331ms 28s 514ms 26s 355ms Operacji: s 396ms 17s 318ms 1s 770ms 72s 786ms 32s 919ms 34s 974ms Operacji: s 874ms 20s 138ms 2s 64ms 85s 500ms 37s 136ms 36s 150ms Operacji: s 563ms 21s 944ms 2s 250ms 95s 173ms 41s 215ms 42s 83ms Operacji: s 35ms 25s 140ms 2s 611ms 115s 178ms 46s 682ms 44s 646ms Tabela 4: Czasy wykonania operacji Insert dla poszczególnych baz danych rozwiązanie autorskie. Jak widać MongoDB jest około dziesięć razy szybsza niż InDB oraz około pięćdziesiąt razy szybsza od najwolniejszej w tym zestawieniu bazy Cassandra. Warto zauważyć, że w przypadku zapisu danych, podejście oparte na Entity Framework nie różni się znacznie od zastosowania ADO.NET. Dzieje się tak ze względu na bardzo mały narzut czasowy związany z przetworzeniem modelu obiektowego na polecenie SQL Insert. Bardzo niską szybkością zapisu cechuje się również RavenDB. Może być to uwarunkowane dodatkowym narzutem czasowym, związanym z brakiem serializacji binarnej przy transferze danych pomiędzy aplikacją a bazą danych. Pomimo tego, że podejście takie znacznie upraszcza implementację, okazuje się znacznie mniej wydajne niż zastosowanie alternatywnego podejścia opartego na BSON, wykorzystanego w bazie danych MongoDB. 77

79 Rysunek 13: Wykres szybkości dodania encji User i 10 encji Post dla poszczególnych baz 4.2 Analiza szybkości odczytu Kolejną oraz najważniejszą operacją, którą każda baza danych powinna implementować, jest odczyt danych. Jest ona zwłaszcza istotna dla aplikacji, które cechują się bardzo dużym natężeniem żądań odczytu. Jest to najczęstszy rodzaj aplikacji, większość operacji w standardowej aplikacji internetowej polega na odczycie danych z bazy. Przykładem takiego systemu może być każdy system zarządzania treścią strony. Jak wiadomo, modyfikacje na stronach dokonywane są stosunkowo rzadko w stosunku do odczytu danych stron. Wyniki pomiarów szybkości odczytu zostały zamieszczone w tabeli numer 5. Procedura testująca była taka sama dla każdej wielkości instancji. W pierwszym kroku zawartość bazy była czyszczona, następnie było dodawanych 1000 encji typu User. W kolejnym kroku wykonywanych było i losowych odczytów encji z bazy danych, na podstawie listy z zapamiętanymi identyfikatorami poszczególnych encji. Losowane indeksy w tablicy podlegały rozkładowi jednostajnemu. Jak widać, najszybszym odczytem cechuje się MSSQL z dostępem przy pomocy ADO.NET. Warto zauważyć, że zastosowanie Entity Framework do wykonania dokładnie tego samego zadania zwiększa czas ponad dwudziestokrotnie. Dzieje się tak ze względu na narzut związany z mapowaniem wyników na encje oraz przetworzeniem polecenia LINQ odpowiedzialnego za wyszukanie encji o zadanym identyfikatorze. 78

80 Cassandra InDB MongoDB RavenDB MSSQL - EF MSSQL Operacji: s 991ms 0s 283ms 0s 291ms 1s 108ms 3s 761ms 0s 252ms Operacji: s 22ms 0s 359ms 0s 489ms 2s 285ms 5s 335ms 0s 290ms Operacji: s 171ms 0s 529ms 0s 738ms 3s 783ms 7s 933ms 0s 562ms Operacji: s 391ms 0s 714ms 0s 989ms 5s 97ms 10s 548ms 0s 551ms Operacji: s 663ms 0s 890ms 1s 238ms 6s 461ms 13s 91ms 0s 698ms Operacji: s 857ms 1s 123ms 1s 580ms 8s 283ms 15s 740ms 0s 818ms Operacji: s 920ms 1s 240ms 1s 728ms 8s 804ms 18s 527ms 0s 930ms Operacji: s 300ms 1s 405ms 1s 972ms 10s 652ms 21s 693ms 1s 169ms Operacji: s 557ms 1s 673ms 2s 224ms 11s 355ms 24s 302ms 1s 210ms Operacji: s 237ms 1s 764ms 2s 537ms 12s 123ms 26s 976ms 1s 306ms Tabela 5: Czasy wykonania operacji GetById dla poszczególnych baz danych Warto zauważyć, że baza danych InDB plasuje się na drugim miejscu w rankingu szybkości odczytu, tuż za MSSQL. MongoDB plasuje się tuż za bazą danych InDB. 79

81 Rysunek 14: Wykres szybkości odczytu encji User dla poszczególnych baz 4.3 Analiza szybkości modyfikacji Kolejną ważną operacją w systemach internetowych jest możliwość modyfikacji danych. Jest ona bardzo istotna, jednak nie tak często wykorzystywana, jak zapis danych. Jako przykład można przytoczyć komunikator internetowy, który pozwala na wysłanie wiadomości, jednak nie udostępnia funkcjonalności jej modyfikacji. Baza danych stanowiąca repozytorium archiwum rozmów, właściwie nie musi implementować możliwości uaktualniania danych Wyniki pomiarów szybkości uaktualnienia zamieszczone zostały w tabeli numer 6. Podobnie jak dla testu szybkości odczytu, w pierwszym kroku cała zawartość bazy danych była czyszczona. Następnie tworzonych było 1000 encji typu User. Kolejnym krokiem było wykonanie i losowych uaktualnień encji z bazy danych. Jak widać najszybszymi rozwiązaniami, umożliwiającymi modyfikację danych w bazie, są MSSQL oraz MongoDB. Jest to podyktowane tym, że zarówno język SQL jak i biblioteka MongoDB umożliwiają wykonanie operacji uaktualnienia bez konieczności wczytywania klasy reprezentującej encję. Efektywnie dzięki temu pomijana jest jedna operacja odczytu z bazy danych. Biblioteki klienckie InDB, RavenDB oraz Entity Framework są zaprojektowane zgodnie z zasadą propagacji zmian dokonanych w encji na zawartość bazy danych. Jest to bardzo wygodne z programistycznego punktu widzenia, jednak niesie za sobą dość poważny spadek wydajności, związany z koniecznością odczytania oraz dokonania mapowania wiersza z bazy 80

82 Cassandra InDB MongoDB RavenDB MSSQL - EF MSSQL Operacji: s 435ms 1s 845ms 0s 498ms 16s 532ms 6s 268ms 0s 513ms Operacji: s 303ms 4s 53ms 0s 586ms 35s 168ms 7s 20ms 0s 517ms Operacji: s 186ms 5s 290ms 0s 832ms 53s 29ms 10s 312ms 0s 511ms Operacji: s 227ms 6s 370ms 1s 208ms 67s 950ms 14s 20ms 0s 758ms Operacji: s 309ms 9s 71ms 1s 385ms 93s 8ms 17s 295ms 0s 820ms Operacji: s 709ms 14s 135ms 1s 663ms 100s 106ms 22s 285ms 0s 906ms Operacji: s 45ms 15s 588ms 2s 10ms 100s 657ms 24s 260ms 1s 57ms Operacji: s 585ms 16s 930ms 2s 229ms 128s 323ms 27s 832ms 1s 208ms Operacji: s 652ms 48s 343ms 2s 807ms 154s 830ms 32s 594ms 1s 306ms Operacji: s 795ms 25s 329ms 2s 595ms 148s 846ms 34s 994ms 1s 516ms Tabela 6: Czasy wykonania operacji Update dla poszczególnych baz danych danych na encję. Dopiero po wykonaniu tego kroku, można dokonać modyfikacji encji oraz propagacji zmian na bazę danych. Jak widać w przedstawionym zestawieniu, podejście to wiąże się ze spadkiem wydajności o rząd wielkości czasu potrzebnego na wykonanie operacji. 81

83 Rysunek 15: Wykres szybkości modyfikacji encji User dla poszczególnych baz 4.4 Analiza szybkości kasowania Kolejną istotną operacją, z punktu widzenia zarządzania danymi zgromadzonymi w bazie, jest operacja kasowania. Nie jest ona tak bardzo popularna jak poprzednie opisywane operacje, jednak musi być implementowana w każdej bazie danych. Wiele aplikacji internetowych jest zaprojektowanych w sposób, który tak na prawdę nie kasuje fizycznie danych z bazy. Zamiast tego oznacza je jako nie używane. Dzięki temu zabiegowi dane pozostają w bazie do celów analitycznych, natomiast z punktu widzenia użytkowników są niewidoczne, tak jakby były faktycznie skasowane. Dodatkową zaletą tego typu podejścia jest większa wydajność. Jak widać po wynikach zgromadzonych w tabeli 6 oraz tabeli 7, operacja uaktualnienia jest szybsza od operacji usunięcia danych. Jest to uwarunkowane koniecznością przeliczenia indeksów oraz, w przypadku relacyjnych baz danych, może wiązać się z koniecznością przebudowania niektórych struktur danych, w oparciu o które dane są przechowywane. Procedura testowa nie różniła się od zastosowanej w poprzednich badaniach. Pierwszym krokiem było dodanie i elementów typu User do bazy danych, a następnie kasowanie ich po kolei przy użyciu oddzielnych połączeń do bazy danych. Identyfikatory encji w bazie danych były zapamiętane podczas tworzenia w specjalnej liście, a następnie w sposób losowy pobierane i przekazywane do funkcji kasującej. Jak widać w tabeli 7, najszybciej dane można usunąć w systemie MongoDB. Tuż za nim 82

84 Cassandra InDB MongoDB RavenDB MSSQL - EF MSSQL Operacji: s 812ms 1s 545ms 0s 322ms 6s 484ms 7s 73ms 0s 518ms Operacji: s 832ms 3s 505ms 0s 750ms 14s 163ms 9s 236ms 0s 889ms Operacji: s 56ms 4s 113ms 0s 976ms 22s 661ms 14s 761ms 1s 674ms Operacji: s 731ms 5s 767ms 1s 244ms 29s 618ms 18s 705ms 1s 907ms Operacji: s 898ms 7s 75ms 2s 252ms 49s 646ms 32s 653ms 2s 656ms Operacji: s 635ms 8s 822ms 1s 982ms 53s 64ms 27s 81ms 2s 912ms Operacji: s 870ms 10s 424ms 2s 269ms 62s 734ms 29s 491ms 3s 491ms Operacji: s 399ms 13s 845ms 2s 868ms 86s 97ms 35s 188ms 4s 369ms Operacji: s 444ms 14s 985ms 3s 414ms 85s 867ms 37s 356ms 4s 553ms Operacji: s 538ms 19s 160ms 3s 354ms 93s 220ms 41s 124ms 4s 848ms Tabela 7: Czasy wykonania operacji Delete dla poszczególnych baz danych plasuje się relacyjna baza danych MSSQL. Bardzo duża wydajność tych systemów wiąże się z możliwością usunięcia wiersza lub dokumentu podając jedynie jego identyfikator. W bibliotekach typu ORM, jak już zostało wspomniane wcześniej, w większości przypadków nie może się to odbyć bez wczytania obiektu do pamięci, a następnie usunięcia z bazy danych. 83

85 Rysunek 16: Wykres szybkości kasowania encji User dla poszczególnych baz 4.5 Podsumowanie Wydajność jest jedną z kluczowych cech każdej bazy danych. W systemach, gdzie potrzebna jest bardzo duża wydajność, brak tej cechy dyskwalifikuje dane rozwiązanie. Wiele z systemów NoSQL szczyci się dwoma cechami: wydajnością oraz dobrym działaniem w warunkach rozproszonych. Rozdział ten miał za zadanie zweryfikować poprawność pierwszej tezy. Jak się okazuje, jest ona prawdziwa, jednak nie dla każdego rozwiązania typu NoSQL. W tabeli 8 zgromadzono pozycje, jakie poszczególne rozwiązania zajęły w testach wydajnościowych. Jasno z niej wynika, że najlepszą bazą danych do operacji zapisu oraz kasowania jest MongoDB. Jeśli tworzymy aplikacje, w której przewidujemy, że będziemy dokonywać wielu odczytów oraz uaktualnień, co w niektórych przypadkach implikuje również logiczne kasowanie danych, najlepiej zastosować tradycyjne rozwiązanie w postaci MSSQL. Przeprowadzone testy jasno pokazują, że zastosowanie biblioteki typu ORM w postaci Entity Framework negatywnie wpływa na wydajność operacji CRUD, wykonywanych na bazie danych. Warto zauważyć, że uzasadnieniem stosowania biblioteki typu ORM jest uproszczenie procesu tworzenia aplikacji poprzez zastosowanie automatycznego narzędzia mapującego właściwości klas z modelu aplikacji na poszczególne kolumny w bazie danych. Mapowanie takie jest znacznie prostsze, jeśli model bazy danych jest bardziej zbliżony do modelu obiektowego niż model relacyjny. 84

Hurtownie danych wykład 5

Hurtownie danych wykład 5 Hurtownie danych wykład 5 dr Sebastian Zając SGH Warszawa 7 lutego 2017 1 Współbieżność i integracja Niezgodność impedancji 2 bazy danych Współbieżność i integracja Niezgodność impedancji Bazy relacyjne

Bardziej szczegółowo

Grzegorz Ruciński. Warszawska Wyższa Szkoła Informatyki 2011. Promotor dr inż. Paweł Figat

Grzegorz Ruciński. Warszawska Wyższa Szkoła Informatyki 2011. Promotor dr inż. Paweł Figat Grzegorz Ruciński Warszawska Wyższa Szkoła Informatyki 2011 Promotor dr inż. Paweł Figat Cel i hipoteza pracy Wprowadzenie do tematu Przedstawienie porównywanych rozwiązań Przedstawienie zalet i wad porównywanych

Bardziej szczegółowo

Baza danych sql. 1. Wprowadzenie. 2. Repozytaria generyczne

Baza danych sql. 1. Wprowadzenie. 2. Repozytaria generyczne Baza danych sql 1. Wprowadzenie Do tej pory operowaliście na listach. W tej instrukcji pokazane zostanie jak stworzyć bazę danych. W zadaniu skorzystamy z możliwości utworzenia struktury bazy danych z

Bardziej szczegółowo

Przetwarzanie danych z wykorzystaniem technologii NoSQL na przykładzie serwisu Serp24

Przetwarzanie danych z wykorzystaniem technologii NoSQL na przykładzie serwisu Serp24 Przetwarzanie danych z wykorzystaniem technologii NoSQL na przykładzie serwisu Serp24 Agenda Serp24 NoSQL Integracja z CMS Drupal Przetwarzanie danych Podsumowanie Serp24 Darmowe narzędzie Ułatwia planowanie

Bardziej szczegółowo

Instalacja SQL Server Express. Logowanie na stronie Microsoftu

Instalacja SQL Server Express. Logowanie na stronie Microsoftu Instalacja SQL Server Express Logowanie na stronie Microsoftu Wybór wersji do pobrania Pobieranie startuje, przechodzimy do strony z poradami. Wypakowujemy pobrany plik. Otwiera się okno instalacji. Wybieramy

Bardziej szczegółowo

Informacje wstępne Autor Zofia Kruczkiewicz Wzorce oprogramowania 4

Informacje wstępne Autor Zofia Kruczkiewicz Wzorce oprogramowania 4 Utrwalanie danych zastosowanie obiektowego modelu danych warstwy biznesowej do generowania schematu relacyjnej bazy danych Informacje wstępne Autor Zofia Kruczkiewicz Wzorce oprogramowania 4 1. Relacyjne

Bardziej szczegółowo

Laboratorium Technologii Informacyjnych. Projektowanie Baz Danych

Laboratorium Technologii Informacyjnych. Projektowanie Baz Danych Laboratorium Technologii Informacyjnych Projektowanie Baz Danych Komputerowe bazy danych są obecne podstawowym narzędziem służącym przechowywaniu, przetwarzaniu i analizie danych. Gromadzone są dane w

Bardziej szczegółowo

Podstawowe pojęcia dotyczące relacyjnych baz danych. mgr inż. Krzysztof Szałajko

Podstawowe pojęcia dotyczące relacyjnych baz danych. mgr inż. Krzysztof Szałajko Podstawowe pojęcia dotyczące relacyjnych baz danych mgr inż. Krzysztof Szałajko Czym jest baza danych? Co rozumiemy przez dane? Czym jest system zarządzania bazą danych? 2 / 25 Baza danych Baza danych

Bardziej szczegółowo

Temat: Ułatwienia wynikające z zastosowania Frameworku CakePHP podczas budowania stron internetowych

Temat: Ułatwienia wynikające z zastosowania Frameworku CakePHP podczas budowania stron internetowych PAŃSTWOWA WYŻSZA SZKOŁA ZAWODOWA W ELBLĄGU INSTYTUT INFORMATYKI STOSOWANEJ Sprawozdanie z Seminarium Dyplomowego Temat: Ułatwienia wynikające z zastosowania Frameworku CakePHP podczas budowania stron internetowych

Bardziej szczegółowo

INFORMATYKA Pytania ogólne na egzamin dyplomowy

INFORMATYKA Pytania ogólne na egzamin dyplomowy INFORMATYKA Pytania ogólne na egzamin dyplomowy 1. Wyjaśnić pojęcia problem, algorytm. 2. Podać definicję złożoności czasowej. 3. Podać definicję złożoności pamięciowej. 4. Typy danych w języku C. 5. Instrukcja

Bardziej szczegółowo

Informatyka I. Standard JDBC Programowanie aplikacji bazodanowych w języku Java

Informatyka I. Standard JDBC Programowanie aplikacji bazodanowych w języku Java Informatyka I Standard JDBC Programowanie aplikacji bazodanowych w języku Java dr inż. Andrzej Czerepicki Politechnika Warszawska Wydział Transportu 2017 Standard JDBC Java DataBase Connectivity uniwersalny

Bardziej szczegółowo

Wykonać Ćwiczenie: Active Directory, konfiguracja Podstawowa

Wykonać Ćwiczenie: Active Directory, konfiguracja Podstawowa Wykonać Ćwiczenie: Active Directory, konfiguracja Podstawowa Instalacja roli kontrolera domeny, Aby zainstalować rolę kontrolera domeny, należy uruchomić Zarządzenie tym serwerem, po czym wybrać przycisk

Bardziej szczegółowo

Dokumentacja wstępna TIN. Rozproszone repozytorium oparte o WebDAV

Dokumentacja wstępna TIN. Rozproszone repozytorium oparte o WebDAV Piotr Jarosik, Kamil Jaworski, Dominik Olędzki, Anna Stępień Dokumentacja wstępna TIN Rozproszone repozytorium oparte o WebDAV 1. Wstęp Celem projektu jest zaimplementowanie rozproszonego repozytorium

Bardziej szczegółowo

Usługi analityczne budowa kostki analitycznej Część pierwsza.

Usługi analityczne budowa kostki analitycznej Część pierwsza. Usługi analityczne budowa kostki analitycznej Część pierwsza. Wprowadzenie W wielu dziedzinach działalności człowieka analiza zebranych danych jest jednym z najważniejszych mechanizmów podejmowania decyzji.

Bardziej szczegółowo

Dokumentacja projektu QUAIKE Architektura oprogramowania

Dokumentacja projektu QUAIKE Architektura oprogramowania Licencjacka Pracownia Oprogramowania Instytut Informatyki Uniwersytetu Wrocławskiego Jakub Kowalski, Andrzej Pilarczyk, Marek Kembrowski, Bartłomiej Gałkowski Dokumentacja projektu QUAIKE Architektura

Bardziej szczegółowo

Referat pracy dyplomowej

Referat pracy dyplomowej Referat pracy dyplomowej Temat pracy: Wdrożenie intranetowej platformy zapewniającej organizację danych w dużej firmie na bazie oprogramowania Microsoft SharePoint Autor: Bartosz Lipiec Promotor: dr inż.

Bardziej szczegółowo

Plan. Wprowadzenie. Co to jest APEX? Wprowadzenie. Administracja obszarem roboczym

Plan. Wprowadzenie. Co to jest APEX? Wprowadzenie. Administracja obszarem roboczym 1 Wprowadzenie do środowiska Oracle APEX, obszary robocze, użytkownicy Wprowadzenie Plan Administracja obszarem roboczym 2 Wprowadzenie Co to jest APEX? Co to jest APEX? Architektura Środowisko Oracle

Bardziej szczegółowo

Programowanie Komponentowe WebAPI

Programowanie Komponentowe WebAPI Programowanie Komponentowe WebAPI dr inż. Ireneusz Szcześniak jesień 2016 roku WebAPI - interfejs webowy WebAPI to interfejs aplikacji (usługi, komponentu, serwisu) dostępnej najczęściej przez Internet,

Bardziej szczegółowo

Diagram wdrożenia. Rys. 5.1 Diagram wdrożenia.

Diagram wdrożenia. Rys. 5.1 Diagram wdrożenia. Diagram wdrożenia Zaprojektowana przez nas aplikacja bazuje na architekturze client-server. W tej architekturze w komunikacji aplikacji klienckiej z bazą danych pośredniczy serwer aplikacji, który udostępnia

Bardziej szczegółowo

Diagramy związków encji. Laboratorium. Akademia Morska w Gdyni

Diagramy związków encji. Laboratorium. Akademia Morska w Gdyni Akademia Morska w Gdyni Gdynia 2004 1. Podstawowe definicje Baza danych to uporządkowany zbiór danych umożliwiający łatwe przeszukiwanie i aktualizację. System zarządzania bazą danych (DBMS) to oprogramowanie

Bardziej szczegółowo

Baza danych sql. 1. Wprowadzenie

Baza danych sql. 1. Wprowadzenie Baza danych sql 1. Wprowadzenie Do tej pory operowaliście na listach. W tej instrukcji pokazane zostanie jak stworzyć bazę danych. W zadaniu skorzystamy z edytora graficznego struktury bazy danych, który

Bardziej szczegółowo

REFERAT PRACY DYPLOMOWEJ Temat pracy: Projekt i realizacja serwisu ogłoszeń z inteligentną wyszukiwarką

REFERAT PRACY DYPLOMOWEJ Temat pracy: Projekt i realizacja serwisu ogłoszeń z inteligentną wyszukiwarką REFERAT PRACY DYPLOMOWEJ Temat pracy: Projekt i realizacja serwisu ogłoszeń z inteligentną wyszukiwarką Autor: Paweł Konieczny Promotor: dr Jadwigi Bakonyi Kategorie: aplikacja www Słowa kluczowe: Serwis

Bardziej szczegółowo

Specjalizacja magisterska Bazy danych

Specjalizacja magisterska Bazy danych Specjalizacja magisterska Bazy danych Strona Katedry http://bd.pjwstk.edu.pl/katedra/ Prezentacja dostępna pod adresem: http://www.bd.pjwstk.edu.pl/bazydanych.pdf Wymagania wstępne Znajomość podstaw języka

Bardziej szczegółowo

AUREA BPM Oracle. TECNA Sp. z o.o. Strona 1 z 7

AUREA BPM Oracle. TECNA Sp. z o.o. Strona 1 z 7 AUREA BPM Oracle TECNA Sp. z o.o. Strona 1 z 7 ORACLE DATABASE System zarządzania bazą danych firmy Oracle jest jednym z najlepszych i najpopularniejszych rozwiązań tego typu na rynku. Oracle Database

Bardziej szczegółowo

PHP: bazy danych, SQL, AJAX i JSON

PHP: bazy danych, SQL, AJAX i JSON 1 PHP: bazy danych, SQL, AJAX i JSON SYSTEMY SIECIOWE Michał Simiński 2 Bazy danych Co to jest MySQL? Jak się połączyć z bazą danych MySQL? Podstawowe operacje na bazie danych Kilka dodatkowych operacji

Bardziej szczegółowo

Szczegółowy opis przedmiotu umowy. 1. Środowisko SharePoint UWMD (wewnętrzne) składa się z następujących grup serwerów:

Szczegółowy opis przedmiotu umowy. 1. Środowisko SharePoint UWMD (wewnętrzne) składa się z następujących grup serwerów: Rozdział I Szczegółowy opis przedmiotu umowy Załącznik nr 1 do Umowy Architektura środowisk SharePoint UMWD 1. Środowisko SharePoint UWMD (wewnętrzne) składa się z następujących grup serwerów: a) Środowisko

Bardziej szczegółowo

REFERAT O PRACY DYPLOMOWEJ

REFERAT O PRACY DYPLOMOWEJ REFERAT O PRACY DYPLOMOWEJ Temat pracy: Projekt i realizacja elektronicznego dziennika ocen ucznia Autor: Grzegorz Dudek wykonanego w technologii ASP.NET We współczesnym modelu edukacji, coraz powszechniejsze

Bardziej szczegółowo

Informatyka I. Programowanie aplikacji bazodanowych w języku Java. Standard JDBC.

Informatyka I. Programowanie aplikacji bazodanowych w języku Java. Standard JDBC. Informatyka I Programowanie aplikacji bazodanowych w języku Java. Standard JDBC. dr hab. inż. Andrzej Czerepicki Politechnika Warszawska Wydział Transportu 2019 Standard JDBC Java DataBase Connectivity

Bardziej szczegółowo

REFERAT PRACY DYPLOMOWEJ

REFERAT PRACY DYPLOMOWEJ REFERAT PRACY DYPLOMOWEJ Temat pracy: Projekt i implementacja środowiska do automatyzacji przeprowadzania testów aplikacji internetowych w oparciu o metodykę Behavior Driven Development. Autor: Stepowany

Bardziej szczegółowo

EXSO-CORE - specyfikacja

EXSO-CORE - specyfikacja EXSO-CORE - specyfikacja System bazowy dla aplikacji EXSO. Elementy tego systemu występują we wszystkich programach EXSO. Może on ponadto stanowić podstawę do opracowania nowych, dedykowanych systemów.

Bardziej szczegółowo

Bazy danych. Plan wykładu. Rozproszona baza danych. Fragmetaryzacja. Cechy bazy rozproszonej. Replikacje (zalety) Wykład 15: Rozproszone bazy danych

Bazy danych. Plan wykładu. Rozproszona baza danych. Fragmetaryzacja. Cechy bazy rozproszonej. Replikacje (zalety) Wykład 15: Rozproszone bazy danych Plan wykładu Bazy danych Cechy rozproszonej bazy danych Implementacja rozproszonej bazy Wykład 15: Rozproszone bazy danych Małgorzata Krętowska, Agnieszka Oniśko Wydział Informatyki PB Bazy danych (studia

Bardziej szczegółowo

Backend Administratora

Backend Administratora Backend Administratora mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2011 W tym celu korzystając z konsoli wydajemy polecenie: symfony generate:app backend Wówczas zostanie stworzona

Bardziej szczegółowo

Leonard G. Lobel Eric D. Boyd. Azure SQL Database Krok po kroku. Microsoft. Przekład: Marek Włodarz. APN Promise, Warszawa 2014

Leonard G. Lobel Eric D. Boyd. Azure SQL Database Krok po kroku. Microsoft. Przekład: Marek Włodarz. APN Promise, Warszawa 2014 Leonard G. Lobel Eric D. Boyd Microsoft TM Azure SQL Database Krok po kroku Przekład: Marek Włodarz APN Promise, Warszawa 2014 Spis treści Wprowadzenie........................................................

Bardziej szczegółowo

Projektowanie rozwiązań Big Data z wykorzystaniem Apache Hadoop & Family

Projektowanie rozwiązań Big Data z wykorzystaniem Apache Hadoop & Family Kod szkolenia: Tytuł szkolenia: HADOOP Projektowanie rozwiązań Big Data z wykorzystaniem Apache Hadoop & Family Dni: 5 Opis: Adresaci szkolenia: Szkolenie jest adresowane do programistów, architektów oraz

Bardziej szczegółowo

Szkolenie autoryzowane. MS 6232 Wdrażanie bazy danych Microsoft SQL Server 2008 R2

Szkolenie autoryzowane. MS 6232 Wdrażanie bazy danych Microsoft SQL Server 2008 R2 Szkolenie autoryzowane MS 6232 Wdrażanie bazy danych Microsoft SQL Server 2008 R2 Strona szkolenia Terminy szkolenia Rejestracja na szkolenie Promocje Opis szkolenia Szkolenie, gdzie uczestnicy zapoznają

Bardziej szczegółowo

Programowanie obiektowe

Programowanie obiektowe Programowanie obiektowe Wykład 13 Marcin Młotkowski 27 maja 2015 Plan wykładu Trwałość obiektów 1 Trwałość obiektów 2 Marcin Młotkowski Programowanie obiektowe 2 / 29 Trwałość (persistence) Definicja Cecha

Bardziej szczegółowo

Nadzorowanie stanu serwerów i ich wykorzystania przez użytkowników

Nadzorowanie stanu serwerów i ich wykorzystania przez użytkowników Uniwersytet Mikołaja Kopernika w Toruniu Wydział Matematyki i Informatyki Wydział Fizyki, Astronomii i Informatyki Stosowanej Tomasz Kapelak Nr albumu: 187404 Praca magisterska na kierunku Informatyka

Bardziej szczegółowo

Dotacje na innowacje. Inwestujemy w waszą przyszłość.

Dotacje na innowacje. Inwestujemy w waszą przyszłość. PROJEKT TECHNICZNY Implementacja Systemu B2B w firmie Lancelot i w przedsiębiorstwach partnerskich Przygotowane dla: Przygotowane przez: Lancelot Marek Cieśla Grzegorz Witkowski Constant Improvement Szkolenia

Bardziej szczegółowo

QUERY język zapytań do tworzenia raportów w AS/400

QUERY język zapytań do tworzenia raportów w AS/400 QUERY język zapytań do tworzenia raportów w AS/400 Dariusz Bober Katedra Informatyki Politechniki Lubelskiej Streszczenie: W artykule przedstawiony został język QUERY, standardowe narzędzie pracy administratora

Bardziej szczegółowo

WPROWADZENIE DO BAZ DANYCH

WPROWADZENIE DO BAZ DANYCH WPROWADZENIE DO BAZ DANYCH Pojęcie danych i baz danych Dane to wszystkie informacje jakie przechowujemy, aby w każdej chwili mieć do nich dostęp. Baza danych (data base) to uporządkowany zbiór danych z

Bardziej szczegółowo

Organizacyjnie. Prowadzący: dr Mariusz Rafało (hasło: BIG)

Organizacyjnie. Prowadzący: dr Mariusz Rafało   (hasło: BIG) Big Data Organizacyjnie Prowadzący: dr Mariusz Rafało mrafalo@sgh.waw.pl http://mariuszrafalo.pl (hasło: BIG) Automatyzacja Automatyzacja przetwarzania: Apache NiFi Źródło: nifi.apache.org 4 Automatyzacja

Bardziej szczegółowo

Systemy baz danych. mgr inż. Sylwia Glińska

Systemy baz danych. mgr inż. Sylwia Glińska Systemy baz danych Wykład 1 mgr inż. Sylwia Glińska Baza danych Baza danych to uporządkowany zbiór danych z określonej dziedziny tematycznej, zorganizowany w sposób ułatwiający do nich dostęp. System zarządzania

Bardziej szczegółowo

GS2TelCOMM. Rozszerzenie do TelCOMM 2.0. Opracował: Michał Siatkowski Zatwierdził: IMIĘ I NAZWISKO

GS2TelCOMM. Rozszerzenie do TelCOMM 2.0. Opracował: Michał Siatkowski Zatwierdził: IMIĘ I NAZWISKO GS2TelCOMM Rozszerzenie do TelCOMM 2.0 Opracował: Michał Siatkowski 29-03-2017 Zatwierdził: IMIĘ I NAZWISKO DATA TEL-STER 2017 Spis treści Wprowadzenie... 3 Architektura... 3 Instalacja... 3 Współpraca

Bardziej szczegółowo

MAMP: Można to pobrać i zainstalować z XAMPP: Można go pobrać i zainstalować z

MAMP: Można to pobrać i zainstalować z   XAMPP: Można go pobrać i zainstalować z WordPress : Omówienie I Instalacja Na początek, dlaczego byłbyś zainteresowany wykorzystaniem WordPressa razem z PhoneGap? Zapytałbym: "Dlaczego byś nie?" Moim zdaniem WordPress jest jednym z najłatwiejszych

Bardziej szczegółowo

Część I Tworzenie baz danych SQL Server na potrzeby przechowywania danych

Część I Tworzenie baz danych SQL Server na potrzeby przechowywania danych Spis treści Wprowadzenie... ix Organizacja ksiąŝki... ix Od czego zacząć?... x Konwencje przyjęte w ksiąŝce... x Wymagania systemowe... xi Przykłady kodu... xii Konfiguracja SQL Server 2005 Express Edition...

Bardziej szczegółowo

System generacji raportów

System generacji raportów Zalety systemu Czym jest ProReports? prostota instalacji, wieloplatformowość (AIX, Linux, Windows, Solaris), obsługa popularnych formatów (PDF, XLS, RTF, HTML,TXT,XML,CSV), obsługa wielu baz danych, raporty

Bardziej szczegółowo

Windows Serwer 2008 R2. Moduł 8. Mechanizmy kopii zapasowych

Windows Serwer 2008 R2. Moduł 8. Mechanizmy kopii zapasowych Windows Serwer 2008 R2 Moduł 8. Mechanizmy kopii zapasowych Co nowego w narzędziu Kopia zapasowa? 1. Większa elastyczność w zakresie możliwości wykonywania kopii zapasowych 2. Automatyczne zarządzanie

Bardziej szczegółowo

MongoDB. wprowadzenie. dr inż. Paweł Boiński, Politechnika Poznańska

MongoDB. wprowadzenie. dr inż. Paweł Boiński, Politechnika Poznańska MongoDB wprowadzenie dr inż. Paweł Boiński, Politechnika Poznańska Plan Historia Podstawowe pojęcia: Dokument Kolekcja Generowanie identyfikatora Model danych Dokumenty zagnieżdżone Dokumenty z referencjami

Bardziej szczegółowo

Podręcznik administratora Systemu SWD ST Instrukcja instalacji systemu

Podręcznik administratora Systemu SWD ST Instrukcja instalacji systemu Podręcznik administratora Systemu SWD ST Instrukcja instalacji systemu (wersja 1.1 dla 2.5.x) Abakus Systemy Teleinformatyczne Sp. z o.o. 2013 Spis treści ABAKUS SYSTEMY TELEINFORMATYCZNE Sp. z o.o. 1.

Bardziej szczegółowo

T-SQL dla każdego / Alison Balter. Gliwice, cop Spis treści. O autorce 11. Dedykacja 12. Podziękowania 12. Wstęp 15

T-SQL dla każdego / Alison Balter. Gliwice, cop Spis treści. O autorce 11. Dedykacja 12. Podziękowania 12. Wstęp 15 T-SQL dla każdego / Alison Balter. Gliwice, cop. 2016 Spis treści O autorce 11 Dedykacja 12 Podziękowania 12 Wstęp 15 Godzina 1. Bazy danych podstawowe informacje 17 Czym jest baza danych? 17 Czym jest

Bardziej szczegółowo

Kadry Optivum, Płace Optivum. Jak przenieść dane na nowy komputer?

Kadry Optivum, Płace Optivum. Jak przenieść dane na nowy komputer? Kadry Optivum, Płace Optivum Jak przenieść dane na nowy komputer? Aby kontynuować pracę z programem Kadry Optivum lub Płace Optivum (lub z obydwoma programami pracującymi na wspólnej bazie danych) na nowym

Bardziej szczegółowo

Szkolenie wycofane z oferty. Apache Cassandra - modelowanie, wydajność, analiza danych

Szkolenie wycofane z oferty. Apache Cassandra - modelowanie, wydajność, analiza danych Szkolenie wycofane z oferty Program szkolenia: Apache Cassandra - modelowanie, wydajność, analiza danych Informacje: Nazwa: Kod: Kategoria: Grupa docelowa: Czas trwania: Forma: Apache Cassandra - modelowanie,

Bardziej szczegółowo

WHITE PAPER. Planowanie, przygotowanie i testowanie działań na wypadek wystąpienia awarii

WHITE PAPER. Planowanie, przygotowanie i testowanie działań na wypadek wystąpienia awarii WHITE PAPER Planowanie, przygotowanie i testowanie działań na wypadek wystąpienia awarii 1 TABLE OF CONTENTS Wstęp...3 Symulator VERITAS Cluster Server...3 Doradca VERITAS Volume Replicator...5 Próbny

Bardziej szczegółowo

Baza danych. Baza danych to:

Baza danych. Baza danych to: Baza danych Baza danych to: zbiór danych o określonej strukturze, zapisany na zewnętrznym nośniku (najczęściej dysku twardym komputera), mogący zaspokoić potrzeby wielu użytkowników korzystających z niego

Bardziej szczegółowo

Wykład I. Wprowadzenie do baz danych

Wykład I. Wprowadzenie do baz danych Wykład I Wprowadzenie do baz danych Trochę historii Pierwsze znane użycie terminu baza danych miało miejsce w listopadzie w 1963 roku. W latach sześcdziesątych XX wieku został opracowany przez Charles

Bardziej szczegółowo

Dokument Detaliczny Projektu Temat: Księgarnia On-line Bukstor

Dokument Detaliczny Projektu Temat: Księgarnia On-line Bukstor Koszalin, 15.06.2012 r. Dokument Detaliczny Projektu Temat: Księgarnia On-line Bukstor Zespół projektowy: Daniel Czyczyn-Egird Wojciech Gołuchowski Michał Durkowski Kamil Gawroński Prowadzący: Dr inż.

Bardziej szczegółowo

Deduplikacja danych. Zarządzanie jakością danych podstawowych

Deduplikacja danych. Zarządzanie jakością danych podstawowych Deduplikacja danych Zarządzanie jakością danych podstawowych normalizacja i standaryzacja adresów standaryzacja i walidacja identyfikatorów podstawowa standaryzacja nazw firm deduplikacja danych Deduplication

Bardziej szczegółowo

Tworzenie i obsługa wirtualnego laboratorium komputerowego

Tworzenie i obsługa wirtualnego laboratorium komputerowego Uniwersytet Mikołaja Kopernika Wydział Fizyki, Astronomii i Informatyki Stosowanej Michał Ochociński nr albumu: 236401 Praca magisterska na kierunku informatyka stosowana Tworzenie i obsługa wirtualnego

Bardziej szczegółowo

Uruchomienie nowego kontekstu aplikacji

Uruchomienie nowego kontekstu aplikacji Uruchomienie nowego kontekstu aplikacji Niniejsza instrukcja (przygotowana dla systemów Debian) dotyczy uruchomienia nowej aplikacji w sytuacji, gdy mamy już jedną działającą. Działanie takie trzeba wykonać

Bardziej szczegółowo

dziennik Instrukcja obsługi

dziennik Instrukcja obsługi Ham Radio Deluxe dziennik Instrukcja obsługi Wg. Simon Brown, HB9DRV Tłumaczenie SP4JEU grudzień 22, 2008 Zawartość 3 Wprowadzenie 5 Po co... 5 Główne cechy... 5 baza danych 7 ODBC... 7 Który produkt

Bardziej szczegółowo

Liczba godzin 1,2 Organizacja zajęć Omówienie programu nauczania 2. Tematyka zajęć

Liczba godzin 1,2 Organizacja zajęć Omówienie programu nauczania 2. Tematyka zajęć rzedmiot : Systemy operacyjne Rok szkolny : 015/016 Klasa : 3 INF godz. x 30 tyg.= 60 godz. Zawód : technik informatyk; symbol 35103 rowadzący : Jacek Herbut Henryk Kuczmierczyk Numer lekcji Dział Tematyka

Bardziej szczegółowo

Django : praktyczne tworzenie aplikacji sieciowych / Antonio Mele. Gliwice, cop Spis treści

Django : praktyczne tworzenie aplikacji sieciowych / Antonio Mele. Gliwice, cop Spis treści Django : praktyczne tworzenie aplikacji sieciowych / Antonio Mele. Gliwice, cop. 2016 Spis treści O autorze 13 O recenzentach technicznych 14 Wprowadzenie 17 Rozdział 1. Utworzenie aplikacji bloga 21 Instalacja

Bardziej szczegółowo

Win Admin Replikator Instrukcja Obsługi

Win Admin Replikator Instrukcja Obsługi Win Admin Replikator Instrukcja Obsługi Monitoring Kopie danych (backup) E-mail Harmonogram lokalne i zewnętrzne repozytorium Logi Pamięć Procesor HDD Administracja sprzętem i oprogramowaniem (automatyzacja

Bardziej szczegółowo

Problemy niezawodnego przetwarzania w systemach zorientowanych na usługi

Problemy niezawodnego przetwarzania w systemach zorientowanych na usługi Problemy niezawodnego przetwarzania w systemach zorientowanych na usługi Jerzy Brzeziński, Anna Kobusińska, Dariusz Wawrzyniak Instytut Informatyki Politechnika Poznańska Plan prezentacji 1 Architektura

Bardziej szczegółowo

Modelowanie hierarchicznych struktur w relacyjnych bazach danych

Modelowanie hierarchicznych struktur w relacyjnych bazach danych Modelowanie hierarchicznych struktur w relacyjnych bazach danych Wiktor Warmus (wiktorwarmus@gmail.com) Kamil Witecki (kamil@witecki.net.pl) 5 maja 2010 Motywacje Teoria relacyjnych baz danych Do czego

Bardziej szczegółowo

2011-11-04. Instalacja SQL Server Konfiguracja SQL Server Logowanie - opcje SQL Server Management Studio. Microsoft Access Oracle Sybase DB2 MySQL

2011-11-04. Instalacja SQL Server Konfiguracja SQL Server Logowanie - opcje SQL Server Management Studio. Microsoft Access Oracle Sybase DB2 MySQL Instalacja, konfiguracja Dr inŝ. Dziwiński Piotr Katedra InŜynierii Komputerowej Kontakt: piotr.dziwinski@kik.pcz.pl 2 Instalacja SQL Server Konfiguracja SQL Server Logowanie - opcje SQL Server Management

Bardziej szczegółowo

Piotr Bubacz Cloud Computing

Piotr Bubacz Cloud Computing Cloud Computing ITA-112 Wersja 0.9 Warszawa, Czerwiec 2011 Spis treści Wprowadzenie i-4 Moduł 1 Wprowadzenie do Cloud Computing 1-1 Moduł 2 Wprowadzenie do Windows 2-1 Moduł 3 Storage Tabele 3-1 Moduł

Bardziej szczegółowo

XQTav - reprezentacja diagramów przepływu prac w formacie SCUFL przy pomocy XQuery

XQTav - reprezentacja diagramów przepływu prac w formacie SCUFL przy pomocy XQuery http://xqtav.sourceforge.net XQTav - reprezentacja diagramów przepływu prac w formacie SCUFL przy pomocy XQuery dr hab. Jerzy Tyszkiewicz dr Andrzej Kierzek mgr Jacek Sroka Grzegorz Kaczor praca mgr pod

Bardziej szczegółowo

AE/ZP-27-16/14. Oprogramowanie do wykonywania kopii zapasowych oraz zarządzania maszynami wirtualnymi

AE/ZP-27-16/14. Oprogramowanie do wykonywania kopii zapasowych oraz zarządzania maszynami wirtualnymi AE/ZP-27-16/14 Załącznik B Oprogramowanie do wykonywania kopii zapasowych oraz zarządzania maszynami wirtualnymi Wykonywanie kopii zapasowych Oprogramowanie do archiwizacji musi współpracować z infrastrukturą

Bardziej szczegółowo

Bazy danych. Zenon Gniazdowski WWSI, ITE Andrzej Ptasznik WWSI

Bazy danych. Zenon Gniazdowski WWSI, ITE Andrzej Ptasznik WWSI Bazy danych Zenon Gniazdowski WWSI, ITE Andrzej Ptasznik WWSI Wszechnica Poranna Trzy tematy: 1. Bazy danych - jak je ugryźć? 2. Język SQL podstawy zapytań. 3. Mechanizmy wewnętrzne baz danych czyli co

Bardziej szczegółowo

LABORATORIUM 8,9: BAZA DANYCH MS-ACCESS

LABORATORIUM 8,9: BAZA DANYCH MS-ACCESS UNIWERSYTET ZIELONOGÓRSKI INSTYTUT INFORMATYKI I ELEKTROTECHNIKI ZAKŁAD INŻYNIERII KOMPUTEROWEJ Przygotowali: mgr inż. Arkadiusz Bukowiec mgr inż. Remigiusz Wiśniewski LABORATORIUM 8,9: BAZA DANYCH MS-ACCESS

Bardziej szczegółowo

Platformy programistyczne:.net i Java L ABORATORIUM 7,8: HACKATHON - JTTT

Platformy programistyczne:.net i Java L ABORATORIUM 7,8: HACKATHON - JTTT Platformy programistyczne:.net i Java L ABORATORIUM 7,8: HACKATHON - JTTT O co chodzi? - Przypomnienie Hackathon - http://en.wikipedia.org/wiki/hackathon A hackathon is an event in which computer programmers

Bardziej szczegółowo

77. Modelowanie bazy danych rodzaje połączeń relacyjnych, pojęcie klucza obcego.

77. Modelowanie bazy danych rodzaje połączeń relacyjnych, pojęcie klucza obcego. 77. Modelowanie bazy danych rodzaje połączeń relacyjnych, pojęcie klucza obcego. Przy modelowaniu bazy danych możemy wyróżnić następujące typy połączeń relacyjnych: jeden do wielu, jeden do jednego, wiele

Bardziej szczegółowo

Dokument Detaliczny Projektu

Dokument Detaliczny Projektu Dokument Detaliczny Projektu Dla Biblioteki miejskiej Wersja 1.0 Streszczenie Niniejszy dokument detaliczny projektu(ddp) przedstawia szczegóły pracy zespołu projektowego, nad stworzeniem aplikacji bazodanowej

Bardziej szczegółowo

Projektowanie baz danych za pomocą narzędzi CASE

Projektowanie baz danych za pomocą narzędzi CASE Projektowanie baz danych za pomocą narzędzi CASE Metody tworzenia systemów informatycznych w tym, także rozbudowanych baz danych są komputerowo wspomagane przez narzędzia CASE (ang. Computer Aided Software

Bardziej szczegółowo

Zmiana treści Specyfikacji Istotnych Warunków Zamówienia.

Zmiana treści Specyfikacji Istotnych Warunków Zamówienia. Projekt współfinansowany przez Unię Europejską z Europejskiego Funduszu Rozwoju Regionalnego w ramach Regionalnego Programu Operacyjnego Województwa Śląskiego na lata 2007-2013 ZP.271.1.2013 Czerwionka-Leszczyny

Bardziej szczegółowo

Sposoby klastrowania aplikacji webowych w oparciu o rozwiązania OpenSource. Piotr Klimek. piko@piko.homelinux.net

Sposoby klastrowania aplikacji webowych w oparciu o rozwiązania OpenSource. Piotr Klimek. piko@piko.homelinux.net Sposoby klastrowania aplikacji webowych w oparciu o rozwiązania OpenSource Piotr Klimek piko@piko.homelinux.net Agenda Wstęp Po co to wszystko? Warstwa WWW Warstwa SQL Warstwa zasobów dyskowych Podsumowanie

Bardziej szczegółowo

Wdrożenie modułu płatności eservice. dla systemu Magento 1.4 1.9

Wdrożenie modułu płatności eservice. dla systemu Magento 1.4 1.9 Wdrożenie modułu płatności eservice dla systemu Magento 1.4 1.9 - dokumentacja techniczna Wer. 01 Warszawa, styczeń 2014 1 Spis treści: 1 Wstęp... 3 1.1 Przeznaczenie dokumentu... 3 1.2 Przygotowanie do

Bardziej szczegółowo

Jak ustawić cele kampanii?

Jak ustawić cele kampanii? Jak ustawić cele kampanii? Czym są cele? Jest to funkcjonalność pozwalająca w łatwy sposób śledzić konwersje wygenerowane na Twojej stronie www poprzez wiadomości email wysłane z systemu GetResponse. Mierzenie

Bardziej szczegółowo

Rok szkolny 2015/16 Sylwester Gieszczyk. Wymagania edukacyjne w technikum. ADMINISTROWANIE BAZAMI DANYCH kl. 4c

Rok szkolny 2015/16 Sylwester Gieszczyk. Wymagania edukacyjne w technikum. ADMINISTROWANIE BAZAMI DANYCH kl. 4c Wymagania edukacyjne w technikum ADMINISTROWANIE BAZAMI DANYCH kl. 4c Lp. 1 2 4 5 Temat Zasady dotyczące zarządzania projektem podczas prac związanych z tworzeniem bazy oraz cykl życiowy bazy Modele tworzenia

Bardziej szczegółowo

CouchDB. Michał Nowikowski

CouchDB. Michał Nowikowski CouchDB Michał Nowikowski Agenda Wprowadzenie do CouchDB Mój przypadek Wyniki i wnioski Dokumenty CouchDB Format JSON Pary nazwa wartość Możliwe tablice i struktury Załączniki Brak limitów na liczbę i

Bardziej szczegółowo

Webowy generator wykresów wykorzystujący program gnuplot

Webowy generator wykresów wykorzystujący program gnuplot Uniwersytet Mikołaja Kopernika Wydział Fizyki, Astronomii i Informatyki Stosowanej Marcin Nowak nr albumu: 254118 Praca inżynierska na kierunku informatyka stosowana Webowy generator wykresów wykorzystujący

Bardziej szczegółowo

Kancelaria Prawna.WEB - POMOC

Kancelaria Prawna.WEB - POMOC Kancelaria Prawna.WEB - POMOC I Kancelaria Prawna.WEB Spis treści Część I Wprowadzenie 1 Część II Wymagania systemowe 1 Część III Instalacja KP.WEB 9 1 Konfiguracja... dostępu do dokumentów 11 Część IV

Bardziej szczegółowo

WEBCON BPS Instalacja Standalone

WEBCON BPS Instalacja Standalone WEBCON BPS Instalacja Standalone 1. Wymagania wstępne... 2 1.1. Software... 2 1.2. Hardware... 2 1.2.1. Scenariusze sprzętowe konfiguracji... 2 1.2.2. Instalacja minimalna all-in-one installation... 2

Bardziej szczegółowo

Spis treści MONITOR PRACY... 4

Spis treści MONITOR PRACY... 4 Co nowego Spis treści MONITOR PRACY...... 4 Konfiguracja plików... 5 Konfiguracja globalna... 6 Pliki... 6 Projekty... 6 Interfejs użytkownika... 7 Synchronizacja... 7 Typ serwera... 8 Test połączenia...

Bardziej szczegółowo

SZKOLENIE: Administrator baz danych. Cel szkolenia

SZKOLENIE: Administrator baz danych. Cel szkolenia SZKOLENIE: Administrator baz danych. Cel szkolenia Kurs Administrator baz danych skierowany jest przede wszystkim do osób zamierzających rozwijać umiejętności w zakresie administrowania bazami danych.

Bardziej szczegółowo

Problemy optymalizacji, rozbudowy i integracji systemu Edu wspomagającego e-nauczanie i e-uczenie się w PJWSTK

Problemy optymalizacji, rozbudowy i integracji systemu Edu wspomagającego e-nauczanie i e-uczenie się w PJWSTK Problemy optymalizacji, rozbudowy i integracji systemu Edu wspomagającego e-nauczanie i e-uczenie się w PJWSTK Paweł Lenkiewicz Polsko Japońska Wyższa Szkoła Technik Komputerowych Plan prezentacji PJWSTK

Bardziej szczegółowo

Płace Optivum. 1. Zainstalować serwer SQL (Microsoft SQL Server 2008 R2) oraz program Płace Optivum.

Płace Optivum. 1. Zainstalować serwer SQL (Microsoft SQL Server 2008 R2) oraz program Płace Optivum. Płace Optivum Jak przenieść dane programu Płace Optivum na nowy komputer? Aby kontynuować pracę z programem Płace Optivum na nowym komputerze, należy na starym komputerze wykonać kopię zapasową bazy danych

Bardziej szczegółowo

Wdrożenie modułu płatności eservice. dla systemu Zen Cart 1.3.9 1.5

Wdrożenie modułu płatności eservice. dla systemu Zen Cart 1.3.9 1.5 Wdrożenie modułu płatności eservice dla systemu Zen Cart 1.3.9 1.5 - dokumentacja techniczna Wer. 01 Warszawa, styczeń 2014 1 Spis treści: 1 Wstęp... 3 1.1 Przeznaczenie dokumentu... 3 1.2 Przygotowanie

Bardziej szczegółowo

JDBC w LoXiMie. Interfejs Java Database Connectivity dla systemu LoXiM. Adam Michalik 2008

JDBC w LoXiMie. Interfejs Java Database Connectivity dla systemu LoXiM. Adam Michalik 2008 JDBC w LoXiMie Interfejs Java Database Connectivity dla systemu LoXiM Adam Michalik 2008 Sterownik JDBC co to jest? Sterownik JDBC to zbiór klas implementujących interfejsy opisane w specyfikacji JDBC

Bardziej szczegółowo

BSX PRINTER INSTRUKCJA UŻYTKOWNIKA. Autor: Karol Wierzchołowski 30 marca 2015

BSX PRINTER INSTRUKCJA UŻYTKOWNIKA. Autor: Karol Wierzchołowski 30 marca 2015 ! BSX PRINTER INSTRUKCJA UŻYTKOWNIKA Autor: Karol Wierzchołowski 30 marca 2015 SPIS TREŚCI WSTĘP... 3 INTERFEJS PROGRAMU... 5 KONFIGURACJA PROGRAMU... 6 DRUKOWANIE PARAGONÓW I FAKTUR... 8 REJESTRACJA PROGRAMU...

Bardziej szczegółowo

SYSTEMY OPERACYJNE I SIECI KOMPUTEROWE

SYSTEMY OPERACYJNE I SIECI KOMPUTEROWE SYSTEMY OPERACYJNE I SIECI KOMPUTEROWE WINDOWS 1 SO i SK/WIN 006 Wydajność systemu 2 SO i SK/WIN Najprostszym sposobem na poprawienie wydajności systemu, jeżeli dysponujemy zbyt małą ilością pamięci RAM

Bardziej szczegółowo

Wydział Informatyki, Elektroniki i Telekomunikacji. Katedra Informatyki

Wydział Informatyki, Elektroniki i Telekomunikacji. Katedra Informatyki Wydział Informatyki, Elektroniki i Telekomunikacji Katedra Informatyki Pastebin w wersji zorientowanej na środowisko mobilne z klientem pozwalającym na oba kierunki przeklejania. Dokumentacja deweloperska

Bardziej szczegółowo

Kadry Optivum, Płace Optivum. Jak przenieść dane na nowy komputer?

Kadry Optivum, Płace Optivum. Jak przenieść dane na nowy komputer? Kadry Optivum, Płace Optivum Jak przenieść dane na nowy komputer? Aby kontynuować pracę z programem Kadry Optivum lub Płace Optivum (lub z obydwoma programami pracującymi na wspólnej bazie danych) na nowym

Bardziej szczegółowo

1. Opis. 2. Wymagania sprzętowe:

1. Opis. 2. Wymagania sprzętowe: 1. Opis Aplikacja ARSOFT-WZ2 umożliwia konfigurację, wizualizację i rejestrację danych pomiarowych urządzeń produkcji APAR wyposażonych w interfejs komunikacyjny RS232/485 oraz protokół MODBUS-RTU. Aktualny

Bardziej szczegółowo

Bazy danych Wykład zerowy. P. F. Góra

Bazy danych Wykład zerowy. P. F. Góra Bazy danych Wykład zerowy P. F. Góra http://th-www.if.uj.edu.pl/zfs/gora/ 2012 Patron? Św. Izydor z Sewilli (VI wiek), biskup, patron Internetu (sic!), stworzył pierwszy katalog Copyright c 2011-12 P.

Bardziej szczegółowo

System zarządzający grami programistycznymi Meridius

System zarządzający grami programistycznymi Meridius System zarządzający grami programistycznymi Meridius Instytut Informatyki, Uniwersytet Wrocławski 20 września 2011 Promotor: prof. Krzysztof Loryś Gry komputerowe a programistyczne Gry komputerowe Z punktu

Bardziej szczegółowo

Uniwersytet Mikołaja Kopernika. Wydział Matematyki i Informatyki Wydział Fizyki, Astronomii i Informatyki Stosowanej

Uniwersytet Mikołaja Kopernika. Wydział Matematyki i Informatyki Wydział Fizyki, Astronomii i Informatyki Stosowanej Uniwersytet Mikołaja Kopernika Wydział Matematyki i Informatyki Wydział Fizyki, Astronomii i Informatyki Stosowanej Marcin HENRYKOWSKI Nr albumu: 158069 Praca magisterska na kierunku Informatyka Archiwizacja

Bardziej szczegółowo

Podstawy technologii WWW

Podstawy technologii WWW Podstawy technologii WWW Ćwiczenie 11 PHP, MySQL: więcej, więcej!, więcej!!. tabel i funkcjonalności. Na dzisiejszych zajęciach zdefiniujemy w naszej bazie kilka tabel powiązanych kluczem obcym i zobaczymy,

Bardziej szczegółowo