Skip to main content
backend2026년 1월 4일10분 소요

클라우드 함수 vs 전통적인 백엔드: 서버리스가 합리적인 경우

서버리스 함수와 전통적인 백엔드의 실제 비교 — 비용, 지연 시간, 개발자 경험, 그리고 각 접근 방식이 언제 유리한지 다룹니다.

serverlesscloud-functionsbackend
클라우드 함수 vs 전통적인 백엔드: 서버리스가 합리적인 경우

새로운 프로젝트를 시작할 때마다 항상 같은 결정을 내려야 합니다. 전통적인 서버를 구축할 것인가, 아니면 클라우드 함수를 작성할 것인가? 이벤트 기반 워크플로우를 위한 Firebase Functions, API 엔드포인트를 위한 AWS Lambda, 그리고 그 외 모든 것을 위한 Express/Fastify 서버 등 양쪽 모두에서 프로덕션 시스템을 출시한 후, 각 접근 방식이 실제로 언제 유리한지에 대한 상당히 미묘한 의견을 갖게 되었습니다. 예상대로 답은 "경우에 따라 다르다"이지만, 무엇에 따라 달라지는지 구체적으로 자세히 살펴볼 가치가 있습니다.

두 가지 접근 방식 정의

비교하기 전에, 각 용어가 무엇을 의미하는지 정확히 설명하겠습니다.

전통적인 백엔드는 VM, 컨테이너 또는 관리형 컴퓨팅 플랫폼에 배포된 Node.js Express 앱, Python FastAPI 서버, Go HTTP 서버와 같은 장기 실행 서버 프로세스를 의미합니다. 프로세스가 시작되어 계속 실행되며 요청이 도착하면 처리합니다. 배포 대상에는 EC2, Cloud Run, ECS, Railway, Fly.io 또는 베어 VPS가 포함됩니다.

클라우드 함수(서버리스 함수)는 이벤트에 응답하여 실행되는 개별 함수 핸들러입니다. 플랫폼이 컴퓨팅 인프라를 전적으로 관리합니다. 코드가 실행되고 응답을 반환하며, 실행 환경은 다음 호출을 위해 유지될 수도 있고 그렇지 않을 수도 있습니다. 제공업체에는 AWS Lambda, Google Cloud Functions, Firebase Functions, Azure Functions, Cloudflare Workers가 있습니다.

이 구분은 언어나 프레임워크에 관한 것이 아니라 실행 모델에 관한 것입니다. 전통적인 백엔드는 자체 프로세스 수명 주기를 소유합니다. 클라우드 함수는 그렇지 않습니다.

콜드 스타트의 현실

콜드 스타트는 가장 많이 논의되는 서버리스의 한계이며, 2026년의 현실은 담론이 제시하는 것보다 더 미묘합니다.

콜드 스타트 시 실제로 일어나는 일

클라우드 함수가 최근에 호출되지 않았거나(또는 동시 호출이 사용 가능한 웜 인스턴스를 초과할 때), 플랫폼은 다음을 수행해야 합니다.

  1. 새로운 실행 환경(마이크로VM 또는 컨테이너) 프로비저닝
  2. 배포 패키지 다운로드 및 압축 해제
  3. 런타임 초기화 (Node.js, Python 등)
  4. 초기화 코드 실행 (모듈 임포트, SDK 설정, DB 연결)
  5. 실제 함수 핸들러 실행

1-3단계는 플랫폼 오버헤드입니다. 4단계는 코드 선택이 엄청나게 중요한 부분입니다.

실제 콜드 스타트 수치

다음은 실제 프로젝트에서 다양한 플랫폼 및 구성에 걸쳐 측정한 콜드 스타트 시간입니다.

플랫폼 런타임 번들 크기 콜드 스타트
AWS Lambda Node.js 20 5 MB 250-400ms
AWS Lambda Node.js 20 50 MB 800-1200ms
AWS Lambda Python 3.12 10 MB 400-600ms
Firebase Functions v2 Node.js 20 15 MB 600-1000ms
Cloudflare Workers JavaScript 1 MB 0-5ms
Google Cloud Functions v2 Node.js 20 10 MB 300-500ms

