12.serverless
Episode 12: "클라우드 네이티브: 서버리스의 등장"
서버를 관리하지 않고 코드만 배포하는 꿈
프롤로그: 서버 관리의 악몽
2014년, 당신은 간단한 웹 애플리케이션을 하나 만들었습니다. 하루에 방문자 10명 정도 오는 작은 서비스였죠. 하지만 서버 관리는 간단하지 않았습니다.
# 2014년, 간단한 앱을 배포하기 위해 필요한 것들
1. EC2 인스턴스 생성 및 설정
- 인스턴스 타입 선택 (t2.micro? t2.small?)
- 키페어 생성, 보안 그룹 설정
- 월 비용: $10-20 (거의 안 쓰는데도)
2. 서버 설정
$ ssh ec2-user@your-instance.com
$ sudo apt-get update && sudo apt-get upgrade
$ sudo apt-get install nginx nodejs npm
$ sudo systemctl enable nginx
3. 애플리케이션 배포
$ git clone your-repo
$ npm install
$ pm2 start app.js
$ sudo nginx -s reload
4. 모니터링 설정
- CloudWatch 알람 설정
- 로그 수집 설정
- 디스크 용량 체크
5. 보안 패치
- 매달 OS 업데이트
- 취약점 점검
- SSL 인증서 갱신
6. 새벽 3시
"⚠️ High CPU Usage Alert!"
(방문자는 여전히 10명...)
전통적인 서버 관리의 문제들
고정 비용:
- 트래픽이 0이어도 서버는 24/7 가동
- 사용하지 않는 시간의 비용도 지불
- 최소 단위가 1대의 서버
과잉 프로비저닝:
- 트래픽 급증을 대비해 여유 용량 확보
- 대부분의 시간에는 낭비
- 비용 효율 10-20%
운영 부담:
- OS 업데이트, 보안 패치
- 스케일링 설정 및 관리
- 장애 대응 24/7
복잡한 인프라:
- 로드 밸런서, 오토스케일링 그룹
- VPC, 서브넷, 보안 그룹
- 학습 곡선이 가파름
개발자들은 생각했습니다:
"나는 그냥 코드만 작성하고 싶은데, 왜 서버 관리자가 되어야 하지?"
2014년 11월, Amazon은 충격적인 발표를 합니다. AWS Lambda.
"더 이상 서버를 관리할 필요가 없습니다. 코드를 업로드하기만 하면 됩니다. 사용한 만큼만 지불하세요."
서버리스 시대가 시작되었습니다.
이 글에서 다룰 내용
- AWS Lambda의 충격적 등장
- "NoOps"의 유토피아와 현실
- JAMstack: 정적 사이트의 화려한 부활
- Edge Computing: CDN에서 컴퓨팅까지
Chapter 1: AWS Lambda의 충격적 등장
2014년, 패러다임의 전환
AWS Lambda는 완전히 새로운 컴퓨팅 모델을 제시했습니다:
// 이것이 전부입니다
exports.handler = async (event) => {
return {
statusCode: 200,
body: JSON.stringify({ message: 'Hello from Lambda!' })
};
};
// 배포하면 끝
// 서버? 없음
// 설정? 최소한
// 비용? 호출당 과금
Lambda의 혁명적인 특징
서버리스의 핵심 개념
서버 관리 제로:
- EC2 인스턴스 없음
- OS 업데이트 없음
- 인프라 설정 없음
- 그냥 코드만
완벽한 종량제:
- 요청당 과금
- 실행 시간만큼만
- 트래픽 0 = 비용 0
- 100ms 단위 과금
자동 스케일링:
- 요청 1개든 1백만 개든
- 자동으로 확장
- 설정 필요 없음
- 무한대로 확장 가능
이벤트 드리븐:
- HTTP 요청
- S3 파일 업로드
- DynamoDB 변경
- 일정 (cron)
Lambda 사용 예제: 이미지 썸네일 생성
// 기존 방식: EC2 서버에서 실행
// - 서버 구축 및 유지보수 필요
// - 24/7 비용 발생
// - 스케일링 복잡
// Lambda 방식: 이벤트에 반응
const AWS = require('aws-sdk');
const sharp = require('sharp');
const s3 = new AWS.S3();
exports.handler = async (event) => {
// S3에 이미지 업로드되면 자동 실행
const bucket = event.Records[0].s3.bucket.name;
const key = event.Records[0].s3.object.key;
// 이미지 다운로드
const image = await s3.getObject({ Bucket: bucket, Key: key }).promise();
// 썸네일 생성
const thumbnail = await sharp(image.Body)
.resize(200, 200)
.toBuffer();
// 썸네일 저장
await s3.putObject({
Bucket: bucket,
Key: `thumbnails/${key}`,
Body: thumbnail
}).promise();
return { statusCode: 200, body: 'Thumbnail created' };
};
// 배포 후:
// - 이미지 업로드할 때만 실행
// - 자동 스케일링 (동시에 1000개 업로드해도 OK)
// - 비용: 실행한 만큼만
비용 비교
EC2 기반 (기존):
- t2.small 인스턴스: $17/월
- 24/7 가동
- 월 1000개 이미지 처리해도 $17
- 사용률 1%라도 $17
Lambda 기반:
- 월 1000개 처리: $0.20
- 사용하지 않으면: $0
- 트래픽 급증해도 자동 대응
- 85배 저렴
서버리스의 핵심 개념
FaaS (Function as a Service)
함수 단위로 코드 실행. 서버 없음, 인프라 없음
이벤트 드리븐
이벤트가 발생할 때만 실행. 유휴 시간 없음
무상태 (Stateless)
각 실행은 독립적. 상태는 외부 저장소에
관리형 서비스
스케일링, 가용성, 보안 등 모두 플랫폼이 관리
Chapter 2: "NoOps"의 유토피아와 현실
NoOps의 꿈
서버리스는 "NoOps"(No Operations)의 꿈을 약속했습니다:
// 개발자가 원하는 이상향
// 1. 코드만 작성
async function processPayment(userId: string, amount: number) {
// 비즈니스 로직에만 집중
const user = await db.users.findById(userId);
const charge = await stripe.charge(user.card, amount);
await db.payments.create({ userId, amount, chargeId: charge.id });
return { success: true };
}
// 2. 배포
// $ serverless deploy
// 3. 끝!
// - 인프라? 신경 쓸 필요 없음
// - 스케일링? 자동
// - 모니터링? 기본 제공
// - 보안? 관리형
NoOps가 가능하게 한 것들
개발자 생산성 혁명
개발 속도:
- 인프라 고민 시간: 0
- 배포까지: 분 단위
- MVP 출시: 며칠
팀 구성:
- DevOps 엔지니어 불필요 (초기)
- 개발자 1-2명으로 시작 가능
- 인건비 절감
집중:
- 비즈니스 로직에 집중
- 고객 가치 창출에 집중
- 차별화에 집중
하지만 현실은...
서버리스를 도입한 지 6개월 후:
// Lambda 함수가 점점 늘어나고...
// ├─ user-create.js
// ├─ user-update.js
// ├─ user-delete.js
// ├─ payment-process.js
// ├─ payment-refund.js
// ├─ email-send.js
// ├─ notification-push.js
// ├─ image-upload.js
// ├─ image-process.js
// ├─ analytics-track.js
// ... (50개 더)
// 문제 발생:
// "어? payment-process에서 에러가 났는데..."
// "어떤 함수가 어떤 함수를 호출하지?"
// "로그가 50개 함수에 흩어져 있어..."
// "디버깅이 왜 이렇게 어려워?"
// "함수 간 의존성을 어떻게 관리하지?"
// "Cold Start로 첫 요청이 3초 걸려..."
서버리스의 현실적인 문제들
복잡성의 이동:
- 서버 관리는 사라짐
- 하지만 분산 시스템 복잡성은 증가
- 함수 간 오케스트레이션 필요
Cold Start:
- 첫 요청은 느림 (수 초)
- Node.js: 100-500ms
- Java: 1-3초
- 사용자 경험 저하 가능
디버깅의 어려움:
- 로컬 실행이 어려움
- 로그가 분산됨
- 추적(tracing) 복잡
벤더 종속:
- AWS Lambda 코드는 GCP에서 안 돌아감
- API가 플랫폼마다 다름
- 이전 비용 높음
비용 예측 어려움:
- 트래픽 급증 시 비용 폭탄 가능
- 잘못된 코드로 무한 루프 = 파산
- 모니터링 필수
서버리스 코드 패턴의 변화
전통적인 서버와 서버리스는 코드 작성 방식이 다릅니다:
// 전통적인 Express.js 서버
// - 상태 유지 가능 (메모리 캐시)
// - 연결 재사용 (DB 커넥션 풀)
// - 긴 실행 시간 OK
const express = require('express');
const app = express();
// 앱 시작 시 한 번만 초기화
const dbPool = createConnectionPool({
max: 10,
min: 2
});
// 메모리 캐시
const cache = new Map();
app.get('/users/:id', async (req, res) => {
// 캐시 확인
if (cache.has(req.params.id)) {
return res.json(cache.get(req.params.id));
}
// DB 조회 (커넥션 재사용)
const user = await dbPool.query('SELECT * FROM users WHERE id = ?', [req.params.id]);
cache.set(req.params.id, user);
res.json(user);
});
app.listen(3000);
// 서버는 계속 실행됨
// Lambda (서버리스)
// - 무상태 (stateless)
// - 커넥션 재사용 제한적
// - 실행 시간 제한 (15분)
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB.DocumentClient();
// 전역 변수는 제한적으로만 재사용됨
// (Lambda 컨테이너가 재사용될 때만)
exports.handler = async (event) => {
const userId = event.pathParameters.id;
// 캐시 불가능 (무상태)
// 매번 DB 조회
const result = await dynamodb.get({
TableName: 'Users',
Key: { id: userId }
}).promise();
return {
statusCode: 200,
body: JSON.stringify(result.Item)
};
};
// 각 요청마다 독립적으로 실행
// 실행 후 컨테이너는 잠들거나 종료됨
서버리스 코드 작성 패턴
새로운 사고방식
상태 관리:
- 메모리 캐시 X → Redis/DynamoDB 사용
- 세션 스토리지 X → JWT 또는 외부 저장소
- 전역 변수 신뢰 X
커넥션 관리:
- DB 커넥션 풀 제한적
- HTTP 커넥션 재사용 어려움
- → Connection Proxy 사용 (RDS Proxy)
실행 시간:
- 긴 작업 X
- 최대 15분 (Lambda)
- → 작업 분할 또는 Step Functions
에러 처리:
- Retry 로직 필수
- 멱등성(idempotency) 보장 필요
- Dead Letter Queue 설정
서버리스가 적합한 경우 vs 부적합한 경우
// ✅ 서버리스가 적합한 경우
// 1. 이벤트 기반 작업
// - 이미지 처리, 파일 변환
// - 웹훅 처리
// - 예약된 작업 (cron)
// 2. 간헐적 트래픽
// - 하루 몇 번만 호출되는 API
// - 주기적인 데이터 동기화
// - 백오피스 도구
// 3. 빠른 프로토타입
// - MVP 개발
// - PoC (Proof of Concept)
// - 해커톤
// 4. 마이크로서비스
// - 작고 독립적인 서비스
// - 느슨한 결합
// - 명확한 책임
// ❌ 서버리스가 부적합한 경우
// 1. 웹소켓 / 긴 연결
// - 실시간 채팅
// - 게임 서버
// - 스트리밍
// 2. 고정된 높은 트래픽
// - 24/7 높은 부하
// - 예측 가능한 트래픽
// - → EC2가 더 저렴할 수 있음
// 3. 상태가 중요한 애플리케이션
// - 인메모리 캐시가 필수
// - 복잡한 세션 관리
// - 커넥션 풀 의존
// 4. 레이턴시가 중요한 경우
// - Cold Start 허용 불가
// - 밀리초 단위 응답 필요
// - 게임, 금융 거래 등
"서버리스는 은탄환이 아닙니다. 특정 사용 사례에 매우 적합하지만, 모든 문제의 해결책은 아닙니다."
Chapter 3: JAMstack - 정적 사이트의 화려한 부활
2015년, Netlify의 새로운 비전
서버리스가 백엔드를 바꾸는 동안, JAMstack은 프론트엔드를 바꾸고 있었습니다.
JAMstack이란?
JavaScript + APIs + Markup
핵심 아이디어:
- 정적 파일을 CDN에 배포
- 동적 기능은 API로 (서버리스!)
- 빌드 타임에 HTML 생성
# 전통적인 워드프레스 블로그 (2010년)
User → Nginx → PHP → MySQL → HTML 생성 → Response
# 매 요청마다 서버에서 HTML 생성
# 느림, 비쌈, 스케일링 어려움
# JAMstack 블로그 (2020년)
Build Time:
Markdown → Static Site Generator → HTML/CSS/JS
Runtime:
User → CDN → HTML (즉시 전송!)
Comments? → API (서버리스)
Search? → API (서버리스)
# 빠름, 저렴, 스케일링 자동
JAMstack의 진화
Jekyll (2008)
GitHub Pages의 정적 사이트 생성기. Ruby 기반
Netlify 설립 (2014)
JAMstack 용어 만들고 플랫폼 제공
Gatsby (2015)
React 기반 정적 사이트 생성기. GraphQL 통합
Next.js SSG (2020)
Static Site Generation 지원. 하이브리드 렌더링
Vercel의 부상
Next.js를 만든 Vercel이 JAMstack 플랫폼의 강자로
Vercel: 개발자 경험의 정점
Vercel은 서버리스와 JAMstack을 완벽하게 결합했습니다:
// Next.js with Vercel
// pages/api/users.ts - API Route (서버리스!)
export default async function handler(req, res) {
// 이 코드는 Vercel의 서버리스 함수로 실행됨
const users = await db.users.findMany();
res.json(users);
}
// pages/index.tsx - 정적 생성
export async function getStaticProps() {
// 빌드 타임에 한 번 실행
const posts = await fetchPosts();
return { props: { posts }, revalidate: 60 };
}
export default function Home({ posts }) {
return (
<div>
{posts.map(post => (
<Article key={post.id} {...post} />
))}
</div>
);
}
// 배포
// $ git push
// → Vercel이 자동 배포
// → 정적 파일은 전 세계 CDN에
// → API는 서버리스 함수로
// → 끝!
Vercel의 혁신
개발자 경험 혁명
제로 설정:
git push만 하면 배포 완료- 프레임워크 자동 감지 (Next.js, Svelte, etc)
- 환경 변수만 설정하면 됨
자동 최적화:
- 이미지 최적화 자동
- 코드 스플리팅 자동
- CDN 캐싱 자동
프리뷰 배포:
- PR마다 자동 프리뷰 환경
- 고유 URL로 테스트 가능
- 팀 리뷰 간편
Edge Functions:
- CDN 엣지에서 코드 실행
- 낮은 레이턴시
- 개인화 가능
분석 내장:
- Core Web Vitals 추적
- 성능 모니터링
- 사용자 경험 개선
# Vercel 배포 예제
# 1. 프로젝트 생성
$ npx create-next-app my-app
$ cd my-app
# 2. Git 연결
$ git init
$ git add .
$ git commit -m "Initial commit"
$ git remote add origin https://github.com/username/my-app.git
$ git push -u origin main
# 3. Vercel 연결
$ vercel login
$ vercel
# 끝!
# - 자동 HTTPS
# - 전 세계 CDN
# - 서버리스 API
# - CI/CD 자동
# - 도메인 연결 간단
# 이후 배포
$ git push
# → 자동으로 프로덕션 배포
# PR 생성 시
# → 자동으로 프리뷰 배포
# → 고유 URL 생성
JAMstack의 장점과 한계
JAMstack의 강력한 장점
성능:
- CDN에서 바로 전송
- TTFB (Time To First Byte) < 100ms
- No server processing
보안:
- 공격 표면 최소화
- 서버 해킹 불가 (서버 없음)
- DDoS 내성 강함
비용:
- 정적 호스팅 거의 무료
- 트래픽 급증해도 문제없음
- Netlify/Vercel 무료 티어 넉넉
개발자 경험:
- Git 기반 워크플로우
- 로컬 개발 쉬움
- 롤백 간단
스케일링:
- 무한대로 확장 가능
- 설정 필요 없음
- 자동으로 전 세계 배포
JAMstack의 한계
빌드 시간:
- 페이지 많으면 빌드 느림
- 수천 페이지면 수십 분 소요
- Incremental Static Regeneration으로 완화
실시간성:
- 빌드 타임에 생성
- 실시간 데이터 어려움
- → ISR 또는 클라이언트 사이드 페칭
복잡한 동적 기능:
- 개인화 어려움
- 사용자별 컨텐츠 제한적
- → Edge Functions로 해결
검색/필터:
- 클라이언트 사이드 또는 외부 서비스 필요
- Algolia, ElasticSearch 등 의존
Chapter 4: Edge Computing - CDN에서 컴퓨팅까지
CDN의 진화
CDN(Content Delivery Network)은 원래 정적 파일 캐싱만 했습니다:
# 전통적인 CDN (2000년대)
User (Seoul) → CDN (Seoul) → Origin (US West)
↓
Cache
↓
User (Seoul) → CDN (Seoul) [Cache Hit!]
# 정적 파일만: HTML, CSS, JS, 이미지
# 동적 컨텐츠는 Origin까지 가야 함
하지만 서버리스 시대에 CDN은 컴퓨팅 플랫폼이 되었습니다:
# Edge Computing (2020년대)
User (Seoul) → CDN Edge (Seoul)
↓
[Code 실행!]
↓
Response
# Origin 서버까지 안 가도 됨
# 레이턴시 최소화
# 개인화 가능
Cloudflare Workers: 엣지에서의 서버리스
Cloudflare Workers는 전 세계 200+ 도시의 엣지에서 코드를 실행합니다:
// Cloudflare Worker 예제
// 전 세계 엣지에서 실행됨
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
});
async function handleRequest(request) {
const url = new URL(request.url);
// A/B 테스트
const variant = Math.random() < 0.5 ? 'A' : 'B';
// 지역별 개인화
const country = request.cf.country; // 'KR', 'US', etc
const language = country === 'KR' ? 'ko' : 'en';
// HTML 수정
const response = await fetch(url);
let html = await response.text();
html = html.replace('{{language}}', language);
html = html.replace('{{variant}}', variant);
return new Response(html, {
headers: { 'Content-Type': 'text/html' }
});
}
// 전 세계 어디서든 < 50ms 응답
Edge Computing의 특징
레이턴시의 최소화
지리적 분산:
- 전 세계 수백 개 위치
- 사용자와 가까운 곳에서 실행
- 레이턴시 최소화
빠른 Cold Start:
- V8 Isolates 사용
- Cold Start < 5ms
- Lambda보다 100배 빠름
무한 확장:
- 자동 스케일링
- DDoS 내성 강함
- 글로벌 트래픽 처리
사용 사례:
- 인증/인가
- 리다이렉션
- A/B 테스트
- 개인화
- 봇 차단
- API 라우팅
Vercel Edge Functions
Vercel도 Edge Functions를 제공합니다:
// app/api/edge/route.ts
import { NextRequest, NextResponse } from 'next/server';
export const runtime = 'edge'; // Edge에서 실행!
export async function GET(request: NextRequest) {
const geo = request.geo;
// 사용자 위치 기반 응답
const message = geo?.country === 'KR'
? '안녕하세요!'
: 'Hello!';
return NextResponse.json({
message,
location: geo?.city,
country: geo?.country,
latency: 'sub-50ms'
});
}
// 배포하면 자동으로 전 세계 엣지에 배포됨
Edge Middleware
요청 전처리, 인증, 리다이렉션
Edge API Routes
낮은 레이턴시의 API 엔드포인트
Edge Rendering
SSR을 엣지에서 (실험적)
Edge vs Lambda: 언제 무엇을 쓸까?
// ⚡ Edge Functions (Cloudflare, Vercel Edge)
// - 실행 시간: < 50ms
// - 메모리: 128MB
// - 언어: JavaScript/TypeScript, Rust, C++
// - Cold Start: < 5ms
// - 비용: 매우 저렴
// 적합한 경우:
// - 간단한 로직
// - 낮은 레이턴시 필수
// - 지역별 개인화
// - 인증/인가
// - 리다이렉션
async function edgeHandler(request: Request) {
// 가볍고 빠른 작업만
const auth = await verifyToken(request.headers.get('authorization'));
if (!auth) {
return new Response('Unauthorized', { status: 401 });
}
return fetch(request);
}
// 🚀 Lambda Functions (AWS, GCP, Azure)
// - 실행 시간: 최대 15분
// - 메모리: 최대 10GB
// - 언어: 거의 모든 언어
// - Cold Start: 100ms-3s
// - 비용: 상대적으로 비쌈
// 적합한 경우:
// - 복잡한 로직
// - 긴 실행 시간
// - 많은 메모리
// - DB 연결
// - 파일 처리
async function lambdaHandler(event) {
// 복잡하고 무거운 작업
const image = await downloadImage(event.imageUrl);
const processed = await heavyImageProcessing(image);
await uploadToS3(processed);
await updateDatabase(event.id, processed.url);
return { statusCode: 200 };
}
하이브리드 아키텍처
현대적인 애플리케이션은 둘 다 사용합니다:
User Request
↓
Edge Function (인증, 라우팅)
↓
필요시 → Lambda (복잡한 처리)
↓
Database
최적의 성능과 비용 효율을 위해 적재적소에 배치!
Edge에서 가능한 새로운 패턴들
// 1. 점진적 마이그레이션
// 레거시 시스템을 점진적으로 교체
export async function middleware(request: NextRequest) {
const url = new URL(request.url);
// 새로운 페이지는 Next.js로
if (url.pathname.startsWith('/new')) {
return NextResponse.next();
}
// 기존 페이지는 레거시 서버로
return NextResponse.rewrite('https://legacy.example.com' + url.pathname);
}
// 2. Feature Flags
// 사용자별로 기능 토글
export async function middleware(request: NextRequest) {
const user = await getCurrentUser(request);
const flags = await getFeatureFlags(user.id);
// 응답 헤더에 플래그 추가
const response = NextResponse.next();
response.headers.set('x-features', JSON.stringify(flags));
return response;
}
// 3. 지능형 캐싱
// 사용자 상태에 따라 캐시 전략 변경
export async function edgeHandler(request: Request) {
const isPremium = await checkPremiumStatus(request);
if (isPremium) {
// 프리미엄 유저는 항상 최신 데이터
return fetch(request, { cache: 'no-cache' });
} else {
// 무료 유저는 캐시된 데이터
return fetch(request, { cache: 'force-cache' });
}
}
// 4. 봇 차단 및 보안
// 엣지에서 악의적인 요청 차단
export async function middleware(request: NextRequest) {
const ip = request.ip;
const userAgent = request.headers.get('user-agent');
// 봇 감지
if (isBot(userAgent) && !isGoodBot(userAgent)) {
return new NextResponse('Forbidden', { status: 403 });
}
// Rate limiting
const rateLimit = await checkRateLimit(ip);
if (rateLimit.exceeded) {
return new NextResponse('Too Many Requests', {
status: 429,
headers: { 'Retry-After': '60' }
});
}
return NextResponse.next();
}
에필로그: 서버리스가 바꾼 세상
2014년 → 2024년: 10년의 변화
AWS Lambda의 등장으로부터 10년, 서버리스는 주류가 되었습니다.
서버리스가 바꾼 것들
소프트웨어 개발의 민주화
스타트업:
- Before: 최소 DevOps 1명 필요, 인프라 비용 월 $500+
- After: 개발자 혼자 시작 가능, 초기 비용 거의 $0
개발 속도:
- Before: MVP까지 2-3개월 (인프라 포함)
- After: MVP까지 1-2주 (코드만 작성)
비용 구조:
- Before: 고정 비용 (서버 24/7)
- After: 변동 비용 (사용량에 비례)
스케일링:
- Before: 수동, 예측 필요, 복잡
- After: 자동, 무한대, 간단
팀 구성:
- Before: 개발자 + DevOps + SRE
- After: 개발자 (풀스택)
숫자로 보는 서버리스
서버리스 현황 (2024)
AWS Lambda:
- 월 10조+ 요청 처리
- 수백만 개발자
- 200+ AWS 서비스와 통합
Vercel:
- 월 100억+ 요청
- 10만+ 팀
- 평균 배포 시간 < 1분
Cloudflare Workers:
- 일 30조+ 요청
- 전 세계 200+ 도시
- Edge Cold Start < 5ms
영향:
- 개발자 생산성: 3-5배 향상
- 인프라 비용: 40-60% 감소
- 출시 속도: 5-10배 빠름
하지만 서버는 사라지지 않았다
서버리스는 **"서버가 없다"**는 뜻이 아닙니다. **"서버를 관리하지 않는다"**는 뜻입니다.
// 서버리스 애플리케이션도 서버 위에서 돌아감
// 단지 우리가 관리하지 않을 뿐
// Lambda 함수는 실제로는:
// - EC2 인스턴스에서 실행됨
// - Container로 격리됨
// - AWS가 모든 것을 관리함
// 우리는 이것만 신경 쓰면 됨:
export async function handler(event) {
return { statusCode: 200, body: 'Hello' };
}
// 나머지는 AWS가:
// - 인스턴스 프로비저닝
// - 스케일링
// - 로드 밸런싱
// - 장애 복구
// - 모니터링
// 모두 자동
"서버리스는 서버가 없다는 뜻이 아닙니다. 개발자가 서버에 대해 생각할 필요가 없다는 뜻입니다."
서버리스의 미래
WebAssembly + Serverless
더 빠른 Cold Start, 더 많은 언어 지원
Serverless Containers
Fargate, Cloud Run 등 컨테이너 기반 서버리스
Edge-First 아키텍처
모든 것을 엣지에서
AI/ML과 통합
서버리스 GPU, 추론 엔드포인트
Database도 서버리스
Aurora Serverless, Neon, PlanetScale
완벽한 추상화는 없다
서버리스는 강력하지만 만능은 아닙니다:
// 서버리스가 숨기는 복잡성들
// 1. 분산 시스템의 복잡성
// - 네트워크 지연
// - 부분 실패
// - 일관성 문제
// 2. Cold Start
// - 첫 요청은 느림
// - 사용자 경험 영향
// 3. 벤더 종속
// - AWS Lambda → GCP로 이전 어려움
// - API 차이
// 4. 디버깅의 어려움
// - 로컬 재현 어려움
// - 분산 추적 필요
// 5. 비용 예측의 어려움
// - 트래픽 급증 시 비용 폭탄
// - 모니터링 필수
서버리스 채택 시 주의사항
다음과 같은 경우 신중하게:
- 레이턴시가 매우 중요한 경우 (< 10ms)
- 상태 관리가 복잡한 경우
- 기존 레거시 시스템이 큰 경우
- 팀이 분산 시스템에 익숙하지 않은 경우
시작 전 확인:
- 비용 모델 이해
- 제한사항 파악 (실행 시간, 메모리 등)
- 모니터링 설정
- Cold Start 전략
서버리스의 본질
결국 서버리스는 추상화의 진화입니다:
# 추상화의 역사
1990s: Physical Servers
"서버 랙에 설치하고 케이블 연결"
2000s: Virtual Machines (AWS EC2)
"가상화로 빠른 프로비저닝"
2010s: Containers (Docker)
"격리와 이식성"
2014~: Serverless (Lambda)
"서버 추상화, 코드만 작성"
2020~: Edge Computing
"지리적 분산, 레이턴시 최소화"
미래: ?
"더 높은 수준의 추상화"
"Good abstractions allow people to build on top of them and create higher-level constructs."
서버리스는 개발자가 비즈니스 로직에 집중할 수 있게 합니다. 인프라는 플랫폼이 관리합니다.
2014년, AWS Lambda는 **"서버를 관리하지 않고 코드만 배포한다"**는 꿈을 현실로 만들었습니다.
2024년, 그 꿈은 표준이 되었습니다.
참고자료
AWS Lambda Documentation
AWS Lambda 공식 문서
Serverless Framework
서버리스 애플리케이션 개발 프레임워크
Next.js Documentation
Next.js 공식 문서
Cloudflare Workers Documentation
Cloudflare Workers 공식 문서
JAMstack.org
JAMstack 공식 사이트
Martin Fowler - Serverless Architectures
서버리스 아키텍처 설명
AWS Lambda: The First Decade
Lambda 10년의 역사
다음 에피소드에서는 "마이크로서비스: 모놀리스의 해체"를 다룰 예정입니다. 거대한 시스템을 작은 조각으로 나누는 여정을 살펴보겠습니다.