Samaradorlikni oshirish


ULASHISH

Nima uchun unumdorlik muhim

Node.js ishlash muammolarini tashxislash uchun turli vositalar va usullarni taklif etadi.

Ushbu qo‘llanmada har tomonlama ishlash tahlili uchun o‘rnatilgan vositalar va mashhur uchinchi tomon echimlari mavjud.

Umumiylik bo‘yicha maslahat: Optimallashtirishdan oldin har doim o‘lchov qiling.

Ishlash muammolari qayerda bo‘lishi mumkinligini taxmin qilish o‘rniga, haqiqiy qiyinchiliklarni aniqlash uchun ushbu qo‘llanmadagi usullardan foydalaning.


Node.js ishlashini tushunish

Node.js ilovalari unumdorligiga bir necha omillar ta’sir qilishi mumkin:

  • Voqealar siklini bloklaydigan protsessor intensiv operatsiyalari
  • Xotiraning oqishi va ortiqcha axlat yig‘ish
  • I/O bottlenecks (database queries, file operations, network requests)
  • Samarasiz kod va algoritmlar
  • Voqea davrining tiqilib qolishi

Ushbu muammolarni tashxislash metodik yondashuv va to‘g‘ri vositalarni talab qiladi.


O‘rnatilgan diagnostika vositalari

console.time() va console.timeEnd()

Operatsiya qancha davom etishini o‘lchashning eng oddiy usuli:

// Measure execution time
console.time('operation');

// Some operation to measure
const array = Array(1000000).fill().map((_, i) => i);
array.sort((a, b) => b - a);

console.timeEnd('operation');
// Output: operation: 123.45ms

Jarayon statistikasi

Node.js process global obyekti orqali jarayon statistikasiga kirish imkonini beradi:

// Memory usage
const memoryUsage = process.memoryUsage();
console.log('Memory Usage:');
console.log(` RSS: ${Math.round(memoryUsage.rss / 1024 / 1024)} MB`);
console.log(` Heap Total: ${Math.round(memoryUsage.heapTotal / 1024 / 1024)} MB`);
console.log(` Heap Used: ${Math.round(memoryUsage.heapUsed / 1024 / 1024)} MB`);
console.log(` External: ${Math.round(memoryUsage.external / 1024 / 1024)} MB`);

// CPU usage
const startUsage = process.cpuUsage();

// Simulate CPU work
const now = Date.now();
while (Date.now() - now < 500); // Busy wait for 500ms

const endUsage = process.cpuUsage(startUsage);
console.log('CPU Usage:');
console.log(` User: ${endUsage.user / 1000}ms`);
console.log(` System: ${endUsage.system / 1000}ms`);

// Uptime
console.log(`Process uptime: ${process.uptime().toFixed(2)} seconds`);


Node.js ishlash hook’lari

Node.js 8.5.0 dan boshlab, perf_hooks moduli samaradorlikni o‘lchash vositalarini taqdim etadi:

const { performance, PerformanceObserver } = require('perf_hooks');

// Create a performance observer
const obs = new PerformanceObserver((items) => {
  items.getEntries().forEach((entry) => {
    console.log(`${entry.name}: ${entry.duration.toFixed(2)}ms`);
  });
});

// Subscribe to performance events
obs.observe({ entryTypes: ['measure'] });

// Mark the beginning of an operation
performance.mark('start');

// Simulate some work
const data = [];
for (let i = 0; i < 1000000; i++) {
  data.push(i * i);
}

// Mark the end and measure
performance.mark('end');
performance.measure('Data processing time', 'start', 'end');

// Clean up marks
performance.clearMarks();

Kengaytirilgan CPU profilini yaratish

CPU profilini qachon ishlatish kerak

  • Haddan tashqari CPU vaqtini sarflaydigan issiq funksiyalarni aniqlash
  • Sinxron kodda optimallashtirish imkoniyatlarini topish
  • Hodisa siklini blokirovkalash operatsiyalarini tahlil qilish
  • Optimallashtirishdan oldin va keyin ishlashni taqqoslash

