Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Both sides previous revision Poprzednia wersja
Nowa wersja
Poprzednia wersja
pl:dydaktyka:ztb:2010:projekty:nosql_casandra:start [2010/06/29 23:32]
ztb2010
pl:dydaktyka:ztb:2010:projekty:nosql_casandra:start [2019/06/27 15:50] (aktualna)
Linia 4: Linia 4:
  
 Cassandra została otwarta przez Facebooka w 2008 roku. Aktualnie rozwijana jest przez Apache oraz współpracowników z różnych firm. Cassandra została otwarta przez Facebooka w 2008 roku. Aktualnie rozwijana jest przez Apache oraz współpracowników z różnych firm.
 +
 +====== Instalacja i Konfiguracja ======
 +
 + ​Poniższy opis dotyczy instalacji i konfiguracji na systemie linuksowym a konkretniej na Debianie. W innych systemach operacyjnych kroki te przebiegają analogicznie. Debian został wybrany ze względu na częste wykorzystywanie go jako OS dla serwera baz danych.
 +
 +===== Apache Thrift =====
 +
 +Thrift wykorzystywany jest do tworzenie skalowalnych,​ multiplatformowych usług webowych. Generuje klienty RPC w dowolnym języku (z pośród C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk, OCaml) które mogą komunikować się z tym samym serwerem RPC. Dzięki takiemu podejściu Cassandra może być dostępna w łatwy i szybki sposób z pośród wielu języków programowania.
 +
 +
 +instalacja dodatkowych pakietów na debianie
 +
 +    * libboost-all-dev
 +    * bison
 +    * flex
 +
 +konfiguracja (bez wsparcia dla ruby):
 +
 +<​code="​bash">​
 +./configure --disable-gen-rb --without-ruby
 +make
 +make install
 +</​code>​
 +
 +do poprawnego działania z pythonem należy jeszcze ręcznie zainstalować biblioteki:
 +<​code>​
 +cd lib/py
 +python setup.py install
 +</​code>​
 +
 +linki:\\
 +tutorial do thrifta [[http://​wiki.apache.org/​thrift/​Tutorial]]\\
 +
 +===== Cassandra =====
 +
 +najprostsza instalacja polega na rozpakowaniu tarballa z plikami cassandry i skonfigurowaniu ścieżek dostępu do logów i do danych w pliku conf/​storage-conf.xml
 +
 +Jeżeli nie chcemy zmieniać defaultowych ścieżek wystarczy że stworzymy poniższe katalogi tak aby odpowiadały tym zdefiniowanym:​
 +
 +<​code="​bash">​
 + sudo mkdir -p /​var/​log/​cassandra
 + sudo chown -R `whoami` /​var/​log/​cassandra
 + sudo mkdir -p /​var/​lib/​cassandra
 + sudo chown -R `whoami` /​var/​lib/​cassandra
 +</​code>​
 +
 +Uruchmienie pojedynczego węzła:
 +
 +<​code="​bash">​
 +bin/​cassandra -f  # -f loguje na stdout
 +</​code>​
 +
 +testowanie węzła poprzez konsole cli:
 +
 +<​code="​bash">​
 +bin/​cassandra-cli --host localhost --port 9160
 +</​code>​
  
 ====== Model ====== ====== Model ======
Linia 226: Linia 283:
 </​code>​ </​code>​
  
-Jak już wspomnieliśmy wyżej każda kolumna musi zawierać pole timestamp. Pierwszą rzeczą którą robimy jest stworzenie ​ zmiennej przechowującej czas utworzenia. Jest ona używana do rozwiązywania konfliktów gdy mamy kilka podobnych kluczy. Dlatego nie należy nigdy ustawiać takich samych wartości tego pola; najczęściej stosuje się liczbę milisekund które upłynęły od roku 1970. +Jak już wspomnieliśmy wyżej każda kolumna musi zawierać pole **timestamp**. Pierwszą rzeczą którą robimy jest stworzenie ​ zmiennej przechowującej czas utworzenia. Jest ona używana do rozwiązywania konfliktów gdy mamy kilka podobnych kluczy. Dlatego nie należy nigdy ustawiać takich samych wartości tego pola; najczęściej stosuje się liczbę milisekund które upłynęły od roku 1970. 
 W następnej linii tworzymy mapę w której będziemy umieszczać wiersze. ​ Kluczem w naszej mapie będzie String który jest nazwą ColumnFamily czyli naszą „tabelą” zdefiniowaną wcześniej w pliku konfiguracyjnym. Wartością mapy będzie lista specjalnej struktury mogącej przechowywać Columnę lub SuperColumnę,​ u nas to będą jak już wcześniej wspomnieliśmy Columny czyli konstrukcja przechowująca trzy pola. W następnej linii tworzymy mapę w której będziemy umieszczać wiersze. ​ Kluczem w naszej mapie będzie String który jest nazwą ColumnFamily czyli naszą „tabelą” zdefiniowaną wcześniej w pliku konfiguracyjnym. Wartością mapy będzie lista specjalnej struktury mogącej przechowywać Columnę lub SuperColumnę,​ u nas to będą jak już wcześniej wspomnieliśmy Columny czyli konstrukcja przechowująca trzy pola.
  
 W kolejnych ​ liniach tworzymy ​ instacje naszych Column: country, population i area oraz wstawiamy do nich odpowiednie wartości przesłane jako argumenty funkcji, a następnie każdą Columne dodajemy do listy. W kolejnych ​ liniach tworzymy ​ instacje naszych Column: country, population i area oraz wstawiamy do nich odpowiednie wartości przesłane jako argumenty funkcji, a następnie każdą Columne dodajemy do listy.
  
-Na końcu używamy metody batch_insert do zapisania wszystkich danych jednorazowo w bazie. W przypadku gdybyśmy chcieli zapisać tylko pojedynczą Columne należy użyć metody insert. Jako parametry dla metody batch_insert wykorzystujemy klucz naszej tabeli czyli miasto do którego odnoszą się wszystkie dane zapisane w strukturze Column, nazwę schematu oraz mapę o której mówiliśmy wcześniej. Ostatnim parametrem jest tzw. ConsistencyLevel który jest wykorzystywany przy wszystkich operacjach zapisu oraz czytania z bazy i wskazuje kiedy żądanie klienta zostaje wykonane. Typ ALL mówi, że zapis powinien się odbyć przed udzieleniem odpowiedzi klientowi. Dokładne znaczenie każdego ​ parametru jest wyjaśnione na stronie wiki Cassandry.+Na końcu używamy metody ​**batch_insert** do zapisania wszystkich danych jednorazowo w bazie. W przypadku gdybyśmy chcieli zapisać tylko pojedynczą Columne należy użyć metody ​**insert**. Jako parametry dla metody batch_insert wykorzystujemy klucz naszej tabeli czyli miasto do którego odnoszą się wszystkie dane zapisane w strukturze Column, nazwę schematu oraz mapę o której mówiliśmy wcześniej. Ostatnim parametrem jest tzw. **ConsistencyLevel** który jest wykorzystywany przy wszystkich operacjach zapisu oraz czytania z bazy i wskazuje kiedy żądanie klienta zostaje wykonane. Typ **ALL** mówi, że zapis powinien się odbyć przed udzieleniem odpowiedzi klientowi. Dokładne znaczenie każdego ​ parametru jest wyjaśnione na stronie wiki Cassandry ​[[http://​wiki.apache.org/​cassandra/​API#​ConsistencyLevel]].
  
 ==== Odczyt z bazy ==== ==== Odczyt z bazy ====
Linia 264: Linia 321:
 </​code>​ </​code>​
  
-KeyRange jest używane do wyspecyfikowania jaki zakres kluczy chcemy wyciągnąć z bazy. W naszym przypadku w rzeczywistości nie definiujemy zakresu a jedynie ilość wierszy które chcemy wczytać z bazy, dlatego w konstruktorze przekazujemy liczbę 3 co odpowiada trzem wierszom.+**KeyRange** jest używane do wyspecyfikowania jaki zakres kluczy chcemy wyciągnąć z bazy. W naszym przypadku w rzeczywistości nie definiujemy zakresu a jedynie ilość wierszy które chcemy wczytać z bazy, dlatego w konstruktorze przekazujemy liczbę 3 co odpowiada trzem wierszom.
  
-SliceRange jest strukturą przechowującą informacje o zakresie, kolejności oraz ilości dla zapytania które zwraca wiele kolumn. Można ją utożsamiać z poleceniami LIMIT oraz ORDER BY z języka SQL. Metoda setStart ustawia kolumnę ​ od której powinniśmy zacząć pobieranie danych. Pusta tablica byte oznacza rozpoczęcie od pierwszej kolumny. Metoda setFinish ustawia Columne na której powinniśmy skończyć pobieranie danych. Pusta tablica byte oznacza odzyskanie wszystkich Column dopóki nie uzyskamy wartości count. +**SliceRange** jest strukturą przechowującą informacje o zakresie, kolejności oraz ilości dla zapytania które zwraca wiele kolumn. Można ją utożsamiać z poleceniami LIMIT oraz ORDER BY z języka SQL. Metoda ​**setStart** ustawia kolumnę ​ od której powinniśmy zacząć pobieranie danych. Pusta tablica byte oznacza rozpoczęcie od pierwszej kolumny. Metoda ​**setFinish** ustawia Columne na której powinniśmy skończyć pobieranie danych. Pusta tablica byte oznacza odzyskanie wszystkich Column dopóki nie uzyskamy wartości count. 
-SliceRange posiada jeszcze jedną funkcje setCount której nie użyliśmy tutaj, a oznaczającą liczbę Column które chcemy zwrócić – coś jak LIMIT w SQL.+SliceRange posiada jeszcze jedną funkcje ​**setCount** której nie użyliśmy tutaj, a oznaczającą liczbę Column które chcemy zwrócić – coś jak LIMIT w SQL.
  
-Następnie dzięki SlicePredicate ustawiamy dane które chcemy odzyskać, u nas jest to zdefiniowany wcześniej przy użyciu SliceRange pewien zakres kolumn.+Następnie dzięki ​**SlicePredicate** ustawiamy dane które chcemy odzyskać, u nas jest to zdefiniowany wcześniej przy użyciu SliceRange pewien zakres kolumn.
  
-W końcu dzięki metodzie get_range_slices wczytujemy dane i przypisujemy je do listy obiektów KeySlice. Jest to obiekt przechowujący ​ odzyskane wiersze zawierający klucz i kolumny należące do danego wiersza.+W końcu dzięki metodzie ​**get_range_slices** wczytujemy dane i przypisujemy je do listy obiektów ​**KeySlice**. Jest to obiekt przechowujący ​ odzyskane wiersze zawierający klucz i kolumny należące do danego wiersza.
  
  
Linia 298: Linia 355:
 Otrzymany rezultat wygląda następująco:​ Otrzymany rezultat wygląda następująco:​
  
-Dodaje miasta +  ​Dodaje miasta 
-Wyciągam dane z bazy:+  Wyciągam dane z bazy:
   Key: '​Warszawa'​   Key: '​Warszawa'​
   name: '​area',​ value: '​51724',​ timestamp: 1276876711965   name: '​area',​ value: '​51724',​ timestamp: 1276876711965
Linia 572: Linia 629:
 pp = pprint.PrettyPrinter(indent = 2) pp = pprint.PrettyPrinter(indent = 2)
 host = '​localhost'​ host = '​localhost'​
-port = 9090+port = 9160
 uri = ''​ uri = ''​
 framed = False framed = False
Linia 578: Linia 635:
 argi = 1 argi = 1
  
-if sys.argv[argi] == '​-h':​+if len(sys.argv)>​1 and sys.argv[argi] == '​-h':​
   parts = sys.argv[argi+1].split(':'​) ​   parts = sys.argv[argi+1].split(':'​) ​
   host = parts[0]   host = parts[0]
   port = int(parts[1])   port = int(parts[1])
   argi += 2   argi += 2
 +
  
 if http: if http:
Linia 600: Linia 658:
     def translate(self,​ lang_from, word_from, lang_to):     def translate(self,​ lang_from, word_from, lang_to):
         colPath = ColumnPath("​Words",​ lang_from, lang_to)         colPath = ColumnPath("​Words",​ lang_from, lang_to)
-        ​pp.pprint(client.get('​Dictionary',​ word_from, colPath, ConsistencyLevel.ONE,​)) +        ​try: 
-    +            ret = client.get('​Dictionary',​ word_from, colPath, ConsistencyLevel.ONE,​) 
 +            if ret: 
 +                print "​translate " + word_from + " (" + lang_from + " - " +lang_to+"​):​ " + ret.column.value 
 +        except NotFoundException:​ 
 +            print "there is no translate for " + word_from + " (" + lang_from + " - " +lang_to+"​)" 
     def getAllTranslates(self,​ lang_from, word_from):     def getAllTranslates(self,​ lang_from, word_from):
         colParent = ColumnParent("​Words",​ lang_from)         colParent = ColumnParent("​Words",​ lang_from)
         slPred = SlicePredicate(None,​ SliceRange('',''​))         slPred = SlicePredicate(None,​ SliceRange('',''​))
-        ​pp.pprint(client.get_slice('​Dictionary',​ word_from, colParent, slPred, ConsistencyLevel.ONE,​))+        ​ret = client.get_slice('​Dictionary',​ word_from, colParent, slPred, ConsistencyLevel.ONE,​) 
 +        print "all transalte for word " + word_from + " (" + lang_from + "):" 
 +        for item in ret: 
 +            print " ​ translate " + word_from + " (" + lang_from + " - " +item.column.name+"​):​ " + item.column.value
         ​         ​
  
Linia 611: Linia 677:
         colPath = ColumnPath("​Words",​ lang_from, lang_to)         colPath = ColumnPath("​Words",​ lang_from, lang_to)
         timestamp = int(time.time())         timestamp = int(time.time())
-        ​pp.pprint(client.insert('​Dictionary',​ word_from, colPath, word_to, timestamp, ConsistencyLevel.ONE,​))+        ​ret = client.insert('​Dictionary',​ word_from, colPath, word_to, timestamp, ConsistencyLevel.ONE,​) 
 +        if ret is None: 
 +            print "​inserted word "​+word_from+"​ ("​+lang_from+"​)"​ + " - " +word_to+"​ ("​+lang_to+"​)
 +        else: 
 +            print ret
  
     def removeWord(self,​ lang_from, lang_to, word_from):     def removeWord(self,​ lang_from, lang_to, word_from):
         colPath = ColumnPath("​Words",​ lang_from, lang_to)         colPath = ColumnPath("​Words",​ lang_from, lang_to)
         timestamp = int(time.time())         timestamp = int(time.time())
-        ​pp.pprint(client.remove('​Dictionary',​ word_from, colPath, timestamp, ConsistencyLevel.ONE,​))+        ​ret = client.remove('​Dictionary',​ word_from, colPath, timestamp, ConsistencyLevel.ONE,​) 
 +        if ret is None: 
 +            print "​removed word " + word_from + " ("​+lang_from+"​ - "​+lang_to+"​)
  
  
Linia 623: Linia 696:
 dic.addWord("​pl","​de","​dom","​house"​) dic.addWord("​pl","​de","​dom","​house"​)
 dic.addWord("​pl","​cz","​dom","​holpiczka"​) dic.addWord("​pl","​cz","​dom","​holpiczka"​)
 +
 +print
  
 dic.removeWord("​pl","​de","​dom"​) dic.removeWord("​pl","​de","​dom"​)
 +
 +print 
  
 dic.translate("​pl",​ "​dom",​ "​en"​) dic.translate("​pl",​ "​dom",​ "​en"​)
 +dic.translate("​pl",​ "​dom",​ "​cz"​)
 +dic.translate("​pl",​ "​dom",​ "​de"​)
 +
 +print
 +
 dic.getAllTranslates("​pl","​dom"​) dic.getAllTranslates("​pl","​dom"​)
  
Linia 648: Linia 730:
   * Odporna na uszkodzenia – dane są automatycznie replikowane do wielu węzłów. Zepsute węzły mogą być zastąpione bez żadnego przestoju.   * Odporna na uszkodzenia – dane są automatycznie replikowane do wielu węzłów. Zepsute węzły mogą być zastąpione bez żadnego przestoju.
   * Elastyczna – wydajność zapisywania i odczytywania wzrasta liniowo wraz z dodawaniem nowych maszyn bez żadnego przestoju lub przerw w działaniu aplikacji.   * Elastyczna – wydajność zapisywania i odczytywania wzrasta liniowo wraz z dodawaniem nowych maszyn bez żadnego przestoju lub przerw w działaniu aplikacji.
 +  * Wytrzymała - Cassandra jest odpowiednia dla aplikacji, które nie mogą sobie pozwolić na utratę danych, nawet gdy całe centrum danych padnie
 +  * "​Sprawdzona"​ - mimo wciąż niezbyt wielkiej popularności z Cassandry korzystają takie firmy jak Digg, Facebook, Twitter, Reddit, Rackspace, Cloudkick, Cisco, SimpleGeo, Ooyala, OpenX, i wiele innych posiadających duże zbiory danych. Największy klaster danych zawiera ponad 100TB danych na ponad 150 urządzeniach.
   ​   ​
 +
 ==== Pozostałe możliwości Cassandry ==== ==== Pozostałe możliwości Cassandry ====
  
pl/dydaktyka/ztb/2010/projekty/nosql_casandra/start.1277847151.txt.gz · ostatnio zmienione: 2019/06/27 15:56 (edycja zewnętrzna)
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0