Ho trascorso un po 'di tempo a rintracciare un problema nella produzione di recente, in cui un server database scomparendo avrebbe causato un blocco fino a 2 ore (lunga attesa per una poll()
chiamata nella libreria client libpq) per un client connesso. Scavando nel problema, mi sono reso conto che questi parametri del kernel dovrebbero essere regolati in modo da poter rilevare tempestivamente le connessioni TCP interrotte:
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_retries2 = 15
I quattro valori sopra riportati provengono da una macchina Ubuntu 12.04 e sembra che questi valori predefiniti siano invariati rispetto ai valori predefiniti del kernel Linux corrente .
Queste impostazioni sembrano essere fortemente distorte nel mantenere aperta una connessione esistente e nell'essere estremamente avari di sonde keepalive. AIUI, il valore predefinito tcp_keepalive_time
di 2 ore significa che quando stiamo aspettando una risposta per un host remoto, aspetteremo pazientemente 2 ore prima di avviare un probe keepalive per verificare che la nostra connessione sia ancora valida. E quindi, se l'host remoto non risponde a una sonda keepalive, riproviamo quelle sonde keepalive 9 volte ( tcp_keepalive_probes
), distanziate di 75 secondi ( tcp_keepalive_intvl
), quindi sono altri 11 minuti prima di decidere che la connessione è davvero interrotta.
Questo corrisponde a quello che ho visto sul campo: ad esempio, se avvio una psql
sessione connessa a un'istanza PostgreSQL remota, con qualche query in attesa di una risposta, ad es.
SELECT pg_sleep(30);
e poi il server remoto muore in modo orribile (ad esempio, rilascia il traffico su quella macchina), vedo la mia sessione psql attendere fino a 2 ore e 11 minuti prima di scoprire che la sua connessione è interrotta. Come puoi immaginare, queste impostazioni predefinite causano seri problemi al codice di cui stiamo parlando con un database durante, ad esempio, un evento di failover del database. Abbassare queste manopole ha aiutato molto! E vedo che non sono il solo a consigliare queste impostazioni predefinite.
Quindi le mie domande sono:
- Da quanto tempo le impostazioni predefinite sono state così?
- Qual è stata la logica originale per rendere predefinite queste impostazioni TCP?
- Le distro Linux cambiano questi valori predefiniti?
E qualsiasi altra storia o prospettiva sulla logica di queste impostazioni sarebbe apprezzata.
TCP_KEEPIDLE
, TCP_KEEPCNT
e TCP_KEEPINTVL
.
TCP_USER_TIMEOUT
, invece di impostare a livello di net.ipv4.tcp_retries2
sistema. Naturalmente molte applicazioni (come PostgreSQL nel mio esempio qui) non supportano TCP_USER_TIMEOUT
ancora.