Cloudflare Workers는 컨테이너 대신 V8 isolates를 사용하기 때문에 컨테이너 시작 페널티를 완전히 제거하여 예외적인 수치를 보입니다. 그 대가로 런타임 환경이 더 제한적입니다.

콜드 스타트 완화

실제로 도움이 되는 몇 가지 전략이 있습니다.

프로비저닝된 동시성 (Lambda): 항상 N개의 인스턴스를 웜 상태로 유지합니다. 프로비저닝된 용량의 GB-초당 $0.0000041667가 청구됩니다. 256MB 함수에 대해 웜 인스턴스당 월 약 $3.20입니다. 지연 시간에 민감한 엔드포인트에 가치가 있습니다.

최소 인스턴스 (Cloud Run, Firebase Functions v2): 동일한 개념, 다른 명칭입니다. Cloud Run은 유휴 인스턴스에 대해 할인된 요금으로 청구합니다.

번들 크기 축소: 이것은 영향 대비 노력 비율이 가장 높습니다. 트리 쉐이킹, 개발 종속성 제외, 더 가벼운 SDK 클라이언트 사용은 초기화 시간을 극적으로 줄입니다.

// Bad: imports the entire AWS SDK (adds 40MB+ to bundle)
import AWS from 'aws-sdk';

// Good: imports only the S3 client (adds ~3MB)
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';

지연 초기화: 모듈 범위에서 데이터베이스 연결을 설정하거나 무거운 리소스를 로드하지 마십시오. 첫 호출 시 초기화하고 웜 호출 전반에 걸쳐 재사용하십시오.

import { Pool } from 'pg';

let pool: Pool | null = null;

function getPool(): Pool {
  if (!pool) {
    pool = new Pool({
      connectionString: process.env.DATABASE_URL,
      max: 1, // Single connection per Lambda instance
    });
  }
  return pool;
}

export async function handler(event: APIGatewayEvent) {
  const db = getPool();
  const result = await db.query('SELECT * FROM users WHERE id = $1', [event.pathParameters?.id]);
  return { statusCode: 200, body: JSON.stringify(result.rows[0]) };
}

다양한 규모에서의 비용 비교

비용은 트래픽 규모에 따라 경제성이 역전되기 때문에 흥미로운 대화가 됩니다.

낮은 트래픽 (일일 1,000 - 50,000 요청)

이 규모에서는 서버리스가 거의 항상 더 저렴합니다. 많은 스타트업과 사이드 프로젝트가 여기에 해당합니다.

일일 30,000 요청, 평균 200ms 지속 시간, 256MB 메모리 사용 시 Lambda 비용:

  • 요청 요금: 월 90만 요청 x 백만 요청당 $0.20 = $0.18
  • 컴퓨팅 요금: 90만 x 0.2초 x 0.25GB x $0.0000166667 = $0.75
  • 총계: 월 약 $1

동등한 전통적인 서버 (AWS의 t4g.small):

  • 온디맨드: 월 $12.26
  • 1년 절약 플랜 적용 시: 월 약 $8

낮은 트래픽에서는 95% 유휴 상태인 항상 켜져 있는 서버에 비용을 지불하는 셈입니다.

중간 트래픽 (일일 100,000 - 1,000,000 요청)

이것은 비교가 근접해지는 교차점입니다.

일일 500,000 요청, 평균 200ms, 256MB 사용 시 Lambda 비용:

  • 요청 요금: 월 1,500만 요청 x 백만 요청당 $0.20 = $3.00
  • 컴퓨팅 요금: 1,500만 x 0.2초 x 0.25GB x $0.0000166667 = $12.50
  • 총계: 월 약 $15.50

t4g.medium (2 vCPU, 4GB RAM):

  • 온디맨드: 월 $24.53
  • 절약 플랜 적용 시: 월 약 $16

