Einführung in Apache Curator

Einführung in Apache Curator

1. Einführung

Apache Curator ist ein Java-Client fürApache Zookeeper, den beliebten Koordinierungsdienst für verteilte Anwendungen.

In diesem Tutorial stellen wir einige der wichtigsten Funktionen von Curator vor:

  • Verbindungsverwaltung - Verwalten von Verbindungen und Wiederholungsrichtlinien

  • Async - Erweitern bestehender Clients durch Hinzufügen von Async-Funktionen und die Verwendung von Java 8-Lambdas

  • Konfigurationsmanagement - mit einer zentralen Konfiguration für das System

  • Stark typisierte Modelle - Arbeiten mit typisierten Modellen

  • Rezepte - Durchführung von Führerwahlen, verteilten Sperren oder Zählern

2. Voraussetzungen

Zunächst wird empfohlen, einen kurzen Blick aufApache Zookeeper und seine Funktionen zu werfen.

In diesem Tutorial wird davon ausgegangen, dass bereits eine eigenständige Zookeeper-Instanz auf127.0.0.1:2181 ausgeführt wird. here are Anweisungen zur Installation und Ausführung, wenn Sie gerade erst anfangen.

Zuerst müssen wir die Abhängigkeit voncurator-x-asynczu unserenpom.xmlhinzufügen:


    org.apache.curator
    curator-x-async
    4.0.1
    
        
            org.apache.zookeeper
            zookeeper
        
    

The latest version of Apache Curator 4.X.X has a hard dependency with Zookeeper 3.5.X befindet sich derzeit noch in der Beta.

In diesem Artikel werden wir stattdessen die aktuell neuesten stabilenZookeeper 3.4.11verwenden.

Wir müssen also die Zookeeper-Abhängigkeit ausschließen undthe dependency for our Zookeeper version zu unserenpom.xml hinzufügen:


    org.apache.zookeeper
    zookeeper
    3.4.11

Weitere Informationen zur Kompatibilität finden Sie unterthis link.

3. Verbindungsmanagement

The basic use case of Apache Curator is connecting to a running Apache Zookeeper instance.

Das Tool bietet eine Factory zum Herstellen von Verbindungen zu Zookeeper mithilfe von Wiederholungsrichtlinien:

int sleepMsBetweenRetries = 100;
int maxRetries = 3;
RetryPolicy retryPolicy = new RetryNTimes(
  maxRetries, sleepMsBetweenRetries);

CuratorFramework client = CuratorFrameworkFactory
  .newClient("127.0.0.1:2181", retryPolicy);
client.start();

assertThat(client.checkExists().forPath("/")).isNotNull();

In diesem kurzen Beispiel werden wir es dreimal wiederholen und bei Verbindungsproblemen 100 ms zwischen den Wiederholungen warten.

Sobald wir über denCuratorFramework-Client mit Zookeeper verbunden sind, können wir jetzt Pfade durchsuchen, Daten abrufen / festlegen und im Wesentlichen mit dem Server interagieren.

4. Async

The Curator Async module wraps the above CuratorFramework client to provide non-blocking capabilities unter Verwendung vonthe CompletionStage Java 8 API.

Sehen wir uns an, wie das vorherige Beispiel mit dem Async-Wrapper aussieht:

int sleepMsBetweenRetries = 100;
int maxRetries = 3;
RetryPolicy retryPolicy
  = new RetryNTimes(maxRetries, sleepMsBetweenRetries);

CuratorFramework client = CuratorFrameworkFactory
  .newClient("127.0.0.1:2181", retryPolicy);

client.start();
AsyncCuratorFramework async = AsyncCuratorFramework.wrap(client);

AtomicBoolean exists = new AtomicBoolean(false);

async.checkExists()
  .forPath("/")
  .thenAcceptAsync(s -> exists.set(s != null));

await().until(() -> assertThat(exists.get()).isTrue());

Jetzt arbeitet die OperationcheckExists()im asynchronen Modus und blockiert den Hauptthread nicht. Wir können Aktionen auch nacheinander verketten, indem wir stattdessen die MethodethenAcceptAsync() verwenden, dieCompletionStage API verwendet.

5. Konfigurationsmanagement

In einer verteilten Umgebung besteht eine der häufigsten Herausforderungen darin, die gemeinsame Konfiguration vieler Anwendungen zu verwalten. We can use Zookeeper as a data store where to keep our configuration.

Sehen wir uns ein Beispiel mit Apache Curator an, um Daten abzurufen und festzulegen:

CuratorFramework client = newClient();
client.start();
AsyncCuratorFramework async = AsyncCuratorFramework.wrap(client);
String key = getKey();
String expected = "my_value";

client.create().forPath(key);

async.setData()
  .forPath(key, expected.getBytes());

AtomicBoolean isEquals = new AtomicBoolean();
async.getData()
  .forPath(key)
  .thenAccept(data -> isEquals.set(new String(data).equals(expected)));

await().until(() -> assertThat(isEquals.get()).isTrue());

In diesem Beispiel erstellen wir den Knotenpfad, legen die Daten in Zookeeper fest und stellen sie dann wieder her, indem wir prüfen, ob der Wert identisch ist. Das Feldkey könnte ein Knotenpfad wie/config/dev/my_key sein.

5.1. Beobachter

Eine weitere interessante Funktion in Zookeeper ist die Möglichkeit, Schlüssel oder Knoten zu überwachen. It allows us to listen to changes in the configuration and update our applications without needing to redeploy.

Lassen Sie uns sehen, wie das obige Beispiel bei Verwendung von Beobachtern aussieht:

CuratorFramework client = newClient()
client.start();
AsyncCuratorFramework async = AsyncCuratorFramework.wrap(client);
String key = getKey();
String expected = "my_value";

async.create().forPath(key);

