웹 서비스 개발(FB,BE,SERVER,DB)/Node.js

5. Node.js WebServer 2

Zoo_10th 2024. 3. 13.

1. Cookie

쿠키(Cookie)는 클라이언트-서버 간의 상태 정보를 유지하는 데 사용되는 작은 데이터 조각이다. 웹 브라우저와 서버 간에 데이터를 저장하고 교환하는 방법으로, 주로 사용자 인증, 세션 관리, 사용자 선호도 기록 등에 활용된다.

1-1. 쿠키의 기본 개념

1) 키-값 쌍: 쿠키는 키=값 형태의 쌍으로 구성되어 있다. 예를 들어, name=uesr1는 name이라는 키에 uesr1라는 값을 저장하고 있다.

2) 요청과 응답에 포함: 쿠키는 HTTP 요청과 응답 헤더에 포함되어 전송된다. 사용자가 웹사이트에 처음 방문할 때 서버는 HTTP 응답 헤더에 쿠키를 설정하고, 이후의 요청에서 브라우저는 이 쿠키를 자동으로 요청 헤더에 포함하여 서버로 전송된다.

3) 클라이언트-서버 상태 유지: 서버는 쿠키 정보를 통해 사용자를 식별하고, 상태 정보를 유지할 수 있다. 예를 들어, 로그인 상태 유지, 쇼핑 카트의 내용 유지 등이 가능하다.

1-2. 쿠키의 사용 예시

1) 사용자 인증: 사용자가 로그인할 때 사용자의 식별 정보를 쿠키에 저장하여, 추후의 요청에서 사용자를 인식할 수 있다.

2) 세션 관리: 사용자의 세션 정보(로그인 상태, 페이지 이용 정보 등)를 쿠키에 저장하여, 서버가 사용자 각각을 구별하고 필요한 정보를 제공할 수 있다.

3) 사용자 선호도 기록: 사용자의 사이트 설정(언어 선택, 테마 등)을 쿠키에 저장하여, 매번 설정을 변경하지 않아도 되도록한다.

1-3. 쿠키의 보안과 제한사항

1) 보안 취약점: 쿠키는 클라이언트에 저장되므로 보안에 취약할 수 있다. 따라서 중요한 정보(비밀번호, 개인정보 등)는 쿠키에 저장하지 않아야 한다.

2) 크기 제한: 쿠키는 일반적으로 크기에 제한이 있으며(대략 4KB), 많은 양의 데이터를 저장하기에는 적합하지 않는다.

3) 도메인과 경로 제한: 쿠키는 특정 도메인과 경로에 속해 있으며, 해당 범위를 벗어난 요청에는 포함되지 않는다.

1-4. Cookie Server 만들기

const http = require('http');

http.createServer((req, res) => {
  console.log(req.url, req.headers.cookie);
  res.writeHead(200, { 'Set-Cookie': 'mycookie=test' });
  res.end('Hello Cookie');
})
  .listen(8083, () => {
    console.log('8083번 포트에서 서버 대기 중입니다!');
  });

1) http 모듈 사용: Node.js의 기본 http 모듈을 사용하여 HTTP 서버를 생성한다.

2) 서버 생성: http.createServer 메서드는 요청을 처리할 콜백 함수를 인자로 받아 서버를 생성한다.

3) 요청 처리: 클라이언트로부터 요청이 들어올 때마다 이 콜백 함수가 호출된다. req 객체에서 요청 URL(req.url)과 함께 클라이언트가 보낸 쿠키(req.headers.cookie)를 확인할 수 있다.

4) 쿠키 설정: res.writeHead 메서드를 사용하여 응답 헤더를 설정한다. 여기서 'Set-Cookie': 'mycookie=test'는 클라이언트에 mycookie라는 이름의 쿠키를 test라는 값으로 설정하도록 지시한다.

5) 응답 전송: res.end('Hello Cookie')는 클라이언트에게 'Hello Cookie'라는 메시지를 담아 응답을 보낸다.

