[한이음 드림업(구.ICT멘토링] Ep.1 수강신청 시스템은 어떻게 돌아갈까? 서버 구조 설계해보기

2025. 5. 2. 15:55·프로젝트 도전기

1. 들어가며

지난 글에서는 프로젝트를 어떻게 시작하게 되었고, 왜 이 주제를 선택했는지에 대해 이야기했다.

2025.04.12 - [프로젝트 도전기] - [한이음 드림업 Ep.0] 진짜 터지지 않는 수강신청 시스템, 가능할까?

 

[한이음 드림업 Ep.0] 진짜 터지지 않는 수강신청 시스템, 가능할까?

1. 들어가며졸업 전, 나만의 규모 있는 프로젝트를 완성해보고 싶다는 욕심이 늘 있었다. 가능하다면 공모전에도 도전해보고 싶다는 생각도 있었고, 마지막 학년인 지금이 아니면 도전하기 어렵

mingking2.tistory.com

 

“진짜 안 터지는 수강신청 시스템”을 만들기 위해서는

기능보다 더 중요한 것이 있다.

바로, 무엇부터 만들 것인가, 그리고 어떻게 작게 시작해서 확장할 것인가다.

 

우리는 모든 걸 한 번에 만들지 않기로 했다.

대신, 핵심 기능만 담은 최소 단위(MVP)부터 만들고,

그 위에 실험과 개선을 반복해 진짜로 견디는 시스템을 완성해가기로 했다.

 

이번 글에서는 다음과 같은 과정을 공유한다:

  1. 우리가 정의한 MVP와 그 배경이 된 요구사항
  2. MVP를 바탕으로 설계한 데이터베이스 구조(ERD)
  3. 그리고 초기 서버 아키텍처는 어떻게 구성했는지
그래서 완벽한 기능보다, “먼저 작동하는지부터 확인해보자”는 마음으로 출발했다.
이제, 그 첫 설계 과정을 하나씩 풀어보려 한다.


2. 어떤 MVP를 만들까?

우리가 만들고자 하는 시스템은 단순한 UI 중심의 프로젝트가 아니다.

실제 수강신청 트래픽 환경에서도 견딜 수 있는 백엔드 시스템을 목표로 한다.

 

그렇기에 처음부터 고성능 기술을 도입하기보다는,

핵심 기능이 실제로 제대로 작동하는지부터 검증해야 했다.

 

🔍 우리가 분석한 초기 요구사항은 다음과 같다.

  • 사용자는 회원가입 및 로그인을 할 수 있어야 한다.
  • 사용자는 개설된 강의를 조회할 수 있어야 한다.
  • 사용자는 강의를 신청 및 취소할 수 있어야 한다.
  • 사용자는 자신의 신청 내역을 조회할 수 있어야 한다.
  • 신청 시 여석을 초과하지 않도록 제한해야 한다.

 

💡 그래서 우리는 먼저, MVP를 정의했다.

MVP(Minimum Viable Product)란

“최소 기능 제품”, 즉 가장 핵심적인 기능만으로 제품이 실제로 작동하는지 검증할 수 있는 단위를 의미한다.

 

완벽한 기능을 다 만드는 것이 아니라,

진짜 중요한 흐름이 문제없이 작동하는지를 빠르게 확인하고 개선하는 것이 MVP의 핵심이다.

 

✅ 우리가 정의한 최소한의 MVP는 다음과 같다:

요구사항 포함 이유
회원가입 / 로그인 사용자 식별 및 접근 제어
개설 강의 목록 조회 수강 신청 전 정보 확인
강의 신청 시스템의 핵심 동작
강의 취소 실수/변경 등 사용자 플로우 보완
신청 내역 조회 결과 확인과 피드백
여석 제한 정원 초과 방지 및 동시성 문제 대응

 

이 MVP는 단순히 기능이 있는지를 보는 게 아니라,

수강신청의 흐름이 끊기지 않고 끝까지 작동하는지를 검증하는 데 목적이 있다.

 

우리는 이 내용을 바탕으로

에픽 1단계: “기본 수강신청 기능 구현”을 정의하고,

하위 사용자 스토리 단위로 세분화하여 애자일 방식으로 개발을 시작했다.


3. 애자일 전략에 따른 에픽 및 사용자 스토리 정의

초기 MVP가 정의되었다면, 이제 실제 개발 단위로 쪼개는 과정이 필요하다.

우리는 애자일 전략에 따라 다음과 같은 흐름으로 작업을 정리했다:

 

 

  1. 에픽(Epic):
    • “수강신청 기본 기능 구현”이라는 하나의 목표 단위로 정의
    • 이 에픽은 MVP에 명시된 요구사항을 기준으로 설정함
  2. 사용자 스토리(User Story):
    • 각 기능을 사용자의 입장에서 “사용자는 ~할 수 있다”의 형태로 정리
    • Jira를 통해 각 스토리를 Task로 분리해 우선순위를 관리 중

 

이렇게 스토리를 구체적으로 나누어 정의함으로써,

각 개발 작업을 명확하게 추적할 수 있었고,

한 번에 모든 기능을 만드는 대신, 작게 → 빠르게 → 점진적으로 구현해 나갈 수 있었다.


4. MVP에 맞춰 설계한 ERD 구조

MVP에 필요한 데이터 흐름을 바탕으로 다음과 같은 주요 테이블을 설계했다:

테이블 설명
student 학번, 이름, 단과대, 학과, 학년 등 사용자 기본 정보
student_policy 해당 학생의 정책 정보 (최대 수강 가능 학점, 전공/교양 최소 학점 등)
course_info 강의가 개설되는 조건(학기, 전공 여부 등)을 정의한 메타 테이블
course 실제 개설된 강의 (과목명, 교수명, 수업시간, 수강 가능 인원 등)
course_time 강의 시간 정보 (요일, 시작/종료 시간 등)
course_enrollment 수강 신청 정보. student와 course 간 다대다 관계를 중간 테이블로 연결

 

📌 설계 포인트

  • student ↔ student_policy: 1:1 관계
    → 학생마다 다른 학사정보가 적용되기 때문에 명확히 분리

  • student ↔ course_enrollment ↔ course: N:M 관계
    → 단순 연결을 넘어, 수강 신청의 도메인 로직(중복 신청, 여석 체크, 신청 시간 검증 등)이 중간 테이블을 중심으로 이루어지도록 설계함

  • course ↔ course_time: 1:N 관계
    → 하나의 강의가 여러 시간대에 열릴 수 있는 구조에 대응

  • course ↔ course_info: N:1 관계
    → 필터링, 조회 성능 향상을 위해 course의 분류 정보는 별도 테이블로 분리

5. 서버 아키텍처는 어떻게 구성할까?

초기 단계에서는 복잡한 구조를 도입하지 않고, 단일 서버 + 단일 DB로 시작했다.

기능 자체의 동작을 먼저 검증하는 것이 목적이었기 때문에, 트래픽 분산이나 캐시, 메시징 큐 같은 고성능 아키텍처는 이 시점에서는 도입하지 않았다.

 

또한, 한이음 드림업에서 제공하는 서버 인스턴스가 1개로 제한되어 있기 때문에,

하나의 인스턴스 안에서 Spring 서버와 MySQL을 컨테이너화하여 동작시키는 방식으로 구성하였다.

 

✏️ 구성 요소

Client → Spring 서버 (REST API)

사용자는 클라이언트를 통해 수강 신청 요청을 보낸다.
이 요청은 Spring Boot 기반 REST API로 구성된 단일 서버에서 처리된다.

 

Spring 서버 → MySQL

서버는 MySQL DB에 직접 접근해 수강 신청 데이터를 저장한다.
이때 신청 정원 제한이나 중복 신청 방지는 @Transactional 기반 트랜잭션 처리와 DB 락을 통해 동시성 제어를 수행한다.

 

Docker 환경 구성

Spring 서버와 MySQL DB는 모두 Docker 컨테이너로 분리되어 배포된다.
이로써 로컬 개발과 추후 확장을 위한 격리된 환경을 유지할 수 있다.

 

📌 구조의 목적

  • MVP 검증에 최적화된 단순 구조
    • 핵심 기능이 정상적으로 동작하는지를 빠르게 확인할 수 있다.
    • 트래픽이 몰릴 경우 어느 구간에서 병목이 발생하는지를 명확하게 확인 가능하다.
  • 다음 단계로의 확장을 고려한 실험 기반 설계
    • 컨테이너 기반 구성이므로 Redis, Kafka 등 추가 컴포넌트를 유연하게 붙일 수 있다.
    • 테스트 결과를 바탕으로 병목 지점을 개선해 나가는 점진적 고도화 전략을 적용할 수 있다.

 

🧩 한계와 다음 목표

이 구조는 개발과 검증에는 적합하지만,

실제 수강 신청처럼 수천 명이 동시에 요청하는 상황에서는 한계를 드러낼 수 있다.

  • 단일 DB에 모든 요청이 집중되기 때문에 병목 발생 가능성
  • 트래픽 급증 시 서버 부하 집중
  • 캐시가 없어 모든 데이터 조회가 DB에 직접 의존
다음 단계에서는 이 구조를 기반으로 JMeter를 이용해 부하 테스트를 진행하고,
실제 병목이 발생하는 지점을 찾아 개선해 나갈 예정이다.

6. 결론

이번 글에서는 MVP를 어떻게 정의하고, 그에 따라 ERD를 설계하고, 최소한의 서버 아키텍처를 구성했는지를 정리했다.

우리는 완성된 구조보다 “작동하는 구조”를 먼저 만들고, 그것이 진짜로 견딜 수 있는지를 실험해나가는 방식을 선택했다.

 

이제 기본 기능은 구현되었다.

다음 단계는, “이 시스템이 실제로 어느 정도의 부하까지 견딜 수 있을까?”라는 질문에 답하는 것이다.

 

 

다음 글에서는

  • JMeter를 활용한 부하 테스트를 어떻게 설계했고
  • 실제로 어떤 병목 구간이 발견되었는지,
  • 그리고 그 데이터를 바탕으로 어떤 개선 방향을 설정했는지

우리가 실험을 통해 얻은 통찰을 자세히 공유할 예정이다.

'프로젝트 도전기' 카테고리의 다른 글

[한이음 드림업(구.ICT멘토링] Ep.0 진짜 터지지 않는 수강신청 시스템, 가능할까?  (0) 2025.04.12
'프로젝트 도전기' 카테고리의 다른 글
  • [한이음 드림업(구.ICT멘토링] Ep.0 진짜 터지지 않는 수강신청 시스템, 가능할까?
mingking2
mingking2
에러와 삽질 속에서 성장하는 응애 개발자의 성장 일지
  • mingking2
    Mingking의 삽질 기록
    mingking2
  • 전체
    오늘
    어제
    • 분류 전체보기 (19)
      • 삽질로그 (10)
      • 스타트업 응애기 (1)
      • 프로젝트 도전기 (2)
      • DB 모르는 백엔드 탈출기 (5)
      • 네트워크 (1)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    servlet
    Tomcat
    Java
    @JoinColumn
    RDB
    Sync
    spring
    DB
    MVC
    batch
    CompletableFuture
    server
    플로우차트
    WebSocket
    연관관계
    orm
    context
    Async
    JPA
    n:m
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
mingking2
[한이음 드림업(구.ICT멘토링] Ep.1 수강신청 시스템은 어떻게 돌아갈까? 서버 구조 설계해보기
상단으로

티스토리툴바