در دنیای همیشه در حال توسعه مهندسی نرم افزار، عملکرد عامل اصلی است که بر انتخاب فناوری شما تأثیر می گذارد. Laravel Octane و Node.js دو فناوری محبوبی هستند که توسط شرکتهای بزرگ مورد استفاده قرار میگیرند که راهحلهایی با کارایی بالا برای ساخت برنامههای وب ارائه میکنند.
در این مقاله سرورهای مختلف HTTP را با استفاده از Swoole، Open Swoole، RoadRunner، Node.js، AdonisJS و Laravel خواهیم ساخت. سپس تجزیه و تحلیل تست بار آنها را انجام می دهیم و مقایسه می کنیم تا بینش بهتری در مورد عملکرد آنها به دست آوریم.
Node.js در مقابل اکتان لاراول
Node.js یک محیط زمان اجرا جاوا اسکریپت بر اساس موتور V8 گوگل کروم است که برای اجرای کد جاوا اسکریپت در خارج از یک مرورگر وب طراحی شده است. این در یک حلقه رویداد تک رشته ای با استفاده از I/O غیر مسدود کننده عمل می کند، که هدف آن بهینه سازی توان عملیاتی و مقیاس پذیری در برنامه های وب با بسیاری از عملیات I/O، ویژگی های real-time و موارد دیگر است.
برخی از موارد استفاده Node.js عبارتند از:
برنامه های real-time
برنامه های کاربردی مقیاس پذیر
همزمانی بالا
میکروسرویس ها
سرورهای پروکسی و پروکسی های معکوس
Octane یک پکیج لاراول است که در لاراول 8 معرفی شده است و هدف آن بهبود عملکرد برنامه های لاراول است. Octane با استفاده از یکی از پسوندهای زیر به این امر دست می یابد:
Swoole: یک برنامه افزودنی کتابخانه جامعه PHP که در C/C++ نوشته شده است که با کارایی بالا، رویداد محور، مقیاس پذیر، TCP، UDP، سوکت یونیکس، HTTP، خدمات WebSocket با PHP و برنامه های کاربردی آسان، Fibers API و سیستم شبکه ناهمزمان برای بهبود برنامه های PHP.
Open Swoole: یک فورک fork از Swoole که در نتیجه مسائل مربوط به تصمیم گیری در میان maintainers core وجود دارد. از gRPC، Websocket، MQTT و غیره پشتیبانی می کند.
RoadRunner: این پکیج Composer از یک سرور Go به عنوان متعادل کننده بار استفاده می کند و برنامه های PHP را قادر می سازد تا به عنوان فرآیندهای worker جداگانه اجرا شوند. از HTTP، ادغام ها، gRPC، TCP، متریک ها، مشاغل و غیره پشتیبانی می کند.
در زمان نگارش، Octane به طور خاص فقط برای فریم ورک لاراول طراحی شده است، اما افزونه ها می توانند مستقیماً در سایر برنامه های PHP نیز استفاده شوند.
برخی از موارد استفاده از اکتان عبارتند از:
برنامه های کاربردی مقیاس پذیر
برنامه های real-time
برنامه های دولتی
برنامه های وب سنتی
میکروسرویس ها
ویژگی های Node.js و Octane
ویژگی ها | Node.js | Octane |
پشتیبانی Async | Node.js پشتیبانی بومی برای عملیات ناهمزمان دارد | اکتان از برنامه های افزودنی خود برای عملیات ناهمزمان استفاده می کند |
پشتیبانی از gRPC | Node.js برای پیاده سازی gRPC به یک پکیج خارجی نیاز دارد | Octane دارای پشتیبانی داخلی برای gRPC از طریق Open Swoole است |
وب سوکت | Node.js دارای پشتیبانی داخلی برای برنامه نویسی سوکت است | Octane دارای پشتیبانی داخلی برای سوکت های با استفاده از Swoole است |
رویداد محور | Node.js از یک حلقه رویداد برای مدیریت همزمانی استفاده می کند | Octane عملیات همزمان را با استفاده از برنامه های PHP انجام می دهد |
TCP & UDP | Node.js دارای پشتیبانی داخلی از TCP و UDP است | Octane همچنین از TCP و UDP از طریق Swoole و RoadRunner پشتیبانی می کند |
بنجمارک Node.js و Octane
مقایسه یک چارچوب وب کامل مانند لاراول با Node.js ممکن است ایدهآلترین رویکرد برای تجزیه و تحلیل عملکرد نباشد، اما ما تلاش میکنیم تا بر اساس یک سری شاخص زمان اجرا هر زبان (PHP و Node.js) در حالت خام، بدون خروجی تمرکز کنیم. کتابخانه ها، برای به دست آوردن بینش معنادار با انجام این کار، هدف ما این است که درک عمیق تری از ویژگی های عملکرد اساسی آنها به دست آوریم.
علاوه بر این، ما تجزیه و تحلیل عملکرد بین Laravel Octane و AdonisJS را بررسی خواهیم کرد، که هر دو چارچوبهای به همان اندازه قوی هستند تا نقاط قوت و ضعف فردی آنها را بهتر درک کنیم.
معیارهای شاخص
برای ارزیابی عملکرد، ما بر روی جنبه های زیر تمرکز خواهیم کرد:
ارزیابی تأخیر: ما تأخیر هر سرور HTTP را با یک پاسخ ساده از سرور ارزیابی خواهیم کرد.
اندازهگیری تأخیر با سرویسهای خارجی: ما تأخیر هر سرور HTTP را هنگام فراخوانی یک سرویس خارجی ارزیابی میکنیم.
نصب Open Swoole
ما می توانیم Open Swoole را با استفاده از PECL یا Docker نصب کنیم. قبل از نصب، مطمئن شوید که PHP از قبل نصب شده باشد، ترجیحا نسخه 7.4 یا بالاتر. برای ادامه نصب، دستورات زیر را اجرا کنید:
pecl install openswoole
در صورتی که قبلاً روی سیستم شما نصب نشده باشد، ممکن است با خطای مواجه شوید.
برای رفع خطا، ممکن است نیاز باشد پکیج OpenSSL را با دستور زیر نصب کنید:
pecl install openssl
اگر همه چیز به خوبی پیش رفت، فرآیند نصب شامل ساخت extension از کد منبع و سپس اضافه کردن آن به فایل php.ini است.
ایجاد ساختار پروژه
بیایید یک پوشه پروژه به نام laravel-vs-octane
ایجاد کنیم تا همه کد منبع و فایل های پروژه ما را در خود جای دهد. این به سازماندهی و مدیریت موثر فرآیند توسعه کمک می کند. در اینجا نمونه ای از ساختار پوشه ما آمده است.
laravel-vs-octane /
adonisjs /
loadtest.yml
...
laravel-octane /
loadtest.octane.yml
...
nodejs /
loadtest.nodejs.yml
...
openswoole /
loadtest.open-swoole.yml
...
roadrunner /
loadtest.roadrunner.yml
...
swoole/
loadtest.swoole.yml
...
نصب سرور Open Swoole HTTP
برای افزایش سازماندهی، اجازه دهید پوشه ای به نام openswoole
در داخل پوشه پدر laravel-vs-octane
ایجاد کنیم. در پوشه openswoole
، یک فایل PHP برای گروه بندی هر سرور در کنار پیکربندی تست بارگذاری آن اضافه کنید. اکنون، بیایید کد زیر را برای ایجاد سرور Open Swoole HTTP
خود اضافه کنیم:
<?php
$server = new OpenSwoole\HTTP\Server("127.0.0.1", 9000);
$server->on("start", function (OpenSwoole\Http\Server $server) {
echo "OpenSwoole http server is started at http://127.0.0.1:9000\n";
});
$server->on("request", function (OpenSwoole\Http\Request $request, OpenSwoole\Http\Response $response) {
$response->header("Content-Type", "text/plain");
$response->end("Hello World\n");
});
$server->start();
نصب Swoole
نصب Swoole شبیه Open Swoole است، زیرا Open Swoole یک فورک از Swoole است. با این حال، یک تفاوت وجود دارد و آن دستور نصب است:
pecl install swoole
نصب سرور Swoole HTTP
برای حفظ رویکرد مشابهی که برای پوشه openswoole
در نظر گرفتیم، اجازه دهید پوشه دیگری به نام swoole
در داخل پوشه والد laravel-vs-octane
ایجاد کنیم. این پوشه حاوی یک فایل PHP برای راه اندازی سرور Swoole HTTP ما خواهد بود:
$http = new Swoole\Http\Server('127.0.0.1', 9501);
$http->on('start', function ($server) {
echo "Swoole http server is started at http://127.0.0.1:9501\n";
});
$http->on('request', function ($request, $response) {
$response->header('Content-Type', 'text/plain');
$response->end('Hello World');
});
$http->start();
برای اجرای هر دو سرور Open Swoole و Swoole، CLI یا ترمینال خود را باز کنید و دستورات زیر را همانطور که در زیر نشان داده شده است، اجرا کنید تا سرورها راه اندازی شوند:
php swoole-server.php
Swoole http server is started at http://127.0.0.1:9501
در اینجا پیش نمایشی از کار ما تا کنون آمده است:
curl -i http://localhost: 9501
HTTP /1.1 200 OK
Content-Type: text/plain
Server: swoole-http-server
Date: Wed, 26 Jul 2023 23:26:11 GMT
Connection: keep-alive
Content-Length: 11
Hello World
راه اندازی سرور HTTP RoadRunner
برای راه اندازی سرور RoadRunner، ساختار پوشه را با ایجاد یک پوشه اختصاصی برای آن لحاظ می کنیم، همانطور که برای Swoole و Open Swoole انجام دادیم. در داخل این پوشه، پکیج های مورد نیاز را با استفاده از Composer نصب می کنیم:
composer require spiral/roadrunner-cli --dev
composer require spiral/roadrunner
composer require spiral/roadrunner-http
این کار باید بعد از نصب پکیج های دیگر انجام شود.
RoadRunner یک پردازنده متمرکز برای برنامه های PHP است که از پلاگین های مختلفی مانند HTTP، gRPC، jobs، مانیتورینگ و میکروسرویس ها استفاده می کند. با استفاده از پروتکل هایی مانند FastCGI یا PSR-7 HTTP با وب سرور Go ارتباط برقرار می کند و آن را جایگزین مناسبی برای PHP-FPM می کند. فایل پیکربندی می تواند در فرمت YAML یا JSON با نام rr.yaml.
یا rr.json.
باشد.
در زیر نمونه ای از فایل پیکربندی ما با استفاده از افزونه HTTP آمده است:
version: '3'
server:
command: 'php app.php'
relay: pipes
http:
address: '0.0.0.0:8000'
در اینجا ورکر PHP است که از طریق PSR-7 HTTP با سرور وب ارتباط برقرار می کند:
<?php
require __DIR__ . '/vendor/autoload.php';
use Nyholm\Psr7\Response;
use Nyholm\Psr7\Factory\Psr17Factory;
use Spiral\RoadRunner\Worker;
use Spiral\RoadRunner\Http\PSR7Worker;
$worker = Worker::create();
$factory = new Psr17Factory();
$psr7 = new PSR7Worker($worker, $factory, $factory, $factory);
while (true) {
try {
$request = $psr7->waitRequest();
} catch (\Throwable $e) {
$psr7->respond(new Response(400));
continue;
}
try {
$psr7->respond(new Response(200, [], 'Hello RoadRunner!'));
} catch (\Throwable $e) {
$psr7->respond(new Response(500, [], 'Something Went Wrong!'));
$psr7->getWorker()->error((string)$e);
}
}
برای راه اندازی سرور از دستور زیر استفاده می کنیم:
./rr serve
اگر همه چیز به درستی تنظیم شده باشد، باید چیزی شبیه به این را ببینید:
> ./rr serve
2023-07-29T13:12:50÷0000
DEBUG server
worker is allocated {"pid": 8328, "inter
nal event name": "EventworkerConstruct!)
2023-07-29113:12:50+0000
DEBUG server
worker is allocated
nal event name"; "EventworkerConstruct"}
{"pid": 8320, "inter
2023-07-2913:12:50+0000
DEBUG server
worker is allocated
nal event name"; "EventworkerConstruct"}
{"pid": 8325, "inter
[INFO] RoadRunner server started; version: 2023.2.1, buildtime: 2023-07-2717:12:33+0000
2023-07-29T13:12:50+0000
DEBUG http
http server was started {"address": "0.0.0.0"}
پیکربندی سرور Node.js
ما سرور Node.js خود را به روشی مشابه با روش قبلی سازماندهی می کنیم. ما یک پوشه خاص به نام nodejs
ایجاد می کنیم و سپس کد سرور را در فایلی به نام server.js
قرار می دهیم.
سرور شامل دو نقطه پایانی است که در آنها /
داده بعداً توسط Laravel Octane و AdonisJS یکپارچه می شود:
const http = require('http');
const hostname = 'localhost';
const port = 3000;
const server = http.createServer((req, res) => {
console.log(`[${new Date().toISOString()}] Incoming request: ${req.method} ${req.url}`);
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET');
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
// Set the response header
if (req.url === '/' && req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello nodejs!');
} else if(req.url === '/data' && req.method === 'GET') {
const data = { message: 'Hello, this is your data!' };
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(data));
}else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found');
}
});
// Log when the server starts listening
server.on('listening', () => {
console.log(`[${new Date().toISOString()}] Server is listening on http://${hostname}:${port}/`);
});
// Log any server errors
server.on('error', (error) => {
console.error(`[${new Date().toISOString()}] Server error: ${error.message}`);
});
server.listen(port, hostname);
نصب AdonisJS
برای نصب AdonisJS در پوشه والد، لطفاً مطمئن شوید که Node.js را نصب کرده اید. سپس، رابط خط فرمان (CLI) یا ترمینال خود را باز کنید و دستور زیر را اجرا کنید:
npm init adonis-ts-app@latest adonisjs-api
دستورالعمل های ارائه شده توسط دستور را دنبال کنید و مطمئن شوید که api را به عنوان نوع برنامه انتخاب کنید. این یک پروژه AdonisJS با تنظیمات لازم برای ساخت یک API ایجاد می کند.
فایل routes.ts
را باز کنید و کد زیر را برای بازیابی رکوردها از سرویس Node.js اضافه کنید:
Route.get('/external-service', async () => {
try {
const url = 'http://localhost:3000/data'
const result = await axios.get(url)
return result
} catch (error) {
return {error: `Error fetching data from the external endpoint: ${error.message}`};
}
})
سپس سرور را با استفاده از:
node ace serve --watch
اضافه کردن لاراول اکتان به پروژه Swoole ما
برای ادغام Laravel Octane در همان پوشه والد پروژه Laravel شما، از Swoole به عنوان سرور برنامه پیش فرض برای برنامه Laravel شما استفاده می کنیم:
composer create-project laravel/laravel laravel-octane
Laravel Octane را با استفاده از دستور زیر نصب کنید:
composer require laravel/octane
این دستور را اجرا کنید تا فایل پیکربندی Octane را در برنامه ما نصب کنید:
php artisan octane:install
دستورالعمل ها را دنبال کنید و 1 را برای Swoole
انتخاب کنید:
Which application server you would like to use?:
[0] roadrunner
[1] swoole
> 1
فایل web.php
را باز کنید و کد زیر را اضافه کنید تا یک نقطه پایانی Octane ایجاد کنید که دادهها را از سرویس Node.js ما میکشد:
Octane::route('GET', '/external-service', function () {
try {
$client = new GuzzleHttp\Client();
$url = 'http://localhost:3000/data';
$result = $client->get($url);
$resp = $result->getBody()->getContents();
return response()->json(json_decode($resp));
} catch (Exception $e) {
return response()->json(['error' => 'error: '. $e->getMessage()]);
}
});
تجزیه و تحلیل عملکرد تست بار
ما Artillery را برای آزمایش بار خود در نظر خواهیم گرفت. با Artillery، ما می توانیم یک پیکربندی تست بار ایجاد کنیم که می تواند برای همه سرورهای ما استفاده شود. بیایید Artillery را از طریق npm نصب و راه اندازی کنیم:
npm install -g artillery@latest
یک فایل تست بار با نام loadtest.nodejs.yml
ایجاد کنید. این فایل پیکربندی برای تست بارگیری سرور Node.js ما طراحی شده است. می توانید URL سرور را برای آزمایش یا تکرار این پیکربندی برای سرورهای دیگر تغییر دهید. این پیکربندی ده کاربر مجازی یا اتصال را در هر ثانیه مشخص میکند که منجر به تقریباً 600 درخواست میشود. ما تاخیر را برای هر سرور در طول تست بارگذاری اندازه گیری می کنیم:
config:
target: "http://localhost:3000" # Replace this with your server's URL
phases:
- duration: 60
arrivalRate: 10 # Number of virtual users per second during the ramp-up phase
name: "Rampp up phase"
scenarios:
- flow:
- get:
url: "/" # Replace this with the endpoint you want to load test
در اینجا مروری بر تست بارگذاری است:
Node.js (ms) | (Open Swoole (ms | Swoole (ms) | RoadRunner (ms) | Test |
2.2 | 2.5 | 2.4 | 2.3 | Average |
9.7 | 9.7 | 10.3 | 9.3 | P99 |
برای آزمایش Laravel Octane و AdonisJS، ما یک فایل پیکربندی Artillery دیگر در دایرکتوری مربوطه آنها ایجاد می کنیم، با 20 کاربر مجازی یا اتصال در ثانیه:
config:
target: "http://localhost:8000" # Replace with :3333 for AdonisJS
phases:
- duration: 60
arrivalRate: 20 # Number of virtual users per second during the ramp-up phase
name: "Ramp up phase"
scenarios:
- flow:
- get:
url: "/external-service" # Replace this with the endpoint you want to load test
نتایج تست بارگذاری نشان داد که هر دو فریم ورک AdonisJS و Laravel Octane با Swoole قادر به انجام به طور موثر و متوسط 20 درخواست در ثانیه بودند. با این حال، شایان ذکر است که تستهای عملکرد در دنیای واقعی میتوانند سختتر باشند. جالب اینجاست که ما شباهت عملکردی نزدیکی بین آنها مشاهده کردیم.
Test AdonisJS (ms) Laravel Octane with Swoole (ms)
Average 6 6.4
P99 13.9 17.3
نتیجه
در نتیجه، تجزیه و تحلیل مقایسه ای Laravel Octane و Node.js اغلب نشان می دهد که تأثیر عملکرد آنها بر برنامه ما نگرانی اصلی نیست. گلوگاه های اصلی اکثر برنامه ها در سطح پایگاه داده قرار دارند، مانند کارایی کوئری، بهینه سازی، نمایه سازی و تعامل با سرویس های خارجی.