6) 서버 시작: .listen(8083, ...) 메서드는 서버를 8083번 포트에서 실행하고, 서버가 준비되면 주어진 콜백 함수를 호출한다.

1-5. 쿠키의 작동 원리

(1) 쿠키 설정: 서버가 클라이언트에게 Set-Cookie 헤더를 포함한 응답을 보내면, 클라이언트(브라우저)는 이 쿠키를 저장한다.

(2) 쿠키 전송: 이후 동일한 서버에 대한 모든 요청에 클라이언트는 자동으로 저장된 쿠키를 요청 헤더에 포함하여 보낸다. 이를 통해 서버는 클라이언트를 식별하고, 상태 정보를 유지할 수 있다.

(3) 상태 관리: 쿠키를 통해 사용자 인증, 세션 관리, 사용자 선호도 저장 등의 다양한 기능을 구현할 수 있다.

1-5. Header 와 Body

HTTP 요청과 응답은 일반적으로 헤더(Header)와 본문(Body) 두 부분으로 구성된다.

1-6. 헤더(Header)

1) 용도: HTTP 요청과 응답에 대한 메타데이터(metadata)를 포함한다. 이 메타데이터에는 여러 종류의 정보가 포함될 수 있으며, 주로 요청의 종류, 서버 또는 클라이언트의 유형, 콘텐츠의 유형, 콘텐츠 길이 등이 포함한다.

2) 쿠키: 쿠키는 요청과 응답의 헤더에 포함되는 부가적인 정보이다. 쿠키는 클라이언트와 서버 간의 상태 정보를 저장하는 데 사용된다. 예를 들어, 서버는 Set-Cookie 헤더를 통해 응답에 쿠키를 설정하고, 클라이언트는 이후 요청의 Cookie 헤더에 이 쿠키를 포함하여 보낸다.

1-7.  본문(Body)

1) 용도: 실제 전송되는 데이터를 담고 있다. 이 데이터는 HTML 문서, JSON 데이터, 이미지 파일 등 다양한 형태일 수 있다.

2) HTTP 메서드: GET 요청은 일반적으로 본문을 포함하지 않으며, 데이터는 URL의 쿼리 문자열을 통해 전송된다. 반면 POST, PUT, DELETE 같은 메서드는 데이터를 본문에 담아 전송된다.

1-8.  Http 상태 코드

HTTP 상태 코드는 클라이언트의 요청에 대한 서버의 응답 상태를 나타내는 코드이다. 이 코드들은 특정 범위에 따라 분류되며, 각 범주는 요청의 성공, 리다이렉션, 클라이언트 오류, 서버 오류 등을 나타낸다.

 - 2XX: 성공 (Success)

1) 200 OK: 요청이 성공적으로 처리되었음을 나타낸다. 가장 흔히 사용되는 HTTP 상태 코드이다.

2) 201 Created: 요청이 성공적으로 이루어져 새로운 리소스가 생성되었음을 나타낸다.

- 3XX: 리다이렉션 (Redirection)

1) 301 Moved Permanently: 요청한 페이지가 새 위치로 영구적으로 이동되었음을 나타낸다. 새 URL이 응답에 포함되어야한다.

2) 302 Found: 요청한 페이지가 임시적으로 다른 위치로 이동했음을 나타낸다. 이는 일시적인 리다이렉션을 의미한다.

- 4XX: 클라이언트 오류 (Client Error)

1) 401 Unauthorized: 인증이 필요한 페이지를 요청했을 때 나타납니다. 사용자 인증이 필요하다.

2) 403 Forbidden: 서버가 요청을 이해했지만 승인을 거부한다. 주로 권한이 없는 접근에 대해 사용된다.

3) 404 Not Found: 서버가 요청한 페이지를 찾을 수 없음을 나타냅니다. URL이 잘못되었거나 페이지가 삭제되었을 때 발생

 - 5XX: 서버 오류 (Server Error)

1) 500 Internal Server Error: 서버 내부 오류로 요청을 수행할 수 없음을 나타낸다. 가장 일반적인 서버 오류이다.

