천명현

Backend Developer

소개

안녕하세요. 백엔드 개발자 천명현입니다. 저는 도메인을 정확히 이해하고, 서비스가 성장해도 안정적으로 운영될 수 있는 확장 가능한 구조를 설계하는 일에 강점이 있습니다. 프로젝트마다 초기 아키텍처 설계를 주도하며 DDD 기반의 도메인 분석, 분산 시스템 구성, 성능 병목 개선을 경험했고, 문제를 추측이 아닌 메트릭과 운영 데이터를 바탕으로 해결해왔습니다. 또한 실제 사용자가 사용하는 서비스를 설계, 런칭, 유지보수한 경험을 바탕으로 개발뿐 아니라 운영 환경의 안정성까지 함께 고려합니다.

프로젝트 경험

백엔드 개발 파트장 | Finvibe 팀 (백엔드 개발팀 3명)
Modular Monolith · Domain-Driven Design(DDD) · WebSocket · Virtual Thread · Redis Pub/Sub · B+ Tree Index

실제 금융 시장 환경을 실시간으로 반영하는 10만 MAU 대응 목표의 모의 투자 플랫폼입니다. 프로젝트 초기 도메인 설계부터 운영 환경에 맞춘 인프라 구조 개편까지 전체 백엔드 아키텍처 구축을 담당했습니다.

Java Spring Boot JPA Spring Cloud Docker Kubernetes Cloudflare Kong API Gateway MySQL(MariaDB) Redis Kafka GitHub Actions Argo CD Prometheus Grafana

아키텍처 설계 내역

1차 설계 - 기능 결합도 완화를 위한 DDD 및 모듈러 모놀리스(Modular Monolith) 도입

앱 내에 AI 챌린지, XP 보상, 랭킹 등 다수의 비즈니스 로직이 혼재되어 상호 결합도가 높아지는 문제가 예상되었습니다. 이를 해결하고자 DDD(도메인 주도 설계)를 채택하여 이벤트 스토밍을 통해 바운디드 컨텍스트를 식별했습니다.

  • 이벤트 주도 아키텍처(EDA) 적용: 컨텍스트 간 데이터 통신을 Kafka 기반 도메인 이벤트로 대체하여 비즈니스 로직의 결합도를 낮추고 기능 개발 리드타임을 단축했습니다.
  • 굵은 입자 서비스 적용: 무조건적인 마이크로서비스 확장은 배제하고, 식별된 컨텍스트 모듈들을 하나의 인스턴스 안에서 격리하여 동작시키는 모듈러 모놀리스 구조를 구성하여 배포 프로세스를 단순화했습니다.
1-1. 세션 진행 현장 사진
실제 오프라인 이벤트 스토밍 진행 모습
1-2. 스토밍 보드 캡처
도메인 이벤트 및 바운더리 식별 결과
2-1. 바운디드 컨텍스트 맵
바운더리 컨텍스트 및 컨텍스트간 관계 식별
2-2. 전술적 설계 이미지
전술적 설계 : 애그리거트 패턴 기반 모델링
3. 전체 시스템 아키텍처
초기 시스템 아키텍처 다이어그램

2차 설계(리팩토링) - 분산 오버헤드 제어 및 기능 중심(Scale-Out) 아키텍처 개편

소규모 팀 환경에서 도메인 단위로 개별 인스턴스를 유지 및 확장하는 것은 불필요한 인프라 및 운영 오버헤드를 발생시켰습니다. 이에 따라 도메인 모듈 경계는 유지하되, 도메인 중심 분산에서 기능 중심 분산으로 아키텍처를 개편했습니다.

  • 손쉬운 인스턴스 병합: 기존 시스템이 모듈러 모놀리스 기반으로 느슨하게 결합되어 있었기에, 복수의 도메인 모듈을 단일 메인 API 인스턴스로 안전하고 빠르게 통합할 수 있었습니다.
  • 선택적 Scale-Out을 통한 트래픽 대응: 대규모 트래픽 부하 분산이 필수적인 웹소켓 리스너와 배치(Batch) 서비스 레이어만을 별도의 외부 인스턴스로 분리 배치하여, 전체 인프라 비용을 절감하면서 동시 접속 수용 능력을 극대화했습니다.
4. 개선된 기능 중심 분산 시스템 아키텍처
웹소켓 및 배치 스케줄러를 분리한 실용적 스케일 아웃 아키텍처

수행한 문제 해결

