배경 및 목표
시트가 유지보수 시 평균 2~3일이 소요되었고, 엑셀 다운로드 로직이 Node 서버에 별도로 존재하여 도메인 로직이 이중으로 관리되고 있었습니다. Node 유지보수가 가능한 인원이 소수였고, 앞으로의 요구 사항과 유지 보수를 위해선 기술 스택 통합이 시급했습니다.
- Node에 엔티티와 도메인 로직을 복제해서 관리 → 변경 시 양쪽 수정 필요
- 시트 추가 시 공통 로직을 매번 복사 → 확장성 없음
- 수만 건 데이터를 메모리에 전부 로드 → OOM 위험
목표
- 엑셀·도메인 로직 이중 관리를 없애고 Spring 단일 스택으로 통합한다.
- 수만 건 다운로드에도 메모리가 일정하게 유지되는 안정적 처리를 확보한다.
해결 방법과 해결 후보군
1. 템플릿 메서드 패턴으로 확장성 확보
단순 포팅이 아닌 구조를 재설계했습니다. 모든 시트는 makeSheet → makeHeader → fillData 공통 흐름을 따르고, 새 시트는 AbstractSheet를 상속해서 2개 메서드만 구현하면 됩니다.
2. 멀티 모듈 형태로 기존 도메인 로직 재사용
멀티 모듈을 이용하여 사용중인 도메인 모듈을 재사용하였습니다. 한 곳에서 비즈니스 로직을 관리할 수 있게 되었고, 예상보다 약 4md 정도 빠르게 엑셀 시스템을 이관할 수 있었습니다.
3. SXSSFWorkbook 스트리밍으로 OOM 방지
XSSFWorkbook(전체 메모리 로드) 대신 SXSSFWorkbook(윈도우 방식)을 적용하여, 일정 행만 메모리에 유지하고 나머지는 디스크로 내려서 메모리 사용량을 일정하게 유지했습니다.
sequenceDiagram participant E as ExcelDownloader participant F as DataFetcher participant S as Sheet 구현체 participant D as Disk E->>E: SXSSFWorkbook 생성 (윈도우: N행) loop 청크 단위 E->>F: Slice 쿼리로 N개 조회 F-->>E: 데이터 청크 E->>S: 시트에 데이터 전달 S->>D: 임시 파일 생성 end E->>E: Streaming 응답
결과
| 지표 | 기존 (Node) | 개선 (Spring) |
|---|---|---|
| 도메인 관리 | 이중 관리 | 단일 관리 |
| 엑셀 유지보수 | 2~3일 | 0.5일 |
| 동시 처리 | 순차 (단일 스레드) | 병렬 (멀티 스레드) |
| 메모리 안정성 | OOM 위험 | 스트리밍 처리 |
모니터링
- 엑셀 다운로드 시 힙 메모리 사용량(스트리밍으로 일정 유지 여부)을 관측한다.
- 시트별 생성 시간·실패율을 관측한다.