비용은 비슷하지만, 전통적인 서버는 상당한 여유 공간으로 이 트래픽을 처리합니다. 트래픽이 꾸준하다면 서버가 약간 더 저렴합니다. 트래픽이 급증하는 경우(주중 집중, 이벤트 기반 버스트), Lambda의 호출당 요금 청구는 조용한 기간에 비용을 지불하지 않는다는 것을 의미합니다.

높은 트래픽 (일일 5,000,000+ 요청)

이 규모에서는 지속적인 워크로드에 대해 서버리스가 거의 항상 더 비쌉니다.

일일 5,000,000 요청, 평균 200ms, 512MB 사용 시 Lambda 비용:

  • 요청 요금: 월 1억 5천만 요청 x 백만 요청당 $0.20 = $30
  • 컴퓨팅 요금: 1억 5천만 x 0.2초 x 0.5GB x $0.0000166667 = $250
  • 총계: 월 약 $280

c6g.large (2 vCPU, 4GB RAM) 및 자동 스케일링 그룹:

  • 절약 플랜 적용 시 2개 인스턴스: 월 약 $60
  • 로드 밸런서 포함: 월 약 $16
  • 총계: 월 약 $76

이 규모에서는 전통적인 접근 방식이 3.7배 더 저렴하며, 트래픽이 증가할수록 격차는 더욱 벌어집니다.

고려해야 할 숨겨진 비용

Lambda의 요금 청구가 전체 그림은 아닙니다. API Gateway(백만 요청당 $1-3.50), CloudWatch Logs(수집된 GB당 $0.50), 그리고 사용하는 경우 X-Ray 추적을 추가해야 합니다. 전통적인 측면에서는 로드 밸런서 비용, 모니터링, 인스턴스 및 배포 관리를 위한 운영 시간을 추가해야 합니다.

개발자 경험 차이

서버리스 개발자 경험

장점:

  • 관리할 인프라가 없음 (패치, 스케일링 구성 없음)
  • 함수별 배포는 영향 범위가 더 작음을 의미
  • 에뮬레이터로 로컬 개발 (Firebase Emulator Suite, SAM CLI, Serverless Framework offline)
  • 플랫폼의 로깅 및 추적을 통한 내장된 관찰 가능성

단점:

  • 로컬 개발이 프로덕션 동작과 완벽하게 일치하지 않음
  • 분산된 함수 간 호출 디버깅은 모놀리식 앱을 단계별로 디버깅하는 것보다 어려움
  • 배포 크기 제한 (Lambda: 압축 해제 시 250MB)으로 종속성 선택이 제한됨
  • IAM 및 권한 구성이 장황하고 실수하기 쉬움
  • 콜드 스타트로 인해 배포된 함수를 테스트할 때 개발 반복 주기가 느려짐

전통적인 백엔드 개발자 경험

장점:

  • 로컬 개발 환경이 곧 프로덕션 환경임 (동일한 프로세스, 동일한 상태)
  • 디버깅이 간단함 — 디버거 연결, 중단점 설정, 단계별 실행
  • 배포 크기 제한 없음
  • 미들웨어 패턴, 요청 수명 주기 훅, 전역 오류 처리가 자연스러움
  • WebSocket 지원, 장기 실행 프로세스, 백그라운드 작업이 추가 서비스 없이 작동

단점:

  • 인프라 수명 주기(업데이트, 스케일링, 상태 확인)를 직접 관리해야 함
  • 배포에는 오케스트레이션이 필요함 (롤링 업데이트, 상태 확인 유예 기간)
  • 스케일링에는 구성이 필요함 (자동 스케일링 그룹, 컨테이너 오케스트레이션)
  • 모니터링 및 로깅에는 명시적인 설정이 필요함

프레임워크 격차는 좁혀지고 있음

