ì€ë²ìì§ëìŽë§ì íšì
"ì°ëЬë ì ëìœìŽ ë ê±°ëê¹ ì²ìë¶í° ë§ìŽí¬ë¡ìë¹ì€ë¡ ê°ì!"
6ê°ì í, ìŽ ì€íížì ì ë³µì¡í ìì€í ì ì§ë³Žìì ì§ì³ íì íìµëë€.
ì€íížì ìí€í ì²ì ëë ë§:
- ë묎 ëšìí멎? â ì±ì¥ ì ì 멎 ì¬ê°ë°
- ë묎 ë³µì¡í멎? â ê°ë° ìë ì í, ë¹ì© íìŠ
- ì ëµì? â ì§í ê°ë¥í ìí€í ì²
ì€ì íµê³:
- ì€íížì ì 90%ë ìì ížëíœì 10%ë 못 ë°ì
- íì§ë§ ì±ê³µí 10%ë 100ë°° ìŽì ì±ì¥
- ì¬ê°ë°ë¡ ìží íê· ìì€: 6ê°ì, 10ìµì
ì€íížì ì±ì¥ ëšê³ë³ ìí€í ì² ì§í
Stage 1: MVP (0-1,000 ì¬ì©ì)
목í: ë¹ ë¥ž ê°ë°ê³Œ ê²ìŠ
âââ ì¬ì©ì: 0-1,000ëª
âââ ížëíœ: 100 req/min
âââ ë°ìŽí°: < 1GB
âââ í ê·ëªš: 1-3ëª
ìí€í
ì²:
âââââââââââââââââââââââ
â Monolithic App â
â (Next.js + API) â
ââââââââââââ¬âââââââââââ
â
ââââââââŒâââââââ
â PostgreSQL â
â (Supabase)â
âââââââââââââââ
êž°ì ì€í:
âââ Frontend: Next.js
âââ Backend: Next.js API Routes
âââ Database: PostgreSQL (Supabase)
âââ Hosting: Vercel
âââ ë¹ì©: ì 0-10ë§ì
ìœë 구조 ìì:
// pages/api/users/[id].ts - ëšìí 몚ë늬ì API
export default async function handler(req, res) {
const { id } = req.query
if (req.method === 'GET') {
const user = await db.user.findUnique({ where: { id } })
return res.json(user)
}
if (req.method === 'PUT') {
const user = await db.user.update({
where: { id },
data: req.body
})
return res.json(user)
}
}
Stage 2: Product-Market Fit (1,000-10,000 ì¬ì©ì)
목í: ìì ì±ê³Œ ì±ë¥ ê°ì
âââ ì¬ì©ì: 1,000-10,000ëª
âââ ížëíœ: 1,000 req/min
âââ ë°ìŽí°: 1-100GB
âââ í ê·ëªš: 3-10ëª
ìí€í
ì²:
ââââââââââââââââ ââââââââââââââââ
â Frontend ââââââ¶â Backend â
â (Next.js) â â (Node.js) â
ââââââââââââââââ ââââââââ¬ââââââââ
â
ââââââââââââŒâââââââââââ
â â
ââââââŒâââââ âââââââŒâââââ
âPrimary DBââââââââââ¶â Redis â
â(PostgreSQL) â Cache â
âââââââââââ ââââââââââââ
êž°ì ì€í:
âââ Frontend: Next.js (Vercel)
âââ Backend: Express.js (AWS EC2)
âââ Database: PostgreSQL (RDS)
âââ Cache: Redis
âââ CDN: CloudFront
âââ ë¹ì©: ì 50-200ë§ì
ê°ì ë ìœë 구조:
// services/userService.ts - ìë¹ì€ ë ìŽìŽ ë¶ëЬ
class UserService {
async getUser(id: string) {
// ìºì 뚌ì íìž
const cached = await redis.get(`user:${id}`)
if (cached) return JSON.parse(cached)
// DB ì¡°í
const user = await db.user.findUnique({ where: { id } })
// ìºì ì ì¥
await redis.setex(`user:${id}`, 3600, JSON.stringify(user))
return user
}
async updateUser(id: string, data: any) {
const user = await db.user.update({ where: { id }, data })
// ìºì 묎íší
await redis.del(`user:${id}`)
return user
}
}
Stage 3: ì€ìŒìŒì (10,000-100,000 ì¬ì©ì)
목í: ìí íì¥ê³Œ ê³ ê°ì©ì±
âââ ì¬ì©ì: 10,000-100,000ëª
âââ ížëíœ: 10,000 req/min
âââ ë°ìŽí°: 100GB-1TB
âââ í ê·ëªš: 10-30ëª
ìí€í
ì²:
âââââââââââââââ
âLoad Balancerâ
ââââââââ¬âââââââ
â
âââââââââââââŒââââââââââââ
â â â
âââââŒââââ ââââââŒââââ âââââââŒââââ
â API â â API â â API â
âServer1â â Server2â â Server3 â
âââââ¬ââââ ââââââ¬ââââ âââââââ¬ââââ
â â â
ââââââââââââŒâââââââââââââ
â
ââââââââââââŒâââââââââââ
â Message Queue â
â (RabbitMQ/SQS) â
ââââââââââââ¬âââââââââââ
â
ââââââââââââŒâââââââââââ
â Worker Nodes â
âââââââââââââââââââââââ
ë°ìŽí° ë ìŽìŽ:
âââ Primary DB: PostgreSQL (Master)
âââ Read Replicas: 2-3ê°
âââ Cache: Redis Cluster
âââ Search: Elasticsearch
âââ File Storage: S3
ë¹ì©: ì 500-2,000ë§ì
ë§ìŽí¬ë¡ìë¹ì€ ì€ë¹:
// 몚ëë³ ë¶ëЬ ìì
// apps/user-service/index.ts
class UserAPI {
@Post('/users')
@RateLimit(100)
async createUser(@Body() data: CreateUserDto) {
// ì¬ì©ì ìì± ë¡ì§
const user = await this.userService.create(data)
// ìŽë²€íž ë°í
await this.eventBus.publish('user.created', user)
return user
}
}
// apps/notification-service/index.ts
class NotificationWorker {
@Subscribe('user.created')
async handleUserCreated(user: User) {
// íì ìŽë©ìŒ ë°ì¡
await this.emailService.sendWelcome(user)
// ížì ì늌
await this.pushService.notify(user)
}
}
Stage 4: íìŽíŒì€ìŒìŒ (100,000+ ì¬ì©ì)
목í: êžë¡ë² íì¥ê³Œ ìµì í
âââ ì¬ì©ì: 100,000+ëª
âââ ížëíœ: 100,000+ req/min
âââ ë°ìŽí°: 1TB+
âââ í ê·ëªš: 30+ëª
ë§ìŽí¬ë¡ìë¹ì€ ìí€í
ì²:
ââââââââââââââââââââââââââââââââââââââââââ
â API Gateway â
â (Kong/AWS API GW) â
ââââââ¬âââââââ¬âââââââ¬âââââââ¬âââââââ¬âââââââ
â â â â â
ââââââŒâââââââŒâââââââŒâââââââŒâââââââŒâââ
â User ââAuth ââOrderââPay ââNoti â
âServiceââSvc ââ Svc ââ Svc ââ Svc â
âââââ¬ââââââââ¬âââââââ¬âââââââ¬âââââââ¬âââ
â â â â â
âââââââââŒâââââââŒâââââââŒâââââââ
â â â
âââââââŒâââââââŒâââââââŒââââââ
â Event Stream â
â (Kafka/Kinesis) â
âââââââââââââââââââââââââââ
ë°ìŽí° ìí€í
ì²:
âââ OLTP: PostgreSQL Sharding
âââ OLAP: Data Warehouse (Redshift)
âââ NoSQL: DynamoDB/MongoDB
âââ Cache: Redis Cluster
âââ CDN: Multi-Region CloudFront
âââ ML Platform: SageMaker
ë¹ì©: ì 5,000ë§ì+
íì¥ ê°ë¥í ìí€í ì² ì€ê³ ìì¹
1. Database-First Design
-- ì²ìë¶í° íì¥ì ê³ ë €í ì€í€ë§ ì€ê³
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- ì€ë© í€ ì€ë¹
shard_key INT GENERATED ALWAYS AS (hashtext(id::text) % 100) STORED,
email VARCHAR(255) UNIQUE,
created_at TIMESTAMPTZ DEFAULT NOW(),
-- ìžë±ì€ ì ëµ
INDEX idx_shard_key (shard_key),
INDEX idx_created_at (created_at)
) PARTITION BY RANGE (created_at);
-- íí°ì
ë ì€ë¹
CREATE TABLE users_2024_01 PARTITION OF users
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
Stateless ì€ê³
// [Bad] ëì ì: ìë²ì ìí ì ì¥
class BadService {
private cache = new Map() // ìë² ë©ëªšëЬì ì ì¥
async getUser(id: string) {
if (this.cache.has(id)) {
return this.cache.get(id)
}
// ...
}
}
// [Good] ì¢ì ì: ìžë¶ ì ì¥ì ì¬ì©
class GoodService {
async getUser(id: string) {
// Redis ê°ì ìžë¶ ìºì ì¬ì©
const cached = await redis.get(`user:${id}`)
if (cached) return JSON.parse(cached)
// ...
}
}
API ë²ì êŽëЬ
// API ë²ì ë ì ëµ
app.use('/api/v1', v1Routes)
app.use('/api/v2', v2Routes)
// GraphQLì ê²œì° - íë deprecation
type User {
id: ID!
name: String!
username: String @deprecated(reason: "Use 'name' instead")
}
// REST API ìëµ ë²ì êŽëЬ
interface ApiResponse<T> {
version: string
data: T
meta: {
timestamp: number
deprecations?: string[]
}
}
ìŽë²€íž êž°ë° ìí€í ì²
// ìŽë²€íž ëëŠ¬ëž ì€ê³ë¡ ëìší ê²°í©
class OrderService {
async createOrder(data: CreateOrderDto) {
// 죌묞 ìì±
const order = await this.orderRepo.create(data)
// ìŽë²€íž ë°í (ë€ë¥ž ìë¹ì€ë€ìŽ êµ¬ë
)
await this.eventBus.publish('order.created', {
orderId: order.id,
userId: order.userId,
amount: order.amount,
items: order.items
})
// ëêž° ì²ëЬ ë¶íì
return order
}
}
// ê° ìë¹ì€ë ë
늜ì ìŒë¡ ìŽë²€íž ì²ëЬ
class InventoryService {
@Subscribe('order.created')
async handleOrderCreated(event: OrderCreatedEvent) {
await this.updateInventory(event.items)
}
}
class NotificationService {
@Subscribe('order.created')
async handleOrderCreated(event: OrderCreatedEvent) {
await this.sendOrderConfirmation(event.userId)
}
}
êž°ì ë¶ì± êŽëЬ ì ëµ
êž°ì ë¶ì± quadrant
ꞎêžë ëì â
â
A â B
ìŠì â ê³í
ìì â ìì
ââââââââââŒâââââââââ
C â D
묞ìíâ 묎ì
â
ââ ìí¥ë ëì
A (ꞎêž+ì€ì): 볎ì ì·šìœì , ë°ìŽí° ìì€ ìí B (ì€ì): ì±ë¥ ë³ëª©, íì¥ì± ì í C (êž°ë¡): ìœë ì€ë©, 늬í©í ë§ íì D (묎ì): ì¬ì©íì§ ìë ìœë, 믞믞í ìµì í
늬í©í ë§ íìŽë°
const refactoringTriggers = {
// ìŠì 늬í©í ë§
immediate: [
"볎ì ì·šìœì ë°ê²¬",
"ë°ìŽí° ì í©ì± 묞ì ",
"ìë¹ì€ ë€ìŽ ìí"
],
// ë€ì ì€í늰íž
nextSprint: [
"ìœë ì€ë³µ 30% ìŽì",
"ìëµ ìê° 2ìŽ ìŽê³Œ",
"í
ì€íž 컀ë²ëŠ¬ì§ 50% 믞ë§"
],
// ë¶êž°ë³ ì 늬
quarterly: [
"ì¬ì©íì§ ìë ì졎ì±",
"ë ê±°ì API ì ê±°",
"묞ì ì
ë°ìŽíž"
]
}
ì죌 ëíëë íšíŽ: ì±ê³µê³Œ ì€íš
íí ì±ê³µ íšíŽ: ëšê³ì ìŒë¡ íì¥í ë°°ë¬ ìë¹ì€
1ëšê³ (MVP):
âââ ìí€í
ì²: Laravel 몚ë늬ì€
âââ ìžíëŒ: ëšìŒ ìë²
âââ ë¹ì©: ì ììë§ìë
âââ ìŒ ì£Œë¬ž: ëìž ì늿ì
2ëšê³ (ì±ì¥êž°):
âââ ìí€í
ì²: API/Frontend ë¶ëЬ
âââ ìžíëŒ: AWS ECS + RDS
âââ ë¹ì©: ì ìë°±ë§ìë
âââ ìŒ ì£Œë¬ž: ë€ ì늿ì
3ëšê³ (íì¥êž°):
âââ ìí€í
ì²: ë¶ë¶ ë§ìŽí¬ë¡ìë¹ì€
â âââ 죌묞 ìë¹ì€
â âââ ë°°ë¬ ìë¹ì€
â âââ ê²°ì ìë¹ì€
âââ ìžíëŒ: K8s + Multi-AZ
âââ ë¹ì©: ì ìì²ë§ìë
âââ ìŒ ì£Œë¬ž: ë€ì¯ ì늿ì
4ëšê³ (ì±ìêž°):
âââ ìí€í
ì²: ìì ë§ìŽí¬ë¡ìë¹ì€
âââ ìžíëŒ: Multi-Region
âââ ë¹ì©: ì ìµ ëšì
âââ ìŒ ì£Œë¬ž: ì¬ì¯ ì늿ì
ì±ê³µ ììž:
- ëšê³ì ì§í
- ë°ìŽí° ì€ì¬ ìì¬ê²°ì
- êž°ì ë¶ì± êŽëЬ
íí ì€íš íšíŽ: ì²ìë¶í° 곌ëíê² ì€ê³í ìì ìë¹ì€
ì€íš 곌ì :
1. ììë¶í° 곌ëí ì€ê³
- ì¬ì©ìê° ìììž ëšê³ë¶í° K8s ëì
- 5ê° ë§ìŽí¬ë¡ìë¹ì€ë¡ ë¶ëЬ
- ì¬ë¬ íë¡ê·žëë° ìžìŽ íŒì©
2. 결곌
- ê°ë° ìëê° ëì ëê² ëšìŽì§
- ì ìŽìë¹ê° í¬ê² ìŠê°íš
- ìê°ì í ìêž ìì§
êµí:
"Premature optimization is
the root of all evil" - Donald Knuth
몚ëí°ë§ê³Œ êŽì°°ì±(Observability)
íì 몚ëí°ë§ ì§í
## 몚ëí°ë§ ì€í
metrics:
application:
- response_time_p99
- error_rate
- throughput
infrastructure:
- cpu_usage
- memory_usage
- disk_io
business:
- daily_active_users
- conversion_rate
- revenue_per_user
## ì늌 ì€ì
alerts:
- name: high_error_rate
condition: error_rate > 1%
action: page_oncall
- name: slow_response
condition: p99_latency > 2s
action: slack_notification
- name: low_disk_space
condition: disk_usage > 80%
action: auto_scale
ë¡ê¹ ì ëµ
// 구조íë ë¡ê¹
class Logger {
info(message: string, context: any) {
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
level: 'info',
message,
...context,
// ì¶ì ì ìí correlation ID
correlationId: getCorrelationId(),
// ìë¹ì€ ì 볎
service: process.env.SERVICE_NAME,
version: process.env.VERSION
}))
}
}
// ì¬ì© ìì
logger.info('Order created', {
orderId: order.id,
userId: user.id,
amount: order.amount,
// ì±ë¥ ì¶ì
duration: Date.now() - startTime
})
ë¹ì© ìµì í ì ëµ
íŽëŒì°ë ë¹ì© ì ê°
const costOptimization = {
// ì ì í ìžì€íŽì€ íì
ì í
compute: {
development: "t3.micro", // ê°ë°: ì $10
staging: "t3.small", // ì€í
ìŽì§: ì $20
production: "c5.xlarge", // ìŽì: ì $150
// Spot Instance íì© (70% ì ê°)
batch: "spot.c5.xlarge"
},
// ìë ì€ìŒìŒë§
autoScaling: {
minInstances: 2,
maxInstances: 10,
targetCPU: 70,
scaleDownDelay: 300 // 5ë¶
},
// ììœ ìžì€íŽì€ (1ë
ìœì ì 40% ì ê°)
reservedInstances: {
type: "c5.xlarge",
term: "1year",
payment: "partial_upfront"
},
// ë°ìŽí° ìëª
죌Ʞ êŽëЬ
storage: {
hot: "gp3", // ì죌 ì¡ìžì€
warm: "gp2", // ê°ë ì¡ìžì€
cold: "glacier" // ì칎ìŽëž
}
}
ë°ìŽí°ë² ìŽì€ ìµì í
-- ìžë±ì€ ìµì í
CREATE INDEX CONCURRENTLY idx_users_email
ON users(email)
WHERE deleted_at IS NULL;
-- íí°ì
ëìŒë¡ ì±ë¥ ê°ì
CREATE TABLE orders_2024_01
PARTITION OF orders
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
-- ì€ëë ë°ìŽí° ì칎ìŽë¹
INSERT INTO orders_archive
SELECT * FROM orders
WHERE created_at < NOW() - INTERVAL '1 year';
DELETE FROM orders
WHERE created_at < NOW() - INTERVAL '1 year';
ë§ìŽê·žë ìŽì ì ëµ
몚ëëŠ¬ì€ â ë§ìŽí¬ë¡ìë¹ì€
Step 1: Strangler Fig Pattern
âââââââââââââââââââââââââââ
â Monolith â
â âââââââââââââââââââ â
â â User Module ââââââŒâââ User Service
â âââââââââââââââââââ â (ì ê·)
â âââââââââââââââââââ â
â â Order Module â â
â âââââââââââââââââââ â
âââââââââââââââââââââââââââ
Step 2: ì ì§ì ë¶ëЬ
- API Gateway ëì
- ì ê· êž°ë¥ì ë³ë ìë¹ì€ë¡
- Ʞ졎 몚ë ìì°š ìŽì
Step 3: ë°ìŽí° ë¶ëЬ
- ìë¹ì€ë³ DB ë¶ëЬ
- Event Sourcing ëì
- SAGA íšíŽìŒë¡ ížëìì
êŽëЬ
첎í¬ëЬì€íž: íì¥ ê°ë¥í ìí€í ì²
ì€ê³ ëšê³
- ëë©ìž ê²œê³ ëª íí ì ì
- ë°ìŽí° ëªšëž íì¥ì± ê³ ë €
- API ë²ì êŽëЬ ì ëµ
- ìºì± ì ëµ ì늜
- 몚ëí°ë§ ê³í
구í ëšê³
- 12-Factor App ìì¹ ì€ì
- íê²œë³ ì€ì ë¶ëЬ
- í¬ì€ì²Ží¬ ìëí¬ìžíž
- ê·žë ìŽì€í ì §ë€ìŽ
- ë¡ê¹ íì€í
ìŽì ëšê³
- CI/CD íìŽíëŒìž
- ëžë£š-귞늰 ë°°í¬
- 례백 ê³í
- ì¬íŽ ë³µêµ¬ ê³í
- ë¹ì© 몚ëí°ë§
ì§ííë ìí€í ì²
ì±ê³µíë ì€íížì ì ìí€í ì²ë ììž¡ìŽ ìë ì§íì 결곌ì ëë€.
íµì¬ ìì¹:
- Start Simple: ë³µì¡ì±ì ëì€ì
- Measure Everything: ë°ìŽí° êž°ë° ê²°ì
- Evolve Gradually: í ë²ì íëì©
- Plan for Change: ë³ê²œì íì°
"The best architecture is the one that lets you defer decisions" - Robert C. Martin
ì€ëì ìµì ìŽ ëŽìŒì ë ê±°ìê° ë ì ììµëë€. íì§ë§ ê·žê²ìŽ ëë €ì ììì¡°ì°š íì§ ìëë€ë©Ž, ëŽìŒì ì€ì§ ìì ê²ì ëë€.
ì§êž ë¹ì¥ íìí ê²ë¶í° ììíë ê²ìŽ íëª í©ëë€. ì±ì¥ì ì ížê° 볎ìŽë©Ž ê·žë ì§íí ì ììµëë€.
ìží ê·žëë¹ì íì¥ ê°ë¥í ìí€í ì² ì€ê³ ìë¹ì€
ìží ê·žëë¹ì MVPë¶í° ì ëìœê¹ì§, ê° ì±ì¥ ëšê³ì ìµì íë ìí€í ì² ì§í륌 ì§ìí©ëë€.
- ìí€í ì² ì»šì€í : íì¬ ìí ì§ëšê³Œ ë¡ëë§µ
- ë§ìŽê·žë ìŽì : 묎ì€ëš ì í ì§ì
- ì±ë¥ ìµì í: ë¹ì© 50% ì ê°
ìí€í ì² ì§ëšìŽ íìíì ê°ì? ìí€í ì² ëŠ¬ë·° ì ì²ì íµíŽ íì¬ ìì€í ì 묞ì ì ì ì§ëšíê³ ë¡ëë§µì ì늜íŽë³Žìžì.