커스텀 웹 프레임워크

2025.03 – 2025.06
Backend / Framework / Low-level
Custom Web Framework
Custom Web Framework
Custom Web Framework

About Project

  • 프로젝트 성격: 개인 프로젝트 (기여도 100%)
  • 담당: 프레임워크 코어 · MVC 애플리케이션 · 배포 전반
  • 기간: 2025.03 ~ 2025.06
  • 배포: Linux 홈 서버 + Docker Compose + Nginx
  • Repository: https://github.com/LLagoon3/Custom_Web_Framework

Objective

Node.js `net` 모듈 기반으로 HTTP 요청 사이클을 직접 구현하고, 그 위에 Express 유사 구조의 커스텀 웹 프레임워크와 MVC 웹 애플리케이션을 구축한 개인 프로젝트.

Tools & Technologies

TypeScript, Node.js net module, HTML, CSS, JavaScript, MySQL, Redis, Lua Script, Docker Compose, Nginx, Linux

Challenge

문제 의식

이 프로젝트는 단순히 Express를 사용하는 데서 끝나지 않고, HTTP 요청이 실제로 어떤 흐름으로 파싱되고, 라우터와 미들웨어가 어떤 방식으로 연결되며, 응답이 어떤 구조로 만들어지는지 직접 구현해보기 위해 시작한 프로젝트입니다.

특히 Express 학습 과정에서 프레임워크의 사용자 관점뿐 아니라 내부 구현 관점까지 이해하고 싶었고, 이를 위해 Node.js net 모듈 위에서 HTTP 서버와 프레임워크 코어를 직접 설계했습니다. 이후 그 위에 MVC 구조의 게시판 애플리케이션을 올려, 프레임워크 계층과 서비스 로직 계층을 분리하는 방식까지 검증했습니다.

구현 범위

프레임워크 코어

  • HTTP/1.1 요청 파싱
  • 모든 HTTP 메서드 지원
  • Request / Response 객체 구현
  • Express 유사 Application / Router / Middleware 구조 구현
  • 전역 / 경로별 미들웨어 지원
  • 동적 라우팅, 와일드카드, 중첩 라우팅 지원
  • send / json / redirect / status / setHeader 응답 메서드 지원
  • 정적 파일 서빙 구현
  • Redis 기반 세션 저장소 구현
  • JSON / form-urlencoded body parsing 구현
  • 대용량 파일 스트리밍 처리 지원

애플리케이션 계층

  • MVC 구조의 게시판 애플리케이션 구현
  • 게시글 CRUD
  • 로그인 및 세션 기반 인증
  • 파일 업로드 기능 구현
  • 개인 서버 배포 및 실제 실행 환경에서 검증

핵심 기술적 판단

1. net 모듈 기반으로 HTTP 요청 처리 흐름을 직접 구현

이 프로젝트에서 가장 중요하게 가져간 목표는 HTTP 요청 사이클을 추상화된 프레임워크 밖에서 직접 이해하는 것이었습니다. 이를 위해 Node.js http 모듈이 아니라 더 하위 레벨인 net 모듈을 사용해 요청을 직접 파싱하도록 설계했습니다.

이 과정에서 다음을 직접 다뤘습니다.

  • 헤더와 바디를 구분하는 요청 파싱 로직
  • 헤더와 바디가 하나의 chunk에 같이 들어오는 경우 처리
  • body가 여러 chunk로 나뉘어 도착하는 경우 처리
  • 스트림 flow 모드 전환 시점 제어
  • data / end 이벤트 기반 body 수집 및 파싱
  • 대용량 데이터 전송과 파일 스트리밍 처리

이를 통해 단순히 웹 프레임워크를 사용하는 수준을 넘어, Node.js 런타임과 네트워크 레벨에서 요청이 어떻게 흘러가는지 직접 구현하고 디버깅한 경험을 만들 수 있었습니다.

2. Express 유사 구조의 Application / Router / Middleware 설계

학습 목적 프로젝트였지만 단순 토이 서버로 끝내지 않기 위해, Express와 유사한 사용성을 갖는 구조를 목표로 했습니다. 이에 따라 Application, Router, Middleware, Request, Response 계층을 나누고, 프레임워크 사용자 입장에서 익숙한 방식으로 사용할 수 있도록 설계했습니다.

주요 설계 포인트는 다음과 같습니다.

  • app.use() 기반 전역/경로별 미들웨어 체인
  • 동적 라우팅, 와일드카드, 중첩 라우팅 지원
  • req.params, req.body, req.session 등 확장 가능한 Request 구조
  • send, json, redirect, status, setHeader 등 Response 인터페이스 제공
  • 정적 파일 서빙과 세션 미들웨어를 코어 구조에 자연스럽게 연결

이 프로젝트를 통해 프레임워크 계층과 애플리케이션 계층의 책임을 분리하고, 재사용 가능한 구조를 먼저 설계한 뒤 그 위에 서비스 로직을 얹는 방식을 직접 경험했습니다.

어려웠던 점과 해결

1. Request / Body 파싱 과정에서 대용량 데이터 전송이 깨지던 문제

실제 서비스 테스트 중 대용량 데이터 파일 전송이 정상적으로 처리되지 않는 문제를 확인했습니다. 원인을 추적한 결과, 요청이 항상 한 번에 오지 않고 여러 chunk로 분리될 수 있으며, 헤더와 바디가 동일 chunk 안에 함께 들어오는 경우도 있다는 점이 핵심이었습니다.

