Building CodeNova: System Design Deep Dive into an AI-Enhanced Coding Platform **Korean Translation:** CodeNova 구축: AI 강화 코딩 플랫폼에 대한 시스템 설계 심층 분석

발행: (2025년 11월 30일 오전 10:14 GMT+9)
13 min read
원문: Dev.to

Source: Original Post

TL;DR

저는 CodeNova라는 확장 가능한 코딩 인터뷰 플랫폼을 설계하고 구축했습니다. 이 플랫폼은 10K+ 동시 사용자를 처리하며, AI 기반 세 가지 기능(비디오 아바타 튜터, 알고리즘 시각화, 협업 화이트보드)을 제공합니다. 아래는 시스템 아키텍처와 설계 결정을 깊이 있게 살펴본 내용입니다.

Overview

CodeNova는 확장성과 학습을 위해 AI를 강화한 코딩 인터뷰 플랫폼입니다. 핵심 기능은 다음과 같습니다.

  • 155개 이상의 문제, 다양한 난이도
  • 샌드박스 실행이 가능한 10개 이상의 프로그래밍 언어
  • 현실감 있는 아바타와 자연스러운 음성을 제공하는 AI 비디오 튜터
  • 모든 코드에 대한 자동 알고리즘 시각화
  • 모의 인터뷰를 위한 실시간 협업 화이트보드
  • 분석 기능이 포함된 대회 리더보드

Scale: 10,000명의 동시 사용자, 분당 1,000건 제출, 99.9% 가동 시간 보장.

Architecture Layers

아키텍처는 6계층으로 구성된 마이크로서비스 지향 설계이며, 각 계층은 명확히 역할을 분리합니다.

Layer 1: Client (Browser)

Layer 2: CDN & Load Balancing (CloudFlare + Nginx)

Layer 3: Application Tier (Next.js + Express + Socket.io)

Layer 4: Data Tier (MongoDB + Redis + PostgreSQL)

Layer 5: Queue Layer (BullMQ)

Layer 6: Workers & External Services (Judge0, Gemini AI, ElevenLabs, ANAM)

Layer 1 – Network Perimeter

  • CloudFlare DDoS 방어 (무제한)
  • Rate limiting: IP당 분당 1,000 요청
  • TLS 1.3 암호화

Layer 2 – Load Balancer (Nginx)

  • 사용자당 Rate limiting (분당 100 req)
  • 요청 크기 제한: 최대 10 MB
  • 헤더 검증 및 정규화

Layer 3 – Authentication & Authorization

  • JWT 토큰: HS256, 7일 만료
  • 매 요청마다 Redis를 통한 세션 검증
  • RBAC: 일반 사용자 vs. 관리자 권한

Layer 4 – Input Validation

  • 코드 크기 제한: 10 KB (DoS 방지)
  • 금지 패턴 탐지 (예: require('child_process'), Runtime.getRuntime().exec(), system(), eval())

Layer 5 – Code Execution Sandbox (Judge0)

  • Docker 격리: 각 제출은 별도 컨테이너에서 실행
  • 리소스 제한:
    • CPU 시간: 최대 2 s
    • 메모리: 최대 256 MB
    • 프로세스 수: 최대 30
    • 네트워크: 차단
    • 파일시스템: 읽기 전용(/tmp 제외)
  • Seccomp 프로파일로 위험한 시스템 콜 차단

Layer 6 – Data Security

  • 저장 시 암호화: AES‑256
  • 비밀번호 해싱: Bcrypt (10 라운드)
  • 비밀 관리: AWS Secrets Manager
  • 데이터베이스 백업: 매일 전체 + 6시간 증분

AI Avatar Generation Pipeline

Three‑Stage Pipeline

User Question → Gemini AI → ElevenLabs → ANAM AI → Cached Video
              (Text Gen)   (TTS)        (Avatar)

Decision 1 – Why Three Separate Services?

  • Gemini AI – 교육용 콘텐츠 생성에 최적
  • ElevenLabs – 가장 자연스러운 TTS (AWS Polly보다 우수)
  • ANAM AI – 현실감 있는 립싱크 (대안: D‑ID, Synthesia)

Trade‑off: 복잡도는 증가하지만 품질이 향상됩니다. 사용자는 로봇식 TTS보다 자연스러운 음성을 선호합니다.

Decision 2 – Caching Strategy

  • 문제: 아바타 비디오 생성에 약 30 s 소요
  • 해결: Redis 캐시(TTL 24 시간)로 흔히 묻는 질문을 저장
  • 결과: 70 % 캐시 적중률, 생성 부하 크게 감소

Decision 3 – Async Processing

  • 이유: 30 초 생성이 API를 블로킹
  • 방법: BullMQ 작업 큐 활용
  • 이점: 사용자는 로딩 화면을 보고, 완료 시 알림을 받음

Algorithm Visualization Pipeline

Flow