SST (Serverless Stack) 및 Architect와 같은 프레임워크는 서버리스 개발자 경험을 극적으로 개선했습니다. 특히 SST는 로컬에서 실행되는 코드가 Lambda 호출을 실시간으로 처리하여 배포-테스트 주기를 완전히 없애는 "Live Lambda" 개발 모드를 제공합니다.

전통적인 측면에서는 Railway, Fly.io, Render와 같은 플랫폼이 git push로 배포를 간소화했습니다. 전통적인 백엔드를 운영하는 운영 부담이 크게 줄었습니다.

서버리스가 유리한 경우

이벤트 기반 워크로드

코드가 파일 업로드, 데이터베이스 변경, 큐 메시지, 예약된 작업과 같은 이벤트에 응답하여 실행되는 경우 서버리스가 자연스럽게 적합합니다. 폴링 루프나 리스너 프로세스를 유지할 필요가 없습니다. 플랫폼이 필요할 때 정확히 코드를 트리거합니다.

// Firebase Functions: Firestore 문서 생성 시 트리거됨
import { onDocumentCreated } from 'firebase-functions/v2/firestore';

export const onOrderCreated = onDocumentCreated('orders/{orderId}', async (event) => {
  const order = event.data?.data();
  if (!order) return;

  // 확인 이메일 전송
  await sendEmail(order.customerEmail, {
    template: 'order-confirmation',
    data: { orderId: event.params.orderId, items: order.items },
  });

  // 재고 업데이트
  await updateInventory(order.items);

  // 레스토랑에 알림
  await sendPushNotification(order.restaurantId, {
    title: 'New Order',
    body: `Order #${event.params.orderId} received`,
  });
});

산발적이거나 예측 불가능한 트래픽

월요일 오전에 50개의 요청을 받고 나머지 주에는 2개의 요청을 받는 내부 도구. 타사 API에서 이벤트를 처리하는 웹훅 수신기. 하루에 한 번 30초 동안 실행되는 예약된 보고서 생성기. 이러한 워크로드는 서버리스에서 거의 제로 비용이며, 항상 켜져 있는 인프라에서는 돈을 낭비합니다.

낮은-중간 트래픽의 API 엔드포인트

하루에 수천 건의 요청을 처리하는 스타트업의 MVP API의 경우, 서버리스는 최소한의 운영 오버헤드와 거의 제로 비용으로 기능적인 백엔드를 제공합니다. 비즈니스 로직에 전적으로 집중할 수 있습니다.

병렬 데이터 처리

10,000개의 이미지를 처리하거나, 500개의 비디오를 트랜스코딩하거나, 대규모 데이터 세트에 대한 분석을 실행해야 합니까? 수천 개의 동시 Lambda 호출로 팬아웃하여 병렬로 처리하고 사용된 컴퓨팅 시간에 대해서만 비용을 지불하십시오. 전통적인 서버로 동일한 병렬 처리를 달성하려면 해당 피크 용량을 프로비저닝(및 비용 지불)해야 합니다.

전통적인 백엔드가 유리한 경우

영구 연결

WebSocket 연결, Server-Sent Events, gRPC 스트림, 롱 폴링은 모두 클라이언트와 서버 간의 영구 연결을 필요로 합니다. Lambda 함수는 15분 실행 제한이 있으며 장기 실행 연결을 위해 설계되지 않았습니다.

API Gateway WebSocket API 또는 AWS IoT Core를 사용하여 이를 해결할 수 있지만, 복잡성과 비용이 Cloud Run 또는 컨테이너 플랫폼의 간단한 WebSocket 서버를 초과하는 경우가 많습니다.

복잡한 요청 파이프라인

요청이 인증, 속도 제한, 입력 유효성 검사, 비즈니스 로직, 데이터베이스 작업, 캐시 업데이트, 이벤트 발행 및 응답 형식 지정을 거칠 때, Express/Fastify/Koa의 미들웨어 파이프라인 패턴은 클라우드 함수의 평면 핸들러 패턴보다 인체공학적으로 우수합니다.

