19 Eylül 2023 Salı

Dönüşüm Hikayeleri 6 - Usta Yazılımcıyı Yaşlandıran O Sorun: Deadlock

    S.A. Arkadaşlar,

    Bir süredir yeni bir projeye başladığımız için legacy tarafındaki dönüşümümüz biraz yavaşladı. O yüzden bu serideki yazısı sıklığı eskiye göre azaldı. Tabii ki tek sebep bu da değil. Legacy olan kodu belirli bir olgunluğa da getirdik, fakat siz de takdir edersiniz ki hayat devam ediyor ve karşımıza her daim yeni problemler çıkacaktır. Bugün de CPU kullanımını tavan yapan bir probleme odaklanacağız. Hazırsanız başlayalım.

    İyi yazılımcı debug yapar, daha iyi yazılımcı log okur sözünü her daim kullanırım. (Söz kime aitti maalesef hatırlamıyorum). Özellikle uç noktalarda log tutmanın ve onu okumanın faydaları çok daha kritik oluyor. Biz de log tarafına düşen kayıtlardan IoT tarafımızda bir problem olduğunu saptadık. Problem 20-30 istemci aynı anda geldiğinde CPU kullanımı fırlıyor ve tekrar eski haline gelmiyor. Buna sebep olan kodu bulduk, fakat bunun neresini düzeltmemiz gerekiyordu? 

    Aşağıdaki yazılanlara bakmadan sizler de hızlıca koda bir göz gezdirip fikir yürütebilirsiniz. 

    

    Bu problemin sebebini ekip arkadaşlarımıza sorunca farklı farklı cevaplar geldi. Bu cevaplar benim ufkumu açtığı için buradan da biraz düzenleyerek paylaşmak istiyorum. Belki sizlerin de ilgisini çeker.

  • TCP'de anlık bağlantı kontrol connected ile kontrol edilmez. Disconnect olunca dışarı atman lazım. Bu bağlantı kaybedildiğinde sonsuz döngüye girebilir. Nedenini tam bilmemekle beraber böyle olabileceğini düşünüyorum.

  • ReadAsync'nin işleyiş mantığından ötürü istemcinin düşüp düşmemesi önemli değil, istemci düşmüş ama ağ akışı düşmemiş olabileceği için hala işleme devam edip sonsuz döngüde kalabilir.

  • Client.Connected özelliği connection’ın o andaki bağlantı durumunu göstermiyor. Sadece en son mesaj operasyonunun sonucuna göre bağlantı durumunu belirtiyor. Yani sadece bir mesaj bile stream'den başarılı olarak okunsa ve bir daha stream'den hiç mesaj gelmese bile client.Connected hep true kalacak ve while koşulu sonsuz döngüye girecek. Bu da CPU’ya tavan yaptıracak.
    https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient.connected?view=net-7.0
    Problemin üzerinde çalışıp çözüme kavuşturan Selman ve Gökhan'ın yorumu/cevabı ise;

  • Buradaki sorun aslında stream'in while dışında tanımlanmasıydı. stream dispose edildiğinde Connected false set ediliyor ancak dış scope'da tanımlandığı için bağlantı koptuğunda içerideki döngü bitiyor ve while(client.Connected) sonsuz dönmeye başlıyor. Stream de Dispose edilmediği için hep true oluyor. bir nevi deadlock oluyor. Stream tanımlaması while içine alındığında ise sorun  çözülüyor. 

  • Tabii bu sorunu çözse de while(client.Connected) kullanımı yine de gereksiz. Zaten Read metodu bağlantı koptuğunda -1 dönüyor. Bu vesileyle Dışarıdaki döngüye gerek kalmıyor.


    Ekibin bu güzel çalışması için kendilerine teşekkür ederken, başlık için Emre'ye, yazmaya teşvik ettiği için de Selman'a ayrıca teşekkürlerimi sunar.

    Yazıyı bir ayet-i kerime ile bitirelim.

“Hiç kuşkusuz biz insanı zorluklarla mücadele etme gücüyle yarattık.” Beled, 90/4

Hiç yorum yok:

Yorum Gönder