커스텀 웹 프레임워크



About Project
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 구조의 게시판 애플리케이션을 올려, 프레임워크 계층과 서비스 로직 계층을 분리하는 방식까지 검증했습니다.
Application / Router / Middleware 구조 구현send / json / redirect / status / setHeader 응답 메서드 지원net 모듈 기반으로 HTTP 요청 처리 흐름을 직접 구현이 프로젝트에서 가장 중요하게 가져간 목표는 HTTP 요청 사이클을 추상화된 프레임워크 밖에서 직접 이해하는 것이었습니다. 이를 위해 Node.js http 모듈이 아니라 더 하위 레벨인 net 모듈을 사용해 요청을 직접 파싱하도록 설계했습니다.
이 과정에서 다음을 직접 다뤘습니다.
data / end 이벤트 기반 body 수집 및 파싱이를 통해 단순히 웹 프레임워크를 사용하는 수준을 넘어, Node.js 런타임과 네트워크 레벨에서 요청이 어떻게 흘러가는지 직접 구현하고 디버깅한 경험을 만들 수 있었습니다.
학습 목적 프로젝트였지만 단순 토이 서버로 끝내지 않기 위해, Express와 유사한 사용성을 갖는 구조를 목표로 했습니다. 이에 따라 Application, Router, Middleware, Request, Response 계층을 나누고, 프레임워크 사용자 입장에서 익숙한 방식으로 사용할 수 있도록 설계했습니다.
주요 설계 포인트는 다음과 같습니다.
app.use() 기반 전역/경로별 미들웨어 체인req.params, req.body, req.session 등 확장 가능한 Request 구조send, json, redirect, status, setHeader 등 Response 인터페이스 제공이 프로젝트를 통해 프레임워크 계층과 애플리케이션 계층의 책임을 분리하고, 재사용 가능한 구조를 먼저 설계한 뒤 그 위에 서비스 로직을 얹는 방식을 직접 경험했습니다.
실제 서비스 테스트 중 대용량 데이터 파일 전송이 정상적으로 처리되지 않는 문제를 확인했습니다. 원인을 추적한 결과, 요청이 항상 한 번에 오지 않고 여러 chunk로 분리될 수 있으며, 헤더와 바디가 동일 chunk 안에 함께 들어오는 경우도 있다는 점이 핵심이었습니다.
이를 해결하기 위해:
\r\n\r\n 기준으로 헤더와 바디를 분리Content-Length 기준으로 수신 완료 여부를 판단data / end 이벤트 등록 시점과 flow 모드 전환을 제어하는 방식으로 구조를 수정했습니다.
그 결과 단순한 JSON 요청뿐 아니라 대용량 파일 전송과 스트리밍 상황에서도 안정적으로 body를 수신할 수 있었습니다.
게시판 조회 API에 Redis 캐시를 적용했지만, 초기에는 기대한 만큼 성능이 개선되지 않았습니다. 배포 환경에서 평균 응답 시간을 확인해보니 병목이 단순 DB 조회가 아니라 캐시 키 생성 과정의 JSON.stringify와 응답 직렬화/역직렬화 비용에도 있음을 확인했습니다.
이를 해결하기 위해:
JSON.stringify 제거JSON.parse 비용 감소를 적용했고, 결과적으로 게시판 조회 API 평균 응답 시간을 15ms → 6ms로 줄일 수 있었습니다.
이 경험을 통해 캐시는 단순히 붙인다고 빨라지는 것이 아니라, 직렬화 비용과 키 설계까지 포함해 최적화해야 한다는 점을 배웠습니다.
정적 파일 응답에도 Redis 캐시를 적용해봤지만, 실제로는 운영체제의 파일 캐시와 비교했을 때 Redis 접근 및 Buffer-String 변환 비용 때문에 기대 이하의 결과가 나왔습니다.
이를 바탕으로 Redis 대신 MemoryCache를 직접 구현해 정적 파일 캐시에 적용했고, 정적 파일 응답 시간을 64ms → 30ms로 개선했습니다.
이 과정에서 얻은 결론은 다음과 같습니다.
게시물 조회수는 업데이트가 빈번하기 때문에 Redis를 이용해 메모리에서 먼저 처리하고, 일정 threshold 이상 차이가 날 때 DB에 반영하는 구조를 설계했습니다. 다만 초기 구현에서는 조회수 초기화와 DB 반영 시점에서 race condition 가능성이 있었습니다.
이를 해결하기 위해:
hSetNX를 사용해 원자적으로 처리hIncrBy를 사용하도록 개선했습니다.
이를 통해 단순 캐시 적용을 넘어, 동시성 문제와 데이터 반영 전략까지 고려한 조회수 처리 구조를 설계할 수 있었습니다.
net 모듈 기반 HTTP 서버 및 프레임워크 코어 직접 구현이 프로젝트를 통해 웹 프레임워크의 내부 동작을 직접 구현하면서, 단순 기능 개발을 넘어 Node.js 런타임·네트워크 레벨의 이해, 구조 설계, 성능 최적화 역량을 함께 키울 수 있었습니다.
Related Projects