List changes = new ArrayList<>();

async.watched()
  .getData()
  .forPath(key)
  .event()
  .thenAccept(watchedEvent -> {
    try {
        changes.add(new String(client.getData()
          .forPath(watchedEvent.getPath())));
    } catch (Exception e) {
        // fail ...
    }});

// Set data value for our key
async.setData()
  .forPath(key, expected.getBytes());

await()
  .until(() -> assertThat(changes.size()).isEqualTo(1));

Wir konfigurieren den Watcher, stellen die Daten ein und bestätigen dann, dass das überwachte Ereignis ausgelöst wurde. Wir können einen oder mehrere Knoten gleichzeitig beobachten.

6. Stark typisierte Modelle

Da Zookeeper hauptsächlich mit Byte-Arrays arbeitet, müssen wir unsere Daten serialisieren und deserialisieren. Dies ermöglicht uns eine gewisse Flexibilität bei der Arbeit mit jeder serialisierbaren Instanz, kann jedoch schwierig zu warten sein.

Um hier zu helfen, fügt der Kurator das Konzept vontyped models unddelegates the serialization/deserialization and allows us to work with our types directly hinzu. Mal sehen, wie das funktioniert.

Zunächst benötigen wir ein Serializer-Framework. Der Kurator empfiehlt die Verwendung der Jackson-Implementierung. Fügen wir alsothe Jackson dependency zu unserenpom.xml hinzu:


    com.fasterxml.jackson.core
    jackson-databind
    2.9.4

Versuchen wir nun, unsere benutzerdefinierten KlassenHostConfig beizubehalten:

public class HostConfig {
    private String hostname;
    private int port;

    // getters and setters
}

Wir müssen die Modellspezifikationszuordnung von derHostConfig-Klasse zu einem Pfad bereitstellen und den von Apache Curator bereitgestellten modellierten Framework-Wrapper verwenden:

ModelSpec mySpec = ModelSpec.builder(
  ZPath.parseWithIds("/config/dev"),
  JacksonModelSerializer.build(HostConfig.class))
  .build();

CuratorFramework client = newClient();
client.start();

AsyncCuratorFramework async
  = AsyncCuratorFramework.wrap(client);
ModeledFramework modeledClient
  = ModeledFramework.wrap(async, mySpec);

modeledClient.set(new HostConfig("host-name", 8080));

modeledClient.read()
  .whenComplete((value, e) -> {
     if (e != null) {
          fail("Cannot read host config", e);
     } else {
          assertThat(value).isNotNull();
          assertThat(value.getHostname()).isEqualTo("host-name");
          assertThat(value.getPort()).isEqualTo(8080);
     }
   });

Die MethodewhenComplete() beim Lesen des Pfads/config/dev gibt die InstanzHostConfigin Zookeeper zurück.

7. Rezepte

Zookeeper stelltthis guideline zur Verfügung, umhigh-level solutions or recipes such as leader election, distributed locks or shared counters. zu implementieren

Apache Curator bietet eine Implementierung für die meisten dieser Rezepte. Die vollständige Liste finden Sie unterthe Curator Recipes documentation.

Alle diese Rezepte sind in einem separaten Modul erhältlich:


    org.apache.curator
    curator-recipes
    4.0.1

Lassen Sie uns gleich loslegen und diese anhand einiger einfacher Beispiele verstehen.

7.1. Führerwahl

In einer verteilten Umgebung benötigen wir möglicherweise einen Master- oder Führungsknoten, um einen komplexen Job zu koordinieren.

So sieht die Verwendung vonthe Leader Election recipe in Curator aus:

CuratorFramework client = newClient();
client.start();
LeaderSelector leaderSelector = new LeaderSelector(client,
  "/mutex/select/leader/for/job/A",
  new LeaderSelectorListener() {
      @Override
      public void stateChanged(
        CuratorFramework client,
        ConnectionState newState) {
      }

      @Override
      public void takeLeadership(
        CuratorFramework client) throws Exception {
      }
  });

// join the members group
leaderSelector.start();

// wait until the job A is done among all members
leaderSelector.close();

Wenn wir den Leader-Selektor starten, tritt unser Knoten einer Mitgliedergruppe innerhalb des Pfads/mutex/select/leader/for/job/A bei. Sobald unser Knoten zum Leader wird, wird die MethodetakeLeadershipaufgerufen, und wir als Leader können den Job wieder aufnehmen.

7.2. Geteilte Schlösser

BeiThe Shared Lock recipe geht es um eine vollständig verteilte Sperre:

CuratorFramework client = newClient();
client.start();
InterProcessSemaphoreMutex sharedLock = new InterProcessSemaphoreMutex(
  client, "/mutex/process/A");

sharedLock.acquire();

// do process A

sharedLock.release();

Wenn wir die Sperre erwerben, stellt Zookeeper sicher, dass keine andere Anwendung zur gleichen Zeit dieselbe Sperre erhält.

7.3. Zähler

The Counters recipe koordiniert ein gemeinsamesInteger unter allen Clients:

CuratorFramework client = newClient();
client.start();

SharedCount counter = new SharedCount(client, "/counters/A", 0);
counter.start();

counter.setCount(counter.getCount() + 1);

assertThat(counter.getCount()).isEqualTo(1);

In diesem Beispiel speichert Zookeeper den Wert vonIntegerim Pfad/counters/A und initialisiert den Wert auf0, wenn der Pfad noch nicht erstellt wurde.

8. Fazit

In diesem Artikel haben wir gesehen, wie Sie mit Apache Curator eine Verbindung zu Apache Zookeeper herstellen und die Hauptfunktionen nutzen können.

Wir haben auch einige der Hauptrezepte in Curator vorgestellt.

Wie üblich können Quellenover on GitHub gefunden werden.