Files
site11/docs/TECHNICAL_INTERVIEW.md
jungwoo choi de0d548b7a docs: Add comprehensive technical interview guide
- Create TECHNICAL_INTERVIEW.md with 20 technical questions
- Cover Backend (5), Frontend (4), DevOps (6), Data/API (3), Problem Solving (2)
- Include detailed answers with code examples
- Use Obsidian-compatible callout format for collapsible answers
- Add evaluation criteria (Junior/Mid/Senior levels)
- Include practical coding challenge (Comments service)

Technical areas covered:
- API Gateway vs Service Mesh architecture
- FastAPI async/await and Motor vs PyMongo
- Microservice communication (REST, Pub/Sub, gRPC)
- Database strategies and JWT security
- React 18 features and TypeScript integration
- Docker multi-stage builds and K8s deployment strategies
- Health checks, monitoring, and logging
- RESTful API design and MongoDB schema modeling
- Traffic handling and failure scenarios

fix: Update Services.tsx with TypeScript fixes
- Fix ServiceType enum import (use value import, not type-only)
- Fix API method name: checkHealthAll → checkAllHealth
- Ensure proper enum usage in form data

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 08:26:00 +09:00

20 KiB

Site11 프로젝트 기술 면접 가이드

프로젝트 개요

  • 아키텍처: API Gateway 패턴 기반 마이크로서비스
  • 기술 스택: FastAPI, React 18, TypeScript, MongoDB, Redis, Docker, Kubernetes
  • 도메인: 뉴스/미디어 플랫폼 (다국가/다언어 지원)

1. 백엔드 아키텍처 (5문항)

Q1. API Gateway vs Service Mesh

질문: Console이 API Gateway 역할을 합니다. Service Mesh(Istio)와 비교했을 때 장단점은?

[!success]- 모범 답안

API Gateway 패턴 (현재):

  • 중앙화된 인증/라우팅, 구축 간단, 단일 진입점
  • SPOF 가능성, 병목 위험, Gateway 변경 시 전체 영향

Service Mesh (Istio):

  • 서비스 간 직접 통신(낮은 지연), mTLS 자동, 세밀한 트래픽 제어
  • 학습 곡선, 리소스 오버헤드(Sidecar), 복잡한 디버깅

선택 기준:

  • 30개 이하 서비스 → API Gateway
  • 50개 이상, 복잡한 통신 패턴 → Service Mesh

Q2. FastAPI 비동기 처리

질문: async/await 사용 시기와 Motor vs PyMongo 선택 이유는?

[!success]- 모범 답안

동작 차이:

# Sync: 요청 1(50ms) → 요청 2(50ms) = 총 100ms
# Async: 요청 1 & 요청 2 병행 처리 = 총 ~50ms

Motor (Async) 추천:

  • I/O bound 작업(DB, API 호출)에 적합
  • 동시 요청 시 처리량 증가
  • FastAPI의 비동기 특성과 완벽 호환

PyMongo (Sync) 사용:

  • CPU bound 작업(이미지 처리, 데이터 분석)
  • Sync 전용 라이브러리 사용 시

주의: time.sleep()은 전체 이벤트 루프 블로킹 → asyncio.sleep() 사용


Q3. 마이크로서비스 간 통신

질문: REST API, Redis Pub/Sub, gRPC 각각 언제 사용?

[!success]- 모범 답안

방식 사용 시기 특징
REST 즉시 응답 필요, 데이터 조회 Synchronous, 구현 간단
Pub/Sub 이벤트 알림, 여러 서비스 반응 Asynchronous, Loose coupling
gRPC 내부 서비스 통신, 고성능 HTTP/2, Protobuf, 타입 안정성

예시:

  • 사용자 조회 → REST (즉시 응답)
  • 사용자 생성 알림 → Pub/Sub (비동기 처리)
  • 마이크로서비스 간 내부 호출 → gRPC (성능)

Q4. 데이터베이스 전략

질문: Shared MongoDB Instance vs Separate Instances 장단점?

[!success]- 모범 답안

현재 전략 (Shared Instance, Separate DBs):

MongoDB (site11-mongodb:27017)
├── console_db
├── users_db
└── news_api_db

