2015-01-18 9 views
10

Ich benutze die Apache Curator-Bibliothek für die Durchführung von Führungswahlen auf dem Zookeeper. Ich habe meinen Anwendungscode auf verschiedenen Rechnern installiert und muss meinen Code nur von einem Rechner aus ausführen. Deshalb führe ich eine Führungswahl am Tierpfleger durch, damit ich prüfen kann, ob ich der Anführer bin, und dann diesen Code ausführen.Wie benutzt man LeaderElection Rezepte effizient mit Curator für Zookeeper?

public class LeaderElectionExecutor { 

    private ZookeeperClient zookClient; 

    private static final String LEADER_NODE = "/testleader"; 

    private static class Holder { 
     static final LeaderElectionExecutor INSTANCE = new LeaderElectionExecutor(); 
    } 

    public static LeaderElectionExecutor getInstance() { 
     return Holder.INSTANCE; 
    } 

    private LeaderElectionExecutor() { 
     try { 
      String hostname = Utils.getHostName(); 

      String nodes = "host1:2181,host2:2181; 

      zookClient = new ZookeeperClient(nodes, LEADER_NODE, hostname); 
      zookClient.start(); 

      // added sleep specifically for the leader to get selected 
      // since I cannot call isLeader method immediately after starting the latch 
      TimeUnit.MINUTES.sleep(1); 
     } catch (Exception ex) { 
      // logging error 
      System.exit(1); 
     } 
    } 

    public ZookeeperClient getZookClient() { 
     return zookClient; 
    } 
} 

Und unten ist mein ZookeeperClient Code

Unten ist meine LeaderElectionExecutor Klasse, die dafür sorgt, ich pro Anwendung einen Kurator Instanz habe -

// can this class be improved in any ways? 
public class ZookeeperClient { 

    private CuratorFramework client; 
    private String latchPath; 
    private String id; 
    private LeaderLatch leaderLatch; 

    public ZookeeperClient(String connString, String latchPath, String id) { 
     client = CuratorFrameworkFactory.newClient(connString, new ExponentialBackoffRetry(1000, Integer.MAX_VALUE)); 
     this.id = id; 
     this.latchPath = latchPath; 
    } 

    public void start() throws Exception { 
     client.start(); 
     leaderLatch = new LeaderLatch(client, latchPath, id); 
     leaderLatch.start(); 
    } 

    public boolean isLeader() { 
     return leaderLatch.hasLeadership(); 
    } 

    public Participant currentLeader() throws Exception { 
     return leaderLatch.getLeader(); 
    } 

    public void close() throws IOException { 
     leaderLatch.close(); 
     client.close(); 
    } 

    public CuratorFramework getClient() { 
     return client; 
    } 

    public String getLatchPath() { 
     return latchPath; 
    } 

    public String getId() { 
     return id; 
    } 

    public LeaderLatch getLeaderLatch() { 
     return leaderLatch; 
    } 
} 

Jetzt in meiner Anwendung, die ich benutze die Code wie folgt -

public void method01() { 
    ZookeeperClient zookClient = LeaderElectionExecutor.getInstance().getZookClient(); 
    if (zookClient.isLeader()) { 
     // do something 
    } 
} 

public void method02() { 
    ZookeeperClient zookClient = LeaderElectionExecutor.getInstance().getZookClient(); 
    if (zookClient.isLeader()) { 
     // do something 
    } 
} 

Problembeschreibung: -

In der Curator-Bibliothek - Aufruf von isLeader() sofort nach dem Start der Verriegelung funktioniert nicht. Es braucht Zeit, bis der Anführer ausgewählt ist. Und nur aus diesem Grund habe ich einen Schlaf von 1 Minute in meinem LeaderElectionExecutor Code hinzugefügt, der gut funktioniert, aber ich denke, ist nicht der richtige Weg, dies zu tun.

Gibt es einen besseren Weg, dies zu tun? Wenn ich das bedenke, muss ich prüfen, ob ich der Anführer bin, und dann diesen Code ausführen. Ich kann nicht alles in einer einzelnen Methode tun, also muss ich isLeader Methode von den verschiedenen Klassen und von den Methoden anrufen, um zu überprüfen, ob ich der Führer bin, dann führe diesen Stück Code nur aus.

Ich bin mit Zookeeper 3.4.5 und Kurator 1.7.1 Version.

Antwort

-1

Ich habe nicht mit zookeeper oder Kurator gearbeitet, so mit einem Körnchen Salz meine Antwort nehmen.

Setzen Sie eine Flagge.

Boolean isLeaderSelected = false;

Zu Beginn des Riegels, das Kennzeichen auf falsch. Wenn der Vorspann ausgewählt wurde, setzen Sie das Flag auf "true".

Im isLeader() Funktion:

isLeader(){ 
while(!isLeaderSelected){} //waits until leader is selected 

//do the rest of the function 
} 

Dies ist auch ein relativ Hacky Problem zu umgehen, aber es sollte die isLeader Methode erlaubt so schnell wie möglich auszuführen. In dem Fall, dass sie sich in verschiedenen Klassen befinden, sollte ein Getter in der Lage sein, isLeaderSelected bereitzustellen.

1

Sobald ich ein Problem sehr ähnlich wie bei Ihnen gelöst. So habe ich es gemacht.

Zuerst hatte ich meine Objekte von Spring verwaltet. Also hatte ich einen LeaderLatch, der durch den Behälter injizierbar war. Eine der Komponenten, die LeaderLatch verwendet, war eine LeadershipWatcher, eine Implementierung der Runnable-Schnittstelle, die das Leadership-Ereignis an andere Komponenten senden würde. Diese letzten Komponenten waren Implementierungen einer Schnittstelle, die ich LeadershipObserver nannte.Die Umsetzung der LeadershipWatcher war meist wie der folgende Code:

@Component 
public class LeadershipWatcher implements Runnable { 
    private final LeaderLatch leaderLatch; 
    private final Collection<LeadershipObserver> leadershipObservers; 

    /* constructor with @Inject */ 

    @Override 
    public void run() { 
    try { 
     leaderLatch.await(); 

     for (LeadershipObserver observer : leadershipObservers) { 
     observer.granted(); 
     } 
    } catch (InterruptedException e) { 
     for (LeadershipObserver observer : leadershipObservers) { 
     observer.interrupted(); 
     } 
    } 
    } 
} 

Da dies nur eine Skizze-up, empfehle ich Ihnen, diesen Code zu verbessern, vielleicht den Befehl Muster der Anwendung für die Beobachter nennen, oder auch die Einreichung Beobachter zu Thread-Pools, wenn ihr Job blockierende oder lang andauernde CPU-intensive Aufgaben sind.

0
leaderLatch = new LeaderLatch(curatorClient, zkPath, String.valueOf(new Random().nextInt())); 
leaderLatch.start(); 
Participant participant; 
while(true) { 
    participant = leaderLatch.getLeader(); 
    // Leader election happens asynchronously after calling start, this is a hack to wait until election happens 
    if (!(participant.getId().isEmpty() || participant.getId().equalsIgnoreCase(""))) { 
    break; 
    } 
} 
if(leaderLatch.hasLeadership()) { 
... 
} 

Beachten Sie, dass getLeader einen Dummy-Teilnehmer mit der ID "" zurückgibt, bis er einen Leader auswählt.

0

Hier ist für eine alte Frage wiederzubeleben ...

Dies ist vergleichbar mit der Antwort srav gab, aber ich warne gegen diesen Code verwenden, weil es ein Besetzt warten verwendet und können bestimmte Rückrufe verursachen, die in ausgegeben werden - Faden, der nie genannt wird, möglicherweise für immer blockiert. Darüber hinaus könnte es für immer wieder versuchen, wenn es echte Probleme gibt.

Das war meine Lösung, die die Retry-Politik des CuratorClient nutzt, um bei Bedarf auf die Wahl von Führungskräften zu warten.

RetryPolicy retryPolicy = _client.getZookeeperClient().getRetryPolicy(); 
    RetrySleeper awaitLeadership = _leaderLatch::await; 

    final long start = System.currentTimeMillis(); 
    int count = 0; 

    do { 
     try { 
      // curator will return a dummy leader in the case when a leader has 
      // not yet actually been elected. This dummy leader will have isLeader 
      // set to false, so we need to check that we got a true leader 
      if (_leaderLatch.getLeader().isLeader()) { 
       return; 
      } 
     } catch (KeeperException.NoNodeException e) { 
      // this is the case when the leader node has not yet been created 
      // by any client - this is fine because we are still waiting for 
      // the algorithm to start up so we ignore the error 
     } 
    } while (retryPolicy.allowRetry(count++, System.currentTimeMillis() - start, awaitLeadership)); 

    // we have exhausted the retry policy and still have not elected a leader 
    throw new IOException("No leader was elected within the specified retry policy!"); 

Obwohl einen Blick auf Ihre CuratorFramework Initialisierung unter ich gegen die Verwendung von Integer.MAX_VALUE warnen würde, wenn die Politik Wiederholungsspezifizierungs ...

Ich hoffe, das hilft!