docs(10_Wiki): Topic_Business/General/Graphic/Programming을 Topics/ 하위로 이동
최상위 10_Wiki/Topic_*였던 4개 카테고리 폴더를 10_Wiki/Topics/Topic_* 로 재배치. 콘텐츠 변경 없음(순수 폴더 이동) — Topics/ 하위 나머지 폴더는 이미 지난 커밋에서 전부 정리된 상태(잔존 항목은 에이전트 운영 상태 및 사용자가 보존을 요청한 업데이트0615/무제 3.canvas 뿐).
This commit is contained in:
@@ -0,0 +1,320 @@
|
||||
---
|
||||
id: wiki-2026-0508-client-server
|
||||
title: Client-Server Architecture Pattern
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [client-server, REST, gRPC, HTTP, web architecture, centralized model, two-tier, three-tier]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [architecture, client-server, rest, grpc, http, network, web-development, scalability]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: language-agnostic
|
||||
framework: HTTP / REST / gRPC / WebSocket
|
||||
---
|
||||
|
||||
# Client-Server Architecture
|
||||
|
||||
## 📌 한 줄 통찰
|
||||
> **"매 자원 의 request ↔ provider"**. 매 dominant network model. 매 single point of failure 가, 매 scale + control 의 huge. 매 modern: 매 BFF, 매 edge, 매 multi-region, 매 P2P 와 의 hybrid.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 components
|
||||
- **Client**: 매 UI + 매 request.
|
||||
- **Server**: 매 logic + 매 data.
|
||||
- **Network protocol**: HTTP, gRPC, WebSocket, MQTT.
|
||||
|
||||
### 매 tier
|
||||
- **Two-tier**: client + DB.
|
||||
- **Three-tier**: client + app server + DB.
|
||||
- **N-tier**: client + BFF + microservices + DB + cache.
|
||||
|
||||
### 매 protocol comparison
|
||||
| Protocol | Use case | Latency | Streaming |
|
||||
|---|---|---|---|
|
||||
| REST/HTTP | General CRUD | mid | ✗ |
|
||||
| gRPC | Internal RPC | low | ✓ (bidirectional) |
|
||||
| GraphQL | Flexible query | mid | partial (subscription) |
|
||||
| WebSocket | Real-time | very low | ✓ |
|
||||
| Server-Sent Events | Server → Client | low | ✓ (one-way) |
|
||||
| MQTT | IoT, low-bandwidth | low | ✓ |
|
||||
| WebRTC | P2P media | very low | ✓ |
|
||||
|
||||
### 매 advantages
|
||||
- 매 centralized control.
|
||||
- 매 division of labor.
|
||||
- 매 independent update.
|
||||
- 매 scale (server-side).
|
||||
- 매 strong security (server-side).
|
||||
|
||||
### 매 disadvantages
|
||||
- 매 single point of failure.
|
||||
- 매 network dependency.
|
||||
- 매 latency.
|
||||
- 매 cost (server infra).
|
||||
- 매 scaling complexity.
|
||||
|
||||
### 매 alternative / hybrid
|
||||
- **P2P** (BitTorrent, IPFS): 매 decentralized.
|
||||
- **Edge computing**: 매 close to user.
|
||||
- **Serverless**: 매 ephemeral.
|
||||
- **CRDT** + 매 sync: 매 offline-first.
|
||||
- **Local-first** (Ink & Switch).
|
||||
|
||||
### 매 modern pattern
|
||||
|
||||
#### BFF (Backend for Frontend)
|
||||
- 매 mobile / web 별 API.
|
||||
- 매 client-specific aggregation.
|
||||
|
||||
#### API Gateway
|
||||
- 매 single entry.
|
||||
- 매 auth / rate / route.
|
||||
|
||||
#### Service Mesh
|
||||
- 매 inter-service communication.
|
||||
- 매 Istio, Linkerd.
|
||||
|
||||
#### CDN / Edge
|
||||
- 매 static content.
|
||||
- 매 closer to user.
|
||||
- 매 Cloudflare Workers, Vercel Edge.
|
||||
|
||||
#### Multi-region
|
||||
- 매 active-active.
|
||||
- 매 latency 의 minimize.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### REST API (Express)
|
||||
```ts
|
||||
import express from 'express';
|
||||
const app = express();
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
app.get('/users/:id', async (req, res) => {
|
||||
const user = await db.users.findById(req.params.id);
|
||||
if (!user) return res.status(404).json({ error: 'Not found' });
|
||||
res.json(user);
|
||||
});
|
||||
|
||||
app.post('/users', async (req, res) => {
|
||||
const user = await db.users.create(req.body);
|
||||
res.status(201).json(user);
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
```
|
||||
|
||||
### gRPC (proto + server)
|
||||
```protobuf
|
||||
// user.proto
|
||||
service UserService {
|
||||
rpc GetUser(GetUserRequest) returns (User);
|
||||
rpc StreamUsers(stream UserFilter) returns (stream User);
|
||||
}
|
||||
|
||||
message GetUserRequest { string id = 1; }
|
||||
message User { string id = 1; string email = 2; }
|
||||
```
|
||||
|
||||
```ts
|
||||
import * as grpc from '@grpc/grpc-js';
|
||||
|
||||
const server = new grpc.Server();
|
||||
server.addService(UserService, {
|
||||
getUser: async (call, callback) => {
|
||||
const user = await db.users.findById(call.request.id);
|
||||
callback(null, user);
|
||||
},
|
||||
});
|
||||
server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => server.start());
|
||||
```
|
||||
|
||||
### WebSocket (real-time)
|
||||
```ts
|
||||
import { WebSocketServer } from 'ws';
|
||||
|
||||
const wss = new WebSocketServer({ port: 8080 });
|
||||
wss.on('connection', (ws) => {
|
||||
ws.on('message', (data) => {
|
||||
// 매 broadcast
|
||||
wss.clients.forEach(c => c.readyState === 1 && c.send(data));
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Server-Sent Events
|
||||
```ts
|
||||
app.get('/events', (req, res) => {
|
||||
res.set({
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Connection': 'keep-alive',
|
||||
});
|
||||
|
||||
const interval = setInterval(() => {
|
||||
res.write(`data: ${JSON.stringify({ time: Date.now() })}\n\n`);
|
||||
}, 1000);
|
||||
|
||||
req.on('close', () => clearInterval(interval));
|
||||
});
|
||||
```
|
||||
|
||||
### Three-tier deployment
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
client:
|
||||
image: my-frontend:latest
|
||||
ports: ['80:80']
|
||||
|
||||
api:
|
||||
image: my-api:latest
|
||||
environment:
|
||||
- DATABASE_URL=postgres://db:5432/app
|
||||
- REDIS_URL=redis://cache:6379
|
||||
deploy:
|
||||
replicas: 3
|
||||
|
||||
cache:
|
||||
image: redis:7
|
||||
|
||||
db:
|
||||
image: postgres:16
|
||||
volumes: ['./data:/var/lib/postgresql/data']
|
||||
```
|
||||
|
||||
### API Gateway (Kong / Express middleware)
|
||||
```ts
|
||||
// 매 simple gateway middleware
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
app.use(rateLimit({ windowMs: 60_000, max: 100 }));
|
||||
|
||||
app.use((req, res, next) => {
|
||||
const token = req.headers.authorization?.split(' ')[1];
|
||||
if (!token) return res.status(401).end();
|
||||
try {
|
||||
req.user = jwt.verify(token, process.env.JWT_SECRET!);
|
||||
next();
|
||||
} catch {
|
||||
res.status(401).end();
|
||||
}
|
||||
});
|
||||
|
||||
app.use('/api/users', proxy('http://user-service:3001'));
|
||||
app.use('/api/orders', proxy('http://order-service:3002'));
|
||||
```
|
||||
|
||||
### BFF (TypeScript)
|
||||
```ts
|
||||
// 매 mobile-specific endpoint
|
||||
app.get('/mobile/dashboard', async (req, res) => {
|
||||
const [user, recent_orders, notifications] = await Promise.all([
|
||||
userService.get(req.user.id),
|
||||
orderService.recent(req.user.id, 5),
|
||||
notificationService.unread(req.user.id),
|
||||
]);
|
||||
|
||||
// 매 mobile-friendly aggregate
|
||||
res.json({
|
||||
user: { id: user.id, name: user.name },
|
||||
recent: recent_orders.map(o => ({ id: o.id, total: o.total })),
|
||||
badge_count: notifications.length,
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Edge Function (Cloudflare Workers)
|
||||
```js
|
||||
export default {
|
||||
async fetch(request, env) {
|
||||
const url = new URL(request.url);
|
||||
|
||||
// 매 edge cache
|
||||
const cache = caches.default;
|
||||
const cached = await cache.match(request);
|
||||
if (cached) return cached;
|
||||
|
||||
// 매 origin fetch
|
||||
const response = await fetch(`https://origin.example.com${url.pathname}`);
|
||||
|
||||
// 매 cache
|
||||
response.headers.set('Cache-Control', 'public, max-age=60');
|
||||
await cache.put(request, response.clone());
|
||||
return response;
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Health check + circuit breaker
|
||||
```ts
|
||||
app.get('/health', (req, res) => {
|
||||
const checks = {
|
||||
db: db.isConnected(),
|
||||
redis: redis.ping(),
|
||||
deps: externalApi.healthy(),
|
||||
};
|
||||
|
||||
if (Object.values(checks).every(v => v)) {
|
||||
res.json({ status: 'ok', checks });
|
||||
} else {
|
||||
res.status(503).json({ status: 'degraded', checks });
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 🤔 결정 기준
|
||||
| 상황 | Pattern |
|
||||
|---|---|
|
||||
| Web app | Three-tier + REST |
|
||||
| Internal services | gRPC + service mesh |
|
||||
| Real-time | WebSocket / SSE |
|
||||
| IoT | MQTT |
|
||||
| Mobile | REST + BFF |
|
||||
| Offline-first | CRDT sync + local-first |
|
||||
| Cross-region read | Edge + CDN |
|
||||
| P2P file | BitTorrent / IPFS |
|
||||
| Heavy media | WebRTC |
|
||||
|
||||
**기본값**: REST + 3-tier. 매 internal = gRPC. 매 real-time = WebSocket.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Software Architecture Styles]] · [[Distributed-Systems]]
|
||||
- 변형: [[REST]] · [[gRPC]] · [[MQTT]] · [[WebRTC]]
|
||||
- 응용: [[BFF]] · [[API-Gateway]] · [[Service Mesh]] · [[Edge Computing|Edge-Computing]]
|
||||
- 대안: [[Local-First]] · [[Serverless]] · [[CRDT]]
|
||||
- Adjacent: [[CAP-Theorem]] · [[Availability-and-Persistence]] · [[Microservices]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 system design. 매 protocol decision. 매 architecture review. 매 onboarding.
|
||||
**언제 X**: 매 single-machine app. 매 P2P-only domain.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Single-point-of-failure 무시**: 매 multi-AZ 의 X.
|
||||
- **Chatty client (N+1)**: 매 BFF 의 lieu.
|
||||
- **Synchronous chain (5+ hop)**: 매 cascading failure.
|
||||
- **No rate limit**: 매 abuse vulnerability.
|
||||
- **REST on real-time**: 매 polling overhead.
|
||||
- **gRPC for browser**: 매 매 gateway 필요.
|
||||
- **No health check**: 매 silent degradation.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Roy Fielding REST thesis, gRPC docs, BFF pattern Sam Newman).
|
||||
- 신뢰도 A.
|
||||
- Related: [[Software Architecture Styles]] · [[Microservices]] · [[CAP-Theorem]] · [[Bounded Contexts (DDD)]] · [[Availability-and-Persistence]].
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — protocol matrix + tier + modern patterns + 매 Express / gRPC / WS / Edge code |
|
||||
Reference in New Issue
Block a user