JavaRush /Blog Java /Random-PL /Zookeeper, czyli jak wygląda życie zookeepera
Viacheslav
Poziom 3

Zookeeper, czyli jak wygląda życie zookeepera

Opublikowano w grupie Random-PL
Zookeeper, czyli jak żyje pracownik zoo - 1

Wstęp

Aplikacje Java często mają różne konfiguracje. Na przykład adres i port połączenia. Na przykład mogłoby to wyglądać tak, gdybyśmy użyli klasy Właściwości :
public static void main(String []args) {
	Properties props = new Properties();
	props.setProperty("host", "www.tutorialspoint.com");
	System.out.println("Hello, " + props.getProperty("host"));
}
I to chyba wystarczy, bo... możemy uzyskać Właściwości z pliku. I wydaje się, że wszystko dobrze się u nas układa na jednej maszynie. Ale wyobraźcie sobie, że nasz system zaczyna składać się z różnych systemów, które są od siebie oddzielone? System taki nazywany jest także systemem rozproszonym. W Wikipedii można znaleźć następującą definicję: Systemy rozproszone to systemy, których komponenty znajdują się na różnych komputerach w sieci, które komunikują się ze sobą i koordynują swoje działania poprzez wymianę między sobą komunikatów. Możesz spojrzeć na następujący diagram:
Zookeeper, czyli jak żyje pracownik zoo - 2
Dzięki takiemu podejściu pojedynczy system jest dzielony na komponenty. Konfiguracja jest oddzielnym wspólnym komponentem. Każdy z pozostałych komponentów działa jako klient dla komponentu konfiguracyjnego. Ten przypadek nazywa się „ Konfiguracją rozproszoną ”. Istnieje wiele różnych implementacji konfiguracji rozproszonej. A w dzisiejszej recenzji proponuję zapoznać się z jednym z nich, zwanym Zookeeperem.
Zookeeper, czyli jak żyje pracownik zoo - 3

Opiekun zoo

Droga do poznania Zookeepera zaczyna się od jego oficjalnej strony internetowej: zookeeper.apache.org. Na oficjalnej stronie należy przejść do sekcji „ Pobierz ” . W tej sekcji pobierz archiwum w formacie .tar.gz, na przykład „zookeeper-3.4.13.tar.gz”. tar to format archiwum tradycyjny dla systemów Unit. gz - oznacza, że ​​do kompresji archiwum używany jest gzip. Jeśli pracujemy na komputerze z systemem Windows, nie powinno nam to przeszkadzać. Większość nowoczesnych archiwizatorów (na przykład 7-zip ) może doskonale współpracować z nimi w systemie Windows. Wyodrębnijmy zawartość do jakiegoś katalogu. Jednocześnie zobaczymy różnicę - na dysku w stanie rozpakowanym zajmie około 60 megabajtów, a my pobraliśmy archiwum o rozmiarze około 35 megabajtów. Jak widać kompresja naprawdę działa. Teraz musisz uruchomić Zookeeper. Ogólnie rzecz biorąc, Zookeeper jest rodzajem serwera. Zookeeper może działać w jednym z dwóch trybów: samodzielnym lub replikowanym . Rozważmy najprostszą opcję, zwaną także pierwszą opcją - tryb samodzielny. Aby Zookeper mógł działać, potrzebny jest plik konfiguracyjny. Dlatego utwórzmy go tutaj: [КаталогРаспаковкиZookeeper]/conf/zoo.cfg. W przypadku systemu Windows zastosujemy zalecenie z Medium: „ Instalowanie Apache ZooKeeper w systemie Windows ”. Zawartość pliku konfiguracyjnego będzie mniej więcej taka:
tickTime=2000
dataDir=C:/zookeeper-3.4.13/data
clientPort=2181
Dodajmy zmienną środowiskową ZOOKEEPER_HOME zawierającą ścieżkę do katalogu głównego zookepera (zgodnie z instrukcją na nośniku), a także dodajmy następujący fragment do zmiennej środowiskowej PATH: ;%ZOOKEEPER_HOME%\bin; Ponadto katalog określony w dataDir musi istnieć, w przeciwnym razie Zookeeper nie będzie możliwość uruchomienia serwera. Teraz możemy bezpiecznie uruchomić serwer za pomocą polecenia: zkServer. Dzięki temu, że do zmiennej środowiskowej path został dodany katalog Zookeeper, możemy wywoływać polecenia Zookeper'a z dowolnego miejsca, a nie tylko z katalogu bin.
Zookeeper, czyli jak żyje pracownik zoo - 4

ZNode