2) 502 Bad Gateway: 서버가 게이트웨이나 프록시로 작동 중이며, 상위 서버로부터 유효하지 않은 응답을 받았을 때 나타난다.

3) 03 Service Unavailable: 서버가 일시적으로 요청을 처리할 수 없음을 나타낸다. 대부분의 경우, 서버 과부하나 유지 보수로 인한 일시적인 상태이다.

1-9. Cookie를 활용한 인증

쿠키를 활용한 인증 방식은 웹 애플리케이션에서 사용자 식별 및 세션 관리를 위해 널리 사용된다. Node.js 환경에서 기본적인 로그인 흐름을 구현할 수 있으며, 이는 주로 사용자가 로그인할 때 사용자 정보를 쿠키에 저장하고, 이후 요청에서 이 쿠키를 확인하여 사용자를 식별하는 과정으로 이루어진다.

 - 기본적인 로그인 흐름 구현

1) 쿠키 파싱:

클라이언트로부터 받은 요청 헤더의 쿠키를 파싱하여 객체로 변환한다. 이렇게 하면 쿠키 내의 각각의 값에 쉽게 접근할 수 있다.

2) 로그인 경로 처리 (/login):

 * 사용자가 로그인 경로(/login)에 접근하면, 쿼리스트링(예: ?name=user1)으로 전달된 사용자 이름을 쿠키로 저장한다.

 * 이를 위해 Set-Cookie 헤더를 응답에 추가하여 클라이언트의 브라우저에 쿠키를 설정한다.

3) 루트 경로 처리 (/):

 * 클라이언트가 루트 경로(/)에 접근할 때, 요청 헤더의 쿠키를 확인

 * 쿠키가 존재하면, 쿠키에 저장된 사용자 이름을 사용하여 환영 메시지를 표시한다.

 * 쿠키가 없으면, 사용자를 로그인 페이지로 리다이렉트한다.

Cookie_Code

const http = require('http');
const fs = require('fs').promises;
const path = require('path');

const parseCookies = (cookie = '') =>
  cookie
    .split(';')
    .map(v => v.split('='))
    .reduce((acc, [k, v]) => {
      acc[k.trim()] = decodeURIComponent(v);
      return acc;
    }, {});

http.createServer(async (req, res) => {
  const cookies = parseCookies(req.headers.cookie); // { mycookie: 'test' }
  // 주소가 /login으로 시작하는 경우
  if (req.url.startsWith('/login')) {
    const url = new URL(req.url, 'http://localhost:8084');
    const name = url.searchParams.get('name');
    const expires = new Date();
    // 쿠키 유효 시간을 현재시간 + 5분으로 설정
    expires.setMinutes(expires.getMinutes() + 5);
    res.writeHead(302, {
      Location: '/',
      'Set-Cookie': `name=${encodeURIComponent(name)}; Expires=${expires.toGMTString()}; HttpOnly; Path=/`,
    });
    res.end();
  // name이라는 쿠키가 있는 경우
  } else if (cookies.name) {
    res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
    res.end(`${cookies.name}님 안녕하세요`);
  } else {
    try {
      const data = await fs.readFile(path.join(__dirname, 'cookie.html'));
      res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
      res.end(data);
    } catch (err) {
      res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
      res.end(err.message);
    }
  }
})
  .listen(8084, () => {
    console.log('8084번 포트에서 서버 대기 중입니다!');
  });

Cookie.js

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>쿠키&세션 이해하기</title>
</head>
<body>
<form action="/login">
    <input id="name" name="name" placeholder="이름을 입력하세요" />
    <button id="login">로그인</button>
</form>
</body>
</html>

cookie.html

1-10. Cookie Options

Set-Cookie 헤더를 사용하여 HTTP 응답에 쿠키를 설정할 때, 다양한 옵션들을 지정할 수 있다. 이 옵션들은 쿠키의 동작 방식과 보안을 제어하는 데 중요한 역할을 한다.

1) 쿠키명=쿠키값

 - 쿠키의 기본 형식입니다. 쿠키의 이름과 값은 =로 연결된다.

 - 예: mycookie=test, name=user1