1. Manba Map’lari bilan V8 Profiler

TypeScript yoki transpilyatsiya qilingan JavaScript-dan foydalanadigan ilovalar uchun manba Map’lari mazmunli profillash natijalari uchun zarurdir:

Node.js protsessor profilini yaratish uchun to‘g‘ridan-to‘g‘ri V8 profiliga kirish imkonini beradi:

const v8Profiler = require('v8-profiler-node8');
const fs = require('fs');
const path = require('path');

// Enable source map support for accurate profiling
require('source-map-support').install();

// Start CPU profiling with source map support
v8Profiler.setGenerateType(1); // Include type information
const profile = v8Profiler.startProfiling('CPU profile', true);

// Run code to profile
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

// Simulate both CPU and I/O work
function processData() {
  const start = Date.now();
  fibonacci(35);
  console.log(`CPU work took: ${Date.now() - start}ms`);

  // Simulate async work
  setImmediate(() => {
    const asyncStart = Date.now();
    fibonacci(30);
    console.log(`Async work took: ${Date.now() - asyncStart}ms`);
  });
}

processData();

// Stop profiling after async work completes
setTimeout(() => {
  const profile = v8Profiler.stopProfiling('CPU profile');
  profile.export((error, result) => {
    const filename = path.join(__dirname, 'profile.cpuprofile');
    fs.writeFileSync(filename, result);
    console.log(`CPU profile saved to ${filename}`);
    profile.delete();
  });
}, 1000);

Yuqoridagi misoldan foydalanish uchun v8-profiler paketini o‘rnatishingiz kerak:

npm install v8-profiler-node8

Yaratilgan .cpuprofile fayli vizualizatsiya uchun Chrome DevTools-ga yuklanishi mumkin.

2. Node.js o‘rnatilgan profillash

Node.js-da buyruq qatori bayroqlari orqali kirish mumkin bo‘lgan o‘rnatilgan profillash imkoniyatlari mavjud:

# Start a Node.js application with profiling enabled
node --prof app.js

# Process the generated log file
node --prof-process isolate-0xNNNNNNNN-NNNN-v8.log > processed.txt

Kengaytirilgan xotira profilini yaratish

Xotira oqishini aniqlash bo‘yicha maslahat: Kutilganidek, chiqindi yig‘ilmaydigan obyektlarni aniqlash uchun turli vaqtlarda olingan bir nechta yig‘ma suratlarni solishtiring.

Chrome DevTools yordamida yig‘ilgan suratlar

Snapshotlar xotira holatini ma’lum bir vaqtda yozib olish orqali xotira oqishini aniqlashga yordam beradi:

const heapdump = require('heapdump');
const fs = require('fs');
const path = require('path');

// Generate some data that might leak
let leakyData = [];
function potentiallyLeaky() {
  const data = {
    id: Date.now(),
    content: Array(1000).fill('potentially leaky data'),
    timestamp: new Date().toISOString()
  };
  leakyData.push(data);
} 
// Simulate a memory leak with different retention patterns
setInterval(() => {
  potentiallyLeaky();
  // Keep only the last 100 items to simulate a partial leak
  if (leakyData.length > 100) {
    leakyData = leakyData.slice(-100);
  }
}, 100);
// Take heap snapshots at intervals
function takeHeapSnapshot(prefix) {
  const filename = path.join(__dirname, `${prefix}-${Date.now()}.heapsnapshot`);
  heapdump.writeSnapshot(filename, (err, filename) => {
    if (err) {
      console.error('Failed to take heap snapshot:', err);
    } else {
      console.log(`Heap snapshot saved to ${filename}`);
    }
  });
}
// Initial snapshot
takeHeapSnapshot('heap-initial');
// Take periodic snapshots
setInterval(() => {   takeHeapSnapshot('heap-periodic');
}, 10000);
// Force garbage collection before final snapshot
setTimeout(() => {
  if (global.gc) {
    global.gc();
    console.log('Garbage collection forced');
  }
  takeHeapSnapshot('heap-final');
}, 30000);