Jak stwierdzono w „ Przeglądzie Zookeepera ”, dane w Zookeper są reprezentowane w postaci ZNodes (węzłów), które są zorganizowane w strukturę drzewa. Oznacza to, że każdy ZNode może zawierać dane i mieć podrzędne ZNode. Więcej informacji na temat organizacji ZNode można znaleźć w dokumentacji Zookeepera: „ Model danych i hierarchiczna przestrzeń nazw ”. Do pracy z Zookeeperem i ZNode użyjemy Zookeeper CLI (interfejs wiersza poleceń). Poprzednio uruchamialiśmy serwer komendą zkServer. Teraz, aby się połączyć, wykonajmy. zkCli.cmd -server 127.0.0.1:2181 Jeśli się powiedzie, zostanie utworzona sesja połączenia z Zookeeperem i zobaczymy mniej więcej następujące dane wyjściowe:
Zookeeper, czyli jak żyje pracownik zoo - 5
Co ciekawe, nawet zaraz po instalacji Zookeeper ma już ZNode. Ma następującą ścieżkę:/zookeeper/quota
Zookeeper, czyli jak żyje pracownik zoo - 6
Są to tak zwane „ kwota ”. Jak stwierdzono w „ Apache ZooKeeper Essentials ”, każdy ZNode może mieć przypisany limit, ograniczający ilość danych, które może przechowywać. Można określić limit liczby znodów i ilości przechowywanych danych. Co więcej, w przypadku przekroczenia tego limitu, operacja z ZNode nie zostanie anulowana, lecz pojawi się ostrzeżenie o przekroczeniu limitu. Zalecane jest przeczytanie o ZNode w " Poradniku programisty ZooKeeper: ZNodes ". Oto kilka przykładów pracy z ZNode:
Zookeeper, czyli jak żyje pracownik zoo - 7
Chciałbym również zauważyć, że ZNode są różne. Zwykłe ZNode (chyba że określisz dodatkowe flagi) są typu " trwałe ". Istnieje ZNode typu " Ephemeral Node ". Takie ZNode istnieją tylko przez czas trwania sesji połączenia Zookeepera, w ramach której zostały utworzone. Istnieje ZNode typu „ Węzeł sekwencji ”. Do tych ZNode dołączany jest numer z sekwencji, aby zapewnić niepowtarzalność. Węzeł sekwencji może być trwały lub efemeryczny. Zalecane jest również wprowadzenie kilku informacji ogólnych na temat ZNode: „ Zookeeper ZNodes – Charakterystyka i przykład ”.
Zookeeper, czyli jak żyje pracownik zoo - 8

ZNode Watcher

Chciałbym także porozmawiać o obserwatorach. Szczegóły na ich temat opisano w dokumentacji Zookeepera: „ Zegarki ZooKeeper ”. Krótko mówiąc, obserwator to jednorazowy wyzwalacz uruchamiany przez jakieś zdarzenie. Pobierając dane poprzez wykonanie operacji getData(), getChildren() lub istnieje() możemy stworzyć wyzwalacz jako dodatkową akcję. Zookeeper dba o kolejność przetwarzania zdarzeń. Dodatkowo w dokumentacji jest napisane, że zanim będziemy mogli zobaczyć nową wartość ZNode, zobaczymy zdarzenie dotyczące zmiany starej wartości na nową. Więcej o obserwatorach możesz przeczytać tutaj: „ Zegarki ZooKeeper – funkcje i gwarancje ”. Aby tego spróbować, użyjmy ponownie CLI : Załóżmy, że mamy jakiś ZNode z wartością, w której przechowujemy status jakiejś usługi:
[zk: 127.0.0.1:2181(CONNECTED) 0] create /services/service1/status stopped
Created /services/service1/status
[zk: 127.0.0.1:2181(CONNECTED) 1] get /services/service1/status [watch]
stopped
Teraz, jeśli dane /services/service1/statusulegną zmianie, uruchomi się nasz jednorazowy wyzwalacz:
Zookeeper, czyli jak żyje pracownik zoo - 9
Co ciekawe, łącząc się z Zookeeperem, widzimy także, jak działa obserwator:
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
SyncConnected jest jednym z możliwych wydarzeń Zookeper. Więcej szczegółów na ten temat znajdziesz w opisie API.
Zookeeper, czyli jak żyje pracownik zoo - 10

Zookeeper i Java