2) Expires=날짜

 - 쿠키의 만료 날짜를 지정한다. 지정된 날짜가 지나면 쿠키는 자동으로 삭제된다.

 - 날짜 형식은 보통 GMT(Greenwich Mean Time) 형식으로 지정된다.

 - 예: Expires=Wed, 09 Jun 2021 10:18:14 GMT

3) Max-age=초

 - 쿠키의 만료 기간을 초 단위로 설정한다. Max-age가 지정되면 Expires보다 우선한다.

 - 예: Max-age=3600 (1시간 후에 만료)

4) Domain=도메인명

 - 쿠키가 전송될 도메인을 지정합니다. 지정되지 않으면 기본적으로 현재 도메인에만 쿠키가 전송된다.

 - 예: Domain=example.com

5) Path=URL

 - 쿠키가 전송될 경로(URL)을 지정합니다. 기본값은 루트 경로(/)이다.

 - 예: Path=/, Path=/account

6) Secure

 - 이 옵션을 설정하면 HTTPS 프로토콜을 통해서만 쿠키가 전송된다.

 - 이는 중간자 공격을 방지하는 데 도움이 된다.

7) HttpOnly

 - 이 옵션이 설정되면 쿠키는 HTTP(S) 프로토콜을 통해서만 접근 가능하고, JavaScript를 통한 접근은 차단된다.

 - 이는 XSS(Cross-Site Scripting) 공격으로부터 쿠키를 보호하는 데 도움이 된다.

2. Session

세션(Session)은 클라이언트와 서버 간의 상태를 유지하는 방법이다. 웹 애플리케이션에서 세션은 일반적으로 사용자가 로그인한 상태를 유지하는 데 사용된다.

2-1. 세션의 핵심 개념

1) 상태 유지: HTTP 프로토콜은 상태가 없는(stateless) 프로토콜이다. 즉, 각 요청은 독립적이며 서로 연결되어 있지 않는다. 세션은 이러한 HTTP의 한계를 극복하고, 사용자의 상태(예: 로그인 상태)를 서버 측에서 유지하는 방법을 제공한다.

2) 세션 ID: 세션을 구별하기 위해 고유한 세션 ID가 사용된다. 이 ID는 일반적으로 서버에 의해 생성되며, 클라이언트(브라우저)와 서버 간의 모든 요청과 응답에서 사용된다.

3) 쿠키 활용: 세션 ID는 종종 쿠키를 통해 클라이언트에 저장되고 서버에 전송된다. 이를 통해 서버는 들어오는 요청이 같은 사용자로부터 왔는지 확인할 수 있다.

2-2. 세션 사용하기

쿠키를 사용하는 경우 중요한 정보가 클라이언트 측에 노출되고, 수정될 위험이 있기 때문에 보안에 취약할 수 있다. 이를 해결하기 위해 세션 기반 인증이 널리 사용된다. 세션 기반 인증에서는 중요한 정보를 서버 측에서 관리하고, 클라이언트에는 세션 키(보통 세션 ID라고 불림)만을 제공한다.

2-3. 세션 기반 인증의 작동 원리

1) 세션 객체 생성: 사용자가 인증 과정(예: 로그인)을 성공적으로 마치면, 서버는 세션 객체를 생성한다. 이 객체는 서버의 메모리에 저장되며, 사용자의 인증 정보, 사용자 설정, 사용자 상태 등을 포함할 수 있다.

2) 세션 키 생성: 서버는 고유한 세션 키(예: uniqueInt)를 생성한다. 이 키는 각 세션을 구별하는 데 사용되며, 보통 임의로 생성된 고유한 식별자이다.

3) 세션 저장: 생성된 세션 키를 사용하여 세션 객체에 사용자 정보를 저장한다. 예를 들어, session[uniqueInt] = { userInfo: ... }와 같은 형태로 사용자 정보를 세션 객체에 할당할 수 있다.

4) 세션 키 전송: 서버는 세션 키를 클라이언트에 전달한다. 일반적으로 이 키는 쿠키를 통해 클라이언트로 전송되며, 이후 클라이언트의 모든 요청에 이 쿠키가 포함된다.

