- Authors

- Name
- Youngju Kim
- @fjvbn20031
들어가며 — "지금 Kubernetes가 필요한가?"
스타트업 창업자가 묻는다.
"우리도 Kubernetes 써야 하나요? Netflix는 Microservices라던데."
답: 사용자 100명이면 VPS 한 대로 충분하다. Netflix가 Microservices를 도입한 건 2억 명 사용자였고, 그 전엔 모놀리스였다. Shopify는 수십억 달러 GMV까지 Rails 모놀리스였다. Stack Overflow는 수천만 방문자를 서버 9대로 처리한다.
스케일링은 "미래의 100만 사용자"를 위한 게 아니다. 지금 막히는 병목을 푸는 것이다.
이 글은 사용자 수 변곡점별로:
- 무엇이 깨지는가 (구체적 병목)
- 어떻게 푸는가 (패턴과 트레이드오프)
- 언제 해야 하는가 (너무 일찍 vs 너무 늦게)
- 실제 회사들의 사례 (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는 아직 복제 전
- 사용자는 자기 글을 못 봄 → 혼란
해결:
- Session stickiness: 쓰기 직후 N초간 Primary 읽기
- 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가지
- Thundering Herd: 인기 키 만료되는 순간 1000개 요청이 동시에 DB 때림 → 분산 락 또는 "확률적 early expiration"
- Cache Stampede: TTL 만료 → 재계산 비용 큰 쿼리 → 줄줄이 대기
- 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대
비결:
- 과격한 캐싱: 거의 모든 페이지 전체 캐싱
- C#과 튜닝: JIT로 컴파일, 수동 최적화
- SQL 서버 의존: 스토어드 프로시저, 인덱스 최적화
- 모놀리스 고수: 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"
- 강하게 연결된 테이블은 같은 DB에
- 약하게 연결된 테이블은 분리
- 점진적으로 여러 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:
- 새 기능은 새 서비스로
- 기존 기능을 하나씩 이관
- 최종적으로 모놀리스는 빈 껍데기
Branch by Abstraction:
- 기존 로직 앞에 추상화 레이어
- 레이어 뒤에서 점진적 구현 교체
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 언어 교체가 정당화되는 경우
- 동시성이 진짜 병목: Python GIL 때문에 멀티코어 못 씀 → Go/Rust
- 메모리가 진짜 병목: Ruby/Python 메모리 2~3배 → Go (1/3)
- 배포 단순화: Ruby 런타임 + gem 지옥 → Go 단일 바이너리
- 팀 역량: 대부분의 개발자가 해당 언어 숙련
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)은 유명하지만:
- Spotify 자신조차 공식적으로 쓰지 않는다고 2020년 밝힘
- "Model"이 아니라 그 순간의 "스냅샷"이었음
- 무비판적 복사는 위험
교훈: 다른 회사의 조직 구조는 참고만. 본인 회사에 맞는 걸 실험.
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은 사용자 규모 커지면 월 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 청구서를 아무도 안 본다. 월 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
- Shopify Pods Architecture
- Figma's Journey to Horizontal Scaling
- Discord Messaging - ScyllaDB
- Dropbox 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 컨텍스트의 차이
- 당신의 회사에 맞는 문화 고르기
다음 글에서.