고부하 시나리오의 웹소켓 동시 연결 병목 개선

  • Situation
    10만 MAU 운영 시나리오를 가정한 상태에서 초단위 실시간 호가를 전송해야 했습니다. 최초 K6 부하 테스트 결과, 약 5,000건의 동시 커넥션에서 Out Of Memory(OOM)가 발생하고 데이터 Fanout(전파) 꼬리 지연 시간이 20초를 초과(p99 > 20s)하는 중대한 병목에 직면했습니다.
  • Task
    OOM의 원인이 되는 메시지 버퍼 누수 구간을 식별하고, 트래픽에 맞춰 선형적 Scale-Out이 가능하도록 서빙 환경을 개편하여 '동시 접속 2만 커넥션' 동기화 목표를 달성해야 했습니다.
  • Action
    메모리 힙 덤프 분석을 통해 Fanout 처리 지연으로 적재된 메시지가 힙 메모리(3GB)를 고갈시킴을 확인했습니다. Fanout 처리에 Virtual Thread를 도입하여 병렬 처리 및 Context Switch 비용을 최적화했습니다. 또한 웹소켓 리스너를 분리하여 외부 인스턴스로 분산 배치하고, 동시성 환경에서의 메시지 순서를 보장하기 위해 세션별 Inbound Task Queue와 Redis Pub/Sub 연동 비동기 통신 구조를 설계했습니다.
  • Result
    시나리오 목표치인 2만 동시 접속 커넥션을 달성하였고, 트래픽 스파이크 하에서 Fanout 지연 시간(p55 및 p99)을 1초 이내로 안정화했습니다.
    Trade-off: Redis Pub/Sub 구조 도입으로 인해 단일 노드 메모리 방식보다 필연적인 네트워크 I/O 비용이 추가되었으며, 메시지 순서 보장용 Inbound Queue 할당으로 인해 활성 세션별 로컬 메모리 점유율이 소폭 상승했습니다.
[ Before & After 성능 지표 비교 ]
개선 전 웹소켓 병목 지표
[ Before ] 개선 전 웹소켓 병목 지표. Fanout Timing이 20초 가까이 걸림
개선 후 웹소켓 안정화 지표
[ After ] Virtual Thread Fanout 적용 후

유저 PK 타입이 UUID일 경우의 B+ Tree 인덱스 성능 개선

  • Situation
    시스템 보안 목적으로 외부 노출 유저 식별자(PK)를 UUIDv4로 설계한 후 테스트 과정에서, 유저 테이블 연관 쿼리 실행 시 높은 Disk I/O 및 지연 현상을 식별했습니다.
  • Task
    문제의 원인을 B+ Tree 인덱스에 무작위 값이 삽입될 때 발생하는 페이지 파편화(Page Split) 및 물리적 Locality 저하로 판단하고, 관련 조회 성능 개선과 스토리지 낭비 방지 방안이 필요했습니다.
  • Action
    내부 데이터 Join 및 스캔에는 순차적 Auto-Increment 특성을 지닌 숫자형 PK(BIGINT)를 사용하고, 외부 API 통신 식별자로는 논리적 PK(UUID)를 매핑하는 이중 키(Dual-Key) 식별 구조로 재설계했습니다. 데이터베이스 접근 오버헤드를 줄이기 위해 두 식별키 간의 매핑 테이블은 Redis에 캐싱하여 Disk I/O를 제어했습니다.
  • Result
    클러스터드 인덱스의 Locality를 복구하여 인덱스 스토리지 공간을 절감하고, 범위 조회 시 탐색 Page 접근 횟수를 33% 감소시켰습니다. 외부 식별 보안성을 유지하면서 Join 쿼리 평균 응답 속도를 최대 30% 개선했습니다.
    Trade-off: B+ Tree 탐색 성능은 극대화되었으나, 이중 구조(Dual-Key)를 연결하는 UUID-BIGINT 매핑 정보를 Redis에 추가로 동기화해야 하므로 데이터 정합성 관리 복잡도와 캐시 의존성이 고질적으로 증가했습니다.

전체 개발 파트장 | Memoria 팀 (백엔드 개발팀 3명)
Asynchronous Queue · Distributed AI Serving · Spring Event · Server-Sent Events(SSE) · Daemon Thread

사용자의 감정을 분석하여 가상 캐릭터의 답장 및 맞춤형 멀티모달 콘텐츠(이미지, 음악)를 제공하는 서비스입니다. 고가용성 AI 서빙 파이프라인 아키텍처를 설계하였으며, 해당 완성도를 바탕으로 교내 캡스톤 디자인 경진대회 금상을 수상했습니다.

Java Spring Boot FastAPI PyTorch PostgreSQL Docker Caddy

아키텍처 설계 내역

중앙 집중형 백엔드와 분산 AI 노드 스케줄링 분리