User Code → Gemini AI → JSON Steps → Canvas Renderer → Interactive Visualization
         (Analyze)    (Generate)    (Frontend)

Decision 1 – Why AI Over Templates?

  • 템플릿 방식은 155개 이상의 알고리즘에 대해 수작업 단계가 필요 → 수개월 소요
  • Gemini은 어떤 코드든 자동으로 분석 가능

Trade‑off: API 의존성 vs. 대규모 자동 생성

Decision 2 – Where to Render?

  • 서버‑사이드 렌더링: CPU 사용량 급증, UX 저하
  • 선택: 클라이언트‑사이드 Canvas API (성능·서버 부하 감소)

Decision 3 – Data Format

각 단계는 다음을 포함합니다.

  • 설명 (일반 영어)
  • 해당 단계의 배열 상태
  • 강조할 요소
  • 비교 포인터

Supported Algorithms

  • 정렬: Bubble, Merge, Quick, Heap, Insertion
  • 검색: Binary, Linear, DFS, BFS
  • 자료구조: Stack, Queue, Trees, Graphs
  • DP: Fibonacci, Knapsack, LCS (테이블 시각화 포함)

Real‑Time Collaborative Whiteboard

WebSocket + Pub/Sub Architecture

User A draws → Socket.io Server → Redis Pub/Sub → All Users in Room

                 MongoDB (persist)

Decision 1 – WebSocket vs. Polling

  • Polling: 구현은 간단하지만 비효율적 (10K 사용자 × 5 s 간격 = 2K QPS)
  • 선택: WebSocket (지속 연결, 즉시 업데이트)
  • Socket.io는 WebSocket → 롱 폴링으로 자동 폴백 제공

Decision 2 – Scaling WebSockets Across Servers

  • 문제: 사용자가 서로 다른 서버 인스턴스에 있을 수 있음
  • 해결: Redis Pub/Sub을 이용해 서버 간 이벤트 전달

동작 방식

  1. Server 1이 그리기 이벤트를 Redis에 publish
  2. Server 2가 subscribe하여 이벤트를 받아 User B에게 WebSocket으로 전송

Decision 3 – Persistence Strategy

  • 옵션 1: 매 그리기마다 저장 → DB 쓰기 과다
  • 옵션 2: 연결 종료 시 저장 → 데이터 손실 위험
  • 선택: 5 초마다 자동 저장 → MongoDB에 기록
  • 복구: 재연결 시 DB에서 로드

Data Model (MongoDB)

{
  "sessionId": "unique identifier",
  "problemId": "which problem being discussed",
  "participants": ["userId1", "userId2"],
  "elements": "Excalidraw drawing data",
  "createdAt": "ISO timestamp",
  "updatedAt": "ISO timestamp"
}

Scaling & Kubernetes

Why Six Layers?

  • 역할이 명확히 구분돼 확장·장애 격리 용이
  • 독립적인 스케일링 가능

Kubernetes HPA (Horizontal Pod Autoscaler)

파라미터
최소 복제본 수3 (고가용성)
최대 복제본 수20 (자원 관리)
Scale‑up 조건CPU > 70 % or Memory > 80 %
Scale‑down 조건CPU < 40 % for 5 min

Benefits of Kubernetes

  • 자동 복구 (Pod 충돌 → 재시작)
  • 롤링 업데이트 (무중단 배포)
  • 자원 제한 (CPU/메모리)
  • 서비스 디스커버리 (자동 DNS)

Databases

MongoDB (Primary Database)

  • 구조: Replica Set (PSS)
    • Primary (us‑east‑1) – 모든 쓰기 처리
    • Secondary (us‑west‑1) – 읽기 전용
    • Secondary (eu‑west‑1) – 읽기 전용
  • 읽기 선호도: secondaryPreferred (각 세컨더리당 ≈40 % 부하)
  • 쓰기 보증: majority (데이터 안전)
  • 향후 계획: 문서 수가 10 M을 초과하면 Sharding 적용, { userId: "hashed" }를 샤드 키로 사용

PostgreSQL (Analytics)

  • 구조: Master‑Replica
    • Master – 메트릭·로그 쓰기
    • Replica 1 – 분석 쿼리
    • Replica 2 – 보고서 대시보드
  • 확장: TimescaleDB 확장으로 시계열 데이터 최적화 (예: 사용자 활동 추세)

Redis (Cache & Pub/Sub)

  • 구조: Cluster (3 노드)
    • Node 1: Master (캐시 + 세션)
    • Node 2 & 3: Replicas (페일오버)
  • 영속성: RDB 스냅샷(5 min) + AOF
  • 최대 메모리: 4 GB, eviction 정책 allkeys-lru

Queues (BullMQ)

Queue최소 워커최대 워커동시성Scale Trigger
Code Execution55010 jobs/workerQueue depth > 100
AI Avatar2205 jobs/workerQueue depth > 50
Visualizer2155 jobs/worker

