Un'analisi approfondita dei problemi di connessione tra Kafka e ZooKeeper
Risolvi i problemi di connessione tra Kafka e ZooKeeper con controlli pratici su configurazione, rete, timeout, log e carico dei broker.
Un'analisi approfondita dei problemi di connessione tra Kafka e ZooKeeper
I problemi di connessione tra Kafka e ZooKeeper riguardano principalmente i cluster Kafka più vecchi e quelli che non sono ancora passati alla modalità KRaft. Le distribuzioni più recenti di Kafka possono funzionare senza ZooKeeper, ma molti sistemi di produzione dipendono ancora da esso. Se i tuoi broker utilizzano zookeeper.connect in server.properties, ZooKeeper fa ancora parte del tuo piano di controllo e merita la stessa attenzione di Kafka stesso.
Quando un broker Kafka non riesce a mantenere la sua sessione ZooKeeper, i sintomi possono apparire più gravi di un semplice problema di connessione. I broker potrebbero riavviarsi. Le elezioni del controller potrebbero ripetersi. Le partizioni potrebbero diventare non disponibili. I log potrebbero mostrare scadenza della sessione, dimissioni del controller o tentativi di riconnessione ripetuti. I produttori e i consumatori potrebbero vedere solo l'effetto a valle: errori di metadati, timeout o leader instabili.
Inizia con il ruolo che ZooKeeper svolge. Nei cluster Kafka basati su ZooKeeper, i broker si registrano lì, l'elezione del controller dipende da esso e il coordinamento dei metadati del cluster passa attraverso di esso. Se un broker perde la sua sessione ZooKeeper per un tempo sufficiente a far scadere la sessione, Kafka considera quel broker come rimosso dal cluster. Anche se il processo del broker è ancora in esecuzione, il cluster potrebbe spostare la leadership lontano da esso.
Il primo controllo è banale e spesso individua il problema: verifica zookeeper.connect su ogni broker.
zookeeper.connect=zk01.example.com:2181,zk02.example.com:2181,zk03.example.com:2181/kafka
zookeeper.connection.timeout.ms=18000
zookeeper.session.timeout.ms=18000
La stringa di connessione dovrebbe elencare i membri dell'ensemble che Kafka può raggiungere. Se utilizzi un percorso chroot come /kafka, includilo coerentemente su ogni broker. Non configurare metà dei broker con /kafka e l'altra metà senza; si comporteranno come se stessero comunicando con cluster Kafka diversi. Se utilizzi un chroot, crealo prima o conferma che esista con gli strumenti di ZooKeeper.
Controlla anche il DNS oltre al testo della configurazione. Un nome host che si risolve correttamente dal tuo laptop potrebbe fallire da una sottorete del broker. Esegui i controlli dall'host del broker Kafka, non da un bastione a meno che il bastione non abbia lo stesso percorso di rete.
getent hosts zk01.example.com
nc -vz zk01.example.com 2181
nc -vz zk02.example.com 2181
nc -vz zk03.example.com 2181
Una connessione TCP riuscita non prova che ZooKeeper sia sano, ma una connessione fallita è sufficiente per continuare a indagare su firewall, gruppi di sicurezza, routing, DNS o configurazione del listener. Testa ogni broker Kafka verso ogni nodo ZooKeeper. La connettività parziale è peggiore di un'interruzione pulita perché il guasto potrebbe apparire solo quando un broker tenta di connettersi a un membro specifico dell'ensemble.
I comandi a quattro lettere di ZooKeeper possono aiutare quando sono abilitati. Molte installazioni li limitano, quindi non dare per scontato che funzionino. Se consentito, ruok dovrebbe restituire imok, e mntr può mostrare statistiche utili del server.
echo ruok | nc zk01.example.com 2181
echo mntr | nc zk01.example.com 2181
Se questi comandi sono disabilitati, utilizza gli strumenti di amministrazione supportati o il tuo stack di monitoraggio. Il punto è rispondere a una semplice domanda: ZooKeeper è in ascolto, partecipa all'ensemble e risponde rapidamente?
Successivamente, ispeziona la salute dell'ensemble ZooKeeper. Un ensemble a tre nodi può tollerare un nodo ZooKeeper down. Non può tollerarne due. Un ensemble a cinque nodi può tollerarne due. Evita ensemble di dimensioni pari perché aggiungono costi senza migliorare il quorum nel modo in cui le persone si aspettano. Tre e cinque sono scelte comuni.
Dal lato ZooKeeper, guarda zoo.cfg. Conferma clientPort, tickTime, initLimit, syncLimit e le righe dei server. Assicurati che i nomi host del server pubblicizzati siano raggiungibili tra i nodi ZooKeeper, non solo dai broker Kafka. I peer ZooKeeper necessitano delle proprie porte per il quorum e l'elezione del leader. Un broker Kafka può raggiungere la porta 2181 mentre l'ensemble ZooKeeper stesso è malsano perché il traffico tra peer è bloccato.
La regolazione del timeout della sessione è un'altra fonte comune di confusione. Kafka chiede a ZooKeeper un timeout della sessione, ma ZooKeeper applica limiti basati sulla propria configurazione. In ZooKeeper, il timeout minimo della sessione è tipicamente 2 * tickTime e il massimo è tipicamente 20 * tickTime, a meno che non venga sovrascritto da impostazioni specifiche del server. Ciò significa che un valore di timeout di Kafka al di fuori dell'intervallo consentito potrebbe essere regolato da ZooKeeper.
Se tickTime=2000, il solito intervallo di sessione consentito è approssimativamente da 4 secondi a 40 secondi. Un'impostazione Kafka come zookeeper.session.timeout.ms=18000 rientra in quell'intervallo. Un timeout molto basso può produrre falsi fallimenti durante brevi pause di rete o pause di garbage collection. Un timeout molto alto può far sì che i veri fallimenti dei broker richiedano più tempo per essere rilevati. Stai scegliendo tra sensibilità e stabilità.
Non modificare tickTime con leggerezza. Influisce sull'ensemble ZooKeeper, non solo su Kafka. Se hai bisogno di maggiore tolleranza per le pause dei broker, spesso è meglio iniziare rivedendo zookeeper.session.timeout.ms di Kafka, il comportamento JVM del broker e la salute della rete prima di modificare i tempi di ZooKeeper.
I log di solito raccontano la storia se li allinei per timestamp. Sui broker Kafka, cerca messaggi relativi a disconnessioni e scadenza della sessione di ZooKeeper:
rg -i "zookeeper|session|expired|controller|reconnect" /var/log/kafka/server.log
I pattern contano più di una singola riga. Una riconnessione una tantum durante un riavvio pianificato di ZooKeeper può essere innocua. La scadenza ripetuta ogni pochi minuti indica instabilità. La scadenza durante la garbage collection punta verso pause JVM o sovraccarico del broker. La scadenza contemporanea su molti broker punta verso ZooKeeper, la rete o un evento di infrastruttura condivisa.
Sui nodi ZooKeeper, controlla cambiamenti di leader, avvisi fsync, limitazione delle connessioni e latenza delle richieste lunga. ZooKeeper è sensibile alla latenza del disco perché scrive i log delle transazioni. Un disco lento può far sembrare il servizio raggiungibile mentre ancora non risponde abbastanza velocemente per sessioni stabili.
La latenza di rete e la perdita di pacchetti sono più importanti della larghezza di banda grezza per ZooKeeper. I broker Kafka non necessitano di un enorme throughput verso ZooKeeper, ma necessitano di comunicazione affidabile e a bassa latenza. Se i broker e ZooKeeper sono divisi su reti distanti, aspettati problemi. Tienili vicini. Negli ambienti cloud, evita di instradare il traffico broker-ZooKeeper attraverso NAT non necessari, firewall sovraccarichi o percorsi cross-regione.
La contesa di risorse sul broker Kafka può apparire esattamente come un problema di ZooKeeper. Se la JVM ferma il mondo per una lunga pausa di garbage collection, il broker potrebbe perdere i battiti cardiaci. Se la CPU è satura, la gestione dei battiti cardiaci può essere ritardata. Se l'host è bloccato in attesa I/O elevata, Kafka potrebbe non tenere il passo con il lavoro di coordinamento. Controlla le metriche del broker agli stessi timestamp delle disconnessioni di ZooKeeper.
Domande utili dal lato broker includono: l'utilizzo dell'heap è aumentato prima della disconnessione, il tempo di pausa GC è aumentato, l'attesa I/O del disco era alta, le ritrasmissioni di rete sono aumentate e c'erano grandi riassegnazioni di partizioni o movimenti di leader nello stesso momento? Un broker sommerso dal carico potrebbe aver bisogno di meno leader di partizione, un disco migliore, ottimizzazione JVM o uno spostamento del traffico. Aumentare i timeout di ZooKeeper può nascondere il sintomo senza risolvere la causa.
La coerenza della configurazione è facile da trascurare. Tutti i broker Kafka nello stesso cluster dovrebbero utilizzare la stessa stringa di connessione ZooKeeper e chroot. Dovrebbero anche avere valori broker.id univoci. Un ID broker duplicato può causare un comportamento di registrazione confuso perché due processi stanno cercando di rappresentare lo stesso broker.
Se hai recentemente modificato nomi host ZooKeeper, certificati, regole firewall o configurazioni dei broker Kafka, confronta il broker funzionante con quello non funzionante. Piccole differenze sono comuni: un vecchio suffisso DNS, un percorso chroot mancante, un gruppo di sicurezza collegato a due broker ma non al terzo, o un errore di battitura in un file di ambiente systemd.
Il recupero dipende da cosa si è rotto. Se mancava una regola firewall, correggila e riavvia il broker interessato se non si riconnette correttamente. Se ZooKeeper ha perso il quorum, ripristina prima il quorum prima di riavviare i broker Kafka. Se un broker è scaduto perché era sovraccarico, riavviarlo potrebbe riportarlo temporaneamente, ma il problema tornerà a meno che non rimuovi la pressione.
Usa riavvii progressivi. Riavviare tutti i broker Kafka contemporaneamente perché ZooKeeper era instabile può trasformare un'interruzione parziale in una totale. Ripristina la salute di ZooKeeper, poi riavvia o recupera i broker uno alla volta mentre osservi la stabilità del controller e la leadership delle partizioni.
Per la stabilità a lungo termine, monitora entrambi i lati. Su ZooKeeper, controlla la latenza delle richieste, le richieste in sospeso, i cambiamenti di leader, lo stato di sincronizzazione dei follower, lo spazio su disco e i riavvii del processo. Su Kafka, controlla i cambiamenti del controller, le partizioni offline, le partizioni sottoreplicate, i riavvii dei broker e i log che menzionano la scadenza della sessione ZooKeeper. Avvisa su pattern ripetuti, non solo sulla morte totale del processo.
La soluzione più pulita, per i team che pianificano un aggiornamento più grande, potrebbe essere la migrazione da ZooKeeper alla modalità KRaft di Kafka. Questo è un progetto, non un passo di risposta agli incidenti. Richiede pianificazione della versione, controlli di compatibilità e un lavoro di migrazione attento. Fino ad allora, tratta ZooKeeper come infrastruttura di produzione. Mantienilo piccolo, vicino a Kafka, configurato coerentemente, monitorato e noioso.
Un pattern pratico di runbook è costruire una piccola matrice durante l'incidente. Metti i broker Kafka su un asse e i nodi ZooKeeper sull'altro. Riempi ogni cella con il risultato di nc -vz host 2181 e, se disponibile, un semplice controllo di salute di ZooKeeper. Questo trasforma vaghi rapporti "Kafka non può raggiungere ZooKeeper" in un pattern visibile. Se ogni broker non riesce a raggiungere zk02, indaga su zk02 o sul suo percorso di rete. Se solo broker-4 non riesce a raggiungere ogni nodo ZooKeeper, indaga sull'host di quel broker, sulla tabella di routing, sul DNS o sul firewall.
Anche la sincronizzazione dell'ora può essere importante. I meccanismi della sessione ZooKeeper non richiedono orologi di parete perfettamente identici per ogni operazione, ma orologi molto distorti rendono i log più difficili da interpretare e possono rompere l'automazione circostante, i certificati e il monitoraggio. Mantieni NTP o chrony sani sui nodi Kafka e ZooKeeper. Quando i timestamp discordano durante un'interruzione, le persone perdono tempo a inseguire la sequenza sbagliata degli eventi.
Fai attenzione con le distribuzioni ZooKeeper containerizzate o orchestrate. ZooKeeper memorizza identità e dati su disco. Se i pod si spostano e perdono l'identità persistente, o se il service discovery punta i client verso nodi che non sono pronti, Kafka potrebbe vedere un comportamento di connessione instabile. L'identità di tipo StatefulSet, i volumi persistenti, il DNS stabile e i controlli di prontezza sono importanti. Un ensemble ZooKeeper non dovrebbe comportarsi come un insieme di pod web stateless usa e getta.
Le impostazioni di sicurezza aggiungono un altro livello. Se SASL, TLS o la policy di rete sono stati introdotti di recente, i fallimenti di connessione potrebbero inizialmente sembrare problemi di raggiungibilità semplici. Controlla se i log Kafka mostrano fallimenti di autenticazione, fallimenti di handshake o errori di autorizzazione piuttosto che timeout TCP. Una porta può essere aperta mentre la sessione fallisce ancora perché il broker non può autenticarsi a ZooKeeper.
Dopo l'incidente, conserva una breve registrazione del sintomo esatto, della causa principale e della soluzione. I problemi di ZooKeeper spesso si ripetono perché la riparazione originale era locale: una regola firewall, un riavvio del broker, un aumento del timeout. Una buona nota post-incidente dovrebbe dire se il cluster aveva quorum, quali broker hanno perso le sessioni, se l'ISR si è ridotto, se il controller è cambiato e quale monitoraggio lo individuerà prima la prossima volta.
Se stai risolvendo i problemi da Kubernetes o da un altro scheduler, controlla anche dove sono finiti i carichi di lavoro Kafka e ZooKeeper. Un problema di rete a livello di nodo, un problema del disco o un evento di carenza di CPU possono influenzare solo i pod programmati lì. Spostare un pod può sembrare risolvere il problema, ma il vero problema potrebbe essere l'host. Confronta eventi e metriche del nodo prima di dichiarare l'applicazione riparata.
I backup e gli snapshot meritano cautela. Le directory dei dati di ZooKeeper non dovrebbero essere sottoposte a snapshot con leggerezza mentre il processo è attivo, a meno che il tuo metodo di backup non sia progettato per questo. Per i metadati di Kafka, uno stato ZooKeeper danneggiato o obsoleto può essere estremamente dirompente. Segui le pratiche di backup supportate da ZooKeeper e testa le procedure di ripristino lontano dalla produzione. Un backup che nessuno ha mai ripristinato è solo un file pieno di speranza.
La mossa preventiva migliore è mantenere ZooKeeper noioso. Non collocarlo con broker Kafka pesanti se puoi evitarlo. Mantieni i suoi dischi affidabili. Mantieni le dimensioni dell'heap conservative e monitorate. Limita chi può modificare l'appartenenza all'ensemble. La maggior parte degli incidenti ZooKeeper che ho visto non sono stati causati da bug esotici; provenivano da un normale scostamento dell'infrastruttura attorno a un piccolo servizio che tutti avevano dimenticato essere critico.