Mamy teraz podstawową wiedzę na temat możliwości Zookeepera. Popracujmy teraz nad tym poprzez Javę, a nie poprzez CLI. A do tego będzie nam potrzebna aplikacja Java, w której zobaczymy jak współpracować z Zookeeperem. Do stworzenia aplikacji wykorzystamy system budowania projektów Gradle . Za pomocą wtyczki „ Gradle Build Init ” utworzymy projekt. W tym celu uruchommy polecenie: gradle init --type java-application Jeżeli Gradle poprosi nas o doprecyzowanie pytań, wówczas pozostawimy wartości domyślne (wystarczy nacisnąć Enter). Otwórzmy teraz skrypt budujący, tj. plik build.gradle. Zawiera opis z czego składa się nasz projekt i od jakich artefaktów (biblioteki, frameworki) zależy. Ponieważ chcemy użyć Zookeepera, musimy go dodać. Dlatego dodajmy zależność od Zookeepera do bloku zależności:
dependencies {
    implementation 'org.apache.zookeeper:zookeeper:3.4.13'
Więcej o Gradle przeczytacie w recenzji: „ Krótkie wprowadzenie do Gradle ”. Mamy więc projekt Java, połączyliśmy z nim bibliotekę Zookeeper. Napiszmy coś teraz. Jak pamiętamy, korzystając z CLI połączyliśmy coś takiego: zkCli.cmd -server 127.0.0.1:2181 Zadeklarujmy atrybut „server” w klasie App w metodzie głównej:
String server = "127.0.0.1:2181";
Połączenie nie jest działaniem natychmiastowym. Będziemy musieli jakoś poczekać w głównym wątku wykonywania programu, aż nastąpi połączenie. Dlatego potrzebujemy zamka. Zadeklarujmy to poniżej:
Object lock = new Object();
Teraz potrzebujemy kogoś, kto powie, że połączenie zostało nawiązane. Jak pamiętamy, kiedy robiliśmy to za pośrednictwem CLI, obserwator pracował dla nas. Zatem w kodzie Java wszystko jest dokładnie takie samo. Nasz obserwator wyświetli komunikat o pomyślnym ukończeniu i powiadomi o tym wszystkich oczekujących poprzez blokadę. Napiszmy obserwatora:
Watcher connectionWatcher = new Watcher() {
	public void process(WatchedEvent we) {
		if (we.getState() == Event.KeeperState.SyncConnected) {
			System.out.println("Connected to Zookeeper in " + Thread.currentThread().getName());
			synchronized (lock) {
            	lock.notifyAll();
            }
		}
	}
};
Dodajmy teraz połączenie do serwera zooKeeper:
int sessionTimeout = 2000;
ZooKeeper zooKeeper = null;
synchronized (lock) {
	zooKeeper = new ZooKeeper(server, sessionTimeout, connectionWatcher);
	lock.wait();
}
Tutaj wszystko jest proste. Wykonując główną metodę w głównym wątku programu, chwytamy blokadę i żądamy połączenia z zookeeperem. Jednocześnie zwalniamy blokadę i czekamy, aż ktoś inny złapie blokadę i powiadomi nas, że możemy kontynuować. Po nawiązaniu połączenia obserwator zacznie działać. Sprawdzi, czy doszło do zdarzenia SyncConnected (jak pamiętamy, to właśnie przechwycił obserwator przez CLI), a następnie napisze wiadomość. Następnie chwytamy blokadę (ponieważ główny wątek ją wcześniej zwolnił) i powiadamiamy wszystkie wątki oczekujące na blokadę, że możemy kontynuować. Wątek przetwarzania zdarzeń opuszcza zsynchronizowany blok, zwalniając w ten sposób blokadę. Główny wątek otrzymał powiadomienie i po oczekiwaniu na zwolnienie blokady kontynuuje wykonywanie, ponieważ dopóki nie otrzyma blokady, nie będzie mógł wyjść z zsynchronizowanego bloku i kontynuować pracę. Tym samym korzystając z wielowątkowości i API Zookeepera możemy wykonywać różne akcje. API Zookeepera jest znacznie szersze niż to, na co pozwala CLI. Na przykład:
// kreacja нового узла
String znodePath = "/zookeepernode2";
List<ACL> acls = ZooDefs.Ids.OPEN_ACL_UNSAFE;
if (zooKeeper.exists(znodePath, false) == null) {
	zooKeeper.create(znodePath, "data".getBytes(), acls, CreateMode.PERSISTENT);
}

// Получение данных из узла
byte[] data = zooKeeper.getData(znodePath, null, null);
System.out.println("Result: " + new String(data, "UTF-8"));
Jak widać, tworząc węzeł, możemy skonfigurować listę ACL. To kolejna ważna cecha. Listy ACL to uprawnienia mające zastosowanie do działań w ZNode. Istnieje wiele ustawień, dlatego zalecam zapoznanie się z oficjalną dokumentacją w celu uzyskania szczegółowych informacji: „ Uprawnienia ACL zookeepera ”.
Zookeeper, czyli jak żyje pracownik zoo - 11

Wniosek

Dlaczego to przeczytaliśmy? Ponieważ Zookeeper jest używany w innych popularnych technologiach. Na przykład Apache Kafka wymaga Zookeepera, o którym możesz przeczytać w „ Krótkim przewodniku po Kafce ”. Jest również używany w bazie danych NOSQL HBase, o której możesz przeczytać więcej w ich „ Przewodniku szybkiego startu HBase ”. W rzeczywistości wiele innych projektów korzysta z Zookeepera. Niektóre z nich są wymienione w części „ Korzystanie z Zookeepera w prawdziwym świecie ”. Mam nadzieję, że odpowiedziałem na pytanie „dlaczego”. Najważniejszym pytaniem jest teraz: „Co dalej?” Najpierw możesz przeczytać następujące książki na temat Apache Zookeeper: Po drugie, istnieją doskonałe raporty wideo na temat Zookeepera. Zalecane obejrzenie: Po trzecie, istnieje kilka przydatnych artykułów, które uzupełnią obraz świata: To bardzo krótka recenzja, ale jako wprowadzenie, mam nadzieję, że będzie przydatna. #Wiaczesław
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION