2015-01-18 14 views
10

Sto utilizzando la libreria Apache Curator per l'elezione della leadership sul Zookeeper. Ho il mio codice applicazione distribuito in varie macchine e ho bisogno di eseguire il mio codice solo da una macchina, ecco perché sto facendo elezioni al comando del guardiano in modo da poter controllare se sono il leader, quindi eseguire questo codice.Come utilizzare la ricetta LeaderElection in modo efficiente usando Curator per Zookeeper?

Qui di seguito è la mia classe che LeaderElectionExecutor fa in modo che sto avendo un'istanza Curatore per applicazione

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; 
    } 
} 

E sotto è il mio codice ZookeeperClient -

// 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; 
    } 
} 

Ora nella mia domanda, sto usando la codice come questo -

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 
    } 
} 

Problem Statement: -

Nella libreria di Curator - Chiamare lo isLeader() immediatamente dopo l'avvio del latch non funzionerà. Ci vuole tempo prima che il leader venga selezionato. E solo per questo motivo, ho aggiunto un sonno di 1 minuto nel mio codice LeaderElectionExecutor che funziona bene, ma credo che non sia il modo giusto per farlo.

C'è un modo migliore per farlo? Tenendo presente questo, ho bisogno di un modo per verificare se sono il leader quindi eseguire questo pezzo di codice. Non posso fare tutto in un unico metodo, quindi ho bisogno di chiamare il metodo isLeader da diverse classi e metodi per verificare se sono il leader, quindi eseguire solo questa parte di codice.

Sto usando Zookeeper 3.4.5 e versione di Curator 1.7.1.

risposta

-1

Non ho mai lavorato con il guardiano o lo spettatore, quindi rispondi con un pizzico di sale.

Impostare una bandiera.

booleano isLeaderSelected = false;

All'inizio del Latch, impostare il flag su false. Quando il leader è stato selezionato, imposta il flag su true.

Nella funzione isLeader():

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

//do the rest of the function 
} 

Questa è anche una soluzione relativamente hacky, ma dovrebbe consentire il metodo isLeader di eseguire non appena possibile. Nel caso in cui siano in classi diverse, un getter dovrebbe essere in grado di fornire isLeaderSelected.

1

Una volta risolto un problema molto simile al tuo. Questo è come l'ho fatto.

In primo luogo, i miei oggetti sono stati gestiti da Spring. Quindi, avevo un LeaderLatch che era iniettabile attraverso il contenitore. Uno dei componenti che utilizzava LeaderLatch era un LeadershipWatcher, un'implementazione dell'interfaccia Runnable che avrebbe inviato l'evento di leadership ad altri componenti. Questi ultimi componenti erano implementazioni di un'interfaccia che ho chiamato LeadershipObserver.L'attuazione del LeadershipWatcher era per lo più come il seguente codice:

@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(); 
     } 
    } 
    } 
} 

Dato che questo è solo un abbozzo-up, vi consiglio di migliorare questo codice, forse l'applicazione del modello di comando per chiamare gli osservatori, o anche la presentazione della osservatori per eseguire il threading dei pool, se il loro lavoro sta bloccando o eseguono attività a lungo termine della CPU.

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()) { 
... 
} 

Nota che getLeader restituisce un partecipante fittizio con ID "" fino a quando non elegge un leader.

0

Ecco a far rivivere una vecchia questione ...

Questo è simile alla risposta srav ha dato, ma vorrei mettere in guardia contro l'uso che il codice perché utilizza un occupato-aspettare e può causare alcuni callback che vengono emesse in -thread per non essere mai chiamato, possibilmente bloccando per sempre. Inoltre, potrebbe riprovare per sempre se ci sono problemi reali.

Questa è stata la mia soluzione, che utilizza la politica di riprovare di CuratorClient per tentare di attendere l'elezione dei dirigenti, se necessario.

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!"); 

Anche dare un'occhiata al vostro inizializzazione CuratorFramework sarei in guardia contro l'uso Integer.MAX_VALUE quando si specifica la politica di tentativi ...

Spero che questo aiuta!

Problemi correlati