2016-04-05 13 views
5

Sto cercando di capire come fare le elezioni per i leader delle applicazioni usando Consul. Sto usando LeaderElectionUtil dal java console-client.Elezione Leader per le applicazioni con java console-client

Posso eleggere un leader, e tutti i nodi sono d'accordo sul leader, ma se l'applicazione leader muore, gli altri nodi sembrano inconsapevoli e continuano a ottenere il leader morto quando chiamano getLeaderInfoForService - cioè nessuna nuova elezione dei dirigenti avviene.

La Guida leader Electrion (https://www.consul.io/docs/guides/leader-election.html) cita:

"Si noti che la sessione di default si avvale del solo rilevatore fallimento pettegolezzi Cioè, la sessione si considera tenuto da un nodo fino a quando la Serf di default. il controllo sanitario non ha dichiarato il nodo non sano. Ulteriori controlli possono essere specificati se lo si desidera. "

Quindi da questo presumo che forse devo aggiungere un controllo dello stato del livello applicazione (TTL ecc.) Alla sessione, in modo che la sessione venga invalidata quando l'applicazione non riesce? È questa l'idea giusta e se è così esiste un modo per farlo tramite il client java? Sto bene abbandonando LeaderElectionUtil e scrivendo il mio codice per eleggere un leader ma sembra che anche in SessionClient non ci sia modo di creare una sessione con un controllo dello stato ad esso associato?

O forse c'è un modo migliore per raggiungere questo (rilevamento dei guasti a livello di applicazione per la rielezione dei leader)? Sono un po 'bloccato così ogni suggerimento sarebbe apprezzato.

risposta

2

Quindi l'ho risolto nel caso in cui qualcun altro si imbattesse in questo problema.

Non riuscivo a utilizzare LeaderElectionUtil ma ho creato la mia classe per fare lo stesso genere di cose, ma nel metodo createSession ho aggiunto un TTL di 10s.

private String createSession(String serviceName) { 
    final Session session = 
ImmutableSession.builder().name(serviceName).ttl("10s").build(); 

return client.sessionClient().createSession(session).getId(); 
} 

Per questo funzioni è necessario avere una thread in background che chiama renewSession sulla sessione almeno una volta ogni 10 secondi.

+0

Questa è la sessione, ma secondo il documento che hai linkato sopra, devi d anche provare ad acquisire un blocco su una chiave. Cura di condividere il codice rilevante per questo? – Guss

1

Sto cercando di implementare lo stesso requisito: ho un servizio Java che deve eleggere un leader e non ho i controlli di integrità del servizio configurati in Consul.

L'utilizzo di LeaderElectionUtil da parte di Consul-client è problematico perché se tutti i motivi indicati sopra. Purtroppo non è nemmeno possibile personalizzare LeaderElectionUtil perché tutti i suoi meccanismi interni vengono eseguiti utilizzando metodi privati ​​(dovrebbe aver utilizzato protected e consentire agli utenti di sovrascrivere la creazione della sessione, ad esempio).

Ho provato a implementare "Registrazione servizio" come documentato in "Uso di base - Esempio 1" nel README consul-client, ma per me calling AgentClient.pass() always throws an exception.

Quindi la mia soluzione è esattamente ciò che hai specificato: avere una sessione con un TTL e rinnovarla finché il servizio è attivo.

Ecco la mia realizzazione, che richiede all'utente di registrare anche un callback che viene utilizzato per controllare se il servizio è ancora valido per il rinnovo, nel caso in cui:

public class SessionHolder implements Runnable { 

    private static final String TTL_TEMPLATE = "%ss"; 
    private Consul client; 
    private String id; 
    private LinkedList<Supplier<Boolean>> liveChecks = new LinkedList<>(); 
    private long ttl; 
    private boolean shutdown = false; 

    public SessionHolder(Consul client, String service, long ttl) { 
     this.client = client; 
     this.ttl = ttl; 
     final Session session = ImmutableSession.builder() 
       .name(service) 
       .ttl(String.format(TTL_TEMPLATE, ttl)) 
       .build(); 
     id = client.sessionClient().createSession(session).getId(); 
     Thread upkeep = new Thread(this); 
     upkeep.setDaemon(true); 
     upkeep.start(); 
    } 

    public String getId() { 
     return id; 
    } 

    public void registerKeepAlive(Supplier<Boolean> liveCheck) { 
     liveChecks.add(liveCheck); 
    } 

    @Override 
    public synchronized void run() { 
     // don't start renewing immediately 
     try { 
      wait(ttl/2 * 1000); 
     } catch (InterruptedException e) {} 
     while (!isShutdown()) { 
      if (liveChecks.isEmpty() || liveChecks.stream().allMatch(Supplier::get)) { 
       client.sessionClient().renewSession(getId()); 
      } 
      try { 
       wait(ttl/2 * 1000); 
      } catch (InterruptedException e) { 
       // go on, try again 
      } 
     } 
    } 

    public synchronized boolean isShutdown() { 
     return shutdown; 
    } 

    public synchronized void close() { 
     shutdown = true; 
     notify(); 
     client.sessionClient().destroySession(getId()); 
    } 
} 

Poi eleggere un leader è più o meno semplice come:

if (consul.keyValueClient().acquireLock(getServiceKey(service), currentNode, sessionHolder.getId())) 
    return true; // I'm the leader 

una cosa che deve ricordare, è che se la sessione termina senza ripulire correttamente (quello che faccio sopra SessionHolder.close()), la funzione lock-delay della console impedirà un nuovo leader da eleggere f o circa 15 secondi (l'impostazione predefinita, che sfortunatamente Consul-client non offre un'API da modificare).

Per risolvere questo problema, oltre a fare in modo che i servizi di terminazione correttamente si ripuliscano da soli come dimostrato sopra, mi assicuro inoltre che il servizio mantenga la posizione di leader per la quantità minima di tempo necessaria e per rilasciare la leadership quando non lo si utilizza più, chiamando consul.keyValueClient().releaseLock(). Ad esempio, ho un servizio in cluster in cui eleggiamo un leader per leggere gli aggiornamenti dei dati da un RDBMS esterno (che vengono quindi distribuiti direttamente nel cluster anziché ogni nodo che ricarica tutti i dati). Dato che questo viene fatto tramite il polling, ogni nodo cercherà di essere eletto prima del polling e, se eletto, interrogherà il database, diffonderà aggiornamenti e dimissioni. In caso contrario, delay-lock non impedirà il polling di un altro nodo.

0

Se è ancora rilevante, I (si spera) ha ottenuto tutto il potenziale di falsi positivi da:

  • Registrazione presso TTL di salute
  • Legando la sessione solo a questo controllo

Rilevante snippet di codice:

sessionClient.createSession(
    ImmutableSession.builder() 
     .addChecks(checkId) // Ties the session to this check 
     .behavior("delete") 
     .lockDelay("15s") 
     .build() 
    ) 
Problemi correlati