Node.js·NestJS 기반 백엔드 14년차입니다. 정산·결제·라이선스처럼 데이터의 정확성이 곧 서비스 신뢰와 직결되는 영역을 주로 다뤄왔습니다. 복잡한 비즈니스 요구사항을 데이터 모델과 시스템 구조로 풀어내고 운영 가능한 상태까지 책임지는 것을 일의 기준으로 삼습니다.
원 단위 정수 연산, 취소 후 재정산을 통한 불변성 유지, 감사 추적을 핵심 요구사항으로 두는 금융성 정산 시스템을 설계했습니다. 출판사·저자 다층 분배와 혼합결제 환불 역산 같은 복잡한 요구사항을 데이터 모델 차원에서 해결했습니다.
천만 건 규모의 정산 데이터를 조회 전용 Flat Table 기반의 CQRS 구조로 재설계하고 결제 임계경로에서 정산을 분리한 SQS 비동기 파이프라인을 구축했습니다. 읽기·쓰기 모델 분리와 멱등성 보장을 고려한 시스템 설계에 익숙합니다.
표면적인 현상보다 병목이 발생하는 레이어를 먼저 구분하고 데이터를 통해 원인을 좁혀가는 방식을 선호합니다. heap·external은 정상인데 RSS만 증가한 메모리 문제, 처리 속도는 정상인데 큐 대기 시간만 누적된 병목 현상이 그런 사례입니다.
오류를 체계적으로 분류하고 복구할 수 있도록 하는 자가복구 구조, 무중단 점진적 마이그레이션(Express → NestJS), 백오피스 공통화를 통해 반복적인 운영 비용을 줄여왔습니다. 한 시스템을 오래 책임지며 지속적으로 개선하는 일을 선호합니다.
교육 콘텐츠 마켓플레이스의 정산을 메인 백엔드(정산 producer·환불 오케스트레이션)와 정산 서버(정산 엔진·조회 최적화) 두 서비스로 나눠 맡았습니다. 결제(동기)와 정산(비동기)의 시간적 차이를 서비스 경계로 분리했고 정산 생성부터 조회 최적화까지 파이프라인 전반을 직접 설계하고 운영했습니다.
설계 배경과 의사결정은 정산 시스템 Deep Dive에 따로 정리했습니다.
사업이 성장하며 정산의 중요성이 커졌지만 당시 정산은 전용 시스템 없이 100% 수기 엑셀로 관리됐습니다. 출판사(원저작권)와 저자(2차 저작권) 권리가 동시에 얽혀 단일 수취인이 아닌 다중 분배가 필요했고 거래량이 늘수록 정합성 오류가 비례해 늘었습니다. 본질은 자동화 부족이 아니라 확장이 불가능한 구조였습니다.
정산 데이터 약 800만 건, 이용 로그 약 1,100만 건 규모에서 성수기 한 달의 무거운 정산 유형(약 166만 건) 조회가 약 19초까지 걸려, 엑셀 다운로드가 사실상 불가능했습니다.
분석 — 정공법을 차례로 시도하며 한계를 확인했습니다.
개별 작업은 1~5초면 끝나는데 사용자 대기 시간이 최대 31분까지 치솟았습니다.
concurrency 미설정(기본값 1)이었습니다. 인스턴스당 한 번에 한 건만 처리하는데 유입량이 처리 용량의 약 3.5배라 백로그가 쌓였습니다.해결 — 단순 동시성 증설로 끝내지 않았습니다.
lockDuration 우선순위 함정 제거onStalled 완료 확인)이미지 처리 워커의 RSS가 시간당 수백 MB씩 우상향하다 spawn ENOMEM으로 죽고, 컨테이너가 반복 재시작됐습니다.
디버깅 — 가설을 차례로 기각하며 좁혀갔습니다.
MALLOC_ARENA_MAX=2) → 상승 속도는 절반으로 줄었지만 방향은 그대로. 원인이 아니라 증상 완화임을 확인했습니다.--max-old-space-size를 올린 조치가 오히려 GC를 게으르게 만들어 RSS 누적을 가속하고 있었습니다. 인과가 거꾸로였음을 인식하고 limit을 낮춰 GC를 적극화했습니다.node-canvas를 @napi-rs/canvas(Rust/skia)로 교체한 뒤 누수 패턴이 사라짐을 확인했습니다.@napi-rs/canvas로 교체(API 호환·prebuilt). 메모리 사용률을 약 40%에서 7% 수준으로 낮추고 이후 수평을 유지했으며, 처리량이 늘어난 피크 구간에서도 누수 패턴이 사라졌습니다. 검증 기준은 배포 직후가 아니라 피크를 통과한 뒤로 잡았습니다.payout 레거시 진단, settlement_prep 2단계 파이프라인, Strategy/Template, CQRS, SQS FIFO 멱등성, advisory lock, 데이터 모델링까지 — 정산 도메인의 설계 배경과 의사결정을 깊이 있게 다룬 기술 심화 문서입니다. → 정산 시스템 Deep Dive 보기
리스트 페이지마다 반복되던 조회·필터·정렬·페이지네이션·엑셀 로직을 설정 객체 하나로 선언하는 재사용 빌더로 공통화했습니다. 로직(useListPage 훅)과 표현(렌더러) 분리, 슬롯·훅 단독 사용이라는 탈출구 설계, 모달 z-index 같은 디테일까지 — 10개 이상의 관리자 페이지가 채택한 백오피스 공통화 사례입니다. → ListBuilder Deep Dive 보기