장점: 운영 단순, 리소스 효율, 백업 간편, 비용 절감 단점: 격리 부족, 확장성 제한, 장애 전파, 리소스 경합

Separate Instances:

  • 장점: 완전 격리, 독립 확장, 장애 격리
  • 단점: 운영 복잡, 비용 증가, 트랜잭션 불가

서비스 간 데이터 접근:

  • 직접 DB 접근 금지
  • API 호출 또는 Data Duplication (비정규화)
  • Event-driven 동기화

Q5. JWT 인증 및 보안

질문: Access Token vs Refresh Token 차이와 탈취 대응 방안?

[!success]- 모범 답안

구분 Access Token Refresh Token
목적 API 접근 권한 Access Token 재발급
만료 짧음 (15분-1시간) 길음 (7일-30일)
저장 메모리 HttpOnly Cookie
탈취 시 제한적 피해 심각한 피해

탈취 대응:

  1. Refresh Token Rotation: 재발급 시 새로운 토큰 쌍 생성
  2. Blacklist: Redis에 로그아웃된 토큰 저장
  3. Device Binding: 디바이스 ID로 제한
  4. IP/User-Agent 검증: 비정상 접근 탐지

서비스 간 통신 보안:

  • Service Token (API Key)
  • mTLS (Production)
  • Network Policy (Kubernetes)

2. 프론트엔드 (4문항)

Q6. React 18 주요 변화

질문: Concurrent Rendering과 Automatic Batching 설명?

[!success]- 모범 답안

1. Concurrent Rendering:

const [query, setQuery] = useState('');
const [isPending, startTransition] = useTransition();

// 긴급 업데이트 (사용자 입력)
setQuery(e.target.value);

// 비긴급 업데이트 (검색 결과) - 중단 가능
startTransition(() => {
  fetchSearchResults(e.target.value);
});

→ 사용자 입력이 항상 부드럽게 유지

2. Automatic Batching:

// React 17: fetch 콜백에서 2번 리렌더링
fetch('/api').then(() => {
  setCount(c => c + 1);  // 리렌더링 1
  setFlag(f => !f);      // 리렌더링 2
});

// React 18: 자동 배칭으로 1번만 리렌더링

기타: Suspense, useDeferredValue, useId


Q7. TypeScript 활용

질문: Backend API 타입을 Frontend에서 안전하게 사용하는 방법?

[!success]- 모범 답안

방법 1: OpenAPI 코드 생성 (추천)

npm install openapi-typescript-codegen
openapi --input http://localhost:8000/openapi.json --output ./src/api/generated
// 자동 생성된 타입 사용
import { ArticlesService, Article } from '@/api/generated';

const articles = await ArticlesService.getArticles({
  category: 'tech',  // ✅ 타입 체크
  limit: 10
});

방법 2: tRPC (TypeScript 풀스택)

// Backend
export const appRouter = t.router({
  articles: {
    list: t.procedure.input(z.object({...})).query(...)
  }
});

// Frontend - End-to-end 타입 안정성
const { data } = trpc.articles.list.useQuery({ category: 'tech' });

방법 3: 수동 타입 정의 (작은 프로젝트)


Q8. 상태 관리

질문: Context API, Redux, Zustand, React Query 각각 언제 사용?

[!success]- 모범 답안

도구 사용 시기 특징
Context API 전역 테마, 인증 상태 내장, 리렌더링 주의
Redux 복잡한 상태, Time-travel Boilerplate 많음, DevTools
Zustand 간단한 전역 상태 경량, 간결, 리렌더링 최적화
React Query 서버 상태 캐싱, 리페칭, 낙관적 업데이트

핵심: 전역 상태 vs 서버 상태 구분

  • 전역 UI 상태 → Zustand/Redux
  • 서버 데이터 → React Query

Q9. Material-UI 최적화

질문: 번들 사이즈 최적화와 테마 커스터마이징 방법?

[!success]- 모범 답안

번들 최적화:

// ❌ 전체 import
import { Button, TextField } from '@mui/material';

// ✅ Tree shaking
import Button from '@mui/material/Button';
import TextField from '@mui/material/TextField';

Code Splitting:

const Dashboard = lazy(() => import('./pages/Dashboard'));

<Suspense fallback={<Loading />}>
  <Dashboard />
</Suspense>

