Abbiamo un'app server client, 1 server, circa 10 client. Comunicano tramite socket TCP usando le query personalizzate.Che cosa ha causato il rallentamento delle connessioni socket dopo Full GC?
Il sistema era stato buon funzionamento per molti mesi, ma ad un certo punto, dopo che il server programmata GC PIENA quotidiano che ha richiesto circa 50, abbiamo capito che il tempo tra le query inviate dal client e le risposte ricevute da il server era grande,> 10-20 secondi. Dopo circa 3 ore il sistema è stato ripristinato, tutto stava funzionando di nuovo bene.
Mentre indaga la questione, abbiamo trovato:
- Nessun problema di raccolta dei rifiuti su entrambi i client e il server
- tempo di elaborazione delle query sul server era piccola.
- Il carico sul server era alto.
- La larghezza di banda della rete non è stata saturata.
- I collegamenti non sono stati azzerati durante l'PIENO GC (GC completo giornaliero è stato un evento normale fino a quel momento)
- La macchina e il sistema operativo cambiato recentemente da CentOS 6 (kernel 2.6.32) a CentOS 7 (kernel 3.10.0) , ma la nuova configurazione è stata testata estensivamente. Anche la versione Oracle JDK è passata da 1.7.65 a 1.7.75.
Abbiamo preso una discarica filo sul server:
java.lang.Thread.State: RUNNABLE
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at util.network.BytesBasedSocketConnection$ReadConnectionRunnable.run(BytesBasedSocketConnection.java:293)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Il FilterInputStream.read()
è la seguente:
public int read() throws IOException {
return in.read();
}
Il in
nel nostro codice è un BufferedInputStream
.
Le domande sono: Perché la maggior parte delle connessioni è rallentata dopo la pausa GC completa? Perché lo stacktrace termina con FilterInputStream.read()
? Non dovrebbe finire da qualche parte nello BufferedInputStream
o nel flusso di input del socket? Questa lettura può comportare un carico elevato sul server?
Il codice che utilizziamo per la lettura:
int constructLength = _socketDIS.readInt();
ByteArrayOutputStream constructBOAS = new ByteArrayOutputStream(constructLength);
for (int i = 0; i != constructLength; i++)
constructBOAS.write(_socketDIS.read());
constructBOAS.close();
byte[] bytes = constructBOAS.toByteArray();
dove:
_socketDIS = new DataInputStream(new BufferedInputStream(_socket.getInputStream()));
Ecco la stacktrace dalle connessioni client e di lavoro:
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:152)
at java.net.SocketInputStream.read(SocketInputStream.java:122)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
- locked <0x00007f522cbebca8> (a java.io.BufferedInputStream)
at java.io.DataInputStream.readInt(DataInputStream.java:387)
at util.network.BytesBasedSocketConnection$ReadConnectionRunnable.run(BytesBasedSocketConnection.java:287)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
UPDATE:
Per quanto riguarda la risposta EJP:
Non c'era EOS coinvolti, i collegamenti erano su, ma erano molto lento
Anche se ci fosse un EOS non riesco a vedere come il codice potrebbe filare a EOS, il valore
for
è limitato dal valoreconstructLength
. Ma ancora, il miglioramento suggerito è valido.La stacktrace il problema termina in una lettura fatta su un
DataInputStream
((_socketDIS.read()
) che viene ereditato daFilterInputStream.read()
, vedere codice precedente.DataInputStream
, nonBufferedInputStream
manca ilread()
. Qui nelFilterInputStream.read()
è presente unin.read()
chiamato suBufferedInputStream
, questo ha il proprio metodoread()
definito. Ma lo stacktrace si ferma nel mezzo, non raggiunge loBufferedInputStream.read()
. Perché?
Ah, infatti esiste un 'ScheduledThreadPoolExecutor' utilizzato in modo errato, ma l'attività è in esecuzione continua, legge solo le query dal socket e le inserisce in una coda. – dcernahoschi