icon

서버리스 NestJS (AWS Lambda 통합)


 서버리스 아키텍처는 개발자가 서버 관리 없이 애플리케이션을 구축하고 실행할 수 있게 해주는 클라우드 컴퓨팅 실행 모델입니다.

 AWS Lambda와 같은 서비스를 사용하면 NestJS 애플리케이션을 서버리스로 구현할 수 있으며, 이는 여러 이점을 제공합니다.

서버리스 아키텍처의 이점

  1. 인프라 관리 최소화
  2. 자동 확장성
  3. 비용 효율성 (사용한 만큼만 지불)
  4. 높은 가용성
  5. 빠른 배포 및 업데이트

NestJS의 서버리스 구현 장단점

 장점

  • 확장성과 비용 효율성 향상
  • 인프라 관리 부담 감소
  • 빠른 개발 및 배포 주기

 단점

  • 콜드 스타트로 인한 지연 가능성
  • 실행 시간 제한
  • 상태 유지의 어려움
  • 로컬 개발 및 디버깅의 복잡성

AWS Lambda에 NestJS 배포 과정

  1. NestJS 프로젝트 준비
nest new serverless-nestjs
cd serverless-nestjs
npm install aws-lambda aws-serverless-express
  1. Lambda 핸들러 생성 (src/lambda.ts)
import { Handler, Context } from 'aws-lambda';
import { Server } from 'http';
import { createServer, proxy } from 'aws-serverless-express';
import { eventContext } from 'aws-serverless-express/middleware';
import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';
import { AppModule } from './app.module';
import * as express from 'express';
 
let cachedServer: Server;
 
async function bootstrap(): Promise<Server> {
  if (!cachedServer) {
    const expressApp = express();
    const nestApp = await NestFactory.create(
      AppModule,
      new ExpressAdapter(expressApp)
    );
    nestApp.use(eventContext());
    await nestApp.init();
    cachedServer = createServer(expressApp);
  }
  return cachedServer;
}
 
export const handler: Handler = async (event: any, context: Context) => {
  cachedServer = await bootstrap();
  return proxy(cachedServer, event, context, 'PROMISE').promise;
};
  1. Serverless Framework 설정 (serverless.yml)
service: serverless-nestjs
 
provider:
  name: aws
  runtime: nodejs14.x
  stage: ${opt:stage, 'dev'}
  region: ${opt:region, 'us-east-1'}
 
functions:
  main:
    handler: dist/lambda.handler
    events:
      - http:
          method: ANY
          path: /{proxy+}
  1. 빌드 및 배포
npm run build
serverless deploy

Serverless Framework 활용

 Serverless Framework를 사용하면 배포 프로세스를 자동화하고 관리할 수 있습니다.

  1. 설치 : npm install -g serverless
  2. 플러그인 추가 : serverless plugin install -n serverless-offline
  3. 로컬 테스트 : serverless offline
  4. 배포 : serverless deploy

AWS API Gateway 통합

 API Gateway는 Lambda 함수를 HTTP 엔드포인트로 노출시킵니다. NestJS의 컨트롤러는 자동으로 API Gateway와 매핑됩니다.

@Controller('users')
export class UsersController {
  @Get()
  findAll(): string {
    return 'This action returns all users';
  }
}

 주의사항

  • CORS 설정 필요
  • 바이너리 데이터 처리 시 추가 설정 필요

데이터베이스 연동 (Amazon DynamoDB)

  1. DynamoDB 클라이언트 설정
import { DynamoDB } from 'aws-sdk';
 
const dynamoDB = new DynamoDB.DocumentClient();
  1. NestJS 서비스에서 사용
@Injectable()
export class UsersService {
  async findAll(): Promise<User[]> {
    const result = await dynamoDB.scan({
      TableName: 'Users'
    }).promise();
    return result.Items as User[];
  }
}

로컬 개발 및 디버깅

  1. serverless-offline 플러그인 사용
  2. AWS SAM CLI 활용
  3. 로컬 DynamoDB 설정

 로컬 디버깅 설정 (launch.json)

{
  "type": "node",
  "request": "launch",
  "name": "Debug Serverless",
  "program": "${workspaceRoot}/node_modules/serverless/bin/serverless",
  "args": ["offline"],
  "env": { "NODE_ENV": "development" },
  "console": "integratedTerminal"
}

성능 최적화 전략

 **1. 콜드 스타트 최소화

  • 함수 크기 줄이기**
  • 외부 의존성 최소화
  • Provisioned Concurrency 사용

 2. 메모리 관리

  • 적절한 메모리 할당
  • 글로벌 변수 활용 (핸들러 외부)

 3. 연결 풀링

  • 데이터베이스 연결 재사용

 4. 비동기 처리 최적화