테마 커스터마이징:

import { createTheme, ThemeProvider } from '@mui/material/styles';

const theme = createTheme({
  palette: {
    mode: 'dark',
    primary: { main: '#1976d2' },
  },
});

<ThemeProvider theme={theme}>
  <App />
</ThemeProvider>

3. DevOps & 인프라 (6문항)

Q10. Docker Multi-stage Build

질문: Multi-stage build의 장점과 각 stage 역할은?

[!success]- 모범 답안

# Stage 1: Builder (빌드 환경)
FROM node:18-alpine AS builder
WORKDIR /app
COPY package.json ./
RUN npm install
COPY . .
RUN npm run build

# Stage 2: Production (런타임)
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html

장점:

  • 빌드 도구 제외 → 이미지 크기 90% 감소
  • Layer caching → 빌드 속도 향상
  • 보안 강화 → 소스코드 미포함

Q11. Kubernetes 배포 전략

질문: Rolling Update, Blue/Green, Canary 차이와 선택 기준?

[!success]- 모범 답안

전략 특징 적합한 경우
Rolling Update 점진적 교체 일반 배포, Zero-downtime
Blue/Green 전체 전환 후 스위칭 빠른 롤백 필요
Canary 일부 트래픽 테스트 위험한 변경, A/B 테스트

News API 같은 중요 서비스: Canary (10% → 50% → 100%)

Probe 설정:

livenessProbe:  # 재시작 판단
  httpGet:
    path: /health
readinessProbe:  # 트래픽 차단 판단
  httpGet:
    path: /ready

Q12. 서비스 헬스체크

질문: Liveness Probe vs Readiness Probe 차이?

[!success]- 모범 답안

Probe 실패 시 동작 실패 조건 예시
Liveness Pod 재시작 데드락, 메모리 누수
Readiness 트래픽 차단 DB 연결 실패, 초기화 중

구현:

@app.get("/health")  # Liveness
async def health():
    return {"status": "ok"}

@app.get("/ready")  # Readiness
async def ready():
    # DB 연결 확인
    if not await db.ping():
        raise HTTPException(503)
    return {"status": "ready"}

Startup Probe: 초기 구동이 느린 앱 (DB 마이그레이션 등)


Q13. 외부 DB 연결

질문: MongoDB/Redis를 클러스터 외부에서 운영하는 이유?

[!success]- 모범 답안

현재 전략 (외부 운영):

  • 데이터 영속성 (클러스터 재생성 시 보존)
  • 관리 용이 (단일 인스턴스)
  • 개발 환경 공유

StatefulSet (내부 운영):

  • Kubernetes 통합 관리
  • 자동 스케일링
  • PV 관리 복잡
  • 백업/복구 부담

선택 기준:

  • 개발/스테이징 → 외부 (간편)
  • 프로덕션 → Managed Service (RDS, Atlas) 추천

Q14. Docker Compose vs Kubernetes

질문: 언제 Docker Compose만으로 충분하고 언제 Kubernetes 필요?

[!success]- 모범 답안

기능 Docker Compose Kubernetes
컨테이너 실행
Auto-scaling
Self-healing
Load Balancing 기본적 고급
배포 전략 단순 다양 (Rolling, Canary)
멀티 호스트

Docker Compose 충분:

  • 단일 서버
  • 소규모 서비스 (< 10개)
  • 개발/테스트 환경

Kubernetes 필요:

  • 고가용성 (HA)
  • 자동 확장
  • 수십~수백 개 서비스

Q15. 모니터링 및 로깅

질문: 마이크로서비스 환경에서 로그 수집 및 모니터링 방법?

[!success]- 모범 답안

로깅 스택:

  • ELK: Elasticsearch + Logstash + Kibana
  • EFK: Elasticsearch + Fluentd + Kibana
  • Loki: Grafana Loki (경량)

모니터링:

  • Prometheus: 메트릭 수집
  • Grafana: 대시보드
  • Jaeger/Zipkin: Distributed Tracing

Correlation ID:

@app.middleware("http")
async def add_correlation_id(request: Request, call_next):
    correlation_id = request.headers.get("X-Correlation-ID") or str(uuid.uuid4())
    request.state.correlation_id = correlation_id

    # 모든 로그에 포함
    logger.info(f"Request {correlation_id}: {request.url}")

    response = await call_next(request)
    response.headers["X-Correlation-ID"] = correlation_id
    return response

