목차
⚡ PM2
PM2는 Node.js 애플리케이션을 위한 프로덕션 프로세스 관리자로, 애플리케이션을 항상 활성 상태로 유지하고 성능을 모니터링합니다.
1. 📋 정의
PM2는 Node.js 애플리케이션을 위한 오픈소스 프로세스 관리자입니다. 이는 애플리케이션을 데몬으로 실행하고, 클러스터 모드를 지원하며, 로드 밸런싱과 모니터링 기능을 제공하여 서버 환경에서 Node.js 애플리케이션을 안정적으로 운영할 수 있도록 돕습니다.
2. 🎯 주요 특징
PM2가 제공하는 핵심 기능들은 다음과 같습니다.
1) 프로세스 관리
PM2는 애플리케이션의 생명 주기를 관리하여 안정적인 운영을 보장합니다.
- 애플리케이션을 백그라운드에서 실행: 서버 재부팅이나 터미널 종료 후에도 애플리케이션이 계속 실행되도록 합니다.
- 자동 재시작 기능: 예기치 않은 오류로 애플리케이션이 종료될 경우 자동으로 재시작하여 서비스 중단을 최소화합니다.
- 프로세스 상태 모니터링: 각 애플리케이션 인스턴스의 현재 상태(실행 중, 중지됨 등)를 쉽게 확인할 수 있습니다.
2) 클러스터 모드
PM2의 클러스터 모드는 Node.js 애플리케이션의 성능과 가용성을 향상시키는 데 매우 중요합니다.
- CPU 코어 수에 맞춰 여러 인스턴스 실행: 단일 스레드인 Node.js의 한계를 극복하고 멀티 코어 CPU를 효율적으로 활용하여 처리량을 늘립니다.
- 로드 밸런싱 자동 처리: 여러 인스턴스 간에 들어오는 요청을 자동으로 분산하여 특정 인스턴스에 부하가 집중되는 것을 방지합니다.
- 고가용성 보장: 한 인스턴스에 문제가 발생해도 다른 인스턴스가 요청을 처리하여 서비스 전체의 중단을 막습니다.
3) 모니터링 및 로깅
PM2는 애플리케이션의 성능을 실시간으로 파악하고 로그를 체계적으로 관리하는 기능을 제공합니다.
- 실시간 성능 모니터링: CPU, 메모리 사용량 등 핵심 메트릭을 실시간으로 확인하여 성능 병목 현상을 식별할 수 있습니다.
- 로그 관리 및 로테이션: 애플리케이션의 표준 출력(stdout)과 에러 출력(stderr)을 파일로 기록하고, 로그 파일이 너무 커지는 것을 방지하기 위한 로테이션 기능을 지원합니다.
- 메트릭 수집: PM2 모듈을 통해 다양한 시스템 및 애플리케이션 메트릭을 수집하고 시각화할 수 있습니다.
3. 🚀 설치 및 기본 사용법
PM2를 시스템에 설치하고 간단한 명령어로 애플리케이션을 실행하는 방법을 알아봅니다.
1) PM2 설치
PM2는 npm을 통해 전역으로 설치합니다. 전역 설치는 어떤 디렉토리에서든 pm2
명령어를 사용할 수 있게 해줍니다.
# 전역 설치: PM2를 시스템 어디서든 사용할 수 있도록 설치합니다. npm install -g pm2 # 버전 확인: 설치가 제대로 되었는지 확인하고 현재 PM2 버전을 출력합니다. pm2 --version
2) 기본 명령어
PM2를 사용하여 Node.js 애플리케이션을 시작하고 관리하는 기본적인 명령어들입니다.
# 애플리케이션 시작: 'app.js' 파일을 PM2를 통해 백그라운드에서 실행합니다. pm2 start app.js # 이름 지정하여 시작: 애플리케이션에 'my-app'이라는 식별하기 쉬운 이름을 부여하여 실행합니다. pm2 start app.js --name "my-app" # 클러스터 모드로 시작: 시스템의 모든 CPU 코어를 활용하여 최대 인스턴스 수만큼 애플리케이션을 실행합니다. pm2 start app.js -i max # 특정 포트로 시작: 애플리케이션에 인수를 전달하여 '3000'번 포트로 시작하도록 합니다. '--' 뒤의 인수는 애플리케이션 자체로 전달됩니다. pm2 start app.js -- --port 3000
4. ⚙️ 설정 파일
ecosystem.config.js
파일을 사용하여 PM2 애플리케이션을 보다 세밀하게 설정할 수 있습니다. 이 파일은 여러 애플리케이션과 환경별 설정을 정의하는 데 유용합니다.
1) ecosystem.config.js 예시
다음은 일반적인 ecosystem.config.js
파일의 구조와 각 속성에 대한 설명입니다.
module.exports = { apps: [{ // 이 배열 안에 관리할 애플리케이션들의 설정을 정의합니다. name: 'baduk-metaverse', // 애플리케이션의 고유 이름입니다. 'pm2 list'에서 이 이름으로 표시됩니다. script: 'server.js', // 실행할 애플리케이션의 메인 스크립트 파일 경로입니다. instances: 'max', // 실행할 인스턴스(워커 프로세스)의 수입니다. 'max'는 CPU 코어 수만큼 생성합니다. exec_mode: 'cluster', // 실행 모드입니다. 'cluster'는 로드 밸런싱을 지원하는 클러스터 모드입니다. env: { // 기본 환경 변수 설정입니다. NODE_ENV: 'development', // 개발 환경임을 나타내는 Node.js 환경 변수입니다. PORT: 3000 // 애플리케이션이 사용할 포트 번호입니다. }, env_production: { // 'pm2 start --env production' 명령어로 실행 시 적용될 환경 변수입니다. NODE_ENV: 'production', // 프로덕션 환경임을 나타냅니다. PORT: 3000 // 프로덕션 환경에서 사용할 포트입니다. }, // 로그 설정 log_file: './logs/combined.log', // 모든 로그(stdout + stderr)가 기록될 파일 경로입니다. out_file: './logs/out.log', // 표준 출력(console.log)이 기록될 파일 경로입니다. error_file: './logs/error.log', // 에러 출력(console.error)이 기록될 파일 경로입니다. log_date_format: 'YYYY-MM-DD HH:mm:ss Z', // 로그 파일에 기록될 시간 형식입니다. // 자동 재시작 설정 autorestart: true, // 애플리케이션이 종료될 경우 자동으로 재시작할지 여부입니다. (기본값: true) watch: false, // 파일 변경 감지 여부입니다. 개발 시에는 'true'로 설정할 수 있지만, 프로덕션에서는 성능 저하를 일으킬 수 있어 'false'가 권장됩니다. max_memory_restart: '1G', // 프로세스 메모리 사용량이 이 값을 초과하면 재시작합니다. 메모리 누수 방지에 유용합니다. // 환경 변수 파일 env_file: '.env' // '.env' 파일에서 환경 변수를 로드합니다. }] };
이 설정 파일을 사용하여 애플리케이션을 시작하려면 다음 명령어를 사용합니다:
pm2 start ecosystem.config.js # 기본 환경 변수(env)로 시작 pm2 start ecosystem.config.js --env production # 'env_production'에 정의된 환경 변수로 시작
5. 🎮 프로세스 관리
PM2는 실행 중인 애플리케이션 프로세스를 효과적으로 제어하고 상태를 확인하는 다양한 명령어를 제공합니다.
1) 프로세스 제어
실행 중인 애플리케이션을 중지, 재시작, 삭제하는 명령어입니다.
# 애플리케이션 중지: 'my-app'이라는 이름의 애플리케이션을 중지합니다. pm2 stop my-app # 애플리케이션 재시작: 'my-app' 애플리케이션을 재시작합니다. 코드 변경 후 적용할 때 유용합니다. pm2 restart my-app # 애플리케이션 삭제: 'my-app' 애플리케이션을 PM2 목록에서 제거하고 완전히 중지시킵니다. pm2 delete my-app # 모든 애플리케이션 중지: PM2가 관리하는 모든 애플리케이션을 중지합니다. pm2 stop all # 모든 애플리케이션 재시작: PM2가 관리하는 모든 애플리케이션을 재시작합니다. pm2 restart all
2) 상태 확인
실행 중인 애플리케이션의 상태, 로그, 상세 정보를 확인하는 명령어입니다.
# 실행 중인 프로세스 목록: PM2가 관리하는 모든 애플리케이션의 간략한 상태(ID, 이름, 모드, 상태, CPU, 메모리 등)를 보여줍니다. pm2 list # 상세 정보 확인: 'my-app' 애플리케이션의 상세한 정보(환경 변수, 로그 경로, 재시작 횟수 등)를 출력합니다. pm2 show my-app # 로그 확인: 'my-app' 애플리케이션의 표준 출력 및 에러 로그를 실시간으로 스트리밍하여 보여줍니다. pm2 logs my-app # 실시간 로그 모니터링: 'my-app'의 로그를 실시간으로 확인하며, 최신 100줄을 보여줍니다. pm2 logs my-app --lines 100
6. 📊 모니터링
PM2는 애플리케이션과 시스템의 상태를 시각적으로 모니터링할 수 있는 강력한 도구를 제공합니다.
1) 대시보드 실행
PM2에는 터미널 기반의 실시간 모니터링 대시보드가 내장되어 있습니다.
# 실시간 모니터링 대시보드: PM2가 관리하는 모든 프로세스의 CPU, 메모리 사용량, 로그 등을 실시간으로 보여주는 대시보드를 실행합니다.
pm2 monit
2) 성능 모니터링 유틸리티
애플리케이션의 성능 관련 정보를 확인하고 관리하는 명령어들입니다.
# CPU/메모리 사용량 확인: 'my-app' 애플리케이션의 CPU 및 메모리 사용량을 포함한 상세 정보를 확인합니다. (위 'pm2 show'와 중복되지만, 성능 관점에서 다시 언급) pm2 show my-app # 로그 파일 크기 확인 및 정리: 모든 애플리케이션의 로그 파일을 비웁니다. 로그 파일이 너무 커졌을 때 공간 확보에 유용합니다. pm2 flush # 웹 기반 메트릭 확인: PM2 Web UI를 통해 웹 브라우저에서 PM2가 관리하는 프로세스의 메트릭을 확인할 수 있습니다. pm2 web
3) 메트릭 수집 모듈
PM2는 다양한 모듈을 설치하여 시스템 및 애플리케이션 메트릭을 확장할 수 있습니다.
# PM2 서버 모니터링 활성화: 서버의 CPU, 메모리, 디스크, 네트워크 등 시스템 자원 사용량을 모니터링하는 모듈을 설치합니다. pm2 install pm2-server-monit # 커스텀 메트릭 추가: 애플리케이션 특정 메트릭을 수집하고 PM2 대시보드에서 볼 수 있도록 하는 모듈을 설치합니다. pm2 install pm2-custom-metrics
7. 🔄 자동화
PM2를 이용하여 시스템 재부팅 시 애플리케이션이 자동으로 시작되도록 설정하고, 배포 과정을 자동화할 수 있습니다.
1) 시스템 부팅 시 자동 시작
서버가 재부팅될 때 PM2가 관리하는 애플리케이션들이 자동으로 다시 시작되도록 설정합니다.
# PM2 시작 스크립트 생성: 현재 운영체제(예: systemd, Upstart)에 맞는 PM2 시작 스크립트를 생성하고 등록합니다. 이 명령어를 실행하면 사용법이 안내됩니다. pm2 startup # 현재 실행 중인 앱들을 저장: 현재 PM2에 의해 관리되고 있는 모든 애플리케이션의 목록과 상태를 저장합니다. 'pm2 startup'으로 생성된 스크립트는 이 저장된 목록을 사용하여 재부팅 시 앱을 시작합니다. pm2 save # 저장된 앱들을 복원: 이전에 'pm2 save'로 저장된 애플리케이션 목록을 불러와 다시 실행합니다. pm2 resurrect
2) 배포 스크립트
애플리케이션 배포 과정을 자동화하기 위한 간단한 쉘 스크립트 예시입니다. 이 스크립트는 새로운 코드를 가져오고, 의존성을 설치하며, PM2를 통해 애플리케이션을 재시작하는 과정을 자동화합니다.
#!/bin/bash # deploy.sh # 이 스크립트는 새로운 코드를 배포하고 애플리케이션을 재시작하는 과정을 자동화합니다. echo "🚀 배포 시작..." # 기존 프로세스 중지: 현재 실행 중인 'baduk-metaverse' 애플리케이션을 중지합니다. pm2 stop baduk-metaverse # 코드 업데이트: Git 저장소에서 최신 코드를 가져옵니다. (예: main 브랜치) git pull origin main # 의존성 설치: 'package.json'에 정의된 Node.js 모듈들을 새로 설치하거나 업데이트합니다. npm install # 프로덕션 환경으로 시작: 'ecosystem.config.js'에 정의된 'env_production' 환경으로 애플리케이션을 시작합니다. pm2 start ecosystem.config.js --env production # 상태 확인: 모든 PM2 애플리케이션의 현재 상태를 확인하여 배포가 성공적으로 이루어졌는지 검증합니다. pm2 list echo "✅ 배포 완료!"
8. 🛠️ 문제 해결
PM2 사용 중 발생할 수 있는 일반적인 문제들과 그 해결 방법을 안내합니다.
1) 메모리 부족
애플리케이션이 너무 많은 메모리를 사용하거나 메모리 누수가 발생할 때 나타나는 문제입니다.
- 증상: 애플리케이션이 예상치 못하게 종료되거나, 서버 전체의 성능이 저하됩니다.
- 해결 방법:
- 메모리 사용량 확인:
pm2 show
명령어를 통해 특정 애플리케이션의 현재 메모리 사용량을 확인합니다.
# 메모리 사용량 확인
pm2 show my-app
- 메모리 제한 설정:
ecosystem.config.js
또는pm2 start
명령어에max_memory_restart
옵션을 추가하여 특정 메모리 사용량을 초과하면 자동으로 재시작하도록 설정합니다.
# 메모리 제한 설정: 애플리케이션이 1GB 메모리를 초과하면 자동으로 재시작합니다. pm2 start app.js --max-memory-restart 1G
2) 로그 파일이 너무 큼
애플리케이션 로그 파일이 과도하게 커져 디스크 공간을 많이 차지하는 문제입니다.
- 증상: 디스크 공간 부족 경고가 발생하거나, 로그 파일을 열기 어렵습니다.
- 해결 방법:
- 로그 파일 정리:
pm2 flush
명령어로 모든 애플리케이션의 로그 내용을 지웁니다.
# 로그 파일 정리
pm2 flush
- 로그 로테이션 설정:
pm2-logrotate
모듈을 설치하여 로그 파일이 일정 크기가 되면 자동으로 압축하거나 삭제하도록 규칙을 설정합니다.
# 로그 로테이션 설정: PM2 로그 로테이션 모듈을 설치합니다. pm2 install pm2-logrotate
3) 프로세스가 자주 재시작됨
애플리케이션이 반복적으로 충돌하여 PM2에 의해 자동으로 재시작되는 문제입니다.
- 증상:
pm2 list
에서restarts
횟수가 지속적으로 증가합니다. - 해결 방법:
- 재시작 횟수 확인:
pm2 show
명령어로 특정 애플리케이션의 재시작 횟수를 확인합니다.
# 재시작 횟수 확인
pm2 show my-app
- 로그에서 에러 확인: 에러 로그를 확인하여 재시작의 원인이 되는 오류 메시지를 찾습니다.
# 로그에서 에러 확인: 'my-app' 애플리케이션의 에러 로그만 확인합니다. pm2 logs my-app --err
4) 포트 충돌
애플리케이션이 이미 사용 중인 포트를 사용하려고 할 때 발생하는 문제입니다.
- 증상: 애플리케이션이 시작되지 않거나 “Address already in use”와 같은 에러 메시지가 발생합니다.
- 해결 방법:
- 사용 중인 포트 확인:
netstat
명령어를 사용하여 특정 포트를 사용 중인 프로세스를 확인합니다.
# 사용 중인 포트 확인: '3000'번 포트를 사용 중인 프로세스를 확인합니다. netstat -tulpn | grep :3000
- 다른 포트로 실행: 애플리케이션을 다른 사용 가능한 포트 번호로 시작하도록 설정합니다.
# 다른 포트로 실행: '3001'번 포트로 'app.js'를 시작합니다. pm2 start app.js -- --port 3001
9. 📈 성능 최적화
PM2를 이용하여 Node.js 애플리케이션의 성능을 극대화하는 방법을 알아봅니다.
1) 클러스터 모드 설정 및 활용
Node.js의 단일 스레드 모델 한계를 극복하기 위해 PM2의 클러스터 모드를 활용하는 방법입니다. ecosystem.config.js
에서 instances: 'max
와
exec_mode: 'cluster를 설정하는 것 외에, 애플리케이션 코드 자체에서 클러스터 모드를 지원하도록 구성할 수도 있습니다.
// server.js에서 클러스터 모드 지원: Node.js의 'cluster' 모듈을 직접 사용하여 마스터-워커 구조를 구현합니다. const cluster = require('cluster'); // Node.js 내장 'cluster' 모듈을 불러옵니다. const numCPUs = require('os').cpus().length; // 시스템의 CPU 코어 수를 가져옵니다. if (cluster.isMaster) { // 현재 프로세스가 마스터(부모) 프로세스인지 확인합니다. console.log(`마스터 프로세스 ${process.pid} 실행 중`); // 워커 프로세스 생성: CPU 코어 수만큼 워커(자식) 프로세스를 생성합니다. 각 워커는 애플리케이션의 독립적인 인스턴스가 됩니다. for (let i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', (worker, code, signal) => { // 워커 프로세스가 종료될 때 발생하는 이벤트를 감지합니다. console.log(`워커 ${worker.process.pid} 종료`); cluster.fork(); // 종료된 워커를 대체할 새로운 워커를 생성하여 고가용성을 유지합니다. }); } else { // 워커 프로세스에서 서버 실행: 현재 프로세스가 워커인 경우, 실제 Node.js 서버 애플리케이션을 실행합니다. require('./server.js'); // 예를 들어, Express 앱이 정의된 'server.js' 파일을 로드합니다. }
PM2를 사용할 경우, ecosystem.config.js
의 exec_mode: 'cluster
와
instances: 'max 설정을 통해 이 모든 것을 PM2가 자동으로 처리해주므로, 위와 같은 코드를 직접 작성할 필요는 없습니다. 하지만 Node.js의 클러스터 모드 동작 방식을 이해하는 데 도움이 됩니다.
2) 메모리 최적화
Node.js 애플리케이션의 메모리 사용량을 주기적으로 관리하여 메모리 누수를 방지하고 안정성을 높이는 방법입니다.
// 주기적인 메모리 정리: Node.js의 가비지 컬렉션(GC)을 수동으로 트리거하여 사용되지 않는 메모리를 해제합니다. setInterval(() => { if (global.gc) { // 'global.gc'는 Node.js를 '--expose-gc' 플래그와 함께 실행했을 때만 사용 가능합니다. global.gc(); // 가비지 컬렉션을 명시적으로 실행합니다. console.log('🧹 가비지 컬렉션 실행'); } else { console.log('가비지 컬렉션은 --expose-gc 플래그가 필요합니다.'); } }, 60000); // 1분(60000 밀리초)마다 가비지 컬렉션을 시도합니다.
주의: global.gc()
는 Node.js를 –expose-gc
플래그와 함께 실행해야만 사용할 수 있습니다. 프로덕션 환경에서는 이 기능을 신중하게 사용해야 하며, 일반적으로 Node.js의 자동 가비지 컬렉션에 의존하는 것이 권장됩니다. PM2의 max_memory_restart
옵션이 더 안전하고 일반적인 메모리 관리 방법입니다.
10. 🔧 고급 설정
PM2를 이용하여 더욱 복잡한 배포 시나리오나 운영 환경에 맞게 애플리케이션을 설정하는 방법을 알아봅니다.
1) 로드 밸런싱 세부 설정
PM2 클러스터 모드는 자체적인 로드 밸런싱을 제공하지만, 외부 로드 밸런서(예: Nginx)와 함께 사용할 경우 각 인스턴스를 특정 포트에 바인딩할 수 있습니다.
- PM2 자체 로드 밸런싱:
ecosystem.config.js
에서instances
수를 지정하여 PM2가 자동으로 여러 인스턴스를 실행하고 요청을 분산하도록 합니다.
# 로드 밸런서 설정: 'ecosystem.config.js'에 정의된 애플리케이션을 4개의 인스턴스로 실행하여 PM2가 로드 밸런싱을 처리하도록 합니다. pm2 start ecosystem.config.js -i 4
- 외부 로드 밸런서와 연동: Nginx와 같은 외부 로드 밸런서를 사용하는 경우, PM2가 관리하는 각 애플리케이션 인스턴스를 서로 다른 포트에서 실행하도록 설정할 수 있습니다.
# 특정 포트로 바인딩: 각 PM2 인스턴스를 고유한 포트(3001, 3002 등)에서 실행하여 외부 로드 밸런서가 이들 포트로 요청을 전달할 수 있도록 합니다. pm2 start server.js --name "baduk-1" -- --port 3001 pm2 start server.js --name "baduk-2" -- --port 3002
2) 환경별 설정 활용
ecosystem.config.js
파일 내에서 개발, 스테이징, 프로덕션 등 다양한 환경에 따라 다른 변수들을 설정하고 관리할 수 있습니다.
// ecosystem.config.js: 다양한 환경에 따른 설정 예시 module.exports = { apps: [{ name: 'baduk-metaverse', script: 'server.js', instances: 'max', env: { // 기본 환경 (예: 개발 환경) NODE_ENV: 'development', PORT: 3000 }, env_staging: { // 'pm2 start --env staging' 시 적용될 환경 NODE_ENV: 'staging', PORT: 3001 }, env_production: { // 'pm2 start --env production' 시 적용될 환경 NODE_ENV: 'production', PORT: 3000 } }] };
이 설정을 사용하면, 단일 설정 파일로 여러 환경에 맞는 애플리케이션을 쉽게 관리할 수 있습니다. 예를 들어, pm2 start ecosystem.config.js –env production
명령어를 실행하면 env_production
블록의 설정이 활성화됩니다.
3) 헬스체크 설정
애플리케이션이 정상적으로 작동하는지 외부 시스템이 확인할 수 있도록 헬스체크 엔드포인트를 구현하는 것은 매우 중요합니다. PM2는 직접적인 헬스체크 기능을 제공하지 않으므로, 애플리케이션 코드 내에서 구현해야 합니다.
// Express.js 기반의 헬스체크 엔드포인트 예시 // 이 코드는 애플리케이션이 정상적으로 응답하는지 확인할 수 있는 '/health' 경로를 만듭니다. app.get('/health', (req, res) => { res.status(200).json({ // HTTP 상태 코드 200 (OK)과 JSON 응답을 보냅니다. status: 'ok', // 애플리케이션 상태 timestamp: new Date().toISOString(), // 현재 시간 uptime: process.uptime() // 프로세스 실행 시간 (초 단위) }); });
이러한 헬스체크 엔드포인트는 로드 밸런서나 컨테이너 오케스트레이션 도구(예: Kubernetes)가 애플리케이션의 상태를 모니터링하고 비정상적인 인스턴스를 트래픽에서 제외하거나 재시작하는 데 활용됩니다.
11. 📚 관련 용어
PM2와 관련된 주요 기술 용어들을 간략히 설명합니다.
- Node.js - Chrome V8 JavaScript 엔진으로 빌드된 JavaScript 런타임으로, 서버 측 애플리케이션 개발에 사용됩니다.
- Cluster - 여러 프로세스를 하나의 논리적 단위로 묶어 병렬 처리를 가능하게 하는 기술입니다. Node.js에서는 멀티 코어 CPU 활용에 사용됩니다.
- 로드 밸런싱 - 여러 서버나 애플리케이션 인스턴스에 네트워크 트래픽을 분산하여 시스템의 성능, 가용성, 확장성을 최적화하는 기술입니다.
- 모니터링 - 시스템, 애플리케이션, 네트워크 등의 성능과 상태를 지속적으로 감시하고 데이터를 수집하는 활동입니다.
- 배포 - 개발된 소프트웨어를 실제 운영 환경에 설치하고 실행 가능하도록 만드는 과정입니다.
12. 🔗 관련 문서
PM2와 관련된 추가 정보를 얻을 수 있는 문서들입니다.
- PM2 프로세스 관리 - DokuWiki 내부의 PM2 관련 문서입니다.
- Node.js 백엔드 설정 - Node.js 백엔드 구성을 위한 일반적인 가이드입니다.
- Linux - PM2와 Node.js 애플리케이션이 주로 배포되는 서버 운영체제에 대한 정보입니다.
- Nginx - 웹 서버이자 리버스 프록시로, PM2와 함께 로드 밸런서로 자주 사용됩니다.
— 이 페이지는 자동으로 생성되었습니다.