async function handler(event) {
  const [result1, result2] = await Promise.all([
    someAsyncOperation1(),
    someAsyncOperation2()
  ]);
  // 처리 로직
}

모니터링과 로깅

 AWS CloudWatch와 통합

  1. 로그 그룹 자동 생성
  2. 커스텀 메트릭 생성
import { CloudWatch } from 'aws-sdk';
 
const cloudwatch = new CloudWatch();
 
await cloudwatch.putMetricData({
  Namespace: 'MyApp',
  MetricData: [{
    MetricName: 'ProcessingTime',
    Value: processingTime,
    Unit: 'Milliseconds'
  }]
}).promise();
  1. 알람 설정
  • 에러율
  • 지연 시간
  • 호출 횟수

Best Practices 및 주의사항

  1. 함수 크기 최소화 : 필요한 의존성만 포함
  2. 상태 비저장 설계 : Lambda의 휘발성 고려
  3. 에러 처리 강화 : 모든 예외 상황 고려
  4. 환경 변수 활용 : 설정 정보 관리
  5. VPC 내 리소스 접근 시 주의 : 콜드 스타트 영향
  6. 타임아웃 설정 최적화 : 기본값 3초 주의
  7. X-Ray 통합 : 분산 추적 구현
  8. 정기적인 성능 테스트 : 부하 테스트 수행
  9. 보안 강화 : IAM 역할 최소 권한 원칙 적용
  10. 비용 모니터링 : 사용량 추적 및 최적화

 서버리스 NestJS 애플리케이션을 AWS Lambda에 통합하는 것은 확장성, 비용 효율성, 관리 용이성 등 많은 이점을 제공합니다.

 그러나 이러한 이점을 최대한 활용하기 위해서는 서버리스 아키텍처의 특성을 이해하고 이에 맞게 애플리케이션을 설계해야 합니다.

 AWS Lambda에 NestJS 애플리케이션을 배포하는 과정에서는 Lambda 핸들러를 적절히 구성하고, Serverless Framework를 활용하여 배포 프로세스를 자동화하는 것이 중요합니다. API Gateway와의 통합을 통해 RESTful API를 쉽게 구현할 수 있으며, 이 과정에서 CORS 설정과 같은 주의사항에 유의해야 합니다.

 데이터베이스 연동에 있어서는 Amazon DynamoDB와 같은 서버리스 데이터베이스 서비스를 활용하는 것이 효과적입니다. 이를 통해 확장성과 관리 용이성을 높일 수 있습니다. 그러나 연결 관리와 쿼리 최적화에 주의를 기울여야 합니다.

 로컬 개발과 디버깅은 서버리스 환경에서 특히 중요한 과제입니다. serverless-offline 플러그인이나 AWS SAM CLI를 활용하여 로컬 환경에서 Lambda 함수를 테스트하고 디버깅할 수 있습니다. 이는 개발 생산성을 크게 향상시킬 수 있습니다.

 성능 최적화는 서버리스 애플리케이션에서 중요한 고려사항입니다. 콜드 스타트를 최소화하고, 메모리 관리를 최적화하며, 연결 풀링을 활용하는 등의 전략을 통해 애플리케이션의 응답 시간과 효율성을 개선할 수 있습니다.

 모니터링과 로깅은 서버리스 환경에서 더욱 중요해집니다. AWS CloudWatch를 활용하여 로그를 중앙화하고, 커스텀 메트릭을 생성하여 애플리케이션의 성능과 동작을 추적할 수 있습니다. 적절한 알람을 설정하여 문제 상황에 신속하게 대응할 수 있습니다.

 마지막으로, 서버리스 NestJS 애플리케이션 개발 및 배포 시 Best Practices를 따르는 것이 중요합니다. 함수 크기 최소화, 상태 비저장 설계, 강화된 에러 처리, 적절한 보안 설정 등을 통해 안정적이고 효율적인 애플리케이션을 구축할 수 있습니다.

 서버리스 아키텍처는 많은 이점을 제공하지만, 동시에 새로운 도전 과제도 제시합니다. NestJS의 강력한 기능과 AWS Lambda의 확장성을 결합함으로써, 개발자는 고성능, 고가용성의 애플리케이션을 효율적으로 구축하고 운영할 수 있습니다. 지속적인 학습과 최적화를 통해 서버리스 NestJS 애플리케이션의 잠재력을 최대한 활용할 수 있을 것입니다.