5) 세션 키를 통한 사용자 식별: 클라이언트로부터 들어오는 요청에 포함된 세션 키를 통해 서버는 해당 사용자의 세션을 조회하고, 사용자의 인증 상태나 관련 정보를 확인할 수 있다.

2-4. 보안 고려사항

1) 세션 하이재킹 방지: 세션 키가 탈취되는 것을 방지하기 위해 HTTPS 사용, 쿠키의 HttpOnly 및 Secure 플래그 설정 등의 조치가 필요하다.

2) 세션 ID 재생성: 로그인 후 새로운 세션 ID를 발급하여 세션 고정 공격을 방지한다.

3) 세션 만료 관리: 사용자가 로그아웃하거나 일정 시간 동안 활동이 없는 경우 세션을 만료시켜야 한다.

const http = require('http');
const fs = require('fs').promises;
const path = require('path');

const parseCookies = (cookie = '') =>
  cookie
    .split(';')
    .map(v => v.split('='))
    .reduce((acc, [k, v]) => {
      acc[k.trim()] = decodeURIComponent(v);
      return acc;
    }, {});

const session = {};

http.createServer(async (req, res) => {
  const cookies = parseCookies(req.headers.cookie);
  if (req.url.startsWith('/login')) {
    const url = new URL(req.url, 'http://localhost:8085');
    const name = url.searchParams.get('name');
    const expires = new Date();
    expires.setMinutes(expires.getMinutes() + 5);
    const uniqueInt = Date.now();
    session[uniqueInt] = {
      name,
      expires,
    };
    res.writeHead(302, {
      Location: '/',
      'Set-Cookie': `session=${uniqueInt}; Expires=${expires.toGMTString()}; HttpOnly; Path=/`,
    });
    res.end();
  // 세션쿠키가 존재하고, 만료 기간이 지나지 않았다면
  } else if (cookies.session && session[cookies.session].expires > new Date()) {
    res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
    res.end(`${session[cookies.session].name}님 안녕하세요`);
  } else {
    try {
      const data = await fs.readFile(path.join(__dirname, 'cookie.html'));
      res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
      res.end(data);
    } catch (err) {
      res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
      res.end(err.message);
    }
  }
})
  .listen(8085, () => {
    console.log('8085번 포트에서 서버 대기 중입니다!');
  });

Session_Code

3. Https & Http2

3-1. Https

HTTPS는 인터넷 보안의 핵심 요소로, HTTP 통신을 보안 강화된 방식으로 진행한다. 이를 통해 데이터 기밀성, 인증, 그리고 데이터 무결성이 보장된다.

3-1-1. HTTPS의 구성 요소와 특징

1) SSL/TLS 암호화

- SSL(Secure Sockets Layer) 및 TLS(Transport Layer Security)는 데이터 전송 중 암호화를 제공한다.

- 이 암호화는 데이터가 전송되는 동안 중간에 데이터를 가로챈 공격자가 내용을 해독할 수 없게 만든다.

2) 암호화 (Encryption)

- 클라이언트와 서버 간에 전송되는 모든 데이터는 암호화 된다. 이는 데이터가 도청되거나 변조되는 것을 방지한다.

3) 인증 (Authentication)

- 서버의 신원은 SSL/TLS 인증서를 통해 검증된다.

- 이 인증서는 신뢰할 수 있는 인증 기관(CA)에 의해 발급되며, 서버의 신뢰성을 보증한다.

4) 데이터 무결성 (Data Integrity)

- 전송된 데이터가 중간에 변경되거나 손상되지 않았음을 보장한다.

3-1-2. HTTPS의 작동 원리

1) 핸드셰이크 (Handshake)

- 연결 시작 시, 클라이언트와 서버 간의 SSL/TLS 핸드셰이크가 진행된다.

- 이 과정에서 서버 신원 확인, 암호화 키 교환 등이 이루어진다.

2) 서버 인증

- 서버는 클라이언트에게 자신의 SSL/TLS 인증서와 공개키를 제공한다.