3가지 관찰성:

  • Metrics (숫자): CPU, 메모리, 요청 수
  • Logs (텍스트): 이벤트, 에러
  • Traces (흐름): 요청 경로 추적

4. 데이터 및 API 설계 (3문항)

Q16. RESTful API 설계

질문: News API 엔드포인트를 RESTful하게 설계하면?

[!success]- 모범 답안

GET    /api/v1/outlets                    # 언론사 목록
GET    /api/v1/outlets/{outlet_id}        # 언론사 상세
GET    /api/v1/outlets/{outlet_id}/articles  # 특정 언론사 기사

GET    /api/v1/articles                   # 기사 목록
GET    /api/v1/articles/{article_id}      # 기사 상세
POST   /api/v1/articles                   # 기사 생성
PUT    /api/v1/articles/{article_id}      # 기사 수정
DELETE /api/v1/articles/{article_id}      # 기사 삭제

# 쿼리 파라미터
GET /api/v1/articles?category=tech&limit=10&offset=0

# 다국어 지원
GET /api/v1/ko/articles  # URL prefix
GET /api/v1/articles (Accept-Language: ko-KR)  # Header

RESTful 원칙:

  1. 리소스 중심 (명사 사용)
  2. HTTP 메소드 의미 준수
  3. Stateless
  4. 계층적 구조
  5. HATEOAS (선택)

Q17. MongoDB 스키마 설계

질문: Outlets-Articles-Keywords 관계를 MongoDB에서 모델링?

[!success]- 모범 답안

방법 1: Embedding (Read 최적화)

{
  "_id": "article123",
  "title": "Breaking News",
  "outlet": {
    "id": "outlet456",
    "name": "TechCrunch",
    "logo": "url"
  },
  "keywords": ["AI", "Machine Learning"]
}
  • 1번의 쿼리로 모든 데이터
  • Outlet 정보 변경 시 모든 Article 업데이트

방법 2: Referencing (Write 최적화)

{
  "_id": "article123",
  "title": "Breaking News",
  "outlet_id": "outlet456",
  "keyword_ids": ["kw1", "kw2"]
}
  • 데이터 일관성
  • 조회 시 여러 쿼리 필요 (JOIN)

하이브리드 (추천):

{
  "_id": "article123",
  "title": "Breaking News",
  "outlet_id": "outlet456",
  "outlet_name": "TechCrunch",  // 자주 조회되는 필드만 복제
  "keywords": ["AI", "ML"]       // 배열 embedding
}

인덱싱:

db.articles.create_index([("outlet_id", 1), ("published_at", -1)])
db.articles.create_index([("keywords", 1)])

Q18. 페이지네이션 전략

질문: Offset-based vs Cursor-based Pagination 차이?

[!success]- 모범 답안

Offset-based (전통적):

# GET /api/articles?page=2&page_size=10
skip = (page - 1) * page_size
articles = db.articles.find().skip(skip).limit(page_size)
  • 구현 간단, 페이지 번호 표시
  • 대량 데이터에서 느림 (SKIP 연산)
  • 실시간 데이터 변경 시 중복/누락

Cursor-based (무한 스크롤):

# GET /api/articles?cursor=article123&limit=10
articles = db.articles.find({
  "_id": {"$lt": ObjectId(cursor)}
}).sort("_id", -1).limit(10)

# Response
{
  "items": [...],
  "next_cursor": "article110"
}
  • 빠른 성능 (인덱스 활용)
  • 실시간 데이터 일관성
  • 특정 페이지 이동 불가

선택 기준:

  • 페이지 번호 필요 → Offset
  • 무한 스크롤, 대량 데이터 → Cursor

5. 문제 해결 및 확장성 (2문항)

Q19. 대규모 트래픽 처리

질문: 순간 트래픽 10배 증가 시 대응 방안?

[!success]- 모범 답안

1. 캐싱 (Redis):

@app.get("/api/articles/{article_id}")
async def get_article(article_id: str):
    # Cache-aside 패턴
    cached = await redis.get(f"article:{article_id}")
    if cached:
        return json.loads(cached)

    article = await db.articles.find_one({"_id": article_id})
    await redis.setex(f"article:{article_id}", 3600, json.dumps(article))
    return article