시스템의 전체 비즈니스 로직과 데이터 정합성은 모놀리식(Monolithic) 기반의 Spring Boot 백엔드가 통제합니다. 반면, 고부하 연산이 발생하는 AI 서빙 계층은 FastAPI와 PyTorch를 결합하여 Stable Diffusion(이미지 생성)과 Yue(음악 생성) 모델을 GPU 환경에서 독립적으로 구동하도록 아키텍처를 분리했습니다.

특히 AI 모델 연산용 노드는 단일 작업 수행 중 다른 콘텐츠를 동시 생성(Concurrency)할 수 없는 제약이 존재합니다. 이를 해결하고자 하위 GPU 노드들을 분산 환경으로 확장(Scale-out) 다중화하였고, 메인 백엔드 서버가 중앙 대기열(Queue)을 관리하며 가용한 노드에 작업을 지시하는 비동기 스케줄링 및 라우팅을 수행하도록 설계했습니다.

사용자 트래픽 분산 및 AI 노드 스케줄링 흐름도
Memoria 시스템 아키텍처

수행한 문제 해결

생성형 모델 서빙 시 대기열 장기화 문제 해결

  • Situation
    야간 피크 시간대에 AI 생성 요청이 특정 단일 추론 노드에 장기간 적체되는 대기열 지연 현상이 발생했습니다. 또한 사용자가 이탈하여 요청 시그널이 끊어지더라도 백그라운드에서는 GPU 자원이 점유되어 후순위 작업 처리가 밀리는 리소스 고갈 문제가 발생했습니다.
  • Task
    AI 추론 노드의 병렬 부하 분산을 구현하고, 사용자에 의해 통신이 단절된 비유효 작업을 식별 및 폐기하여 효율적인 자원 스케줄링 환경을 마련해야 했습니다.
  • Action
    외부 추론 노드들을 비동기 Node Pool로 추상화하고, 노드별 상태(Health & Load)를 고려하는 커스텀 라우팅 스케줄러를 구축했습니다. 사용자 세션 종료 시 Transactional Spring Event 레이어가 이를 인지하여 처리 중인 고아(Orphan) 태스크를 시스템에서 파기하는 로직을 연동했습니다. 추가적으로 SSE를 통해 사용자에게 작업 진행 상태를 실시간 송출하도록 구현했습니다.
  • Result
    대기열의 꼬리 지연(Tail Latency) 현상을 완화하고 비유효 GPU 자원 점유율을 억제했습니다. 서빙 구조를 외부 비동기 풀로 이전함에 따라, 외부 AI 서버 장애가 메인 서비스로 파급되지 않도록 장애 경계를 분리(Decoupling)했습니다.
    Trade-off: 비동기 Node Pool 방식을 통해 시스템 장애 전파는 완벽히 차단하였으나, 클라이언트 입장에서 결과를 수신하기 위해 끊임없는 SSE(Server-Sent Events) 연결을 별도로 유지해야 하는 통신 인프라 오버헤드가 부가되었습니다.

SSE Heartbeat 스케줄링 누적 자원 병목 및 타임아웃 개선

  • Situation
    초기 SSE Heartbeat 유지를 위해 개별 연결마다 단일 스케줄러 스레드에 Ping 태스크를 하나씩 할당했습니다. 네트워크 불안정으로 클라이언트가 재연결될 때 이전 스레드가 수거되지 않는 현상이 발생하여, Task가 기하급수적으로 누적되고 스레드 자원 고갈(OOM) 오류가 보고되었습니다.
  • Task
    구독 연결 해제 시 스케줄러 스레드의 자원 반환을 보장하고, 서버 부하 상황에서도 OOM이나 클라이언트 타임아웃 없이 안정적인 연결 유지가 가능한 구조가 필요했습니다.
  • Action
    단일 커넥션마다 스레드를 점유하는 구조를 탈피하여, 중앙 집중형 공유 스케줄러(Shared Scheduler) 방식으로 아키텍처를 최적화했습니다. 단일 백그라운드 데몬 스레드가 전체 Emitter 컬렉션을 순회하며 일괄적으로 Ping을 전송합니다. 또한 사용자 재구독 시 분산 환경을 고려하여 불필요해진 기존 Emitter를 명시적으로 종료 처리하도록 구성했습니다.
  • Result
    유휴 스레드 점유 문제가 해결되어 3,000여 건 이상 누적되던 Scheduled Task 메트릭이 지속적으로 20건 미만으로 유지되었습니다. K6 스트레스 테스트 환경에서 기존 스레드 병목으로 발생하던 대량의 타임아웃 오류를 1건 수준으로 제어하였고, 서버의 전체 SSE 패킷 전송 처리량(Throughput) 메트릭을 약 11.6배 향상시켰습니다.
    Trade-off: 단일 스레드가 컬렉션을 순회하며 일괄 처리하는 방식으로 스레드 동시성 병목은 방어했지만, 활성 클라이언트 수가 1개 스레드의 단일 틱(Tick) 처리 임계치를 극단적으로 넘어갈 경우 Heartbeat 발송 전체가 일시적으로 밀릴(Lag) 수 있는 구조적 한계점이 내포되었습니다.