// Traditional: clean middleware pipeline
app.use(cors());
app.use(helmet());
app.use(rateLimiter);
app.use(authenticate);
app.use('/api/v1', apiRouter);
app.use(errorHandler);

Lambda에서 이를 복제하려면 Middy와 같은 프레임워크(무게와 복잡성을 추가함)를 사용하거나 함수 전반에 걸쳐 설정 코드를 중복해야 합니다.

상태 저장 작업

애플리케이션이 인메모리 상태(캐시, 연결 풀, 속도 제한 카운터, 세션 데이터)를 유지하는 경우, 전통적인 서버가 이를 자연스럽게 처리합니다. Lambda 함수는 웜 호출 전반에 걸쳐 상태를 재사용할 수 있지만, 이에 의존할 수는 없습니다. 지속되어야 하는 모든 상태는 외부 서비스(Redis, DynamoDB)가 필요하며, 이는 지연 시간과 비용을 추가합니다.

엄격한 지연 시간 요구 사항

실시간 입찰, 게임 서버, 금융 거래와 같이 모든 밀리초가 중요한 API의 경우, 프로비저닝된 동시성을 사용하더라도 콜드 스타트로 인해 발생하는 예측 불가능한 지연 시간은 용납할 수 없습니다. 연결 풀링과 웜 캐시를 갖춘 잘 튜닝된 서버 프로세스는 서버리스가 보장할 수 없는 일관된 10ms 미만의 응답 시간을 제공합니다.

하이브리드 접근 방식

실제로 제가 구축하는 대부분의 프로덕션 시스템은 하이브리드 방식으로 끝납니다. 핵심 API는 전통적인 백엔드(Cloud Run 또는 컨테이너 플랫폼)에서 실행되는 반면, 보조 워크로드는 클라우드 함수에서 실행됩니다.

실용적인 하이브리드 아키텍처

클라이언트
  │
  ├─→ API Gateway / 로드 밸런서
  │     └─→ Cloud Run (메인 API)
  │           ├─→ PostgreSQL (Cloud SQL)
  │           ├─→ Redis (Memorystore)
  │           └─→ Pub/Sub (이벤트 버스)
  │
  └─→ Cloud Functions (이벤트 핸들러)
        ├─→ 이미지 처리 (업로드 시)
        ├─→ 이메일 전송 (주문 생성 시)
        ├─→ 분석 집계 (예약됨)
        └─→ 웹훅 처리 (HTTP 트리거)

메인 API는 영구 데이터베이스 연결, 인메모리 캐싱 및 일관된 지연 시간으로 동기식 요청-응답 트래픽을 처리합니다. 클라우드 함수는 사용자가 응답을 기다리지 않으므로 콜드 스타트가 중요하지 않은 비동기식, 이벤트 기반 워크로드를 처리합니다.

마이그레이션 전략: 전통적인 방식에서 서버리스로

기존의 전통적인 백엔드가 있고 서버리스를 선택적으로 채택하려는 경우:

  1. 현재 백그라운드 작업, cron 작업 또는 큐 소비자로 실행되는 이벤트 기반 작업을 식별합니다. 이들은 마이그레이션하기 가장 쉽습니다.
  2. 다른 엔드포인트와 상태를 공유하지 않는 독립적인 엔드포인트를 추출합니다. 상태 확인 엔드포인트, 웹훅 수신기, 유틸리티 API가 좋은 후보입니다.
  3. 분해해야 할 강력한 이유가 없는 한 핵심 API는 전통적인 방식으로 유지합니다. 50개의 Lambda 함수를 관리하는 운영 오버헤드는 하나의 컨테이너를 관리하는 것보다 더 큰 경우가 많습니다.
  4. 전통적인 API와 서버리스 함수 간의 통합 계층으로 이벤트 버스(Pub/Sub, EventBridge, SQS)를 사용합니다. API는 이벤트를 발행하고, 함수는 구독하고 반응합니다.

마이그레이션 전략: 서버리스에서 전통적인 방식으로