Yuqoridagi misoldan foydalanish uchun siz yig‘ma to‘plamni o‘rnatishingiz kerak:

npm install heapdump

Xotira oqishini aniqlash uchun yig‘ilgan suratlarni Chrome DevTools-da tahlil qilish mumkin.


Hodisa sikli va kechikish tahlili

Monitoring uchun voqealar davri ko‘rsatkichlari

  • Event loop lag (time between event loop ticks)
  • Faol tutqichlar va so‘rovlar
  • Kutilayotgan asinxronizatsiya operatsiyalari
  • Axlat yig‘ish to‘xtatiladi

Voqealar sikli Node.js ishlashi uchun markaziy hisoblanadi. Uni blokirovka qilish ishlashning pasayishiga olib keladi:

const toobusy = require('toobusy-js');
const http = require('http');

// Configure thresholds (in milliseconds)
toobusy.maxLag(100); // Maximum allowed lag before considering server too busy
toobusy.interval(500); // Check interval for event loop lag

// Create HTTP server with event loop monitoring
const server = http.createServer((req, res) => {
  // Check if event loop is overloaded
  if (toobusy()) {
    res.statusCode = 503; // Service Unavailable
    res.setHeader('Retry-After', '10');
    return res.end(JSON.stringify({
      error: 'Server is too busy',
      message: 'Please try again later',
      status: 503
    }));
  }
  // Simulate some work based on URL
  if (req.url === '/compute') {
    // CPU-intensive work
    let sum = 0;
    for (let i = 0; i < 1e7; i++) {
      sum += Math.random();
    }
    res.end(`Computed: ${sum}`);
  } else {
    // Normal response
    res.end('OK');
  }
});
// Add error handling
server.on('error', (err) => {
  console.error('Server error:', err);
});
// Start server
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});
// Monitor event loop lag and memory usage
setInterval(() => {
  const lag = toobusy.lag();
  const mem = process.memoryUsage();
  console.log(`Event loop lag: ${lag}ms`);
  console.log(`Memory usage: ${Math.round(mem.heapUsed / 1024 / 1024)}MB / ${Math.round(mem.heapTotal / 1024 / 1024)}MB`);
}, 1000);
// Graceful shutdown
process.on('SIGINT', () => {
  console.log('Shutting down...');
  server.close(() => {
    process.exit(0);
  });
});

Yuqoridagi misoldan foydalanish uchun siz toobusy-js paketini o‘rnatishingiz kerak:

npm install toobusy-js

Olovli grafikalar

Olovli grafiklar protsessor namunalarini vizual tarzda taqdim etadi, bu sizning ilovangizda qancha vaqt sarflanganligini aniqlashga yordam beradi:

# Using 0x for flame graphs (install globally)
npm install -g 0x

# Run your application with 0x
0x app.js

# A browser will open with the flame graph visualization when the process exits

Benchmarking

Benchmarking eng samaralisini tanlash uchun turli ilovalarni solishtirishga yordam beradi:

const Benchmark = require('benchmark');
const suite = new Benchmark.Suite;

// Add tests
suite
  .add('RegExp#test', function() {
    /o/.test('Hello World!');
  })
  .add('String#indexOf', function() {
    'Hello World!'.indexOf('o') > -1;
  })
  .add('String#includes', function() {
    'Hello World!'.includes('o');
  })
  // Add listeners
  .on('cycle', function(event) {
    console.log(String(event.target));
  })
  .on('complete', function() {
    console.log('Fastest is ' + this.filter('fastest').map('name'));
  })
  // Run benchmarks
  .run({ 'async': true });

Yuqoridagi misoldan foydalanish uchun siz benchmark paketini o‘rnatishingiz kerak:

npm install benchmark

Node.js inspektori

Node.js’da Chrome DevTools orqali foydalanish mumkin bo‘lgan integratsiyalangan tuzatuvchi va profil yaratuvchi mavjud:

# Start an application with the inspector
node --inspect app.js

# Start and immediately break (for debugging)
node --inspect-brk app.js

Node.js ilovangiz uchun DevTools-ga kirish uchun Chrome brauzerini oching va chrome://inspect ga o‘ting. Bu quyidagilarga kirish imkonini beradi:

  • CPU profili
  • Xotira to‘plamining suratlari
  • Xotirani ajratish xronologiyasi
  • Nosozliklarni tuzatuvchi

Clinic.js to‘plami

Clinic.js - bu Node.js ilovalarida ishlash muammolarini tashxislash uchun vositalar to‘plami:

# Install the Clinic.js suite
npm install -g clinic

# Use Doctor to identify issues
clinic doctor -- node app.js

# Use Flame to generate CPU flame graphs
clinic flame -- node app.js

# Use Bubbleprof for async operations analysis
clinic bubbleprof -- node app.js

Amaliy samaradorlik diagnostikasi

1-qadam: Asosiy ko‘rsatkichlarni o‘rnating

Optimallashtirishdan oldin ilovangiz uchun asosiy ko‘rsatkichlarni belgilang:

const autocannon = require('autocannon');
const { writeFileSync } = require('fs');

// Run a benchmark against your application
const result = autocannon({
  url: 'http://localhost:8080',
  connections: 100,
  duration: 10
});

// Save the results
result.on('done', (results) => {
  console.log('Baseline performance metrics:');
  console.log(` Requests/sec: ${results.requests.average}`);
  console.log(` Latency: ${results.latency.average}ms`);

  writeFileSync('baseline-metrics.json', JSON.stringify(results, null, 2));
});

2-qadam: To‘siqlarni aniqlang

To‘siqlarni aniqlash uchun profildan foydalaning:

  1. Hisoblash intensiv operatsiyalari uchun CPU profilini yaratish
  2. Xotiraning oqishi uchun xotira suratlari
  3. Chaqiruvlar stekini (call stack) tahlil qilish uchun flame grafiklar (flame graphs)
  4. Kirish-chiqarish va callback funksiyasi qilish kechikishlari uchun hodisa sikli monitoringi

3-qadam: Tuzatish va tasdiqlash

Optimallashtirishni qo‘llaganingizdan so‘ng, asosiy ko‘rsatkichga nisbatan yaxshilanishlarni tekshiring.


Umumiy ishlash muammolari va yechimlari

1. Xotiraning oqishi

Belgilari: Vaqt o‘tishi bilan xotiradan foydalanishni oshirish, bu plato emas.

Yechimlar:

  • Vaqti-vaqti bilan yig‘ilgan suratlarni oling va solishtiring
  • Global o‘zgaruvchilar, voqea tinglovchilari va havolalarni saqlaydigan yopishlarni tekshiring
  • Obyektlar endi kerak bo‘lmaganda, to‘g‘ri tozalashni amalga oshiring

2. Uzoq muddatli operatsiyalar

Belgilari: yuqori hodisa loop kechikishi, mos kelmaydigan javob vaqtlari.

Yechimlar:

  • Protsessor talab qiladigan ishni ishchi iplarga o‘tkazing
  • setImmediate/process.nextTick yordamida uzun vazifalarni kichikroq bo‘laklarga bo‘ling
  • Maxsus xizmatlarga tushirishni o‘ylab ko‘ring

3. Ma’lumotlar bazasiga samarasiz so‘rovlar

Belgilari: sekin javob vaqtlari, yuqori kechikish.

Yechimlar:

  • Profil ma’lumotlar bazasi operatsiyalari
  • To‘g‘ri indekslash bilan so‘rovlarni optimallashtiring
  • Ulanish birlashmasidan foydalaning
  • Tez-tez foydalaniladigan ma’lumotlar uchun keshlashni amalga oshiring


W3Schools Pathfinder

Yutuqlaringizni kuzating – bu bepul!