- 클라이언트는 인증서의 유효성을 확인하여 서버의 신뢰성을 검증한다.

3) 키 교환 (Key Exchange)

- 암호화된 세션을 위한 공유 비밀 키가 안전하게 교환된다.

4) 암호화된 통신

- 핸드셰이크가 완료되면, 모든 통신 데이터는 암호화되어 전송된다.

3-1-3. HTTPS의 중요성

1) 데이터 보호: HTTPS는 개인 정보, 금융 정보 등 민감한 데이터를 안전하게 보호한다.

2) 신뢰성: 사용자는 HTTPS를 사용하는 웹사이트를 더 신뢰하며, 이는 웹사이트의 신뢰도를 높인다.

3) SEO 개선: 검색 엔진은 HTTPS를 사용하는 웹사이트를 우선적으로 순위에 반영한다.

3-1-4. HTTPS 서버 구현 in Node.js

Node.js에서 https 모듈을 사용하여 HTTPS 서버를 구현할 수 있다. 서버를 구성하기 위해 SSL/TLS 인증서(.pem, .crt, .key 파일 등)가 필요하다. 이 인증서는 신뢰할 수 있는 인증 기관으로부터 발급받아야 한다. createServer 메서드를 사용하여 서버를 구성하고, 필요한 인증서 정보와 서버 로직을 제공한다.

const https = require('https');
const fs = require('fs');

https.createServer({
  cert: fs.readFileSync('도메인 인증서 경로'),
  key: fs.readFileSync('도메인 비밀키 경로'),
  ca: [
    fs.readFileSync('상위 인증서 경로'),
    fs.readFileSync('상위 인증서 경로'),
  ],
}, (req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
  res.write('<h1>Hello Node!</h1>');
  res.end('<p>Hello Server!</p>');
})
  .listen(443, () => {
    console.log('443번 포트에서 서버 대기 중입니다!');
  });

https_code

3-2. Http2

3-2-1. HTTP/2의 특징

1) 헤더 압축(Header Compression):

- HTTP/2는 HPACK 압축을 사용하여 헤더 데이터의 크기를 줄인다. 이는 불필요한 네트워크 트래픽 감소와 성능 향상에 기여한다.

2) 서버 푸시(Server Push):

- 서버가 클라이언트의 요청을 기다리지 않고, 미리 필요한 리소스를 클라이언트에게 푸시할 수 있다. 이를 통해 추가적인 라운드 트립 시간이 줄어들어 성능이 향상된다.

3) 멀티플렉싱(Multiplexing):

- HTTP/2는 한 커넥션에서 여러 요청과 응답을 동시에 전송할 수 있다. 이는 HTTP/1.1에서 발생하는 헤드-오브-라인 블로킹 문제를 해결하고, 네트워크 사용의 효율성을 높인다.

4) 스트림 우선순위(Stream Prioritization):

- 클라이언트는 리소스의 중요도에 따라 요청의 우선순위를 지정할 수 있다. 이를 통해 중요한 리소스의 로드 시간을 단축할 수 있다.

3-2-2. Node.js에서의 HTTP/2 구현

1) http2 모듈 사용:

 - Node.js에서 http2 모듈을 import하여 HTTP/2 기능을 사용한다.

2) SSL/TLS 인증서 사용:

 - createSecureServer 메서드를 통해 SSL/TLS 인증서를 사용하는 HTTP/2 서버를 구성한다.

 - 이는 HTTPS 연결을 통해 보안을 강화하고, HTTP/2 프로토콜의 이점을 활용할 수 있게 해준다.

3) 서버 구성 및 실행:

 - 서버 로직을 정의하고, 서버를 시작합니다. 이 과정에서 필요한 SSL/TLS 인증서 파일(예: .key, .cert)을 지정해야 한다.

const http2 = require('http2');
const fs = require('fs');

