CASE STUDY
한눈에 보는 변화
처음에는 적합한 Connection Pool을 고르는 문제로 봤습니다. Spring Boot·MyBatis Pool·직접 JDBC를 같은 조건에서 구현하고 구간별로 측정하자, 반응마다 JVM이 시작되고 Pool과 함께 종료되는 방식이 반복 비용을 만들고 있었습니다. JVM과 Pool을 계속 유지하는 REST API로 연계 방식을 바꿨습니다.
초기안은 분석 반응마다 Java 모듈을 새로 실행해 LIMS와 연계하는 방식이었습니다. 기존 분석시간에 JVM 기동과 DB 연결 비용이 반복해서 더해졌고, 프로세스가 종료될 때마다 Connection Pool도 함께 사라져 재사용할 수 없었습니다.
직접 담당한 범위
- 팀 프로젝트 내 기존 CES 분석·발송 프로세스와 데이터 처리 구조 분석
- 연계 방식별 성능 검증과 상시 기동 REST API 전환 제안
- LIMS API 설계·개발, 유럽법인 테스트 환경 설계·구성과 법인별 배포·테스트·운영 반영
| 구분 | 변경 전 | 변경 후 | 확인된 변화 |
|---|---|---|---|
| 실행 생명주기 | 분석 반응마다 Java 모듈을 실행하고 처리 후 JVM 종료 | LIMS 연계 애플리케이션을 상시 기동하고 REST 요청 반복 처리 | 요청마다 반복되던 초기화 제거 |
| Connection 재사용 | 반응 종료와 함께 Pool도 사라져 첫 Connection 생성 비용 반복 | JVM과 HikariCP를 유지해 후속 요청에서 Connection 재사용 | 후속 요청에서 Pool의 Connection 재사용 |
| 연계 방식 | 모듈 실행 인자와 종료 결과에 의존한 데이터 전달 | 샘플 조회·결과 저장·실패 저장을 3개 API로 분리 | 결과·오류·Comment 전달 방식 표준화 |
| 법인별 환경 | 본사·유럽·일본의 DBMS와 설정 차이가 호출 코드에 혼재 | 공통 요청·응답 형식을 유지하고 Profile과 Oracle·MariaDB Mapper 분리 | 3개 환경에 동일 애플리케이션 적용 |
| 업무 실패 응답 | Well 좌표 충돌 시 HTTP 200과 빈 응답으로 실패 원인 식별 곤란 | HTTP 500과 표준 errorCode·errorMessage 반환 | 호출 측에서 업무 실패를 명시적으로 판별 |
EVIDENCE CHAIN
문제를 좁힌 과정
- 01 · 초기안 분석
프로세스 시작부터 종료까지 한 건의 비용으로 측정했습니다
초기 연계안은 반응마다 Java 모듈을 실행해 설정 로드, DB 연결, 데이터 처리 후 종료하는 구조였습니다. 요청마다 반복되는 애플리케이션 초기화와 DB 연결 비용이 전체 처리량을 좌우할 수 있어 쿼리 외의 구간도 분석 대상으로 잡았습니다.
판단쿼리 실행시간만 비교하면 JVM 기동과 DB 연결이라는 반복 비용을 놓치므로 측정 범위를 프로세스 전체로 넓혀야 했습니다.
- 02 · 비교 구현
세 가지 DB 접근 방식을 같은 조건에서 직접 구현했습니다
Spring Boot·HikariCP, Non-Spring MyBatis Connection Pool, 직접 JDBC 방식을 구현하고 초기화·Connection·Query·Mapping 구간을 나누는 측정 코드를 구성했습니다. 반복 비용이 생기는 위치를 비교할 수 있도록 프레임워크 외의 조건은 맞췄습니다.
판단라이브러리를 고르기 전에 각 방식이 같은 실행 구조에서 어떤 비용을 반복하는지 비교할 수 있었습니다.
- 03 · 구간 분석
초기화·Connection·Query·Mapping을 분리해 병목의 위치를 확인했습니다
애플리케이션 초기화, Connection 획득, 쿼리 실행, Result Mapping을 따로 측정하도록 코드를 구성했습니다. 이 비교에서 반응이 끝날 때 JVM과 Pool도 함께 종료되는 구조를 확인했습니다.
판단Pool을 적용해도 재사용할 다음 요청이 없으므로 초기화 비용만 더하고 재사용 이점은 얻기 어려운 구조였습니다.
- 04 · 문제 재정의
Pool을 재사용할 수 있도록 프로세스 생명주기를 바꿨습니다
HikariCP·MyBatis Pool·직접 JDBC 사이의 차이를 줄이는 것으로는 반응마다 반복되는 상위 비용을 제거할 수 없었습니다. JVM과 Pool을 여러 요청 동안 유지하는 구조가 필요하다는 근거로 연계안 변경을 제안했습니다.
판단프로세스가 매번 종료되는 한 라이브러리를 최적화해도 반복 비용이 남으므로 실행 방식을 바꿔야 했습니다.
- 05 · 운영 보완
API 전환 뒤에는 요청 형식과 데이터 일관성을 별도로 안정화했습니다
3개 API를 본사·유럽·일본 환경에 적용한 뒤 파라미터 누락, Key 채번, Run 시간, 부분완료 주문 처리 조건을 점검하고 보완했습니다. 실행 방식의 성능과 업무 데이터 정합성을 별도 검증 항목으로 관리했습니다.
판단상시 기동으로 반복 비용을 줄인 뒤에도 요청값과 트랜잭션 처리는 운영 시나리오로 다시 검증해야 했습니다.
- 06 · 2026년 후속 안정화
빈 성공 응답으로 보이던 Well 좌표 충돌을 명시적인 오류 응답으로 바꿨습니다
Well 좌표 충돌 경로가 HTTP 200과 빈 응답을 반환해 호출 측에서 정상과 실패를 구분하기 어려웠습니다. Service·Mapper 호출을 추적한 뒤, 이 연계의 기존 오류 처리 규칙에 맞춰 HTTP 500과 표준 errorCode·errorMessage를 반환하도록 수정했습니다.
판단연계 API는 저장 성공과 업무 조건 불일치를 호출 측이 일관되게 판별할 수 있어야 했습니다.
DECISION LOG
검토한 대안과 선택 근거
반응별 Spring Boot·HikariCP 실행
프로세스 종료 시 Pool도 사라져 Connection 재사용 없이 초기화 비용이 매번 반복되기 때문입니다.
Non-Spring MyBatis Pool로 경량화
초기화 차이는 줄일 수 있어도 반응마다 Pool이 폐기되는 생명주기 문제는 그대로 남기 때문입니다.
직접 JDBC 호출 유지
비교 기준으로는 유효했지만 연결 생성과 프로세스 기동을 반응마다 반복하는 구조적 비용은 제거하지 못했습니다.
상시 기동 LIMS REST API
JVM과 Pool을 유지해 반복 비용을 제거하면서 분석 시스템과 LIMS 사이의 요청·응답 형식도 명시적으로 관리할 수 있었습니다.
IMPLEMENTATION
설계와 구현
API별 역할
- 분석 성공 결과와 관련 데이터를 저장하는 API
- 분석에 필요한 샘플 정보를 조회하는 API
- 실패 상태·원인·Comment를 전달하는 API
트랜잭션·데이터
- 결과·결과 파일·신호·반응 상태·주문 집계를 하나의 업무 처리로 구성
- Report와 변경 이력까지 같은 트랜잭션에서 반영
- 기존 데이터 유무에 따른 Insert·Update 분기를 API 내부에서 처리
공통 API 기반
- 토큰 인증과 요청값 검증 적용
- 표준 예외 응답과 요청·응답 이력 저장
- 호출 측이 성공·업무 실패·시스템 실패를 구분할 수 있는 응답 구성
다법인 실행 환경
- 본사·유럽·일본 Profile로 접속정보와 환경 설정 분리
- Oracle·MariaDB 차이는 MyBatis Mapper를 나눠 처리
- 같은 API 요청·응답 형식을 유지한 채 법인별 데이터 구조 차이 반영
VERIFICATION
테스트 매트릭스
| 검증 영역 | 검증 방법 | 완료 기준 |
|---|---|---|
| 실행 방식의 성능 | 세 구현의 초기화·Connection·Query·Mapping 구간별 비교 | 병목 구간과 프로세스 반복 비용을 분리해 전환 근거 확보 |
| API 입력·응답 | 샘플 조회·성공 결과·실패 결과의 정상·누락·잘못된 요청 실행 | 검증 규칙과 표준 성공·오류 응답 일관성 |
| 데이터 일관성 | 기존 데이터 유무별 Insert·Update와 트랜잭션 실패 재현 | 결과·상태·집계·Report·이력이 부분 반영되지 않음 |
| 다법인 환경 | 본사·유럽·일본 Profile과 Oracle·MariaDB Mapper별 실행 | 같은 API 형식으로 법인별 조회·저장 기능 정상 동작 |
| 운영 회귀 | 파라미터·Key·Run 시간·부분완료 주문 조건 재검증 | 후속 보완 조건을 포함한 분석·LIMS 상태 정합성 유지 |
| Well 좌표 충돌 | 사용자 검증 2개 고유 시나리오와 Service·Mapper 변경 경로 검증 | HTTP 500과 표준 errorCode·errorMessage로 실패 원인 전달 |
OPERATION
운영 반영과 후속 안정화
필수 파라미터 누락
- 분리한 원인
- 분석 시스템과 API 사이에서 필수 값이 전달되는 조건 확인
- 대응
- 검증 규칙과 전달 항목을 보완하고 요청·응답 이력으로 재확인
Key 채번·Run 시간 반영
- 분리한 원인
- 신규·기존 데이터 분기와 분석 실행 정보의 저장 시점 점검
- 대응
- Insert·Update 조건과 관련 데이터 반영 순서 보완
부분완료 주문 상태
- 분리한 원인
- 반응 단위 완료와 주문 집계 완료 조건을 구분
- 대응
- 부분완료 조건에서도 주문·반응 상태가 일관되도록 집계 로직 보완
Well 좌표 충돌의 빈 성공 응답
- 분리한 원인
- 업무 조건 불일치가 HTTP 200과 빈 응답으로 종료되는 경로 확인
- 대응
- 기존 연계 규칙에 맞는 HTTP 500과 표준 오류 코드·메시지로 응답 보완
- 측정 코드와 프로세스 생명주기 분석으로 반응별 모듈 기동 방식의 반복 비용을 식별해 도입 전 제거
- 분석 시스템과 LIMS 사이에 결과·오류·Comment를 전달하는 REST API 운영 반영
- 일본법인 CIWER 운영 반영을 2025.11.04 완료
- 유럽법인 CIWER를 운영 환경까지 반영
- Well 좌표 충돌을 HTTP 500·표준 오류 응답으로 전달하도록 2026.04~05 후속 안정화
TAKEAWAYS
이 사례에서 드러난 역량
- Connection Pool의 효과는 구현체보다 Pool을 재사용할 수 있는 프로세스 생명주기에 먼저 좌우됩니다.
- 성능은 쿼리 실행시간에 한정하지 않고 호출 한 건이 부담하는 초기화부터 결과 반환까지 측정해야 합니다.
- 실행 방식을 바꿀 때는 프레임워크 선호보다 비교 구현·측정 코드와 생명주기 분석이 설득력 있는 근거가 됩니다.
- 프로세스의 반복 비용과 API 입력·트랜잭션의 정합성은 서로 다른 검증 항목으로 관리해야 합니다.