서버리스 API가 아키텍처를 능가할 때 때때로 다른 방향으로 가는 것이 필요합니다.

  1. 모든 것을 한 번에 다시 작성하지 마십시오. 가장 많은 트래픽을 처리하는 함수를 단일 API 서버로 통합하는 것부터 시작하십시오.
  2. 이벤트 기반 함수는 함수로 유지합니다. 요청-응답 핸들러만 마이그레이션합니다.
  3. 동일한 API 경로를 사용합니다. 마이그레이션된 경로에 대해 API Gateway/로드 밸런서를 새 서버로 지정하고 나머지는 Lambda로 계속 라우팅합니다.
  4. 데이터베이스 연결을 먼저 마이그레이션합니다. 가장 큰 성능 향상은 호출당 연결 설정에서 영구 연결 풀링으로 전환하는 것입니다.

플랫폼별 참고 사항

Firebase Functions (v2)

Firebase Functions v2는 내부적으로 Cloud Run에서 실행되므로 v1에 비해 상당한 이점을 제공합니다. 구성 가능한 동시성(인스턴스당 여러 요청), 최소 인스턴스, 더 긴 타임아웃(최대 60분), 더 큰 메모리 할당 등이 있습니다. Firebase v1 함수를 사용 중이라면 v2로의 업그레이드는 마이그레이션 노력을 들일 가치가 있습니다.

Firebase Emulator Suite는 서버리스 공간에서 최고의 로컬 개발 경험을 제공합니다. Firestore, Auth, Storage, Functions를 단일 로컬 환경에서 에뮬레이트하며, 코드 변경 시 핫 리로드를 지원합니다.

AWS Lambda

Lambda는 가장 깊은 통합 생태계를 가지고 있습니다. 거의 모든 AWS 서비스의 트리거, 공유 코드를 위한 레이어, Java 워크로드를 위한 SnapStart를 제공합니다. 함수 URL 기능은 간단한 사용 사례에 대해 API Gateway의 필요성을 없애 백만 요청당 $3.50를 절약합니다.

Lambda@Edge 및 CloudFront Functions는 CDN 수준에서 요청/응답 조작에 강력하지만, 개발 및 디버깅 경험은 표준 Lambda보다 훨씬 좋지 않습니다.

Cloud Run

Cloud Run은 서버리스와 전통적인 방식의 경계를 모호하게 만듭니다. 컨테이너(모든 언어, 모든 프레임워크)를 실행하고, 0으로 스케일링되며, 동시성(인스턴스당 여러 요청)을 지원합니다. 청구 모델은 서버리스이지만 실행 모델은 전통적입니다. 코드를 함수 핸들러로 다시 작성하지 않고 서버리스 경제성을 원하는 팀에게 Cloud Run은 종종 올바른 답입니다.

결정 내리기

다음은 제가 사용하는 결정 프레임워크입니다.

  1. 워크로드가 이벤트 기반이며 비동기식인가? 서버리스.
  2. 트래픽이 적고 예측 불가능한가? 서버리스.
  3. 영구 연결 또는 인메모리 상태가 필요한가? 전통적인 방식.
  4. 일관된 낮은 지연 시간이 중요한가? 전통적인 방식.
  5. 팀이 작고 운영에 부담을 느끼는가? 서버리스 (또는 Cloud Run).
  6. 트래픽이 많고 꾸준한가? 전통적인 방식 (더 저렴함).
  7. 위의 사항들이 혼합되어 있는가? 하이브리드.

가장 나쁜 결정은 이것을 전부 아니면 전무한 선택으로 취급하는 것입니다. 각 워크로드에 적합한 도구를 사용하고, 잘 정의된 인터페이스를 통해 연결하면, 어느 한쪽에 전적으로 전념하지 않고도 두 가지 모두의 이점을 얻을 수 있습니다.

DU

Danil Ulmashev

Full Stack Developer

함께 일하는 데 관심이 있으신가요?