근무 경력

메사쿠어 컴퍼니 (서울)

2024.02 – 2025.11
프리랜서 백엔드 개발 외주
Spring Boot Spring4 MyBatis JPA React C# WPF MQTT FCM

레거시 웹 어드민 리뉴얼부터 인증 서버 POC, 공통 라이브러리 개발, 윈도우 클라이언트 개발까지 다양한 외주 프로젝트를 수행하며 백엔드 설계와 운영 관점의 의사결정을 주도했습니다.

핵심 프로젝트

  • 레거시 프레임워크 어드민 리뉴얼Spring4, MyBatis, JSP 기반 기존 코드베이스와 도메인을 분석하고, Spring Boot, MyBatis, React 기반 풀스택 리뉴얼을 수행했습니다.
  • 얼굴 기반 OTP 인증 서버 POCPC 에이전트와 모바일 앱을 연동하는 Spring Boot, JPA 기반 서버를 개발하고, 임시 비밀번호 생성 로직과 인증 트랜잭션 관리 기능을 구현했습니다.
  • 윈도우 클라이언트 개발병의원 신원확인 시스템과 얼굴 보안 번들 소프트웨어를 C#, WPF로 개발하며 MQTT 실시간 이벤트 처리와 캡처 성능 최적화를 적용했습니다.

설계 및 라이브러리

  • 데이터 접근 구조 재설계객체 중심 테이블 설계가 아닌 환경에서는 JPA 전환이 오버헤드라고 판단해 MyBatis를 유지하고, DAO 앞에 Repository 레이어를 두어 객체 중심 접근 구조를 설계했습니다.
  • JWT 인증 라이브러리 개발반복적인 어드민 인증 요구를 줄이기 위해 Spring Boot Starter 기반 JWT 인증 라이브러리를 구현하고 사내 Maven Repository와 Maven Central에 배포했습니다.
  • 디바이스 인증 및 푸시 연동유저별 기기 인증 토큰 발급 체계와 발급 토큰 기반 FCM 메시지 전송 시스템을 구현해 다중 기기 인증 흐름을 구성했습니다.

공군 정보체계 관리단 (계룡)

2021.10 – 2023.10
자원관리 체계 개발팀 소프트웨어 개발병
Spring4 JSP Struts Java SSO Polling MD5

공군 소프트웨어 개발병으로 복무하며 레거시 체계 유지보수와 신규 업무 시스템 개발을 함께 수행했고, 실제 운영 환경에서 필요한 자료구조, 검증 로직, 팀 공용 라이브러리까지 직접 구현했습니다.

운영 및 유지보수

  • 레거시 시스템 유지보수Spring4, JSP, Struts 기반 시스템 코드를 분석하고 병사 사적 해외여행, 간부 시간외 근무, 자격검정 체계 유지보수를 담당했습니다.
  • 수사단 업무체계 신규 개발SSO 토큰의 기능별 접근 제어 정책에 Strategy 패턴을 적용해 보안 기능을 강화하고 역할별 인증 흐름을 확장 가능하게 설계했습니다.
  • 실시간 알림 및 업로드 고도화이미지 Magic Code Byte 기반 파일 검증, MD5 기반 중복 업로드 방지, Last-Received-Time 기반 Polling 최적화를 구현했습니다.

신규 설계 및 공통화

  • 병사 홈페이지 설계 및 개발자율위원회 포털을 설계하고 개발했으며, Java 내부 정렬 우선순위를 제어하기 위한 SortedGroup 자료구조를 직접 구현했습니다.
  • 자동 차출 시스템 구현Pipeline 아키텍처와 SortedGroup 자료구조를 결합해 기수, 카운트 횟수 등 커스텀 우선순위에 따라 자동 차출되는 프로세스를 구현했습니다.
  • 팀 공용 라이브러리 개발Spring Boot 파일 업로드 API 라이브러리 Uploadable과 Entity-DTO 필드 자동 매핑 라이브러리 ObjectMapper를 구현해 팀 생산성을 높였습니다.

학력 및 수상

명지대학교 (용인)

2020.03 – 2026.02

컴퓨터 공학 학사 — 학점: 4.19 / 4.5

교내 캡스톤 디자인 경진대회 금상

2025.11

명지대학교 — 프로젝트 메모리아 시스템 기획 및 백엔드 안정화 역량을 크게 인정받아 교내 최고상(금상) 수상