http2.createSecureServer({
  cert: fs.readFileSync('도메인 인증서 경로'),
  key: fs.readFileSync('도메인 비밀키 경로'),
  ca: [
    fs.readFileSync('상위 인증서 경로'),
    fs.readFileSync('상위 인증서 경로'),
  ],
}, (req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
  res.write('<h1>Hello Node!</h1>');
  res.end('<p>Hello Server!</p>');
})
  .listen(443, () => {
    console.log('443번 포트에서 서버 대기 중입니다!');
  });

https2_Code

4. Cluster

4-1. Cluster

1) 싱글 스레드 기본 동작: Node.js는 기본적으로 싱글 스레드로 동작하며, 이로 인해 CPU 코어를 하나만 사용한다.

2) Cluster 모듈의 역할: Cluster 모듈은 이러한 싱글 스레드 동작을 확장하여 멀티 코어 CPU를 모두 활용할 수 있도록 도와준다. 

3) 포트 공유: Cluster 모듈을 사용하면 여러 개의 노드 프로세스를 하나의 포트를 공유하여 실행할 수 있다. 이는 요청이 많이 들어왔을 때, 각 노드 프로세스가 요청을 분산 처리하는 데 도움이 된다.

4) 성능 개선: CPU 코어가 8개인 서버의 경우, 기본적으로는 하나의 코어만 사용되지만 Cluster 모듈을 사용하면 코어 하나당 노드 프로세스 하나를 배정하여 모든 코어를 활용할 수 있다.

5) 단점: Cluster 모듈을 사용하는 경우 컴퓨터 자원(메모리, 세션 데이터 등)을 공유하기 어려울 수 있다. 각 노드 프로세스는 독립적으로 실행되므로 메모리 사용량이 증가하거나 세션 관리가 복잡해질 수 있다. 이를 해결하기 위해서는 Redis와 같은 별도의 서버나 데이터베이스를 사용하여 데이터를 공유하고 동기화해야 할 수 있다.

4-2. Master

1) 마스터 프로세스:

마스터 프로세스는 Cluster 모듈을 사용하여 CPU 코어 수만큼 워커 프로세스를 생성하고 관리하는 부모 프로세스입니다. 마스터 프로세스는 주로 다음과 같은 역할을한다.

 - CPU 코어 수만큼 워커 프로세스를 생성하고 관리한다.

 - 워커 프로세스 간에 작업을 분배하고 로드 밸런싱을 수행한다.

 - 워커 프로세스의 동작을 모니터링하고 필요할 때 다시 생성한다.

 - 주로 마스터 프로세스는 웹 서버로 동작하며 클라이언트의 요청을 받는다.

2) 워커 프로세스:

워커 프로세스는 마스터 프로세스가 생성한 자식 프로세스로서 클라이언트의 요청을 처리하는 역할을 한다. 여러 개의 워커 프로세스가 동시에 실행되며 각각이 독립적으로 요청을 처리한다. 이로 인해 성능 향상과 요청 분산이 가능해진다.

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`마스터 프로세스 아이디: ${process.pid}`);
  // CPU 개수만큼 워커를 생산
  for (let i = 0; i < numCPUs; i += 1) {
    cluster.fork();
  }
  // 워커가 종료되었을 때
  cluster.on('exit', (worker, code, signal) => {
    console.log(`${worker.process.pid}번 워커가 종료되었습니다.`);
    console.log('code', code, 'signal', signal);
    cluster.fork();
  });
} else {
  // 워커들이 포트에서 대기
  http.createServer((req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
    res.write('<h1>Hello Node!</h1>');
    res.end('<p>Hello Cluster!</p>');
    setTimeout(() => { // 워커 존재를 확인하기 위해 1초마다 강제 종료
      process.exit(1);
    }, 1000);
  }).listen(8086);

  console.log(`${process.pid}번 워커 실행`);
}
728x90

'웹 서비스 개발(FB,BE,SERVER,DB) > Node.js' 카테고리의 다른 글

Express_Server2  (0) 2024.03.18
6. Express_Server  (1) 2024.03.15
4. Node.js WebServer  (0) 2024.03.12
3. Node.js_Basic2  (0) 2024.03.11
2. Node.js_Basic  (0) 2024.03.11

댓글