Math Check (Peak Load)

  • 피크 제출량: 1,000/min = 16.7 /sec
  • 평균 실행 시간: 2 s
  • 필요한 동시 워커 수: 16.7 × 2 ≈ 33.4 → 최대 50으로 설정 (≈47 % 여유)

Performance & SLA

MetricTarget
Code execution latency (p95)< 3 s
Page load time (p95)< 2 s
API latency (p95)< 500 ms
WebSocket latency (p95)< 100 ms
Cache hit rate> 70 %
Uptime99.9 % (≤ 43 min downtime/month)

Monitoring Stack

  • Prometheus – 메트릭 수집
  • Grafana – 대시보드
  • Sentry – 오류 추적
  • ELK Stack – 로그 집계

Lessons Learned & Best Practices

  • Async everything – 큐는 최고의 친구
  • Cache aggressively – 성능 향상 및 부하 감소
  • Security in layers – 방어 깊이 확보
  • Measure first, optimize second – 지표를 기반으로 스케일링
  • Build monitoring from day 1 – 측정하지 못하면 최적화도 못한다

Pros / Cons Summary

Component장점단점
BullMQ (Redis)< 10 ms 지연, 네이티브 우선순위 큐, 내장 재시도, 로컬 개발 용이Redis 클러스터에 종속
AWS SQS관리형 서비스50‑100 ms 높은 지연, 우선순위 없음, 수동 재시도 필요
Socket.io자동 폴백, 재연결 로직, 방 기반 메시징번들 크기 다소 큼
Next.jsSEO를 위한 SSR, API 라우트, 이미지 최적화, 코드 스플리팅Node 런타임 필요
MongoDB + PostgreSQL문서형 저장 + 관계형 분석, 장점 결합운영 복잡도 증가

Frequently Asked Questions

Q: 코드 실행에 AWS Lambda를 사용하지 않는 이유는?
A: Docker 기반 Judge0은 세밀한 리소스 제한과 격리를 제공하며, Lambda에서는 보장하기 어렵습니다.

Q: MongoDB와 PostgreSQL을 모두 사용하는 이유는?
A: MongoDB는 유연한 문서 저장(문제, 제출)에서 강점이 있고, PostgreSQL(TimescaleDB)은 복잡한 조인 및 시계열 분석에 효율적입니다.

Q: 단일 사용자가 플랫폼을 DDoS 공격하는 것을 어떻게 방지하나요?
A: CloudFlare, Nginx, 사용자별 Rate limiting 등 다계층 제한과 JWT 검증·입력 정규화를 통해 방어 깊이를 확보합니다.

Q: Redis가 다운되면 어떻게 되나요?
A: 복제 노드로 페일오버하고, 중요한 캐시는 기본 DB에서 재구성합니다. BullMQ는 재시도 메커니즘으로 작업을 계속 처리합니다.

Q: 99.9 % 가동 시간을 목표로 하는 이유는?
A: 99.9 %는 비용·복잡도 사이의 균형을 맞추면서 이 규모 SaaS 제품의 SLA 요구사항을 충족합니다.

Future Directions

  • Kubernetes에 Judge0 자체 호스팅 → 자원 제어 강화
  • 멀티‑리전 배포 (CloudFlare Workers + 엣지 캐시) → 아시아·유럽 사용자 레이턴시 감소
  • 데이터베이스 샤딩 → 제출 건수가 10 M을 초과하면 userId 해시 키로 샤드
  • GraphQL API 도입 → 과다 조회 감소 (예상 데이터 전송량 40 % 절감)
  • 대체 AI 제공업체 탐색 → 아바타 생성·TTS 품질 향상

Resources & References

  • Books

    • Designing Data‑Intensive Applications – Martin Kleppmann
    • System Design Interview – Alex Xu
  • Online

    • LeetCode System Design (HelloInterview)
    • MongoDB Sharding Guide
    • Redis Sorted Sets for Leaderboards

Key Takeaways

  • Async everything – 큐는 최고의 친구
  • Cache aggressively – 성능 향상 및 부하 감소
  • Security in layers – 방어 깊이 확보
  • Measure first, optimize second – 지표를 기반으로 스케일링

Call to Action

비슷한 시스템을 설계한다면 어떻게 할까요?
다음 항목들을 고려해 보세요:

  • 서버리스(Lambda) 대신 Kubernetes?
  • REST 대신 GraphQL?
  • MongoDB 대신 DynamoDB?
  • 다른 AI 제공업체?

댓글에 여러분의 생각을 남겨 주세요! 👇

Built with ❤️ and lots of ☕ by Bhupesh Chikara

Tags: #systemdesign #architecture #webdev #ai #mongodb #kubernetes #redis #postgresql #websocket #nodejs #react #typescript #microservices #cloudcomputing #devops

Back to Blog

관련 글

더 보기 »