net ๋ชจ๋์ ํ์ฉํด HTTP ์์ฒญ ์ฒ๋ฆฌํ๊ธฐ
1. net ๋ชจ๋ ๊ธฐ๋ฐ HTTP ์๋ฒ ์์ฑ
์ฐ์ ๊ฐ์ฅ ๋จผ์ HTTP ์์ฒญ์ ์ฒ๋ฆฌํ ์น์๋ฒ๋ฅผ ๋ง๋ค์ด์ผํฉ๋๋ค.
net ๋ชจ๋์ ํ์ฉํด ์๋ฒ๋ฅผ ์์ฑํ๊ณ server.listen ์ผ๋ก ์ง์ ๋ PORT ์ ๋ค์ด์ค๋ ์์ฒญ์ listen ํ๋ฉฐ
socket.on ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์์ ํ ์ ์์ต๋๋ค.
import net from 'net';
// ๊ธฐ๋ณธ HTTP ์๋ฒ ์ค์
const PORT = 80;
const HOST = '0.0.0.0';
/**
* net ๋ชจ๋ ๊ธฐ๋ฐ HTTP ์๋ฒ
* Express ๋ฑ ์ธ๋ถ ํ๋ ์์ํฌ ์์ด ์์ net ๋ชจ๋๋ก HTTP ์๋ฒ ๊ตฌํ
*/
const server = net.createServer((socket) => {
console.log('ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ๋จ:', socket.remoteAddress + ':' + socket.remotePort);
// HTTP ์์ฒญ ๋ฐ์ดํฐ ์์
socket.on('data', (data) => {
const request = data.toString();
console.log('์์ ๋ ์์ฒญ:');
console.log(request);
// ๊ธฐ๋ณธ HTTP ์๋ต (์์)
const response = [
'HTTP/1.1 200 OK',
'Content-Type: text/html; charset=utf-8',
'Connection: close',
'',
'<h1>Codestargram Web Server</h1>',
'<p>net ๋ชจ๋ ๊ธฐ๋ฐ HTTP ์๋ฒ๊ฐ ์ ์ ๋์ ์ค์
๋๋ค.</p>'
].join('\r\n');
socket.write(response);
socket.end();
});
// ์ฐ๊ฒฐ ์ข
๋ฃ ์ฒ๋ฆฌ
socket.on('close', () => {
console.log('ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ ์ข
๋ฃ');
});
// ์๋ฌ ์ฒ๋ฆฌ
socket.on('error', (err) => {
console.error('์์ผ ์๋ฌ:', err);
});
});
// ์๋ฒ ์์
server.listen(PORT, HOST, () => {
console.log(`๐ Codestargram Web Server running on http://${HOST}:${PORT}`);
});
// ์๋ฒ ์๋ฌ ์ฒ๋ฆฌ
server.on('error', (err) => {
console.error('์๋ฒ ์๋ฌ:', err);
});
// ํ๋ก์ธ์ค ์ข
๋ฃ ์ ์๋ฒ ์ ๋ฆฌ
process.on('SIGINT', () => {
console.log('\n์๋ฒ๋ฅผ ์ข
๋ฃํฉ๋๋ค...');
server.close(() => {
console.log('์๋ฒ ์ข
๋ฃ ์๋ฃ');
process.exit(0);
});
});
๊ทธ๋ฆฌ๊ณ node server.js ๋ฅผ ํตํด ์ ํ์ผ์ ์คํํฉ๋๋ค.

๊ทธ๋ฌ๋ฉด 80๋ฒ ํฌํธ์์ HTTP ์๋ฒ๊ฐ ์๋ํ๊ฒ ๋ฉ๋๋ค.
์ด ์ํ์์ ํ๋ฒ http://localhost ์ ์ ์ํด๋ณด๊ฒ ์ต๋๋ค.
๊ทธ๋ผ ๋ค์๊ณผ ๊ฐ์ด ํญ์ ์ ์ํ ๋ธ๋ผ์ฐ์ ์ ํ๋ก์ธ์ค ์ฃผ์์ PORT ์ ๋ณด๊ฐ ์ฐํ๊ณ ,
socket.on ์์ ๋ค์ด์จ HTTP ์์ฒญ ๋ฐ์ดํฐ๋ฅผ ํ์ธํด๋ณผ ์ ์์ต๋๋ค.
๋ธ๋ผ์ฐ์ ์ URL ๋ก ์ ์ํ์ ๋ฟ์ธ๋ฐ, ์ด๋ป๊ฒ HTTP GET ์์ฒญ์ด ์์ ๋๋์ง ๋ฌป๋๋ค๋ฉด,
๊ทธ๊ฒ์ด ๋ธ๋ผ์ฐ์ ์ ๊ธฐ๋ณธ ๋์์ด๊ธฐ ๋๋ฌธ์ ๋๋ค. URL ์ ์ ์ํ๋ฉด ํด๋น ์๋ฒ์ 80๋ฒ ํฌํธ๋ก HTTP GET ์์ฒญ์ ๋ณด๋ด๋๋ก ๋์ด์์ต๋๋ค.
// HTTP ์์ฒญ ๋ฐ์ดํฐ ์์
socket.on('data', (data) => {
const request = data.toString();
console.log(request);
}

๊ฐ์ฅ ์ฒซ์ค์ Request line ์ผ๋ก์ method urI ํ๋กํ ์ฝ ๋ฒ์ ์ด ๋ช ์๋ฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๊ทธ ํ์ HTTP ํค๋์๋ ๋ณด๋ธ์ด์ ์ ์, ์์ ์ ํ๊ฒฝ, ์์ฒญ์ ๋ํ ์ ๋ณด๊ฐ ๋ค์ด๊ฐ ์๋ ๊ฒ์ ํ์ธํด๋ณผ ์ ์์ต๋๋ค.
์ฌ๊ธฐ์ ์์ฒญ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ๋์ฌ๊ฒจ๋ด์ผ ํ ํ๋๋ URI ์ Accept ์ ๋๋ค.
์ฌ๊ธฐ์ ์ ๊น, URL ๊ณผ URI ์ ์ฐจ์ด๋ฅผ ์ดํดํ๊ณ ๋์ด๊ฐ ํ์๊ฐ ์์ต๋๋ค.


๐ URI (Uniform Resource Identifier, ํตํฉ ์์ ์๋ณ์)
- ์ ์: ์ธํฐ๋ท ์์ ์ด๋ค “์์(Resource)”์ ์๋ณ(identify) ํ๊ธฐ ์ํ ๋ฌธ์์ด.
- ์ฆ, ์ด ์์์ด ๋ฌด์์ธ์ง ์๋ ค์ฃผ๋ ์๋ณ์.
- URI๋ ๋ ๊ฐ์ง ํ์ ๊ฐ๋
์ผ๋ก ๋๋ ์ ์์:
- URL (Locator) → ์์์ ์์น๋ฅผ ์๋ ค์ค (์ด๋์ ์๋์ง)
- URN (Name) → ์์์ ์ด๋ฆ์ ์๋ ค์ค (์ด๋ค ์ด๋ฆ์ ๊ฐ๋์ง)
๐ URL (Uniform Resource Locator, ํตํฉ ์์ ์์น์)
- ์ ์: URI์ ํ ์ข ๋ฅ๋ก, ์์์ ์์น(location) ๋ฅผ ๊ตฌ์ฒด์ ์ผ๋ก ํํํ ๊ฒ.
- ์ฆ, “์์์ด ์ด๋์ ์๋์ง, ์ด๋ป๊ฒ ์ ๊ทผํ๋์ง” ์๋ ค์ค.
- ๋ณดํต ์ฐ๋ฆฌ๊ฐ ์น์์ ์ฐ๋ ์ฃผ์(http://, https://, ftp://)๋ ์ ๋ถ URL.
URL
https://www.example.com:443/path/page.html?query=abc#section2
- https → ์คํด(ํ๋กํ ์ฝ)
- www.example.com:443 → ํธ์คํธ + ํฌํธ
- /path/page.html → ๊ฒฝ๋ก
- ?query=abc → ์ฟผ๋ฆฌ ์คํธ๋ง
- #section2 → ํ๋๊ทธ๋จผํธ(๋ฌธ์ ๋ด๋ถ ์์น)
์ฆ, URL ์ ์ด๋ค Host ์ ์ด๋ค Port ์ธ์ง ๋ฑ ์ด๋ค ๊ฒฝ๋ก(Path) ์ ์์์ด ์์นํ๋์ง์ ๊ด๋ จํ ์ ๋ณด์ด๊ณ ,
URI ๋ ๊ฑฐ๊ธฐ์ ๋ ๋์๊ฐ์ ๊ฒฝ๋ก์ ์ ๊ทผํ์ ๋ ๊ทธ ์ค ์ด๋ค ์ ํํ ์์์ ์ํ๋์ง ์๋ณํ๊ธฐ ์ํ ์ฟผ๋ฆฌ ์คํธ๋ง ๋ฑ์ ์ ๋ณด๋ฅผ ํฌํจํ๊ณ ์๋ค๊ณ ๋ณผ ์ ์์ต๋๋ค.
๋ฐ๋ผ์ Url ์ผ๋ก๋ ์ ํํ ์ด๋ค ์์์ ์๊ตฌํ๋์ง, Accept ์์๋ ์ด๋ค ํ์ผ ํ์์ ์ํ๋์ง ํ์ ํด์ผ ํฉ๋๋ค.
Index.html ๋ฐํํ๊ธฐ
์น์๋ฒ๋ HTML, CSS, JS ๊ฐ์ ์ ์ ์์๋ค์ ์๋นํ๋ ์ญํ ์ ํฉ๋๋ค.
SPA ๋ ๋ณดํต index.html + bundle.js ๋ก ๊ตฌ์ฑ๋์ด ์๋๋ฐ,
http://localhost/index.html ์ ์ ์ํ๋ฉด ๋ธ๋ผ์ฐ์ -> ์๋ฒ๋ก index.html ์์ฒญ์ด ๋ ์๊ฐ๊ณ ,
์ฐ๋ฆฌ๋ ์ ์ ํ ๊ฒฝ๋ก์ ์๋ ํ์ผ์ ์๋ตํด์ฃผ๋ฉด ๋ฉ๋๋ค.
์ ๊ฐ์ ๊ฒฝ์ฐ ๋ด๋ถ frontend/dist ๊ฒฝ๋ก์ ์ต์ข ๋น๋๋ ํ๋ก ํธ์๋ ๋ฒ๋ค ํ์ผ์ ์์นํ์์ผ๋ฏ๋ก ์ฌ๊ธฐ๋ฅผ ๊ธฐ์ค์ ์ผ๋ก index.html ์ ์ฝ๊ณ ์๋ต์ ๋ฐํํด์ค๋๋ค.
// frontend/dist ๊ฒฝ๋ก ์ค์
const FRONTEND_DIST_PATH = path.join(process.cwd(), '../frontend/dist');
/**
* net ๋ชจ๋ ๊ธฐ๋ฐ HTTP ์๋ฒ
* Express ๋ฑ ์ธ๋ถ ํ๋ ์์ํฌ ์์ด ์์ net ๋ชจ๋๋ก HTTP ์๋ฒ ๊ตฌํ
*/
const server = net.createServer((socket) => {
const startTime = Date.now();
const clientAddress = socket.remoteAddress + ':' + socket.remotePort;
console.log('ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ๋จ:', clientAddress);
// HTTP ์์ฒญ ๋ฐ์ดํฐ ์์
socket.on('data', async (data) => {
try {
const request = data.toString();
// HTTP ์์ฒญ ํ์ฑ
const lines = request.split('\r\n');
const requestLine = lines[0];
const [method, url] = requestLine ? requestLine.split(' ') : ['', ''];
// User-Agent ํค๋ ์ถ์ถ
const userAgentLine = lines.find((line) =>
line.toLowerCase().startsWith('user-agent:')
);
const userAgent = userAgentLine
? userAgentLine.split(': ')[1]
: 'Unknown';
// ์์ฒญ ๋ก๊ทธ ๊ธฐ๋ก
logRequest(method, url, userAgent, socket.remoteAddress);
// URI, MIME TYPE ์ ๋ฐ๋ผ HTTP ์์ฒญ์ ์ฒ๋ฆฌํ๋ ํจ์
let responseBody;
let statusCode = 200;
let contentType = 'text/html; charset=utf-8';
// GET /index.html ๋๋ GET / ์์ฒญ ์ฒ๋ฆฌ
if (method === 'GET' && (url === '/' || url === '/index.html')) {
try {
const indexPath = path.join(FRONTEND_DIST_PATH, 'index.html');
responseBody = await fs.readFile(indexPath, 'utf8');
} catch (error) {
logError(error, 'Failed to read index.html');
statusCode = 404;
responseBody =
'<h1>404 Not Found</h1><p>index.html ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค.</p>';
}
}
const statusText = statusCode === 200 ? 'OK' : 'Not Found';
const response = [
`HTTP/1.1 ${statusCode} ${statusText}`,
`Content-Type: ${contentType}`,
'Connection: close',
`Content-Length: ${Buffer.byteLength(responseBody, 'utf8')}`,
'',
responseBody,
].join('\r\n');
// ์๋ต ๋ก๊ทธ ๊ธฐ๋ก
const responseTime = Date.now() - startTime;
logResponse(statusCode, contentType, responseTime);
socket.write(response);
socket.end();
} catch (error) {
logError(error, 'Request processing error');
const errorResponse = [
'HTTP/1.1 500 Internal Server Error',
'Content-Type: text/html; charset=utf-8',
'Connection: close',
'',
'<h1>500 Internal Server Error</h1><p>์๋ฒ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.</p>',
].join('\r\n');
socket.write(errorResponse);
socket.end();
}
});
๊ทธ๋ฐ๋ฐ index.html ๋ง ์๋ตํ๋ค๊ณ ์นํ์ด์ง๊ฐ ๊ทธ๋ ค์ง์ง ์์ต๋๋ค.
index.html ์ ํด๋ ํ๋ฉด์ ๋ธ๋ผ์ฐ์ ๊ฐ ๋ค์ํ๋ฒ bundle.js ํ์ผ์ ์์ฒญํ ํ ๋ฐ ์ด๋ฅผ ์ฒ๋ฆฌํ๋ ์ฝ๋๋ฅผ ์์ฑํ์ง ์์๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋ฐ๋ผ์ ๋ค์ ๋๋ชฉ์ ์ถ๊ฐํด์ฃผ์ด ๋ธ๋ผ์ฐ์ ๊ฐ bundle.js ๋ฅผ ์ ๋๋ก ๋ก๋ํ ์ ์๋๋ก ํฉ๋๋ค.
// GET /bundle.js ์์ฒญ ์ฒ๋ฆฌ
else if (method === 'GET' && url === '/bundle.js') {
try {
const bundlePath = path.join(FRONTEND_DIST_PATH, 'bundle.js');
responseBody = await fs.readFile(bundlePath, 'utf8');
contentType = 'application/javascript; charset=utf-8';
} catch (error) {
logError(error, 'Failed to read bundle.js');
statusCode = 404;
responseBody = 'console.error("bundle.js not found");';
contentType = 'application/javascript; charset=utf-8';
}
}
๊ทธ๋ฌ๋ฉด ๋ค์๊ณผ ๊ฐ์ด index.html ์ bundle.js ์ฝ๋๋ฅผ ์คํํ๋ฉด์ ํ๋ฉด์ด ์ ๋๋ก ๊ทธ๋ ค์ง๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.

๋คํฌ์ํฌ ํญ์ ํ์ธํด๋ณด๋ฉด ๋๊ฐ์ ์์ฒญ+์๋ต์ ์ฃผ๊ณ ๋ฐ์ ์ฌ์ค์ ์ ์ ์์ต๋๋ค.


๊ทธ๋ฆฌ๊ณ ํ๊ฐ์ง ์ ๊ธฐํ ์ฌ์ค์ ๋ธ๋ผ์ฐ์ ๋ ๊ธฐ๋ณธ์ ์ผ๋ก /favicon.ico ๋ฅผ ์์ฒญํ๋ค๋ ์ ์ ๋๋ค.
์ฆ, http://example.com/ ์ ์ → http://example.com/favicon.ico ์๋ ์์ฒญํฉ๋๋ค.
๋ฐ๋ผ์ ์ด๋ฅผ ์ฒ๋ฆฌํด์ค ์ ์๋๋ก ์ ์ ๋ฐฐํฌ dist ํด๋์ favicon.ico์ ์์น์์ผ์ค ํ์๊ฐ ์์ต๋๋ค.

CopyWebpackPlugin์ด๋?
๋์ฉ๋ ํธ๋ํฝ์ ๊ฒฌ๋๋ ๊ณ ์ฑ๋ฅ ์น์๋ฒ ๊ตฌํํ๊ธฐ
์ฌํ๊น์ง๋ ์ฑ๊ธ ์ค๋ ๋์์ ์ฒ๋ฆฌ๋๋ HTTP ์น ์๋ฒ๋ฅผ ๋ค๋ฃจ์์ต๋๋ค. ๊ทธ๋ฐ๋ฐ ๋ง์ฝ ์์ฒญ์ ์๊ฐ ๊ธ์ฆํ๋ค๋ฉด,
๋ฉํฐ ์ฝ์ด CPU ํ๊ฒฝ์์ ํ๋์ ์ค๋ ๋๋ง ์ฌ์ฉํด์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๊ฒ์ด ๋ค์ ์์ฝ๊ฒ ๋๊ปด์ง ์ ์์ต๋๋ค.
๋ง์ฝ ๋ฉํฐ ์ค๋ ๋๋ฅผ ํ์ฉํด์ ์ปค๋ฒํ ์ ์๋ ์์ญ์ด๋ผ๋ฉด ๊ตณ์ด ์ธ์คํด์ค๋ฅผ ์ํ ํ์ฅํ ํ์๋ ์๊ธฐ์ ์๋ ์์์ ์ต๋ํ ํจ์จ์ ์ผ๋ก ํ์ฉํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
๋ฐ๋ผ์ ์น ์๋ฒ๋ฅผ ๊ฐ๊ฐ ๋ฉํฐ ํ๋ก์ธ์ค/ ๋ฉํฐ ์ค๋ ๋ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํด๋ณด๊ณ ๊ฐ ๋ฐฉ์์ ๋น๊ต ๋ถ์ํ๊ณ ์ ํ์์ต๋๋ค.
1. cluster ๋ชจ๋์ ํ์ฉํด CPU ์ฝ์ด ์๋งํผ ์์ปค ํ๋ก์ธ์ค๋ฅผ ์์ฑ
2. Worker Threads ๊ธฐ๋ฐ ์๋ฒ ๊ตฌํ
์ด ๋, ์ฑ๋ฅ ๊ฐ์ ํ์ ์ ์ ์ฑ๋ฅ ์ฐจ์ด๋ฅผ ํ์ธํด๋ณด๊ธฐ ์ํด์ ์น ์ฑ๋ฅ ๋ถํ๋ฅผ ํ ์คํธ ํ๊ธฐ ์ํด Apache Bench ๋ฅผ ํ์ฉํ๊ณ ์ ํ์ต๋๋ค.
Apache Bench (ab)
- ์ํ์น HTTP ์๋ฒ์ ํจ๊ป ์ ๊ณต๋๋ ๊ฐ๋จํ ๋ฒค์น๋งํฌ ๋๊ตฌ
- ๊ธฐ๋ณธ ๊ธฐ๋ฅ: ๋์ ์ ์ ์, ์์ฒญ ์๋ฅผ ์ง์ ํด์ ์๋ฒ์ ๋ถํ ๊ฑธ๊ธฐ
- ์:
- -n 1000 → ์ด 1000๋ฒ ์์ฒญ
- -c 100 → ๋์์ 100๊ฐ ์์ฒญ
- ab -n 1000 -c 100 http://localhost/
๐ฅ ์ฑ๋ฅ ํ
์คํธ ์คํจ: Apache Bench failed with code 60: Completed 5000 requests
apr_socket_recv: Operation timed out (60)
(base) kimseoyeon@gimseoyeons-MacBook-Air-2 webserver % npm run test:performance
> codestargram-webserver@1.0.0 test:performance
> node test/performanceTest.js
๐ ์น์๋ฒ ์ฑ๋ฅ ํ
์คํธ ์์
๐ก ๋์ ์๋ฒ: http://127.0.0.1:80
============================================================
๐ ๊ธฐ๋ณธ ํ์ด์ง ๋ก๋ ์ฑ๋ฅ ํ
์คํธ
๐ ์คํ ์ค: ab -n 1000 -c 10 -s 60 -g gnuplot.dat -e results.csv http://127.0.0.1:80/
๐ ํ
์คํธ: HTML ํ์ด์ง ๋ก๋ (index.html)
๐ JavaScript ํ์ผ ๋ก๋ ์ฑ๋ฅ ํ
์คํธ
๐ ์คํ ์ค: ab -n 500 -c 10 -s 60 -g gnuplot.dat -e results.csv http://127.0.0.1:80/bundle.js
๐ ํ
์คํธ: JavaScript ํ์ผ ๋ก๋ (bundle.js)
๐ ํ๋น์ฝ ๋ก๋ ์ฑ๋ฅ ํ
์คํธ
๐ ์คํ ์ค: ab -n 500 -c 10 -s 60 -g gnuplot.dat -e results.csv http://127.0.0.1:80/favicon.ico
๐ ํ
์คํธ: ํ๋น์ฝ ๋ก๋ (favicon.ico)
๐ ๋์ ์ฐ๊ฒฐ ์ ์คํธ๋ ์ค ํ
์คํธ
๐ฅ ๋์ ์ฐ๊ฒฐ ์: 1
๐ ์คํ ์ค: ab -n 200 -c 1 -s 60 -g gnuplot.dat -e results.csv http://127.0.0.1:80/
๐ ํ
์คํธ: ๋์ ์ฐ๊ฒฐ 1๊ฐ
๐ฅ ๋์ ์ฐ๊ฒฐ ์: 5
๐ ์คํ ์ค: ab -n 200 -c 5 -s 60 -g gnuplot.dat -e results.csv http://127.0.0.1:80/
๐ ํ
์คํธ: ๋์ ์ฐ๊ฒฐ 5๊ฐ
๐ฅ ๋์ ์ฐ๊ฒฐ ์: 10
๐ ์คํ ์ค: ab -n 200 -c 10 -s 60 -g gnuplot.dat -e results.csv http://127.0.0.1:80/
๐ ํ
์คํธ: ๋์ ์ฐ๊ฒฐ 10๊ฐ
๐ฅ ๋์ ์ฐ๊ฒฐ ์: 20
๐ ์คํ ์ค: ab -n 200 -c 20 -s 60 -g gnuplot.dat -e results.csv http://127.0.0.1:80/
๐ ํ
์คํธ: ๋์ ์ฐ๊ฒฐ 20๊ฐ
๐ฅ ๋์ ์ฐ๊ฒฐ ์: 50
๐ ์คํ ์ค: ab -n 200 -c 50 -s 60 -g gnuplot.dat -e results.csv http://127.0.0.1:80/
๐ ํ
์คํธ: ๋์ ์ฐ๊ฒฐ 50๊ฐ
๐ Keep-Alive ์ฑ๋ฅ ๋น๊ต ํ
์คํธ
๐ ์คํ ์ค: ab -n 500 -c 10 -s 60 -g gnuplot.dat -e results.csv http://127.0.0.1:80/
๐ ํ
์คํธ: Keep-Alive ๋นํ์ฑํ
๐ ์คํ ์ค: ab -n 500 -c 10 -s 60 -g gnuplot.dat -e results.csv -k http://127.0.0.1:80/
๐ ํ
์คํธ: Keep-Alive ํ์ฑํ
๐ ์ง์ ๋ถํ ํ
์คํธ (20์ด)
๐ ์คํ ์ค: ab -t 20 -c 10 -s 60 -g gnuplot.dat -e results.csv http://127.0.0.1:80/
๐ ํ
์คํธ: 20์ด๊ฐ ์ง์ ๋ถํ ํ
์คํธ
============================================================
๐ ์ฑ๋ฅ ํ
์คํธ ๊ฒฐ๊ณผ ์์ฝ
============================================================
๐ฏ HTML ํ์ด์ง ๋ก๋ (index.html)
โ
์๋ฃ๋ ์์ฒญ: 1000
โ ์คํจํ ์์ฒญ: 0
โก ์ด๋น ์์ฒญ ์: 7008.74 req/sec
โฑ๏ธ ํ๊ท ์๋ต ์๊ฐ: 1.43 ms
๐ ์ ์ก ์๋: 3114.24 KB/sec
โฐ ์ด ์์ ์๊ฐ: 0.143 ์ด
๐ฏ JavaScript ํ์ผ ๋ก๋ (bundle.js)
โ
์๋ฃ๋ ์์ฒญ: 500
โ ์คํจํ ์์ฒญ: 0
โก ์ด๋น ์์ฒญ ์: 4468.08 req/sec
โฑ๏ธ ํ๊ท ์๋ต ์๊ฐ: 2.24 ms
๐ ์ ์ก ์๋: 163857.07 KB/sec
โฐ ์ด ์์ ์๊ฐ: 0.112 ์ด
๐ฏ ํ๋น์ฝ ๋ก๋ (favicon.ico)
โ
์๋ฃ๋ ์์ฒญ: 500
โ ์คํจํ ์์ฒญ: 0
โก ์ด๋น ์์ฒญ ์: 5574.26 req/sec
โฑ๏ธ ํ๊ท ์๋ต ์๊ฐ: 1.79 ms
๐ ์ ์ก ์๋: 947.19 KB/sec
โฐ ์ด ์์ ์๊ฐ: 0.09 ์ด
๐ฏ ๋์ ์ฐ๊ฒฐ 1๊ฐ
โ
์๋ฃ๋ ์์ฒญ: 200
โ ์คํจํ ์์ฒญ: 0
โก ์ด๋น ์์ฒญ ์: 1048.29 req/sec
โฑ๏ธ ํ๊ท ์๋ต ์๊ฐ: 0.95 ms
๐ ์ ์ก ์๋: 465.79 KB/sec
โฐ ์ด ์์ ์๊ฐ: 0.191 ์ด
๐ฏ ๋์ ์ฐ๊ฒฐ 5๊ฐ
โ
์๋ฃ๋ ์์ฒญ: 200
โ ์คํจํ ์์ฒญ: 0
โก ์ด๋น ์์ฒญ ์: 6928.81 req/sec
โฑ๏ธ ํ๊ท ์๋ต ์๊ฐ: 0.72 ms
๐ ์ ์ก ์๋: 3078.72 KB/sec
โฐ ์ด ์์ ์๊ฐ: 0.029 ์ด
๐ฏ ๋์ ์ฐ๊ฒฐ 10๊ฐ
โ
์๋ฃ๋ ์์ฒญ: 200
โ ์คํจํ ์์ฒญ: 0
โก ์ด๋น ์์ฒญ ์: 8215.24 req/sec
โฑ๏ธ ํ๊ท ์๋ต ์๊ฐ: 1.22 ms
๐ ์ ์ก ์๋: 3650.33 KB/sec
โฐ ์ด ์์ ์๊ฐ: 0.024 ์ด
๐ฏ ๋์ ์ฐ๊ฒฐ 20๊ฐ
โ
์๋ฃ๋ ์์ฒญ: 200
โ ์คํจํ ์์ฒญ: 0
โก ์ด๋น ์์ฒญ ์: 9794.80 req/sec
โฑ๏ธ ํ๊ท ์๋ต ์๊ฐ: 2.04 ms
๐ ์ ์ก ์๋: 4352.18 KB/sec
โฐ ์ด ์์ ์๊ฐ: 0.02 ์ด
๐ฏ ๋์ ์ฐ๊ฒฐ 50๊ฐ
โ
์๋ฃ๋ ์์ฒญ: 200
โ ์คํจํ ์์ฒญ: 0
โก ์ด๋น ์์ฒญ ์: 8990.38 req/sec
โฑ๏ธ ํ๊ท ์๋ต ์๊ฐ: 5.56 ms
๐ ์ ์ก ์๋: 3994.75 KB/sec
โฐ ์ด ์์ ์๊ฐ: 0.022 ์ด
๐ฏ Keep-Alive ๋นํ์ฑํ
โ
์๋ฃ๋ ์์ฒญ: 500
โ ์คํจํ ์์ฒญ: 0
โก ์ด๋น ์์ฒญ ์: 8943.58 req/sec
โฑ๏ธ ํ๊ท ์๋ต ์๊ฐ: 1.12 ms
๐ ์ ์ก ์๋: 3973.96 KB/sec
โฐ ์ด ์์ ์๊ฐ: 0.056 ์ด
๐ฏ Keep-Alive ํ์ฑํ
โ
์๋ฃ๋ ์์ฒญ: 500
โ ์คํจํ ์์ฒญ: 0
โก ์ด๋น ์์ฒญ ์: 7413.89 req/sec
โฑ๏ธ ํ๊ท ์๋ต ์๊ฐ: 1.35 ms
๐ ์ ์ก ์๋: 3294.26 KB/sec
โฐ ์ด ์์ ์๊ฐ: 0.067 ์ด
๐ฏ 20์ด๊ฐ ์ง์ ๋ถํ ํ
์คํธ
โ
์๋ฃ๋ ์์ฒญ: 12342
โ ์คํจํ ์์ฒญ: 0
โก ์ด๋น ์์ฒญ ์: 559.31 req/sec
โฑ๏ธ ํ๊ท ์๋ต ์๊ฐ: 17.88 ms
๐ ์ ์ก ์๋: 248.52 KB/sec
โฐ ์ด ์์ ์๊ฐ: 22.067 ์ด
๐ ์ฑ๋ฅ ํ
์คํธ ์๋ฃ!
Cluster ๋ชจ๋ ๊ธฐ๋ฐ ๋ฉํฐ ์ค๋ ๋ ์๋ฒ ๊ตฌํ
(base) kimseoyeon@gimseoyeons-MacBook-Air-2 webserver % node test/clusterTest.js
๐ ํด๋ฌ์คํฐ ๋ชจ๋ ์ฑ๋ฅ ๋น๊ต ํ
์คํธ ์์
๐ก ๋์ ์๋ฒ: ClusterPerformanceTester
============================================================
๐ ๋จ์ผ vs ๋ฉํฐ ํ๋ก์ธ์ค ์ฑ๋ฅ ๋น๊ต ํ
์คํธ
๐น ๋จ์ผ ํ๋ก์ธ์ค ๋ชจ๋ ํ
์คํธ
๐ ์คํ ์ค: ab -n 2000 -c 50 -s 60 -g gnuplot.dat -e results.csv http://127.0.0.1:80/
๐ ํ
์คํธ: ๋จ์ผ ํ๋ก์ธ์ค ๋ชจ๋
โณ ํด๋ฌ์คํฐ ๋ชจ๋ ์ ํ์ ์ํด ์๋ฒ ์ฌ์์ ํ์
๐ก ๋ค์ ๋ช
๋ น์ด๋ก ํด๋ฌ์คํฐ ๋ชจ๋ ์๋ฒ๋ฅผ ์์ํ์ธ์:
USE_CLUSTER=true node webserver/server.js
๋๋
node webserver/server.js --cluster
โธ๏ธ ํด๋ฌ์คํฐ ๋ชจ๋ ์๋ฒ ์์ ํ ์๋ฌด ํค๋ ๋๋ฅด์ธ์...
๐น ํด๋ฌ์คํฐ ๋ชจ๋ ํ
์คํธ
๐ ์คํ ์ค: ab -n 2000 -c 50 -s 60 -g gnuplot.dat -e results.csv http://127.0.0.1:80/
๐ ํ
์คํธ: ํด๋ฌ์คํฐ ๋ชจ๋
============================================================
๐ ํด๋ฌ์คํฐ ์ฑ๋ฅ ๋น๊ต ๋ถ์
============================================================
๐น ๋จ์ผ ํ๋ก์ธ์ค:
โก RPS: 6191.91 req/sec
โฑ๏ธ ์๋ต์๊ฐ: 8.07 ms
๐ ์ ์ก์๋: 2751.29 KB/sec
๐น ํด๋ฌ์คํฐ ๋ชจ๋:
โก RPS: 5421.27 req/sec
โฑ๏ธ ์๋ต์๊ฐ: 9.22 ms
๐ ์ ์ก์๋: 2408.87 KB/sec
๐ ์ฑ๋ฅ ๊ฐ์ ๋:
โก RPS ํฅ์: -12.45%
โฑ๏ธ ์๋ต์๊ฐ ๊ฐ์ : -14.22%
๐ ์ ์ก์๋ ํฅ์: -12.45%
โ ๏ธ ํด๋ฌ์คํฐ ๋ชจ๋์์ ์์๋ณด๋ค ์ฑ๋ฅ ํฅ์์ด ์ ์ต๋๋ค.
๋์ ๋์์ฑ ๋ถํ์์ ๋ ํฐ ์ฐจ์ด๋ฅผ ๋ณด์ผ ์ ์์ต๋๋ค.
============================================================
๐ ์ฑ๋ฅ ํ
์คํธ ๊ฒฐ๊ณผ ์์ฝ
============================================================
๐ฏ ๋จ์ผ ํ๋ก์ธ์ค ๋ชจ๋
โ
์๋ฃ๋ ์์ฒญ: 2000
โ ์คํจํ ์์ฒญ: 0
โก ์ด๋น ์์ฒญ ์: 6191.91 req/sec
โฑ๏ธ ํ๊ท ์๋ต ์๊ฐ: 8.07 ms
๐ ์ ์ก ์๋: 2751.29 KB/sec
๐ฏ ํด๋ฌ์คํฐ ๋ชจ๋
โ
์๋ฃ๋ ์์ฒญ: 2000
โ ์คํจํ ์์ฒญ: 0
โก ์ด๋น ์์ฒญ ์: 5421.27 req/sec
โฑ๏ธ ํ๊ท ์๋ต ์๊ฐ: 9.22 ms
๐ ์ ์ก ์๋: 2408.87 KB/sec
๐ ์ฑ๋ฅ ํ
์คํธ ์๋ฃ!
๐พ ํด๋ฌ์คํฐ ๋น๊ต ๊ฒฐ๊ณผ ์ ์ฅ๋จ: cluster-performance-test-2025-09-17T13-26-31-597Z.json
(base) kimseoyeon@gimseoyeons-MacBook-Air-2 webserver %
'๐ WEB' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| ์น ์ฌ์ดํธ ์ต์ ํ ๋ฐฉ๋ฒ (0) | 2026.01.19 |
|---|---|
| HTTP Multipart/form-data ์ง์ ํ์ ๋ง๋ค๋ฉฐ ์๋ฆฌ ์ดํดํ๊ธฐ (0) | 2025.10.01 |
| Node.js๋ก ๊ณ ์ฑ๋ฅ ์น์๋ฒ ๋ง๋ค๊ธฐ: Cluster์ Worker Threads (0) | 2025.09.28 |
| HTTP ํจํท ๊ตฌ์กฐ, ์์ฒญ ํค๋/๋ฐ๋ (0) | 2025.09.17 |
| Web Server ์ WAS(Web Application Server)๋ ? (0) | 2025.09.15 |