Node.js Sunucuda Yüksek RAM Kullanımı Nasıl Çözülür?

Node.js uygulamanız başlangıçta sorunsuz çalışıyor ancak birkaç saat sonra yavaşlıyor veya kapanıyorsa bellek kullanımını incelemek gerekir. Özellikle yoğun API trafiği, büyük dosya işlemleri ve kontrolsüz büyüyen önbellekler, sunucudaki RAM’in hızla dolmasına neden olabilir.

Node.js yüksek RAM kullanımı sorununu çözmek için önce belleği hangi işlemin tükettiğini belirlemeli, ardından uygulamanın kullanımını zaman içinde izlemelisiniz. Bellek limitini artırmak bazı durumlarda yardımcı olur; ancak uygulama kaynaklı bir bellek sızıntısını ortadan kaldırmaz.

1. Sunucunun ve Node.js İşlemlerinin Bellek Kullanımını Kontrol Edin

Ubuntu veya benzer bir Linux sunucuda SSH bağlantısı kurduktan sonra şu komutu çalıştırın:

free -h

Çıktıdaki available alanı, yeni işlemler için kullanılabilecek yaklaşık belleği gösterir. Linux’un dosya önbelleği nedeniyle yalnızca free alanına bakmak yanıltıcı olabilir.

En fazla RAM kullanan işlemleri listeleyin:

ps -eo pid,comm,rss,%mem --sort=-rss | head -n 15

Burada RSS, işlemin fiziksel bellekte kapladığı alanı KiB cinsinden gösterir. Birden fazla node işlemi varsa her birini ayrı değerlendirin.

PM2 kullanıyorsanız:

pm2 list

pm2 monit

Docker üzerinde çalışıyorsanız:

docker stats --no-stream

Sunucuda boş RAM bulunmasına rağmen uygulama kapanıyorsa container’a veya servise özel bir bellek sınırı tanımlanmış olabilir.

2. Node.js İçindeki Bellek Kullanımını Ölçün

İşletim sisteminin gösterdiği RAM tüketimi ile JavaScript nesnelerinin kullandığı bellek aynı şey değildir. Daha ayrıntılı ölçüm için aşağıdaki kodu uygulamanızın başlangıcında bir kez çalışacak şekilde ekleyebilirsiniz:

const memoryMonitor = setInterval(() => {

  const memory = process.memoryUsage();

  console.log({

  time: new Date().toISOString(),

   pid: process.pid,

   rssMiB: Math.round(memory.rss / 1024 / 1024),

   heapUsedMiB: Math.round(memory.heapUsed / 1024 / 1024),

   externalMiB: Math.round(memory.external / 1024 / 1024)

  });

}, 60000);

memoryMonitor.unref();

Bu örnek, dakikada bir bellek ölçümü kaydeder. Kodu her HTTP isteğinde çalışan bir fonksiyonun içine koymayın.

Değer

Ne gösterir?

rss

İşlemin RAM’de kapladığı alanı

heapUsed

V8’in JavaScript nesneleri için kullandığı heap belleğini

external

JavaScript nesnelerine bağlı, V8 heap’i dışında yönetilen belleği

Bu değerleri birbirine eklemeyin; ayrı ve tamamen bağımsız bellek alanları değildir. Ayrıca Worker Threads kullanılıyorsa rss tüm süreci, diğer alanlar ise ölçümü yapan thread’i temsil eder.

3. Normal Bellek Artışı ile Bellek Sızıntısını Ayırın

Uygulama açıldıktan sonra modüllerin yüklenmesi ve önbelleğin dolması nedeniyle RAM kullanımı artabilir. Bu artışın bir noktada dengelenmesi normaldir.

Node.js, kullanılmayan JavaScript nesnelerini çöp toplama mekanizmasıyla temizler. Ancak uygulamanın hâlâ referans tuttuğu nesneler otomatik olarak kaldırılamaz.

Benzer trafik altında heapUsed değeri sürekli yükseliyorsa şu alanları inceleyin:

  • Her istekte büyüyen global diziler veya Map yapıları.
  • Süre veya boyut sınırı bulunmayan önbellekler.
  • İş bitince temizlenmeyen zamanlayıcılar ve event listener’lar.
  • Bağlantı kapandıktan sonra saklanmaya devam eden WebSocket kullanıcı verileri.
  • Tamamlanmayı bekleyen ve giderek biriken işler.

Tek bir yüksek ölçüm, bellek sızıntısını kanıtlamaz. Aynı iş yükü altında ölçümleri karşılaştırın. heapUsed dengeliyken RSS yükseliyorsa Buffer kullanımı, native modüller veya bellek parçalanması da araştırılmalıdır. 

4. Büyük Verileri Tek Seferde Belleğe Almayın

