از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
راه اندازی Node.js Cluster همه می دانیم که Node.js در مدیریت ناهمزمان بسیاری از رویدادها عالی است، اما چیزی که بسیاری از مردم نمی دانند این است که همه این کارها انجام شده است. روی یک رشته Node.js در واقع چند رشته ای نیست، بنابراین همه این درخواست ها فقط در این رویداد رسیدگی می شوند…
سرفصلهای مطلب
همه ما می دانیم که Node.js در مدیریت بسیاری از رویدادها به صورت ناهمزمان عالی است، اما چه تعداد زیادی از مردم نکن بدانید که همه اینها انجام شده است روی یک رشته Node.js در واقع چند رشته ای نیست، بنابراین همه این درخواست ها فقط در حلقه رویداد یک رشته مدیریت می شوند.
پس چرا با استفاده از کلاستر Node.js از پردازنده چهار هسته ای خود بیشترین بهره را نبرید؟ با این کار چندین نمونه از کد شما برای رسیدگی به درخواست های بیشتر راه اندازی می شود. این ممکن است کمی دشوار به نظر برسد، اما در واقع انجام آن با آن بسیار آسان است خوشه ماژول که در Node.js v0.8 معرفی شد.
بدیهی است که این برای هر برنامه ای که می تواند کار را بین فرآیندهای مختلف تقسیم کند مفید است، اما به ویژه برای برنامه هایی که بسیاری از درخواست های IO را مدیریت می کنند، مانند یک وب سایت، مهم است.
متاسفانه، به دلیل پیچیدگی های پردازش موازی، خوشه بندی یک برنامه روی یک سرور همیشه ساده نیست. وقتی برای گوش دادن به چندین فرآیند نیاز دارید چه کار می کنید؟ روی همان پورت؟ به یاد بیاورید که تنها یکی process می تواند در هر زمان به یک پورت دسترسی داشته باشد. راه حل ساده در اینجا پیکربندی هر یک است process برای گوش دادن روی یک پورت دیگر و سپس Nginx را راه اندازی کنید تعادل بار درخواست های بین پورت ها
این یک راه حل قابل اجرا است، اما برای راه اندازی و پیکربندی هر کدام به کار بسیار بیشتری نیاز دارد processو نه به پیکربندی Nginx اشاره کنیم. با این راه حل شما فقط چیزهای بیشتری را برای مدیریت خود به خود اضافه می کنید.
در عوض، می توانید استاد را چنگال کنید process در چندین پردازش فرزند (معمولا داشتن یک فرزند در هر پردازنده). در این صورت بچه ها هستند اجازه به اشتراک گذاری پورت با والدین (به لطف بینprocess ارتباط، یا IPC، بنابراین نیازی به نگرانی در مورد مدیریت چندین پورت نیست.
این دقیقا همان چیزی است که cluster
ماژول برای شما انجام می دهد.
کار با The Cluster Module
خوشه بندی یک برنامه بسیار ساده است، به خصوص برای کدهای وب سرور مانند بیان پروژه ها. تنها کاری که واقعا باید انجام دهید این است:
var cluster = require('cluster');
var express = require('express');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
// Create a worker
cluster.fork();
}
} else {
// Workers share the TCP connection in this server
var app = express();
app.get('/', function (req, res) {
res.send('Hello World!');
});
// All workers use this port
app.listen(8080);
}
عملکرد کد به دو بخش اصلی کد و کد کارگر تقسیم می شود. این در بیانیه if انجام می شود (if (cluster.isMaster) {...}
). تنها هدف استاد در اینجا ایجاد همه کارگران است (تعداد کارگران ایجاد شده بر اساس آن است روی تعداد CPU های موجود)، و کارگران مسئول اجرای نمونه های جداگانه سرور Express هستند.
هنگامی که یک کارگر از برق اصلی جدا می شود process، کد را از ابتدای ماژول دوباره اجرا می کند. وقتی کارگر به حالت if می رسد، برمی گردد false
برای cluster.isMaster
، بنابراین در عوض برنامه Express، یک مسیر را ایجاد می کند و سپس گوش می دهد روی بندر 8080
. در مورد پردازندههای چهار هستهای، ما چهار کارگر تولید میکنیم که همگی گوش میکنند روی همان پورت برای ورود درخواست ها
اما چگونه درخواست ها بین کارگران تقسیم می شود؟ بدیهی است که آنها نمی توانند (و نباید) همه به تک تک درخواست هایی که ما دریافت می کنیم گوش دهند و پاسخ دهند. برای انجام این کار، در واقع یک بار متعادل کننده تعبیه شده در داخل وجود دارد cluster
ماژولی که به توزیع درخواست ها بین کارگران مختلف رسیدگی می کند. در لینوکس و OSX (اما نه ویندوز) دور روبین (cluster.SCHED_RR
) خط مشی به طور پیش فرض در حال اجرا است. تنها گزینه زمانبندی موجود دیگر واگذاری آن به سیستم عامل است (cluster.SCHED_NONE
) که پیش فرض است روی پنجره ها.
خط مشی زمانبندی را می توان در یکی از این دو تنظیم کرد cluster.schedulingPolicy
یا با تنظیم آن روی متغیر محیطی NODE_CLUSTER_SCHED_POLICY
(با مقادیر ‘rr’ یا ‘none’).
همچنین ممکن است تعجب کنید که چگونه فرآیندهای مختلف می توانند یک پورت واحد را به اشتراک بگذارند. بخش دشوار اجرای بسیاری از فرآیندهایی که درخواست های شبکه را رسیدگی می کنند این است که به طور سنتی فقط یک پورت می تواند یک پورت را به طور همزمان باز کند. فایده بزرگ از cluster
این است که به اشتراک گذاری پورت را برای شما مدیریت می کند، بنابراین هر درگاهی که باز کنید، مانند یک وب سرور، برای همه کودکان قابل دسترسی خواهد بود. این کار از طریق IPC انجام می شود، به این معنی که استاد فقط دسته پورت را برای هر کارگر ارسال می کند.
به لطف ویژگی هایی مانند این، خوشه بندی بسیار آسان است.
()cluster.fork در مقابل child_process.fork()
اگر تجربه قبلی با child_process
‘s fork()
پس ممکن است به این فکر کنید cluster.fork()
تا حدودی شبیه است (و از بسیاری جهات مشابه هستند)، بنابراین ما در این بخش برخی از تفاوت های کلیدی را در مورد این دو روش فورک توضیح خواهیم داد.
چند تفاوت اصلی بین آنها وجود دارد cluster.fork()
و child_process.fork()
. این child_process.fork()
متد کمی سطح پایینتر است و از شما میخواهد مکان (مسیر فایل) ماژول را بهعنوان آرگومان ارسال کنید، به علاوه آرگومانهای اختیاری دیگر مانند دایرکتوری فعلی، کاربر مالک process، متغیرهای محیطی و موارد دیگر.
تفاوت دیگر این است که cluster
اجرای کارگر را از ابتدای همان ماژولی که از آن اجرا شد شروع می کند. بنابراین اگر نقطه ورود برنامه شما باشد index.js
، اما کارگر در آن تخم ریزی می شود cluster-my-app.js
، سپس اجرای خود را از ابتدا در ساعت آغاز خواهد کرد index.js
. child_process
از این جهت متفاوت است که در هر فایلی که به آن ارسال می شود، اجرا را ایجاد می کند، و نه لزوماً نقطه ورود برنامه داده شده.
شاید قبلا حدس زده باشید که cluster
ماژول در واقع از child_process
ماژول زیر برای ایجاد کودکان، که با انجام می شود child_process
مال خود است fork()
روش، به آنها اجازه می دهد تا از طریق IPC ارتباط برقرار کنند، به این ترتیب دسته های پورت بین کارگران به اشتراک گذاشته می شود.
برای روشن بودن، فورکینگ در Node با a بسیار متفاوت است چنگال POISIX از این نظر که در واقع جریان را شبیه سازی نمی کند process، اما یک نمونه V8 جدید راه اندازی می کند.
اگرچه این یکی از ساده ترین راه های چند رشته ای است، اما باید با احتیاط از آن استفاده کرد. فقط به این دلیل که شما قادر به تولید 1000 کارگر هستید به این معنی نیست که باید این کار را انجام دهید. هر کارگری منابع سیستم را اشغال می کند، بنابراین فقط منابعی را که واقعاً مورد نیاز هستند تولید کنید. اسناد Node بیان می کنند که از هر کودک process یک نمونه جدید V8 است، باید انتظار زمان راه اندازی 30 میلی ثانیه برای هر نمونه و حداقل 10 مگابایت حافظه در هر نمونه داشته باشید.
رسیدگی به خطا
پس وقتی یک (یا چند نفر!) از کارگران شما می میرند، چه می کنید؟ اگر نتوانید کارگران را پس از خرابی مجدد راه اندازی کنید، اساساً کل نکته خوشه بندی از بین می رود. خوش شانس برای شما cluster
ماژول گسترش می یابد EventEmitter
و یک رویداد “خروج” را ارائه می دهد، که به شما می گوید زمانی که یکی از فرزندان کارگر شما می میرد.
می توانید از این برای ثبت رویداد و راه اندازی مجدد آن استفاده کنید process:
cluster.روی('exit', function(worker, code, signal) {
console.log('Worker %d died with code/signal %s. Restarting worker...', worker.process.pid, signal || code);
cluster.fork();
});
اکنون، پس از تنها 4 خط کد، مانند این است که شما داخلی خود را دارید process مدیر!
مقایسه عملکرد
خوب، حالا به بخش جالب می پردازیم. بیایید ببینیم که خوشه بندی در واقع چقدر به ما کمک می کند.
برای این آزمایش، یک برنامه وب شبیه به کد مثالی که در بالا نشان دادم راه اندازی کردم. اما بزرگترین تفاوت این است که ما کار انجام شده در مسیر Express را با استفاده از آن شبیه سازی می کنیم خواب ماژول و با برگرداندن دسته ای از داده های تصادفی به کاربر.
در اینجا همان برنامه وب است، اما با خوشه بندی:
var cluster = require('cluster');
var crypto = require('crypto');
var express = require('express');
var sleep = require('sleep');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
// Create a worker
cluster.fork();
}
} else {
// Workers share the TCP connection in this server
var app = express();
app.get('/', function (req, res) {
// Simulate route processing delay
var randSleep = Math.round(10000 + (Math.random() * 10000));
sleep.usleep(randSleep);
var numChars = Math.round(5000 + (Math.random() * 5000));
var randChars = crypto.randomBytes(numChars).toString('hex');
res.send(randChars);
});
// All workers use this port
app.listen(8080);
}
و در اینجا کد “کنترل” وجود دارد که ما مقایسه های خود را از آن انجام خواهیم داد. اساساً دقیقاً همان چیزی است، فقط بدون cluster.fork()
:
var crypto = require('crypto');
var express = require('express');
var sleep = require('sleep');
var app = express();
app.get('/', function (req, res) {
// Simulate route processing delay
var randSleep = Math.round(10000 + (Math.random() * 10000));
sleep.usleep(randSleep);
var numChars = Math.round(5000 + (Math.random() * 5000));
var randChars = crypto.randomBytes(numChars).toString('hex');
res.send(randChars);
});
app.listen(8080);
برای شبیه سازی بار سنگین کاربر، از یک ابزار خط فرمان به نام استفاده می کنیم محاصره، که می توانیم از آن برای ایجاد یک دسته درخواست همزمان به URL مورد نظر خود استفاده کنیم.
Siege همچنین از این نظر خوب است که معیارهای عملکرد، مانند در دسترس بودن، توان عملیاتی، و نرخ رسیدگی به درخواستها را ردیابی میکند.
در اینجا دستور Siege است که برای آزمایش ها استفاده خواهیم کرد:
$ siege -c100 -t60s http://localhost:8080/
پس از اجرای این دستور برای هر دو نسخه برنامه، در اینجا برخی از نتایج جالب تر آورده شده است:
تایپ کنید | کل درخواست ها رسیدگی شد | درخواست ها / دوم | میانگین زمان پاسخگویی | توان عملیاتی |
---|---|---|---|---|
بدون خوشه بندی | 3467 | 58.69 | 1.18 ثانیه | 0.84 مگابایت بر ثانیه |
خوشه بندی (4 فرآیند) | 11146 | 188.72 | 0.03 ثانیه | 2.70 مگابایت بر ثانیه |
همانطور که می بینید، برنامه خوشه ای تقریباً 3.2 برابر بهبود یافته است.process برنامه تقریباً برای تمام معیارهای ذکر شده، به جز میانگین زمان پاسخگویی، که پیشرفت بسیار چشمگیری دارد.
منتشر شده در 1403-01-29 04:22:04