2. Auto-scaling (HPA):

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: news-api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: news-api
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

3. Rate Limiting:

from slowapi import Limiter

limiter = Limiter(key_func=get_remote_address)

@app.get("/api/articles")
@limiter.limit("100/minute")
async def list_articles():
    ...

4. Circuit Breaker (장애 전파 방지):

from circuitbreaker import circuit

@circuit(failure_threshold=5, recovery_timeout=60)
async def call_external_service():
    ...

5. CDN: 정적 리소스 (이미지, CSS, JS)


Q20. 장애 시나리오 대응

질문: MongoDB 다운/서비스 무응답/Redis 메모리 가득 시 대응?

[!success]- 모범 답안

1. MongoDB 다운:

@app.get("/api/articles")
async def list_articles():
    try:
        articles = await db.articles.find().to_list(10)
        return articles
    except Exception as e:
        # Graceful degradation
        logger.error(f"DB error: {e}")

        # Fallback: 캐시에서 반환
        cached = await redis.get("articles:fallback")
        if cached:
            return {"data": json.loads(cached), "source": "cache"}

        # 최후: 기본 메시지
        raise HTTPException(503, "Service temporarily unavailable")

2. 마이크로서비스 무응답:

from circuitbreaker import circuit

@circuit(failure_threshold=3, recovery_timeout=30)
async def call_user_service(user_id):
    async with httpx.AsyncClient(timeout=5.0) as client:
        response = await client.get(f"http://users-service/users/{user_id}")
        return response.json()

# Circuit Open 시 Fallback
try:
    user = await call_user_service(user_id)
except CircuitBreakerError:
    # 기본 사용자 정보 반환
    user = {"id": user_id, "name": "Unknown"}

3. Redis 메모리 가득:

# redis.conf
maxmemory 2gb
maxmemory-policy allkeys-lru  # LRU eviction
# 중요도 기반 TTL
await redis.setex("hot_article:123", 3600, data)  # 1시간
await redis.setex("old_article:456", 300, data)   # 5분

Health Check 자동 재시작:

livenessProbe:
  httpGet:
    path: /health
  failureThreshold: 3
  periodSeconds: 10

평가 기준

초급 (Junior) - 5-8개 정답

  • 기본 개념 이해
  • 공식 문서 참고하여 구현 가능
  • 가이드 있으면 개발 가능

중급 (Mid-level) - 9-14개 정답

  • 아키텍처 패턴 이해
  • 트레이드오프 판단 가능
  • 독립적으로 서비스 설계 및 구현
  • 기본 DevOps 작업 가능

고급 (Senior) - 15-20개 정답

  • 시스템 전체 설계 가능
  • 성능/확장성/보안 고려한 의사결정
  • 장애 대응 및 모니터링 전략
  • 팀 리딩 및 기술 멘토링

실무 과제 (선택)

과제: Comments 서비스 추가

기사에 댓글 기능을 추가하는 마이크로서비스 구현

요구사항:

  1. Backend API (FastAPI)
    • CRUD 엔드포인트
    • 대댓글(nested comments) 지원
    • 페이지네이션
  2. Frontend UI (React + TypeScript)
    • 댓글 목록/작성/수정/삭제
    • Material-UI 사용
  3. DevOps
    • Dockerfile 작성
    • Kubernetes 배포
    • Console과 연동

평가 요소:

  • 코드 품질 (타입 안정성, 에러 핸들링)
  • API 설계 (RESTful 원칙)
  • 성능 고려 (인덱싱, 캐싱)
  • Git 커밋 메시지

소요 시간: 4-6시간


면접 진행 Tips

  1. 깊이 있는 질문: "이전 프로젝트에서는 어떻게 해결했나요?"
  2. 화이트보드 세션: 아키텍처 다이어그램 그리기
  3. 코드 리뷰: 기존 코드 개선점 찾기
  4. 시나리오 기반: "만약 ~한 상황이라면?"
  5. 후속 질문: 답변에 따라 심화 질문

작성일: 2025-10-28 프로젝트: Site11 Microservices Platform 대상: Full-stack Developer