Büyük bir dosyayı tamamen okumak veya yüz binlerce veritabanı kaydını tek sorguda uygulamaya taşımak, kısa sürede yüksek RAM tüketimine yol açabilir.

Örneğin rapor oluştururken bütün siparişleri bir diziye doldurmak yerine kayıtları sayfalar veya parçalar halinde işleyin. Dosya aktarımında uygun olduğunda stream kullanın.

Stream kullanımında da veri akışının hızını kontrol etmek gerekir. Veriyi üreten taraf, işleyen taraftan hızlıysa bellek içinde kuyruk oluşabilir. Node.js’in backpressure mekanizmasına uygun çalışan pipeline gibi araçları tercih etmek bu birikimi sınırlamaya yardımcı olur. 

Aynı anda başlatılan işleri de sınırlandırın. Örneğin binlerce dosya işlemini tek seferde Promise.all() ile başlatmak yerine kontrollü sayıda eşzamanlı görev çalıştırın.

5. Heap Limitini İhtiyaca Göre Ayarlayın

Uygulama günlüklerinde şu hata görülüyorsa JavaScript heap sınırına ulaşılmış olabilir:

FATAL ERROR: Reached heap limit

Allocation failed - JavaScript heap out of memory

Node.js’in V8 old-space sınırı şu şekilde ayarlanabilir:

node --max-old-space-size=2048 app.js

app.js yerine uygulamanızın giriş dosyasını yazın. 2048 örnek bir değerdir ve MiB cinsindendir. Uygulama PM2, systemd veya Docker tarafından yönetiliyorsa bu seçeneği ilgili başlangıç yapılandırmasına ekleyin; çalışan uygulamanın yanında ikinci bir kopya başlatmayın.

Bu ayar, Node.js’in toplam RAM tüketimini 2 GB ile sınırlamaz. Buffer’lar, diğer V8 alanları ve native bileşenler ek bellek kullanabilir. Sunucunun veya container’ın bütün belleğini heap’e ayırmayın.

Sınırı gereğinden düşük tutmak da daha sık çöp toplama ve uygulamanın kapanmasıyla sonuçlanabilir. Değeri iş yüküne ve kullanılabilir kaynaklara göre belirleyin. 

6. Uygulama Süreçlerinin Sayısını Kontrol Edin

PM2 cluster modu veya birden fazla container kullanıyorsanız her uygulama sürecinin kendi bellek ihtiyacı vardır. Tek süreç için uygun görünen tüketim, süreç sayısı arttığında sunucuyu zorlayabilir.

Süreç sayısını yalnızca işlemci çekirdeğine göre belirlemeyin. Uygulamanın önbelleğini, bağlantı havuzlarını ve yoğun saatlerdeki tüketimini de hesaba katın.

Bellek kullanımına göre otomatik yeniden başlatma, hizmeti geçici olarak ayakta tutabilir. Ancak sorunun nedenini düzeltmez ve devam eden istekleri etkileyebilir.

7. Sorun Devam Ediyorsa Heap Snapshot İncelemesi Yapın

Bellekte hangi nesnelerin biriktiğini anlamak için heap snapshot alınarak Chrome DevTools üzerinden karşılaştırma yapılabilir. Özellikle aynı işlem tekrarlandıkça büyüyen nesne grupları araştırılmalıdır.

Heap snapshot almak ana thread’i duraklatır ve ciddi miktarda ek bellek gerektirebilir. Belleği zaten dolmak üzere olan canlı uygulamada doğrudan denemek yerine sorunu test ortamında yeniden oluşturun veya kesintisi tolere edilebilen bir uygulama örneği kullanın. Snapshot dosyaları hassas veriler içerebileceğinden erişimini sınırlandırın. 

RAM Artırmak Ne Zaman Gerekir?

Bellek kullanımı normal yük altında dengeleniyor ancak uygulamanın gerçek ihtiyacı mevcut kapasiteyi aşıyorsa RAM artırımı değerlendirilebilir. Kullanım sürekli ve kontrolsüz büyüyorsa önce uygulama tarafındaki neden çözülmelidir.

Node.js performans optimizasyonunda hedef yalnızca RAM yüzdesini düşürmek değildir. Yanıt sürelerini, hata oranını ve bellek kullanımını birlikte takip ederek uygulamanın kararlı çalıştığını doğrulayın.

API, e-ticaret veya kurumsal uygulamanız için uygun kaynakları planlamak üzere Ekiphost üzerinden VDS ve fiziksel sunucu seçeneklerini inceleyebilir, ihtiyaçlarınıza göre bizimle iletişime geçebilirsiniz.

Bu cevap yeterince yardımcı oldu mu? 0 Bu dökümanı faydalı bulan kullanıcılar: (0 Oy)