Prod'da Teşhis — Heap Dump, Thread Dump ve İlk On Beş Dakika
Önce şunu oku: Concurrency Araçları — Executor, Lock, Atomic ve Deadlock , Garbage Collection — Üçlü Takas
30 saniyede özet
Servis yavaşladığında önce belirtiye bakılır: bellek mi tırmanıyor, CPU mu yanıyor, thread'ler bir şey mi bekliyor? Her belirtinin bir aracı var. Kanıt, yeniden başlatmadan önce toplanır.
Doktora “halsizim” dediğinde doktor hemen ilaç yazmaz. Önce birkaç soru sorar, sonra belirtiye uyan tahlili ister.
Adım adım oku
- Hasta halsiz olduğunu söyler; bu henüz bir teşhis değil.
- Doktor belirtiyi sorar: ateş mi, öksürük mü, ağrı mı?
- Belirtiye uyan tek tahlili ister.
- Tahlil sonucu hastalığa bir ad koyar; tedavi ondan sonra gelir.
-
Bayt: Destek ekibi yazıyor: havaleler bir saattir çok yavaş!
-
Sen: Hemen yeniden başlatalım, düzelir.
-
Bayt: Düzelir... ama neden yavaşladığını da yanına alıp gider.
-
Bayt: Önce birkaç fotoğraf çekelim. Beş dakika sürer.
Önce belirti, sonra araç
Yavaşlığın arkasında genellikle üç şeyden biri vardır. Her biri başka bir iz bırakır:
| Belirti | İlk bakılacak yer |
|---|---|
| Bellek günlerdir tırmanıyor | GC sonrası kalan heap, sonra heap dumpJVM'in heap'indeki bütün nesnelerin bir dosyaya yazılmış anlık görüntüsü. Kimin kimi tuttuğunu gösterir; alınırken JVM durur.Eclipse MAT gibi araçlarla açılır. Bellekteki veriyi de içerdiği için müşteri verisi gibi korunur.Sözlükte gör → |
| Bir çekirdek sürekli yüzde yüzde | top -H ile hangi thread, sonra thread dump |
| CPU boşta ama istekler bitmiyor | Birkaç thread dumpO anda JVM'deki bütün thread'lerin adını, durumunu ve yığınını gösteren metin. Uygulamayı durdurmadan saniyeler içinde alınır.jcmd PID Thread.print ya da jstack ile alınır. Birkaç saniye arayla birden fazla alınır ve tekrar eden desene bakılır.Sözlükte gör → |
Bu araçların hepsi servis hâlâ hastayken çalışır. Yeniden başlatınca belirti de gider; bu yüzden kanıt önce alınır.
Kafam karıştı, daha basit anlat
Önce ne tür bir yavaşlık olduğunu sor: bellek mi, CPU mu, bekleme mi? Sonra ona uyan fotoğrafı çek.
Üretimdeki bir servis yavaşladı ve kullanıcılar şikâyet ediyor. İlk iş ne yapılır?
Sızıntı mı, yük mü?
Heap grafiği bir testere gibidir: nesneler ayrılır, çizgi yükselir; GC toplar, çizgi düşer. Asıl bilgi dişlerin dibindedir.
Servisin heap'i öğleden sonra yüzde 85'e çıkıyor ve GC sık çalışıyor. Bu bir bellek sızıntısı mı? Cevabı göster
Buna bakarak söyleyemezsin. Sızıntıyı gösteren, GC’den sonra kalan heap’tir. Bu taban her gün biraz yükselip trafik düşünce inmiyorsa sızıntı, akşam eski yerine dönüyorsa yalnızca yüktür.
Sızıntı olduğu belliyse sıradaki soru, nesneleri kimin tuttuğudur. Heap dump’ı Eclipse MAT gibi bir araçla açıp nesneleri retained sizeBir nesne ortadan kalksaydı serbest kalacak toplam bellek: nesnenin kendisi ve yalnızca onun sayesinde canlı kalan her şey.Nesnenin kendi boyuna shallow size denir. Sızıntı ararken nesneler retained boya göre sıralanır.Sözlükte gör →’a göre sıralarsın. En üstte çoğunlukla bir static koleksiyon, bir cache ya da hiç çıkarılmayan bir dinleyici listesi durur.
Sızıntının tipik kaynaklarını Garbage Collection ve ThreadLocal derslerinde gördün. Burada önemli olan onları bulma yolu.
Kafam karıştı, daha basit anlat
Dolu heap tek başına bir şey söylemez. GC temizledikten sonra kalan her gün artıyorsa bir şey nesneleri bırakmıyordur; heap dump onun adını söyler.
Hangi gözlem bir bellek sızıntısına işaret eder?
Heap dump'ta küçük bir HashMap nesnesi heap'in yüzde 70'ini "tutuyor" görünüyor, oysa nesnenin kendisi birkaç düzine byte. Bu nasıl olur?
Satır satır: bir thread dump okumak
CPU boşta, istekler bitmiyor. jcmd PID Thread.print ile bir thread dump aldın; iki bloğa birlikte bakalım.
Bekleyenler ve tutanlar
$ jcmd 4121 Thread.print"http-nio-8080-exec-12" #58 daemon prio=5 nid=0x4b12 waiting on condition java.lang.Thread.State: TIMED_WAITING (parking) at jdk.internal.misc.Unsafe.park(Native Method) at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:181) at com.bank.transfer.TransferService.send(TransferService.java:31) "http-nio-8080-exec-3" #49 daemon prio=5 nid=0x4a01 runnable java.lang.Thread.State: RUNNABLE at sun.nio.ch.SocketDispatcher.read0(Native Method) at com.bank.fx.FxRateClient.fetch(FxRateClient.java:44) at com.bank.transfer.TransferService.send(TransferService.java:24)Debug
sen Her blok bir thread: adı, nid'i (işletim sistemindeki kimliği) ve kısa durumu.
- thread
- = exec-12
Sol/sağ ok tuşlarıyla da gezebilirsin.
Bu bir connection poolAçık veritabanı bağlantılarını tutan ve isteklere ödünç veren havuz. Bağlantı açmanın maliyetini bir kez öder; boyutu veritabanının kapasitesine göre seçilir.Sözlükte gör → tükenmesi. Tek dump bir fotoğraftır; birkaç saniye arayla üç dump alırsın ve aynı tablo tekrar ediyorsa desen budur.
CPU’yu tek bir thread yakıyorsa yol biraz farklıdır: top -H -p PID o thread’in kimliğini verir. Kimliği onaltılığa çevirip dump’taki nid alanında ararsın. Deadlock varsa JVM onu dump’ın sonunda kendisi raporlar; Concurrency araçları dersindeki gibi.
CPU yüzde 5, ama istekler zaman aşımına düşüyor. Thread dump'ta 200 http thread'inin 190'ı TIMED_WAITING durumunda ve yığının tepesinde HikariPool.getConnection var. En olası açıklama?
top -H çıktısında TID 19007 olan thread yüzde 99 CPU kullanıyor. Thread dump'ta bu thread'i nasıl bulursun?
Kendin gör
Servis yavaşladı ve arkasında dört gizli sorundan biri var. Bir olay ve bir araç seç; araç sana o olayda ne gösterirdi, izle.
Prod yavaşladı: hangi araçla bakarsın?
Tohum 1- Yanıt süreleri günlerdir yavaş yavaş uzuyor.
- GC loglarında toplama sıklaşmış.
Oynat ya da adımla.
Şu an ne oldu?
Servis yavaşladı
Yanıt süreleri günlerdir yavaş yavaş uzuyor. GC loglarında toplama sıklaşmış. Belirtiye bak ve aracı ona göre seç.
Görevler0/3
Sızıntıyı tutan alanı adıyla bulaçık
İpucu
Önce sızıntı olduğunu gör, sonra kimin tuttuğuna bak.
CPU boştayken yavaşlayan servisin neyi beklediğini bulaçık
İpucu
Thread'ler bir şey bekliyorsa ne beklediklerini sor.
Bir çekirdeği yakan kod satırını bulaçık
İpucu
Dump tek başına yetmez; hangi thread'in CPU yediğini de bilmen gerekir.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanı oynat. Gizli sorun A’ya thread dump ile bakıyorsun. Thread’ler normal: yanlış araç.
- Aracı “GC sonrası heap grafiği” yap. Taban tırmanıyor, sızıntı var ama kimin tuttuğu belli değil. Heap dump’a geç.
- Gizli sorun B’yi seç. CPU boşta: hangi araç bekleyenleri gösterir?
- Gizli sorun C ve D’yi dene. Birinde tek bir thread suçlu, ötekinde hiçbir araç suçlu bulamıyor. Bu da bir cevap.
Her belirtiyi ilk bakılacak araca göre ayır.
Tuzaklar
Önce yeniden başlatmak. Servis düzelir, kanıt gider, sorun geri gelir. Bir instance’ı trafikten çıkarıp kanıtı ondan al; diğerlerini sonra yeniden başlat.
Trafikteyken heap dump. Dump boyunca JVM durur ve dosya heap kadar yer kaplar. İçinde IBAN’lar, token’lar ve müşteri adları olduğu için dosya müşteri verisi gibi korunur.
Sebebi bilmeden büyütmek. Havuzu ya da heap’i büyütmek sızıntıyı ve yavaş dış çağrıyı yalnızca erteler. Önce teşhis, sonra ayar.
Kafam karıştı, daha basit anlat
Önce fotoğraf, sonra yeniden başlatma. Heap dump’ı trafikte olmayan bir instance’tan al ve dosyayı kasadaki para gibi koru.
Kur servisi yavaşladığı günlerde bu havale servisi bütün uygulamayı kilitliyor ve thread'ler bağlantı bekliyor. Sorunun kaynağı hangi satır?
Derinleş · Havale servisi: kanıt betiği, hazır JVM ayarları ve düzeltilmiş servis 4 dosya · ~54 satır · ilk okumada atlayabilirsin
Kendini sına
Önce hızlı bir ısınma: puan yok, kayıt yok. Sonra asıl sorular.
Heap'in yüzde 85 dolu olması tek başına bir sızıntı olduğunu gösterir.
Üretimde 16 GB heap'li bir JVM'den heap dump alacaksın. Hangisini hesaba katman gerekir?
Aklında kalacak üç şey
- 1 Önce belirti, sonra araç. Bellek tırmanıyorsa GC sonrası heap ve heap dump; bir çekirdek yanıyorsa top -H ve thread dump; CPU boştayken yavaşsa birkaç thread dump.
- 2 Sızıntıyı heap'in doluluğu değil, GC'den sonra kalan taban gösterir. Heap dump'ta suçlu, retained boyu en büyük tutucudur.
- 3 Yeniden başlatmak kanıtı siler. Bir instance trafikten çıkarılır, kanıt ondan alınır; heap dump JVM'i durdurur ve müşteri verisi içerir.
4 kart sonraki derste seni bekliyor