이를 해결하기 위해:

  • \r\n\r\n 기준으로 헤더와 바디를 분리
  • 헤더 파싱 직후 남아 있는 body 조각을 별도 버퍼에 보관
  • 이후 들어오는 chunk를 누적해 Content-Length 기준으로 수신 완료 여부를 판단
  • data / end 이벤트 등록 시점과 flow 모드 전환을 제어

하는 방식으로 구조를 수정했습니다.

그 결과 단순한 JSON 요청뿐 아니라 대용량 파일 전송과 스트리밍 상황에서도 안정적으로 body를 수신할 수 있었습니다.

2. Redis API 캐시를 적용했는데 오히려 기대만큼 빨라지지 않던 문제

게시판 조회 API에 Redis 캐시를 적용했지만, 초기에는 기대한 만큼 성능이 개선되지 않았습니다. 배포 환경에서 평균 응답 시간을 확인해보니 병목이 단순 DB 조회가 아니라 캐시 키 생성 과정의 JSON.stringify와 응답 직렬화/역직렬화 비용에도 있음을 확인했습니다.

이를 해결하기 위해:

  • 캐시 키 생성 로직 단순화
  • 불필요한 JSON.stringify 제거
  • 응답 방식 개선으로 JSON.parse 비용 감소

를 적용했고, 결과적으로 게시판 조회 API 평균 응답 시간을 15ms → 6ms로 줄일 수 있었습니다.

이 경험을 통해 캐시는 단순히 붙인다고 빨라지는 것이 아니라, 직렬화 비용과 키 설계까지 포함해 최적화해야 한다는 점을 배웠습니다.

3. 정적 파일 캐시에서 Redis보다 인메모리 캐시가 더 적합했던 문제

정적 파일 응답에도 Redis 캐시를 적용해봤지만, 실제로는 운영체제의 파일 캐시와 비교했을 때 Redis 접근 및 Buffer-String 변환 비용 때문에 기대 이하의 결과가 나왔습니다.

이를 바탕으로 Redis 대신 MemoryCache를 직접 구현해 정적 파일 캐시에 적용했고, 정적 파일 응답 시간을 64ms → 30ms로 개선했습니다.

이 과정에서 얻은 결론은 다음과 같습니다.

  • API JSON 응답 캐시와 정적 파일 캐시는 같은 전략으로 다루면 안 됨
  • 캐시 계층은 데이터 형태와 접근 비용에 따라 달라져야 함
  • 정적 파일에서는 인메모리 캐시가 더 적합할 수 있음

4. 조회수 처리에서 동시성과 DB 반영 시점 문제

게시물 조회수는 업데이트가 빈번하기 때문에 Redis를 이용해 메모리에서 먼저 처리하고, 일정 threshold 이상 차이가 날 때 DB에 반영하는 구조를 설계했습니다. 다만 초기 구현에서는 조회수 초기화와 DB 반영 시점에서 race condition 가능성이 있었습니다.

이를 해결하기 위해:

  • 초기화에는 hSetNX를 사용해 원자적으로 처리
  • 증가에는 hIncrBy를 사용
  • 최종적으로 Lua Script를 적용해 조회수 증가와 조건부 DB 반영 판단을 원자적으로 처리

하도록 개선했습니다.

이를 통해 단순 캐시 적용을 넘어, 동시성 문제와 데이터 반영 전략까지 고려한 조회수 처리 구조를 설계할 수 있었습니다.

구현 포인트

  • Node.js net 모듈 기반 HTTP 서버 및 프레임워크 코어 직접 구현
  • Express 유사 구조(Application / Router / Middleware / Request / Response) 설계
  • 전역/경로별 미들웨어, 와일드카드/중첩 라우팅 지원
  • Redis 기반 세션 저장 및 로그인 인증 기능 구현
  • MVC 게시판 애플리케이션과 프레임워크 계층 분리
  • Redis / 인메모리 캐시 비교를 통한 API 및 정적 파일 응답 최적화
  • Lua Script 기반 조회수 동시성 문제 해결
  • Linux 홈 서버 + Docker Compose + Nginx 리버스 프록시 배포

배포 환경

  • Linux 기반 홈 서버에 Docker Compose로 배포
  • Nginx 리버스 프록시 구성
  • MySQL / Redis 등 의존 서비스도 컨테이너로 운영
  • 학습용 배포이면서 동시에 멘토 피드백을 받기 위한 검증 환경으로 활용

성과 및 배운 점

  • 웹 프레임워크를 사용하는 수준을 넘어, 내부 동작을 직접 설계하고 구현하는 경험을 쌓았습니다
  • HTTP 요청 파싱, 스트림 처리, 미들웨어 체인, 응답 객체 설계 등 Node.js 런타임/네트워크 레벨에 대한 이해를 깊게 가져갈 수 있었습니다
  • 캐시와 조회수 처리에서 단순 적용이 아니라 병목 분석, 동시성, 반영 전략까지 고려하는 백엔드 관점을 경험했습니다
  • 프레임워크 계층과 애플리케이션 계층을 분리해 구조적으로 사고하는 습관을 얻었습니다

한 줄 회고

이 프로젝트를 통해 웹 프레임워크의 내부 동작을 직접 구현하면서, 단순 기능 개발을 넘어 Node.js 런타임·네트워크 레벨의 이해, 구조 설계, 성능 최적화 역량을 함께 키울 수 있었습니다.

© 2026 Lagoon Portfolio. All rights reserved.