Ti sei perso le scorse puntate? Niente paura, eccole qui:
- Introduzione ai performance monitoring tool – parte 1
- Esempio di un APM open source per un’app web Java J2EE: Glowroot – parte 2
- Glowroot – Profilazione e transazioni web – parte 3
- Glowroot Slow traces – parte 4
- Glowroot: monitoring della JVM – parte 5
- Heap dump in situazioni critiche – parte 6
- Un caso reale di memory leak – parte 7
- Thread dump in situazioni critiche – parte 8
- Thread dumps e strumenti di analisi – parte 9
A giugno del 2018 in una nostra azienda cliente, la stessa nella quale si è manifestato il problema di performance di Web.UP descritto in questo articolo ha iniziato a manifestarsi un comportamento anomalo.
Il comportamento classico della macchina server consisteva in un andamento della CPU stabile, oscillante attorno al 20%. Prima del riavvio della domenica (viene effettuato un riavvio settimanale) iniziò a capitare che tale valore nel giro di 24 ore salisse fino al 99% rallentando in maniera inaccettabile la macchina e l’applicazione. A questo punto per non bloccare la produzione era necessario riavviare il server.
A differenza del caso descritto in questo articolo, in cui si è estratto il dump direttamente dalla produzione, si è tentato, con esito positivo, di riprodurre il problema in un ambiente di test parallelo attraverso simulazioni di carico.
L’esame del thread dump estratto in due momenti differenti durante il manifestarsi del rallentamento ha mostrato la seguente particolarità: più di un thread risultava essere sempre esecuzione sullo stesso punto di codice.
Vediamo nelle due figure sottostanti il thread t@204 alle 11.00.43 e ben 49 minuti dopo, alle 11.49.00 essere RUNNABLE e sempre in esecuzione della riga 2379 del metodo fixAfterDeletion della classe TreeMap.
Ora il thread non era bloccato sulla riga, essendo lo stato RUNNABLE e non BLOCKED. Era pertanto in esecuzione perenne, ma sempre della stessa parte di codice. Si presentava pertanto uno scenario di livelock.
Effettuando una ricerca sul web relativamente ad alta cpu in caso di presenza del metodo fixAfterDeletion della classe TreeMap (la TreeMap è una classe distribuita con Java) abbiamo trovato alcuni post di problemi analoghi al nostro riscontrati da altri sviluppatori software e varie soluzioni consigliate e attuate.
Il problema era dovuto all’utilizzo della classe TreeMap in maniera non sincronizzata tra più thread. La struttura dati TreeMap non è programmata in maniera tale da gestire la sincronizzazione al suo interno quindi se più thread rimuovono coppie di chiavi-valori simultaneamente si può generare uno stato inconsistente e un livelock tra di essi.
E’ quindi necessario nell’usarla, se condivisa da più thread, gestire programmaticamente la sincronizzazione. Un’altra alternativa può essere quella di utilizzare mappe concepite appositamente per essere condivise da più thread, come le classi ConcurrentHashMap o SynchronizedHashMap.
Nel nostro caso la TreeMap in questione veniva utilizzata per mantenere la lista delle variabili smeup necessarie alla visualizzazione dell’utente. L’evidenza del fatto che tale mappa venisse acceduta da più thread contemporaneamente ha fatto riflettere sulle procedure utilizzate per trattarla, più complesse del necessario. Grazie alla semplificazione di codice effettuata l’accesso di più thread a tale mappa è stato rimosso e pertanto il livelock e i conseguenti disagi avuti dal cliente sono felicemente spariti.
Chiara Zambelli
Responsabile CI/CD – smeup
My LinkedIn Profile
Naviga per categoria:
Seleziona una categoria d’interesse dal nostro magazine