들어가며 — "지금 Kubernetes가 필요한가?"
스타트업 창업자가 묻는다.
> "우리도 Kubernetes 써야 하나요? Netflix는 Microservices라던데."
답: **사용자 100명이면 VPS 한 대로 충분**하다. Netflix가 Microservices를 도입한 건 **2억 명** 사용자였고, 그 전엔 모놀리스였다. Shopify는 **수십억 달러 GMV**까지 Rails 모놀리스였다. Stack Overflow는 **수천만 방문자**를 서버 9대로 처리한다.
**스케일링은 "미래의 100만 사용자"를 위한 게 아니다. 지금 막히는 병목을 푸는 것이다.**
이 글은 사용자 수 변곡점별로:
1. **무엇이 깨지는가** (구체적 병목)
2. **어떻게 푸는가** (패턴과 트레이드오프)
3. **언제 해야 하는가** (너무 일찍 vs 너무 늦게)
4. **실제 회사들의 사례** (Stack Overflow, Shopify, Discord, Figma, Instagram)
을 한 번에 꿰어서 다룬다. Season 3 Episode 3이자, 지난 글 "유명 포스트모템 해부"에서 다뤘던 실패 사례들이 결국 "스케일링 변곡점을 잘못 다뤘을 때" 터진다는 교훈의 연장선이다.
Chapter 1: 100명 — 단일 서버의 시대
1.1 아키텍처
[사용자]
↓
[DNS → VPS 1대]
↓
[Nginx + App + SQLite + Redis 모두 한 박스]
- **서버**: DigitalOcean $12/월 드롭렛 (2vCPU, 4GB RAM)
- **DB**: SQLite 또는 Postgres (로컬)
- **배포**: git pull + systemctl restart
- **모니터링**: htop + tail -f
- **백업**: cron으로 매일 S3에 덤프
1.2 왜 이게 충분한가
100명이 동시에 접속해도 초당 요청 수(RPS)는 고작 10~50 정도다. 최신 노트북조차 **수천 RPS**를 처리한다. 병목은 사용자 수가 아니라 쿼리 품질이다.
> "Premature optimization is the root of all evil." — Donald Knuth
1.3 하지 말아야 할 것들
- Kubernetes 클러스터 구성 (운영 비용 > 이득)
- Microservices 분리 (팀 1명이 5개 서비스 운영 지옥)
- Kafka 도입 (PostgreSQL의 NOTIFY/LISTEN으로 충분)
- Elasticsearch 별도 운영 (Postgres full-text search로 충분)
1.4 실제 사례 — Pieter Levels의 Nomad List
Pieter Levels는 혼자서 **월 $100K** 매출의 SaaS를 운영한다. 구성:
- 단일 VPS
- SQLite
- PHP
- jQuery
- 배포: rsync
복잡도를 거부한 덕에 혼자 10개 제품을 동시에 유지한다. **"보링한 기술(Boring Technology)"의 힘**.
Chapter 2: 1,000명 — 수직 확장의 황금기
2.1 깨지는 것
- DB와 앱이 CPU를 놓고 싸움
- 백업 중 IO 병목으로 응답 지연
- 한 번 재부팅하면 전체 다운타임
2.2 해결책: 분리와 수직 확장
[사용자]
↓
[Cloudflare (CDN + DNS)]
↓
[App 서버 1대] ── [DB 서버 1대]
↓
[Daily Backup → S3]
- **App/DB 분리**: 서로 간섭 제거
- **DB는 수직 확장**: 8vCPU, 32GB RAM까지 충분
- **CDN 도입**: 정적 자산 오프로드 (Cloudflare 무료 플랜)
- **헬스체크 + 자동 재시작**: systemd 또는 Docker --restart unless-stopped
2.3 수직 확장의 미덕
> "수평 확장을 고민하기 전에, 수직 확장의 한계를 알아야 한다."
AWS r7i.48xlarge는 **192 vCPU, 1,536GB RAM**을 제공한다. 대부분의 스타트업은 이 크기에 도달하기 전에 팔리거나 망한다.
- **단순함**: 샤딩 없음, 트랜잭션 그대로 작동
- **운영 부담 최소**: "서버 한 대 잘 돌보면 끝"
- **비용 효율**: 인스턴스 단가는 코어당 비슷, 운영 시간 > 하드웨어 비용
2.4 이 단계에서 해야 할 것
- **정기 백업 + 복구 리허설** (월 1회)
- **슬로우 쿼리 로그 활성화** (`log_min_duration_statement = 1000`)
- **에러 추적 도구** (Sentry 무료 플랜)
- **인덱스 점검** (`pg_stat_user_indexes`)
Chapter 3: 10,000명 — 캐시와 읽기 복제본의 시대
3.1 깨지는 것
- DB 읽기가 쓰기보다 100배 많음 (전형적 Read/Write 비율)
- 단일 App 서버 CPU 한계
- 페이지 로드 시간 증가 (DB 왕복 너무 많음)
3.2 해결책: Read Replica + Redis + 로드 밸런서
[사용자]
↓
[CDN: Cloudflare/Fastly]
↓
[Load Balancer: ALB/Cloudflare]
↓
[App x 2~4대]
↓
[Redis (세션/캐시)] — [Postgres Primary] ──replication──→ [Replica x 1~2]
3.3 Read Replica 전략
Django 예시
DATABASES = {
'default': {'HOST': 'primary.db', ...},
'replica': {'HOST': 'replica.db', ...},
}
class ReadReplicaRouter:
def db_for_read(self, model, **hints):
return 'replica'
def db_for_write(self, model, **hints):
return 'default'
**주의: Read-Your-Write 문제**
- 사용자가 게시글 작성 직후 목록 페이지로 이동
- Primary에 쓰여진 직후, Replica는 아직 복제 전
- 사용자는 자기 글을 못 봄 → 혼란
**해결**:
1. **Session stickiness**: 쓰기 직후 N초간 Primary 읽기
2. **Causal consistency**: 쓰기 LSN(Log Sequence Number) 추적, Replica가 해당 LSN까지 올라올 때까지 대기
3.4 Redis 캐싱 패턴 3가지
**Cache-aside (가장 흔함)**:
def get_user(user_id):
cached = redis.get(f'user:{user_id}')
if cached:
return json.loads(cached)
user = db.query('SELECT * FROM users WHERE id = %s', user_id)
redis.setex(f'user:{user_id}', 300, json.dumps(user))
return user
**Write-through**: 쓰기 시 DB + Cache 동시 업데이트. 일관성 높음, 쓰기 레이턴시 증가.
**Write-behind**: Cache에 쓰고 비동기로 DB에 쓰기. 빠름, but Redis 죽으면 데이터 손실 위험.
3.5 캐시 함정 3가지
1. **Thundering Herd**: 인기 키 만료되는 순간 1000개 요청이 동시에 DB 때림 → 분산 락 또는 "확률적 early expiration"
2. **Cache Stampede**: TTL 만료 → 재계산 비용 큰 쿼리 → 줄줄이 대기
3. **Cache Invalidation**: "2 hard things in CS: naming things, cache invalidation, and off-by-one errors"
3.6 실제 사례 — Stack Overflow
Stack Overflow는 **월 13억 페이지뷰**를 서버 **9대**로 처리한다 (2023년 기준):
- Web 서버 4대
- SQL 서버 2대 (Primary/Replica)
- Redis 2대
- Elasticsearch 3대
- HAProxy 2대
비결:
1. **과격한 캐싱**: 거의 모든 페이지 전체 캐싱
2. **C#과 튜닝**: JIT로 컴파일, 수동 최적화
3. **SQL 서버 의존**: 스토어드 프로시저, 인덱스 최적화
4. **모놀리스 고수**: Microservices 거부
**교훈: 기술 선택보다 "잘하는 것"이 중요하다.**
Chapter 4: 100,000명 — Write 확장의 시작
4.1 깨지는 것
- Read Replica 10개 있어도 Primary는 여전히 1대
- 쓰기 병목: 초당 수천 INSERT/UPDATE
- DB 백업 시간 > 복구 RTO
- 단일 AZ 장애 = 전체 다운
4.2 해결책 1: Queue 기반 비동기화
[User Request]
↓
[Web] → [SQS/Redis Queue] ← Pop ← [Worker x N]
↓ ↓
"접수됨" 즉시 응답 [DB Write]
- **즉시 응답 + 백그라운드 처리**: 사용자 체감 빨라짐
- **부하 흡수**: 스파이크 시 Queue가 버퍼 역할
- **재시도 용이**: 실패 시 재큐잉
**대상 작업**:
- 이메일 발송
- 썸네일 생성
- 대용량 집계
- 웹훅 전송
- 외부 API 호출
4.3 해결책 2: CQRS (Command Query Responsibility Segregation)
- **Command (쓰기)**: Primary DB
- **Query (읽기)**: 별도 읽기 최적화된 저장소 (Elasticsearch, Materialized View, read replica)
예: 전자상거래
- 주문 쓰기 → Postgres
- 검색/리스트 읽기 → Elasticsearch (비동기 동기화)
4.4 해결책 3: Connection Pooling
PostgreSQL은 **각 연결이 OS 프로세스**. 1만 연결 = 1만 프로세스 = 메모리 고갈.
**PgBouncer** 도입:
[App x 100대 × 100 conn = 10,000 conn]
↓
[PgBouncer: 500 실제 연결만 유지]
↓
[Postgres (500 backend)]
모드:
- **Session**: 클라이언트 세션 동안 1:1 (LISTEN/NOTIFY 필요 시)
- **Transaction**: 트랜잭션 단위로 재사용 (가장 흔함)
- **Statement**: 쿼리 단위 (Prepared Statement 못 씀)
4.5 해결책 4: Multi-AZ
- **Primary는 AZ-a**
- **Standby는 AZ-b** (동기 복제)
- **Read Replica는 AZ-c**
RDS Multi-AZ는 자동으로 이걸 해준다. Failover 30~60초.
4.6 실제 사례 — Shopify의 Pod 아키텍처
Shopify는 2020년경 **"Pod" 아키텍처**로 전환:
- 각 Pod는 독립된 DB + Redis + Memcached
- Shop ID로 Pod 라우팅
- 한 Pod 장애 = 일부 상점만 영향
이건 샤딩의 한 형태지만, 중요한 건:
> "We kept it a Rails monolith. Pods are operational boundaries, not service boundaries."
모놀리스 + 수평 파티셔닝 조합으로 **Black Friday에 초당 수천만 요청** 처리.
Chapter 5: 1,000,000명 — 샤딩의 시대
5.1 깨지는 것
- 단일 Primary의 쓰기 한계 (NVMe SSD로도 초당 수만 IOPS가 끝)
- DB 크기 > 10TB → 백업, 인덱스 재구성 시간 증가
- 모든 쿼리가 글로벌 락(autovacuum, ALTER TABLE) 영향받음
5.2 샤딩 전략 3가지
**1) Hash-based Sharding**:
shard_id = hash(user_id) % N
- **장점**: 균등 분포
- **단점**: 리샤딩 어려움 (N 바꾸면 대부분 데이터 이동)
- **해결**: Consistent Hashing (링 구조)
**2) Range-based Sharding**:
user_id 1~1M → shard_1
user_id 1M~2M → shard_2
- **장점**: 범위 쿼리 효율
- **단점**: Hot shard 생기기 쉬움 (최근 사용자 몰림)
**3) Directory-based (Lookup) Sharding**:
lookup_table: user_id → shard_id
- **장점**: 유연한 재분배
- **단점**: Lookup 자체가 병목 가능성
5.3 샤드 키 선택의 예술
**좋은 샤드 키**:
- user_id, tenant_id: 대부분 쿼리가 이걸로 시작
- 카디널리티 높음 (골고루 분산)
**나쁜 샤드 키**:
- timestamp: 항상 최신 shard에 몰림
- country: 한국 유저 많으면 한국 shard만 터짐
5.4 Cross-shard 쿼리 지옥
-- 샤딩 전
SELECT COUNT(*) FROM orders WHERE status = 'pending';
-- 샤딩 후: 모든 shard에 fan-out
SELECT COUNT(*) FROM shard_1.orders WHERE status = 'pending'
UNION ALL
SELECT COUNT(*) FROM shard_2.orders WHERE status = 'pending'
...
-- 집계 로직은 애플리케이션 레이어에서
**JOIN across shards**는 거의 불가능. 설계 초기에:
- 관련 데이터는 같은 shard에 (user의 모든 데이터는 user shard에)
- 글로벌 데이터는 별도 테이블 (products, categories)
5.5 실제 사례 — Discord의 Cassandra → ScyllaDB
Discord는 **초당 수백만 메시지**를 다룬다. 2017년 Cassandra 도입:
- 초기: MongoDB (스키마 변경 지옥, 특정 쿼리에서 느림)
- 이동: Cassandra (메시지 저장 전용)
- 2022: ScyllaDB (Cassandra 호환, C++ 재작성, 2-5배 빠름)
Partition key: `(channel_id, bucket)` where bucket = timestamp / 2주
→ 한 채널 메시지가 여러 partition에 분산. Hot partition 회피.
**트레이드오프**: 채팅 검색이 어려워짐 (Elasticsearch 별도).
Chapter 6: 10,000,000명 — 멀티 리전과 엣지
6.1 깨지는 것
- 미국 서버에서 일본 사용자 → 200ms+ 왕복
- 단일 리전 장애 = 전체 다운
- Compliance (GDPR, 개인정보보호법) — 데이터 거주 지역 요구
6.2 전략 1: CDN + 엣지 컴퓨팅
[사용자, 도쿄] → [Cloudflare 엣지, 도쿄] → (cache hit) 1ms
↓ (cache miss)
[Origin, 미국] 150ms
**Cloudflare Workers**, **Vercel Edge Functions**, **AWS Lambda@Edge**:
- 인증, 리다이렉트, A/B 테스트를 엣지에서
- 전체 페이지는 엣지 캐싱 (SWR, ISR)
- Origin 부하 90%+ 절감
6.3 전략 2: Multi-region Active-Active
**문제**: 동일 사용자의 쓰기가 여러 리전에서 발생 → 충돌 해결 필요
**해결책**:
- **CRDT** (Conflict-free Replicated Data Types): 카운터, 집합 등은 수학적으로 충돌 해결
- **Last-Write-Wins**: 단순하지만 데이터 소실 가능
- **Region pinning**: 사용자를 특정 리전에 고정, 리전 장애 시만 다른 리전으로
6.4 전략 3: 글로벌 분산 DB
- **Spanner** (Google): TrueTime API로 전 세계 강 일관성
- **CockroachDB**: Spanner 오픈소스 대안
- **YugabyteDB**: PostgreSQL 호환
- **DynamoDB Global Tables**: 쉬움, eventually consistent
6.5 실제 사례 — Figma의 분할 점령
Figma는 2020년 기준 **단일 Postgres**를 썼다. 그러다 CPU 65%+ 도달 위기.
**선택**: Microservices로 완전 분해 (risky, 느림) vs 수평 파티셔닝 (incremental).
**전략**: "colo (co-location) by foreign key"
1. 강하게 연결된 테이블은 같은 DB에
2. 약하게 연결된 테이블은 분리
3. 점진적으로 여러 Postgres로 쪼갬
결과: **무중단으로 9개 DB로 분산**, 단일 장애점 제거.
**교훈**: 빅뱅 리팩토링 대신 점진적 분할. 각 단계마다 롤백 가능하게.
Chapter 7: Microservices는 언제?
7.1 Conway의 법칙
> "조직은 자신의 의사소통 구조를 복제한 시스템을 설계한다." — Melvin Conway
팀이 10개면 서비스 10개. 팀이 2개면 서비스 2개로 충분.
7.2 Microservices 준비도 체크리스트
모놀리스로 먼저 해결해야 할 질문들:
- [ ] CI/CD 자동화됐는가?
- [ ] 10분 이내 배포 가능한가?
- [ ] Feature flag로 Dark launch 가능한가?
- [ ] 관측성(Observability) 갖췄는가?
- [ ] 온콜 문화 정착됐는가?
- [ ] 팀이 진짜 여러 개 있는가? (한 팀이 여러 서비스 ≠ Microservices)
**답이 "No"가 많다면, 모놀리스 유지.**
7.3 모놀리스 → Microservices 전환 패턴
**Strangler Fig Pattern**:
1. 새 기능은 새 서비스로
2. 기존 기능을 하나씩 이관
3. 최종적으로 모놀리스는 빈 껍데기
**Branch by Abstraction**:
1. 기존 로직 앞에 추상화 레이어
2. 레이어 뒤에서 점진적 구현 교체
7.4 실제 사례 — Netflix의 7년
Netflix가 DVD 대여에서 스트리밍으로 전환하며 Microservices 도입:
- 2008년: 모놀리스 DB 장애 → 3일간 DVD 배송 중단
- 2009~2016년: 7년 동안 점진적 이관
- 2016년: 완전 Microservices + AWS
**7년!** 하룻밤에 안 된다.
Chapter 8: 언어 바꾸기 — 언제?
8.1 언어 교체의 진짜 이유
흔한 오해: "Python이 느려서 Go로 바꿨다."
실제: **CPU가 병목인 경우는 드물다**. 대부분 병목은:
- DB 쿼리
- 외부 API 대기
- 네트워크 IO
8.2 언어 교체가 정당화되는 경우
1. **동시성이 진짜 병목**: Python GIL 때문에 멀티코어 못 씀 → Go/Rust
2. **메모리가 진짜 병목**: Ruby/Python 메모리 2~3배 → Go (1/3)
3. **배포 단순화**: Ruby 런타임 + gem 지옥 → Go 단일 바이너리
4. **팀 역량**: 대부분의 개발자가 해당 언어 숙련
8.3 실제 사례 — Twitter의 Scala
Twitter 초기: Ruby on Rails. "Fail Whale"로 유명.
2009년: 백엔드를 JVM 기반 Scala로 전환.
이유:
- JVM의 성숙한 GC
- 정적 타입 (대규모 팀 유지보수)
- 기존 Java 생태계
**주의**: 프론트엔드/웹은 한동안 Rails 유지. "적재적소(right tool for the job)".
8.4 실제 사례 — Dropbox의 Go
Dropbox 초기: Python.
2014년: 일부 시스템을 Go로 재작성.
**재작성한 것**: 동기화 엔진(Sync engine), 성능 크리티컬 코드.
**유지한 것**: 웹, API 대부분은 여전히 Python.
**교훈**: "전체 재작성"이 아니라 "핫패스만 재작성".
8.5 Magic Pocket — Dropbox의 Go 스토리지
Dropbox는 2016년 **Amazon S3에서 자체 스토리지**로 이전 — Magic Pocket 프로젝트:
- 언어: Go
- 이유: 저장 비용, 레이턴시, 성능 제어
- 규모: **엑사바이트** 수준
- 결과: 수억 달러 절감
Go 선택 이유:
- 쉬운 동시성 (goroutine)
- GC 있어도 레이턴시 예측 가능
- 팀 온보딩 빠름 (문법 단순)
Chapter 9: 데이터 계층의 10배 성장
9.1 1GB → 10GB
단일 Postgres에서 편안. 인덱스 관리, VACUUM 주의.
9.2 10GB → 100GB
- 슬로우 쿼리 튜닝 필수
- Partial index 고려
- Connection pooling 필수
9.3 100GB → 1TB
- Partitioning (테이블 파티셔닝): 시간 기반 또는 해시 기반
- pg_partman, TimescaleDB 고려
- Archival 전략 (S3로 오래된 데이터 이관)
9.4 1TB → 10TB
- 논리적 파티셔닝만으론 부족
- 다른 DB로 쪼개기 시작 (로그성 → OLAP로)
- Read replica 추가
9.5 10TB → 100TB
- 완전 샤딩 시대
- OLAP는 Snowflake/BigQuery/Redshift로 분리
- 시계열은 ClickHouse
- 벡터는 전용 DB (Pinecone, pgvector)
9.6 실제 사례 — GitHub의 Vitess
GitHub는 **MySQL** 위에서 돌아간다. 규모가 커지자 Vitess 도입:
- Vitess = MySQL 샤딩 게이트웨이 (YouTube 출신)
- 애플리케이션은 그대로 MySQL 쿼리
- Vitess가 샤드 라우팅, 백업, 스키마 변경 자동화
**교훈**: "샤딩을 애플리케이션 코드에 스며들게 하지 말라. 게이트웨이로 추상화."
Chapter 10: 조직의 스케일링
10.1 팀 크기별 원칙
**1~10명**: 모두가 모든 코드 이해. 소통 비용 적음. Microservices 금지.
**10~50명**: 팀 분리 시작 (Frontend, Backend, Platform). Monorepo + 모듈 분리.
**50~200명**: Service ownership 명확화. Platform team이 공통 인프라 담당.
**200~1000명**: Organizational boundary = Service boundary. 전담 SRE, Security, DBA.
**1000명+**: 회사 안에 회사. 내부 플랫폼이 오픈소스화되기도 (Google Borg → Kubernetes).
10.2 Amazon의 Two-Pizza Rule
> "팀은 피자 2판으로 먹일 수 있는 크기여야 한다." — Jeff Bezos
약 6~10명. 이 크기에서 소통 비용 최소화. 각 팀은 풀스택 오너십.
10.3 Spotify Model의 오해
"Spotify Model" (Squad, Tribe, Chapter, Guild)은 유명하지만:
1. Spotify 자신조차 공식적으로 쓰지 않는다고 2020년 밝힘
2. "Model"이 아니라 그 순간의 "스냅샷"이었음
3. 무비판적 복사는 위험
**교훈**: 다른 회사의 조직 구조는 참고만. 본인 회사에 맞는 걸 실험.
Chapter 11: Observability의 스케일링
11.1 로그의 진화
**100명**: grep
**10K명**: CloudWatch Logs, Papertrail
**1M명**: ELK (Elasticsearch + Logstash + Kibana)
**10M명**: Loki, ClickHouse 기반 자체 구축 (비용)
11.2 메트릭의 진화
**100명**: Cloudwatch 기본
**10K명**: Prometheus + Grafana
**1M명**: Thanos/Cortex로 Prometheus 수평 확장
**10M명**: M3DB, VictoriaMetrics
11.3 Trace의 진화
**100명**: 안 씀
**10K명**: Sentry 같은 APM
**1M명**: Datadog APM, New Relic
**10M명**: OpenTelemetry + Tempo/Jaeger, 샘플링 전략 필수
11.4 비용 폭발 주의
Datadog은 사용자 규모 커지면 **월 $100K+** 쉽게 간다. Coinbase는 2022년 월 **$65M** Datadog 비용 썼다고 알려짐.
**완화**:
- Log sampling
- Low-cardinality 메트릭만 Datadog, 고카디널리티는 자체 시스템
- Trace 샘플링 (1%~0.1%)
Chapter 12: 스케일링 변곡점 체크리스트 (12항목)
- [ ] **사용자 수 확인**: 현재, 6개월 후, 1년 후 예상
- [ ] **병목 측정**: CPU, IO, Memory, Network 중 무엇이 먼저 빨간불인가
- [ ] **Read/Write 비율**: 100:1인가, 10:1인가, 1:1인가
- [ ] **Read replica 도입 시점**: Primary read CPU 60%+
- [ ] **Cache 도입**: 동일 쿼리 반복, 외부 API 비용 높음
- [ ] **비동기화 대상 식별**: 이메일, 썸네일, 웹훅, 집계
- [ ] **Connection pooling**: Postgres connection > 200
- [ ] **Multi-AZ**: 매출이 다운타임 1시간을 용납 못 할 때
- [ ] **샤딩 검토**: 단일 Primary 쓰기 한계 도달 or DB > 1TB
- [ ] **Multi-region**: 글로벌 사용자 > 30%, 또는 compliance 요구
- [ ] **Microservices 타당성**: 팀 10개+, CI/CD 성숙, 관측성 갖춤
- [ ] **비용 추적**: 사용자당 인프라 비용(CAC, LTV와 함께)
Chapter 13: 10가지 안티패턴
1) 조기 Microservices 분리
팀 5명인데 서비스 10개. 각자 5개씩 운영. 배포만으로 하루 끝. **모놀리스부터.**
2) 과도한 추상화
미래의 교체 가능성을 대비해 모든 의존성에 인터페이스. **YAGNI (You Aren't Gonna Need It).**
3) Resume-driven Development
"이력서에 쓰려고" Kafka, Kubernetes, Microservices 도입. **팀 과제가 아니라 개인 과제.**
4) Big Bang Rewrite
전체 코드베이스 2년에 걸쳐 재작성. 끝났을 땐 시장이 바뀌어 있음. **Strangler Fig 사용.**
5) Cache만 추가하면 해결된다는 착각
캐시는 일관성 문제, Stampede 문제, 무효화 문제를 덤으로 준다. **캐시 없이 먼저 튜닝.**
6) Premature Sharding
사용자 1만에 샤딩 시작. Cross-shard 쿼리 지옥. **수직 확장의 끝까지 가라.**
7) 3-tier 흉내내기
"DB — Backend — Frontend 3 tier"만 있으면 확장성 있다는 미신. **실제 병목은 측정해야 안다.**
8) "It works on my machine"
로컬에선 SQLite, 프로덕션은 Postgres. 로컬 Mongo 3.4, 프로덕션 Mongo 7.0. **Dev/Prod parity (12-factor).**
9) Observability 후순위
"바빠서 로그/메트릭은 나중에." 장애 나면 맨눈으로 디버깅. **Day 1부터 관측성.**
10) 비용 무관심
AWS 청구서를 아무도 안 본다. 월 $50K가 $200K 됨. **FinOps는 Day 1.**
마치며 — 스케일링의 진짜 원칙
원칙 1: 측정 먼저
추측으로 최적화하지 말라. 프로파일링, APM, 로그 보고 진짜 병목 확인.
원칙 2: 충분히 늦게, 충분히 일찍
- **너무 일찍**: Kubernetes를 사용자 100명에 도입. 운영 부담 폭발.
- **너무 늦게**: 1M 사용자에 단일 Postgres. 매일 장애.
- **적절히**: "3개월 후 필요할 것 같다" 정도 타이밍.
원칙 3: 가장 지루한 솔루션 먼저
Postgres, Redis, Linux, Nginx. 50년 된 기술들이 최신 "혁신" 대부분을 이긴다.
원칙 4: 점진적 진화
빅뱅은 실패율이 높다. 각 단계마다 롤백 가능하게.
원칙 5: 스케일링은 기술만이 아니다
조직, 프로세스, 문화가 함께 스케일해야 한다. Conway의 법칙을 기억하라.
원칙 6: 원본을 읽어라
- [Stack Overflow Architecture 2016](https://nickcraver.com/blog/2016/02/17/stack-overflow-the-architecture-2016-edition/)
- [Shopify Pods Architecture](https://shopify.engineering/a-pods-architecture-to-allow-shopify-to-scale)
- [Figma's Journey to Horizontal Scaling](https://www.figma.com/blog/how-figmas-databases-team-lived-to-tell-the-scale/)
- [Discord Messaging - ScyllaDB](https://discord.com/blog/how-discord-stores-trillions-of-messages)
- [Dropbox Magic Pocket](https://dropbox.tech/infrastructure/inside-the-magic-pocket)
다음 글 예고 — "빅테크 개발 문화 완전 가이드: Google, Meta, Amazon, Netflix의 차이"
Season 3 Ep 4는:
- Google: TGIF, Design doc 문화, Perf review의 디테일
- Meta: Move fast, Bootcamp, Dogfooding
- Amazon: Two-pizza team, Working backwards, 6-page memo
- Netflix: Keeper test, Freedom & Responsibility
- Apple: 비밀주의, Hardware/Software 통합
- 한국 빅테크(네이버, 카카오, 쿠팡)는 무엇이 다른가
- 문화를 모방할 수 있을까 vs 컨텍스트의 차이
- 당신의 회사에 맞는 문화 고르기
다음 글에서.
현재 단락 (1/360)
스타트업 창업자가 묻는다.