🎯 Giriş
Node.js tek iş parçacıklı bir mimariye sahiptir. Bu yapı, I/O odaklı işlemler için mükemmel olsa da CPU yoğun görevler Event Loop’u bloke eder ve tüm uygulamanın yanıt verme süresini düşürür.
Bu rehberde, Node.js’in worker_threads yapısını kullanarak CPU yoğun işleri ana iş parçacığından ayırmayı, iş yüklerini gerçek paralellik ile çalıştırmayı ve üretimde kullanılan işçi havuzlarını, kaynak limitlerini ve güvenlik uygulamalarını öğreneceksiniz.
📘 Bu Rehberde Ne Öğreneceksiniz?
- worker_threads modülünün mantığı
- CPU yoğun görevleri ana iş parçacığından ayırma
- Tekil worker kullanımı
- Piscina ile Worker Pool kurma
- Kaynak limitleri: bellek, timeout, stack
- Görev kuyruğu & performans izleme (Prometheus)
- Üretim ortamında güvenli multithreading
1. Node.js Çoklu İş Parçacığı Mantığını Anlamak
Node.js'te iki çalışma modeli vardır:
| Yapı | Açıklama |
|---|---|
| Event Loop | I/O işlerini yönetir. Tek iş parçacıklıdır. |
| Worker Threads | CPU yoğun işleri paralel yürütmek için ek iş parçacıklarıdır. |
Worker Thread’ler şunları sağlar:
- Ana iş parçacığından bağımsız çalışma
- Kendi Event Loop’larına sahip olma
postMessageile veri aktarımı- SharedArrayBuffer ile paylaşımlı bellek
✔ Bu sayede CPU yoğun işler sunucuyu dondurmaz.
2. Proje Kurulumu
Dizin oluşturma
mkdir rabisu-worker-demo
cd rabisu-worker-demo
npm init -y
ES Modules aktif etme
npm pkg set type=module
Gerekli paketler
npm install express piscina poolifier p-queue prom-client
3. İşçi (Worker) Dosyası Oluşturma
// worker.js
import { parentPort, workerData } from 'node:worker_threads';
import { createHash } from 'node:crypto';
function hashBuffer(payload) {
const hash = createHash('sha256');
hash.update(payload, 'utf8');
return hash.digest('hex');
}
try {
const result = hashBuffer(workerData.payload);
parentPort.postMessage({ status: 'ok', result });
} catch (error) {
parentPort.postMessage({ status: 'error', message: error.message });
}
✔ Bu worker, CPU yoğun SHA-256 hash işlemi yapar.
✔ Sonucu ana iş parçacığına gönderir.
4. Tek İşçi ile Görev Çalıştırma (Klasik Yöntem)
// index.js
import express from 'express';
import { Worker } from 'node:worker_threads';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const workerPath = join(__dirname, 'worker.js');
const app = express();
app.use(express.json({ limit: '1mb' }));
function runWorker(workerData) {
return new Promise((resolve, reject) => {
const worker = new Worker(workerPath, {
workerData,
resourceLimits: { maxOldGenerationSizeMb: 64, stackSizeMb: 4 }
});
const timeout = setTimeout(() => {
worker.terminate();
reject(new Error('İşçi zaman aşımı (10s)'));
}, 10_000);
worker.once('message', msg => {
clearTimeout(timeout);
worker.terminate();
msg.status === 'ok' ? resolve(msg.result) : reject(msg.message);
});
worker.once('error', err => reject(err));
});
}
app.post('/api/hash-tekil', async (req, res) => {
const hash = await runWorker({ payload: req.body.text });
res.json({ hash });
});
app.listen(3000, () => console.log('Sunucu çalıştı')); ✔ Her istek için yeni worker oluşturulur → maliyetlidir. ✔ Yüksek trafiğe GELMEZ.
Bu yüzden Worker Pool gerekir.
5. Worker Pool (Piscina) ile Yüksek Performans
import Piscina from 'piscina';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export const piscina = new Piscina({
filename: resolve(__dirname, 'worker.js'),
minThreads: 2,
maxThreads: Math.max(4, Piscina.availableParallelism()),
idleTimeout: 30000,
resourceLimits: { maxOldGenerationSizeMb: 80 }
});
export async function hashWithPool(payload) {
const result = await piscina.run({ payload });
return result.result;
}
✔ İşçiler oluşturulup saklanır ✔ İşler boş işçilere dağıtılır ✔ Queue sistemi performansı artırır
6. Pool’u API’ye entegre etme
import express from 'express';
import { hashWithPool } from './pool.js';
const app = express();
app.use(express.json());
app.post('/api/pool/hash', async (req, res) => {
const hash = await hashWithPool(req.body.text);
res.json({ hash });
});
app.listen(3000, () => console.log('Pool aktif'));
7. Kaynak Limitleri ve Güvenlik
Worker oluştururken:
resourceLimits: {
maxOldGenerationSizeMb: 64,
maxYoungGenerationSizeMb: 16,
stackSizeMb: 4
}
✔ Bellek taşmasını engeller ✔ Sonsuz döngü riskini azaltır ✔ Sunucunun çökmesini önler
Payload doğrulaması:
if (req.body.text.length > 1_000_000) {
return res.status(400).json({ error: 'Yük çok büyük.' });
}
8. Üretim Ortamı İzleme (Prometheus)
import client from 'prom-client';
export function createMetricsRegistry(piscina) {
const register = new client.Registry();
client.collectDefaultMetrics({ register });
const queueGauge = new client.Gauge({
name: 'worker_queue_size',
help: 'Kuyrukta bekleyen iş sayısı'
});
register.registerMetric(queueGauge);
setInterval(() => {
queueGauge.set(piscina.queueSize);
}, 5000).unref();
return register;
}
9. /metrics endpoint
import { createMetricsRegistry } from './metrics.js';
import { piscina } from './pool.js';
const register = createMetricsRegistry(piscina);
app.get('/metrics', async (req, res) => {
res.set('Content-Type', register.contentType);
res.end(await register.metrics());
});
✔ Grafana & Prometheus ile tam izleme yapılabilir. ✔ Worker kuyruk yoğunluğu takip edilir.
10. SSS – Sıkça Sorulan Sorular
- Node.js neden CPU yoğun işleri kaldıramıyor?
Event Loop tek iş parçacıklıdır → CPU yoğun iş tüm sistemi dondurur.
- Worker Thread’ler neden daha iyi?
Ayrı bir event loop ve ayrı bir JS bağlamına sahiptir.
- Worker Pool kullanmak zorunlu mu?
Trafik yoğunsa EVET.
- cluster ile worker_threads farkı?
cluster → process bazlı
worker_threads → thread bazlı
✔ Sonuç
Bu rehberle:
CPU yoğun işlemleri ana iş parçacığından ayırdın
Worker Thread’leri öğrendin
Piscina ile yüksek performanslı havuz kurdun
Kaynak limiti ve güvenlik tekniklerini uyguladın
Prometheus ile üretim takibi ekledin
Node.js uygulaman artık gerçek paralelliğe geçti. Bu mimariyi Rabisu Bulut üzerinde çok çekirdekli sunucularda deneyerek maksimum performans elde edebilirsin. 🚀🔥