블로그 본문

[개발 환경 세팅] Node.js-Express 웹 애플리케이션 생성 및 mysql2 연결 라이브러리 연동 준비

📌 목차 바로가기

    지난 포스팅에서는 프리티어 가상 서버(t2/t3.micro)의 1GB 물리 램 한계로 발생하는 시스템 프리징 현상을 해결하기 위해 가상 메모리(Swap File 4GB)를 EBS gp3 볼륨에 할당하고 관리하는 리눅스 커널 최적화 과정을 수행했습니다. 이로써 대규모 압축 해제 연산이나 빌드 연산 시 서버가 비정상적으로 다운되는 현상을 완전 차단하여 안정적인 백엔드 개발 공간을 마련했습니다.

    이번 포스팅에서는 실제 웹 서비스의 핵심을 가동할 차례입니다. 원격 개발 서버에 디렉토리를 생성하여 Node.js 프로젝트를 초기화하고, 웹 백엔드 구축에 필수적인 라이브러리 패키지들을 설치하는 프로시저를 명세하겠습니다. 특히 데이터베이스 연결 효율성을 극대화해 주는 커넥션 풀(Connection Pool)의 아키텍처 구조를 RDBMS의 자원 통제 원리와 함께 상세히 분석해 드리겠습니다.

    1. 배포의 뼈대 설계: package.json과 멱등성(Idempotency)

    원격 가상 서버에 접속한 후 웹 백엔드 애플리케이션 개발을 위한 디렉토리를 생성하고 프로젝트 초기화 명령어를 실행하는 것으로 실습을 시작합니다.

    # Node.js 애플리케이션 개발 전용 디렉토리 생성 및 이동
    mkdir my-express-app
    cd my-express-app
    
    # 프로젝트 초기화 (기본 package.json 설정 명세서 생성)
    npm init -y
    

    npm init -y 명령어를 실행하면 해당 디렉토리에 프로젝트의 메타데이터와 패키지 의존성을 기록하는 package.json 파일이 자동으로 생성됩니다. 실무 관점에서 이 파일은 단순한 설정 텍스트 파일이 아닌 '배포 명세서' 역할을 합니다.

    • 멱등성(Idempotency)의 보장: package.json은 내 로컬 환경에서 개발하던 어플리케이션을 클라우드 EC2 인스턴스나 온프레미스 실서버로 이식할 때, 언제 어디서나 동일한 라이브러리 실행 환경을 완벽하게 재현하도록 보장합니다.
    • 의존성 일치: 협업 단계나 서비스 배포 시 복잡한 node_modules 폴더 전체를 압축해서 수송할 필요 없이, 오직 이 배포 명세서 파일 하나만 넘긴 뒤 원격지에서 npm install 명령어를 단 한 번 실행하는 것만으로 완전히 동일한 라이브러리 의존성 생태계를 구축할 수 있습니다.

    2. 백엔드 필수 7대 라이브러리 패키지 설치 및 명세

    프로젝트 초기화를 마친 뒤, 웹 애플리케이션의 핵심 기능을 수립하기 위해 7대 실무 패키지를 연이어 설치합니다.

    # Express 웹 프레임워크 및 데이터베이스 연동 핵심 라이브러리 설치
    npm install express express-session body-parser session-file-store cors mysql2 bcrypt
    

    설치되는 각 패키지의 기술적 가치와 역할 분담은 다음과 같습니다:

    1. express: Node.js용 초경량 웹 애플리케이션 프레임워크로, 미들웨어 기반 아키텍처 상에서 유연한 HTTP 라우팅과 API 서버 기능을 기본 제공합니다.
    2. mysql2: MySQL 데이터베이스와 연결하기 위한 드라이버 모듈입니다. 비동기 Promise 기반 프로그래밍을 완벽히 수용하며, SQL 인젝션 공격을 예방하는 준비된 문장(Prepared Statements) 제어 능력을 제공합니다.
    3. express-session: HTTP 프로토콜의 본질적인 한계인 무상태(Stateless) 특성을 해소하고 사용자의 로그인 상태를 유지하기 위해 가상의 세션 식별자를 생성하고 제어하는 미들웨어입니다.
    4. body-parser: 사용자가 입력창에 적은 HTTP 요청 바디(Body) 내부의 JSON이나 URL-encoded 데이터를 파싱하여 백엔드 변수로 즉시 매핑 처리해 줍니다. (Express 최신 버전에서는 내장 미들웨어로도 지원됩니다.)
    5. session-file-store: 서버 메모리에만 상주하다가 재부팅 시 휘발되어 증발하기 쉬운 세션 데이터들을 리눅스 파일 시스템에 물리적 파일 형태로 보존하여 상태 손실을 막아줍니다.
    6. cors: 서로 다른 도메인이나 포트(예: 프론트엔드 포트 3000 vs 백엔드 API 포트 5000) 사이에서 패킷 신호가 부딪힐 때 브라우저 보안에 의해 접속이 전면 차단되는 CORS(Cross-Origin Resource Sharing) 정책을 서버 측에서 유연하게 통제하도록 지원합니다.
    7. bcrypt: 사용자의 소중한 비밀번호를 일방향 해시 함수로 암호화하여 저장하고 검증하기 위한 암호학 라이브러리로, 단방향 솔트(Salt) 대입 연산을 통해 레인보우 테이블 공격을 예방합니다.

    3. 자원 효율성의 분수령: Single Connection vs Connection Pool

    백엔드 아키텍처 설계 단계에서 데이터베이스 연동을 기획할 때 마주하는 가장 결정적인 의사결정은 "어떤 방식으로 DB와 소통의 길을 뚫을 것인가"입니다. 여기에는 두 가지 명확한 기술 노선이 존재합니다.

    ① 단일 연결 방식 (createConnection)

    클라이언트의 요청이나 쿼리가 트리거 될 때마다, 그때그때 데이터베이스 서버와 새롭게 TCP 3-Way Handshake를 맺으며 통신 세션을 열고 작업 종료 후 다시 세션을 파괴하는 원시적인 구조입니다.

    • 장점: 백그라운드에서 유지하는 고정 자원이 없으므로 물리적인 메모리 점유율을 아주 낮게 통제할 수 있습니다.
    • 단점: 요청이 빈번하게 몰려들 때마다 매번 네트워크 연결 세션을 열고 닫는 오버헤드가 누적되므로 레이턴시가 극도로 증가하며, 동시 수천 명의 가입자가 들어오면 병목 현상과 함께 서버가 응답 불능 크래시를 겪게 됩니다.

    ② 연결 풀 방식 (createPool) - 실무 권장 표준

    메모리 영역 내에 데이터베이스와 미리 세팅을 끝마친 연결 객체(Connection) 여러 개를 마치 수영장(Pool) 안에 물을 받아두듯 사전에 여러 개 생성하여 가동 대기시키는 방식입니다.

    클라이언트의 HTTP 요청이 올 때마다 매번 새로 연결 세션을 맺지 않고, 미리 할당된 10개의 커넥션 풀(Connection Pool)에서 대기 중인 연결 객체를 고속 임대(Acquire) 및 반납(Release) 처리하여 DB 오버헤드를 극적으로 제어하는 mysql2 아키텍처 구성도
    • 동작 메커니즘: 요청이 들어오면 대기 상태인 연결 객체를 순식간에 빌려주고(Acquire) 연산 처리가 끝나면 다시 고스란히 풀 안으로 반납(Release)하여 재사용하게 만듭니다.
    • 장점: 네트워크 핸드쉐이크 절차가 생략되므로 응답 지연 속도가 극적으로 빨라지며, 최대 동시 연결 제한(connectionLimit) 속성을 통해 데이터베이스 서버의 자원 오버로드를 한계선 이하로 예방 통제할 수 있습니다.
    • 단점: 고정적으로 연결 객체들을 점유하고 유지해야 하므로 단일 연결 방식에 비해 점유하는 메모리 크기가 상대적으로 다소 큽니다.

    4. [코드 분석] mysql2/promise 패키지를 가동하는 db.js 구성 규칙

    실무 백엔드 개발에서 공통으로 적용하는 데이터베이스 연결 모듈(db.js)의 정밀 구성 옵션과 아키텍처적 선언 방법을 해부해 보겠습니다.

    // db.js - mysql2 promise 기반 연결 풀 설정
    const mysql = require('mysql2/promise');
    require('dotenv').config();
    
    // 데이터베이스 연결 풀 인스턴스 생성 및 세부 튜닝
    const db = mysql.createPool({
      host: process.env.MYSQL_HOST,            // 데이터베이스 엔드포인트 주소
      user: process.env.MYSQL_USER,            // 접속 계정명 (admin)
      password: process.env.MYSQL_PASSWORD,    // 마스터 암호 (mysql1234)
      database: process.env.MYSQL_DATABASE,    // 사용할 스키마 (shopping_db)
      waitForConnections: true,                // 가용 연결이 없을 때 대기열에서 대기할지 여부 (true)
      connectionLimit: 10,                     // 동시에 유지할 최대 데이터베이스 연결 세션 개수 (10개)
      queueLimit: 0                            // 대기열의 최대 한계 수치 (0 지정 시 무제한 대기 허용)
    });
    
    // 페일 패스트(Fail-Fast) 검증 장치 가동
    db.getConnection()
      .then(connection => {
        console.log('데이터베이스에 성공적으로 연결되었습니다.');
        connection.release();                  // 상태 검증 직후 자원을 쿨하게 풀로 즉각 반납
      })
      .catch(err => {
        console.error('데이터베이스 연결에 치명적 에러 발생:', err);
      });
    
    module.exports = db;
    

    ■ 설계 패턴 및 견고한 예외 수습 노하우

    • 페일 패스트(Fail-Fast) 전략: 이 db.js 파일은 백엔드 서버 웹 구동의 극초기 단계인 부팅 타임라인에 기상하여 db.getConnection()을 통해 RDS 본진에 핑(Ping)을 전송해 봅니다. 문제가 있다면 서버 시작 직후 곧바로 크래시 에러를 뿜으며 자진 종료하게 설계되어 있습니다. 나중에 사용자가 실시간 거래를 시도하다가 에러를 겪는 파국보다, 시스템 부팅 시 실패를 앞당겨 수습(Fail-Fast)하는 것이 아키텍처 안전성 측면에서 압도적으로 우수합니다.
    • 싱글톤(Singleton) 디자인 패턴: 마지막 줄의 module.exports = db를 통하여, 생성된 이 데이터베이스 연결 풀 인스턴스는 단 하나의 공통 싱글톤 객체 형태로 전역 애플리케이션 코드베이스에 이식됩니다. 불필요하게 코드 파일마다 새로운 커넥션 풀을 이중 개설하여 RDS 메모리를 중복 낭비하는 재앙을 원천 예방해 줍니다.

    마치며: 백엔드의 심장과 수송망이 완성되었습니다

    오늘 우리는 Node.js-Express 웹 어플리케이션을 초기화하고, 백엔드 수호를 위한 7대 패키지를 명세 완료하였으며, 단순 단일 연결의 오버헤드를 극복하고 무제한 트래픽 정체를 다스릴 커넥션 풀(Connection Pool)의 아키텍처 통합 설계를 이해했습니다.

    "매번 요청이 들어올 때마다 새롭게 DB 인프라 성문을 열고 닫으며 오버헤드 통행세를 내던 비효율을 탈출하여, 10차선의 고속도로 게이트를 사전에 상시 개방해 두고 자원을 실시간으로 재사용 통제하는 고성능 데이터 수송망을 마침내 빌딩해 낸 것입니다."

    든든하게 백엔드 웹 서버의 뼈대와 고속 수송망 셋업을 완료했으나, 아직 한 가지 중대한 보안적 아킬레스건이 남아 있습니다. 바로 이 db.js 파일 코드 뒤편에 들어가는 호스트 엔드포인트 주소와 마스터 패스워드 등 일급 정보들을 소스 코드에 그대로 노출해 두었다가 깃허브(GitHub)와 같은 공공 저장소에 무단 유출하는 참사를 대비해야 합니다.

    다음 포스팅이자 클라우드 아키텍처 및 DevSecOps의 핵심 보안 코딩의 정수라 할 수 있는 '[DevSecOps 보안 코딩] 소스 코드 유출을 대비하는 환경 변수(.env) 보호 기법과 깃허브(.gitignore) 연동 전략' 편에서는, 민감 정보들을 완벽하게 소스 코드에서 물리 격리하는 dotenv 환경 변수 차단선 구축 비법과 유출 사고를 원천 봉쇄하는 .gitignore 배포 규칙에 대해서 설명하겠습니다.

    오늘 package.json 디렉토리 초기화 과정에서 npm 버전 충돌이 났거나, createPool 옵션 간의 관계성이 아리송하다면 주저하지 말고 운영자 메일로 문의주세요. 오늘도 안전하고 영리한 클라우딩 라이프 하세요. 감사합니다! 😉

    출처

    • 이현호. 실무 프로젝트로 완성하는 클라우드 환경에서 DB 구축과 웹 개발. 길벗캠퍼스. 2026.04. (4.3장 '로컬 개발 환경 구축 - 관련 패키지 설치', 114-115페이지 및 7.1장 'DB 연결 모듈(db.js)', 174-177페이지 참조)
    • 이현호. "07장. 애플리케이션_개발_-_DB_연결_및_사용자인증" 설명 오디오 가이드 스크립트 기반 createConnection() vs createPool() 아키텍처 딜레마 극복 및 db.js 파일의 싱글톤과 페일패스트 전략 대화록 완벽 반영.
    • Express.js Guide - Installing & Getting Started (https://expressjs.com/) 및 mysql2 Connection Pools API Reference Manual.

    자주 묻는 질문 (FAQ)

    Q. mysql2 라이브러리의 단일 연결(createConnection)과 연결 풀(createPool)의 가장 결정적인 성능 차이는 무엇인가요?

    A. 매번 새로운 연결 세션을 맺을 때 발생하는 네트워크 핸드쉐이크 오버헤드 유무입니다. 단일 연결은 요청마다 연결을 새로 생성해 느리지만, 연결 풀은 대기 중인 연결 객체를 즉시 재사용하므로 응답 지연(Latency)을 극적으로 단축시킬 수 있습니다.

    Q. Connection Pool 설정값 중에서 'waitForConnections'와 'connectionLimit'의 상호 관계는 어떻게 되나요?

    A. 동시 최대 연결 한도 초과 시 대기 여부의 차이입니다. 'waitForConnections'가 true이면 초과 연결 요청을 에러 없이 대기열에 임시 보관하여 차례대로 처리하며, false이면 대기 없이 데이터베이스 연결 실패 오류를 즉각 즉각 반환합니다.

    Q. 데이터베이스 공통 연결 모듈인 db.js 맨 하단에 'getConnection()' 검증 코드를 굳이 넣어서 실행해 보는 진짜 이유는 무엇인가요?

    A. 서버 초기 기상 시 연결 안전성을 선제 보증하는 페일 패스트(Fail-Fast) 전략입니다. 구동 즉시 DB 핑 테스트를 실행하여 예기치 못한 원격 연결 장애가 발견되면 서버를 즉각 강제 종료시켜 실제 사용자 요청 중의 오류 발생을 원천 차단해 줍니다.