Post

이력서 기반의 면접 예상질문 자문자답

이력서 기반 면접 예상 질문/답변

이력서 내용 중 일부

📜 주요 프로젝트 경험

콘텐츠 플랫폼 전면 개편 및 운영 효율화

  • 대규모 레거시 시스템의 API 구조를 DTO 중심 정적 타입 기반으로 재설계하고, 유효성 검증 계층을 도입하여 시스템 안정성과 감사 추적 가능성을 확보함.
  • 시퀀스 기반 키 생성 병목 문제를 해결하기 위해 낙관적 락 기반의 캐시 선점 구조 설계 → 트랜잭션 처리 속도 5배 향상 (1m 30s → 500ms)
  • 도메인 중심 API 통합 및 불필요한 호출 제거 → 초기 로딩 시간 56% 개선 (5.2s → 2.3s)
  • 과도한 트랙 데이터 조회 문제를 쿼리 범위 제한 및 필드 필터링으로 최적화 → 운영 리소스 1.5MM 절감

글로벌 콘텐츠 유통 시스템 구축

  • RBAC 기반 접근 제어와 이벤트 기반 전송 기능을 포함한 유통 플랫폼 백엔드 개발
  • DTO 매핑 및 아키텍처 검증 도구 도입으로 코드 일관성과 품질 향상
    SonarCloud 위반 건수 480건 → 75건 (약 84% 감소)
  • 전체 다운로드 요청의 성능 병목을 해결하기 위해 조건 기반 예측 모델 및 캐시 분기처리 적용
    API 서버 CPU 사용률 peak 85% → 40% 감소

대용량 Excel 배치 성능 최적화

  • 대규모 엑셀 다운로드/업로드 시 발생하는 OOM과 GC 병목을 해결
  • POI Streaming 도입 및 청크 조회 기반 쿼리 최적화 적용
    메모리 사용량 85% 절감 (1.2GB → 180MB)
  • Flush & Clear 주기 조정 및 GC 튜닝으로 JVM 안정화
    힙 메모리 peak 3.8GB → 1.6GB (약 58% 절감), OOM 발생 0건

대량 데이터 등록 병렬 처리 및 락 경쟁 해소

  • 80만 건 이상의 데이터를 월 단위로 일괄 등록하는 배치 성능 개선
  • 분산 락과 병렬 처리 도입으로 정합성 보장 및 처리 시간 단축
    삭제 성능 24배 개선 (2시간 → 5분), 등록 시간 70% 단축 (40분 → 12분)

오디오 콘텐츠 제작 플랫폼 구축 및 인증 인프라 개선

  • 트랜잭션 커밋 이후 외부 API 호출을 보장하는 이벤트 기반 구조 설계 (@TransactionalEventListener)
  • Redis 기반 인증 세션 관리 및 TTL 설정으로 분산 환경에서 인증 안정성 확보
  • ISMS 대응을 위한 JSON 기반 로그 포맷 정비 및 Kibana 대시보드 구축
    ISMS 인증 3회 연속 심사 통과

예상 질문

공통 질문 (전체 프로젝트 기반)

  1. 사용했던 Java 버전 중 Java 21의 주요 기능은 무엇이며, 어떻게 활용하셨나요?
  2. Spring Boot 3.2.2로 전환하면서 겪은 주요 이슈나 마이그레이션 포인트는 무엇이었나요?
  3. Package by Component 구조의 장점은 무엇이고, 어떤 방식으로 적용하셨나요?
  4. @TransactionalEventListener를 도입하신 이유는 무엇이며, 실제 어떤 문제를 해결했는지 설명해주세요.
  5. ArchUnit, SonarCloud를 사용한 코드 품질 관리 방식은 구체적으로 어떻게 이루어졌나요?
  6. ZGCG1GC를 사용한 경험이 모두 있으신데, 각각의 GC를 선택한 이유와 성능 차이는 어땠나요?

콘텐츠 플랫폼 전면 개편 및 운영 효율화

  1. JSP 기반 레거시에서 어떤 문제들이 있었고, 그것을 어떤 구조로 개편했나요?
  2. DTO 중심의 정적 타입 구조로의 전환 시 유효성 검증 체계를 어떻게 구성했는지 설명해주세요.
  3. 계약 코드 생성 시 병목과 락 경합 문제를 어떻게 해결했는지 기술적으로 상세히 설명해주세요.
  4. 낙관적 락 적용과 메모리 캐싱 방식 도입 후의 성능 개선 수치는 어떻게 측정했나요?

글로벌 콘텐츠 유통 시스템 구축

  1. DDEX 기반 음원 전송 시스템은 어떤 방식으로 구현되었나요?
  2. RBAC 기반 접근 제어를 어떻게 설계하고 구현하셨나요?
  3. 메시지 큐(SQS)를 활용한 비동기 엑셀 다운로드 처리를 어떻게 구성했는지 설명해주세요.
  4. 전체 다운로드 요청을 예측 기반으로 처리하신 방식의 핵심 로직은 어떤 기준으로 설계되었나요?

대용량 배치 및 엑셀 처리 최적화

  1. Apache POI Streaming API를 선택한 이유는 무엇인가요?
  2. EntityManager.flush()/clear() 호출 주기 조절을 통해 얻은 효과는 무엇이었나요?
  3. Full GC 문제를 Thread Dump, Heap Dump 분석을 통해 어떻게 파악하고 개선하셨나요?
  4. FastExcel 대신 Apache POI를 사용하신 이유가 있나요?

대량 데이터 등록 병렬 처리 및 락 경쟁 해소

  1. Redis 기반 분산 락을 어떻게 구현했으며, 어떤 동시성 이슈를 방지했나요?
  2. 협회 지분율 데이터의 특성과 분기 처리 전략을 구체적으로 설명해주세요.
  3. 병렬 처리 시 작업 단위는 어떻게 설정했으며, 병렬성이 성능에 미친 영향을 수치로 설명해주세요.

오디오 콘텐츠 제작 플랫폼 구축 및 인증 인프라 개선

  1. @TransactionalEventListener를 활용한 외부 API 호출 처리 흐름을 설명해주세요.
  2. Redis를 통한 인증 토큰 저장 전략의 TTL 관리 방식은 어떤 기준으로 설계했나요?
  3. ISMS 대응을 위한 로그 수집 체계 개선 과정에서 가장 어려웠던 부분은 무엇이었나요?
  4. Filebeat, ELK 스택 기반 로그 분석 구조를 어떤 순서로 구축하셨는지 설명해주세요.

확장형 응용 질문

  1. 메시지 큐, 배치, 캐싱, 이벤트리스너를 적절히 조합하여 “대용량 데이터에 대해 정합성을 유지하며 빠르게 처리하는 시스템”을 설계하라고 하면 어떤 아키텍처를 제안하시겠습니까?
  2. Package by Component 구조 하에서 팀 협업 시 발생할 수 있는 문제점과 해결 전략은 어떤 것이 있을까요?
  3. 만약 MDS 시스템에 실시간 정산 기능을 도입한다고 하면 어떤 기술과 구조를 제안하실 수 있나요?

답변 정리

공통 질문 (전체 프로젝트 기반)

  1. Java 21의 주요 기능은 무엇이며, 어떻게 활용하셨나요? Java 21에서는 Record Patterns, Virtual Threads, Sequenced Collections 등의 기능이 도입되었습니다. 이 중 Virtual Thread는 Blocking I/O 처리 성능을 개선할 수 있어 대규모 비동기 작업의 부하 분산에 유용하며, 테스트 환경 및 비동기 이벤트 리스너 구현에서 적용을 검토했습니다. Java 21 Features
  2. Spring Boot 3.2.2 전환에서의 주요 이슈는? Jakarta EE 10으로 전환되며 javax.*jakarta.* 네임스페이스 변경이 있었고, 서드파티 라이브러리 호환성 이슈가 발생했습니다. 또한 Spring Security 구조 변경으로 인해 기존의 WebSecurityConfigurerAdapter 폐지 대응이 필요했습니다.
  3. Package by Component 구조의 장점과 적용 방식은? 기능 중심으로 패키지를 구성하여 관련 로직(Controller, Service, Repository, DTO 등)을 하나의 컴포넌트 단위로 관리합니다. 이를 통해 코드 응집도는 높이고 변경 영향 범위는 줄이며, 신규 기능 추가 시 전체 구조에 미치는 영향을 최소화했습니다.
  4. @TransactionalEventListener 도입 이유 및 해결한 문제는? 트랜잭션 커밋 이후 외부 API 호출이 필요했던 경우, 이벤트를 트리거로 비동기 처리를 함으로써 롤백 시 부정합을 방지했습니다. 트랜잭션이 완료되기 전에 메시지 큐를 전송하거나 외부 API를 호출하는 문제를 사전에 방지하기 위한 목적이었고, 이를 통해 API 호출의 시점 제어와 트랜잭션 일관성 유지가 가능했습니다.
  5. ArchUnit, SonarCloud를 활용한 코드 품질 관리 방식은? ArchUnit으로 패키지 간 의존성 및 계층 구조 규칙을 정하고 테스트에 반영했으며, SonarCloud는 정적 분석을 통해 코드 스멜, 보안 이슈, 중복을 점검하고 PR 리뷰에 반영해 지속적으로 품질을 개선했습니다.
  6. ZGC와 G1GC 사용 경험 비교 G1GC는 예측 가능한 GC 시간을 제공하지만 힙 사이즈 증가에 따라 Stop-The-World 시간이 늘어났습니다. ZGC는 낮은 지연 시간과 STW 최소화를 통해 대용량 배치와 실시간 작업에서 더 안정적인 성능을 보였습니다. 단, 메모리 소비량은 ZGC가 더 높았습니다.

콘텐츠 플랫폼 전면 개편

  1. JSP 기반 레거시 문제점 및 개편 구조 프론트에 집중된 비즈니스 로직, 비정형 Map 기반 DTO 사용, 검증 부재 등으로 유지보수와 타입 안정성이 저하됐습니다. 이를 API 명세 기반의 DTO 구조, 서비스 계층 도입, 유효성 검증 계층 구성으로 개편했습니다.
  2. DTO 중심 유효성 검증 체계 구성 JSR-380 기반 Bean Validation을 활용하고, 커스텀 애노테이션을 통해 도메인 규칙 검증을 수행했습니다. Controller, DTO, Service 계층 각각에서 역할에 맞게 검증을 분리하여 책임을 명확히 했습니다.
  3. 계약 코드 생성 병목 및 락 경합 해결 기존 시퀀스 테이블 기반 ID 생성 구조를 유지하되, 애플리케이션 레벨에서 사전 확보(Pre-Fetch)된 ID 캐시를 메모리에 저장하고 소비하는 구조로 변경했습니다. 충돌 방지를 위해 낙관적 락을 적용했습니다.
  4. 성능 개선 수치 측정 방식 배포 전후 트랜잭션 처리 시간, 응답 속도, 동시 요청 처리량을 기준으로 Datadog APM과 로그 기반 지표를 수집해 개선 수치를 측정했습니다.

글로벌 콘텐츠 유통 시스템 구축

  1. DDEX 기반 전송 시스템 구성 방식 앨범/곡 메타데이터를 DDEX XML로 변환한 후 FTP/SFTP 또는 API를 통해 각 플랫폼으로 자동 전송하며, 전송 성공 여부를 비동기로 수신받는 구조입니다.
  2. RBAC 기반 접근 제어 설계 도메인 기반 Role-Policy 매핑 테이블을 구성하고, 권한 검증 인터셉터를 적용해 API 진입 전에 권한을 선제적으로 판단하는 구조를 설계했습니다.
  3. SQS 기반 엑셀 비동기 처리 엑셀 요청 시 조건을 메시지로 전송하여 별도의 워커 서버가 비동기 처리한 뒤, 결과를 S3에 업로드하고 사용자는 상태를 Polling하여 확인하도록 구성했습니다.
  4. 예측 기반 처리 방식 설계 기준 전체 데이터를 요청할 가능성이 높은 조건 조합에 가중치를 부여하고, 처리 이력을 기반으로 예상 처리 시간 임계값 초과 시 캐시 저장 대상으로 분기하는 로직을 구성했습니다.

대용량 배치 및 엑셀 처리 최적화

  1. Apache POI Streaming 선택 이유 FastExcel 대비 기능은 제한되지만, 메모리 사용량이 낮고 매우 큰 XLSX 파일 처리에 안정적이기 때문에 선택했습니다.
  2. flush()/clear() 호출 주기 효과 JPA의 영속성 컨텍스트에 쌓이는 객체 수를 주기적으로 비워 메모리 누수를 방지하고 Full GC 빈도를 줄였습니다.
  3. Full GC 원인 분석 및 개선 방식 Heap Dump, GC 로그를 분석하여 특정 시점에 객체 수가 급증하는 것을 확인했고, 해당 배치에서 Flush 지연이 원인임을 파악하여 Chunk 크기 조정 및 반복 Clear를 적용했습니다.
  4. Apache POI를 선택한 이유 FastExcel은 처리 속도는 빠르지만 대용량 처리 시 메모리 사용량이 증가하는 문제가 있어, 안정성과 범용성이 더 높은 POI를 선택했습니다.

대량 데이터 병렬 처리 및 락 경쟁 해소

  1. Redis 기반 분산 락 구현 방식 Redisson의 RLock을 활용하여 배치 작업 시작 시 키 락을 선점하고, 작업 완료 후 해제하는 구조로 설계했습니다. TTL 설정으로 락 유실도 방지했습니다.
  2. 협회 지분율 데이터 특성 및 처리 전략 월 단위, 대량 일괄 등록이라는 특성상 배치 트리거 빈도가 낮아 분기 처리 전략이 유효했고, 트랜잭션 단위로 5만 건씩 나누어 순차 혹은 병렬 처리하도록 구성했습니다.
  3. 병렬 처리 단위 및 성능 수치 8개 워커 스레드 기반으로 최대 10만 건까지 병렬 처리하였고, 기존 40분 소요 작업을 약 12분 내외로 단축했습니다 (약 70% 개선).

오디오 콘텐츠 제작 플랫폼 구축 및 인증 인프라 개선

  1. @TransactionalEventListener 외부 API 호출 흐름 Entity 저장 후 발행되는 이벤트 리스너에서 외부 API 호출 로직을 수행하도록 구성함으로써, 커밋 이후에만 호출되도록 보장했습니다.
  2. Redis 기반 토큰 저장 TTL 관리 기준 액세스 토큰의 exp 필드를 기준으로 TTL을 설정하되, 서버 간 시간 차이를 고려해 버퍼를 추가 적용했습니다.
  3. ISMS 로그 체계 개선 중 가장 어려웠던 부분 각 기능에 대한 로깅 범위 정의와 실시간 로그 필터링 기준 설정이 가장 어려웠습니다. 개발자마다 로깅 기준이 달라 이를 통합하는 작업에 시간이 소요됐습니다.
  4. Filebeat 및 ELK 로그 분석 구축 순서 JSON 포맷 로그 정의 → Logback MDC 설정 → Filebeat 수집기 설정 → Elasticsearch 저장 → Kibana 대시보드 구성

확장형 응용 질문

  1. 대용량 데이터 처리 아키텍처 설계 제안 Kafka 또는 SQS 기반 메시징으로 요청을 분산하고, Spring Batch 혹은 비동기 Worker로 처리 후, 처리 결과를 Redis/S3에 캐싱하여 API 레이어는 빠른 응답 제공. 트랜잭션 정합성은 DB 락 또는 분산 트랜잭션(Eventual Consistency) 모델로 유지.
  2. Package by Component 구조 팀 협업 전략 명확한 디렉토리 기준과 각 컴포넌트별 책임 구분 문서를 작성하고, 공통 모듈의 의존성 분리 및 인터페이스 기반으로 팀 간 충돌 최소화.
  3. 실시간 정산 기능 설계 제안 CDC 기반 Kafka 스트리밍으로 거래 데이터 실시간 수집 → Flink/Spark로 처리 → Redis/Elastic 등에 실시간 누적 및 조회 제공. 정합성 보장을 위해 수신 로그 및 비즈니스 이벤트 저장소 구성.

추가 질문/답변

꼬리질문


API 구조 개편 및 정적 타입 전환 관련

  1. 기존 JSP 기반 시스템을 DTO 중심의 정적 타입 구조로 전환하셨다고 했는데, 어떤 문제가 해결되었고 어떤 방식으로 접근하셨나요? → 꼬리 질문:
    • 유효성 검증은 어떤 계층에서 어떻게 수행하셨나요?
    • Swagger 명세는 어떻게 관리하셨고, 실제 개발과 어떻게 연동하셨나요?
  2. JSR-380 및 커스텀 유효성 검증을 도입하셨다고 했는데, 커스텀 검증이 필요한 사례와 구현 방법을 설명해주실 수 있나요? → 꼬리 질문:
    • 복합 조건 (예: 날짜 유효성, 복수 필드 간 제약 등) 검증은 어떻게 구현하셨나요?

시퀀스 테이블 병목 및 키 생성 전략

  1. 시퀀스 테이블 병목 현상을 어떻게 진단하셨고, 해결을 위해 어떤 방식을 적용하셨나요? → 꼬리 질문:
    • 낙관적 락 방식 적용 시, 충돌이 발생하면 어떻게 처리되나요?
    • Redis 기반 키 생성은 어떤 이유로 도입되지 않았나요?

레거시 API 통합 및 응답 최적화

  1. 단편적인 API 호출을 도메인 기반 API로 통합하셨다고 했는데, 구조 재설계 과정에서 어떤 기준으로 API를 분리·통합하셨나요? → 꼬리 질문:
    • 통합 API에서 발생하는 데이터 응답량 증가 문제는 어떻게 해결하셨나요?

엑셀 대용량 처리 및 배치 최적화

  1. POI Streaming을 적용하셨다고 했는데, 기존 방식 대비 어떤 점이 개선되었고 어떤 제한사항이 있었나요? → 꼬리 질문:
    • 청크 기반 조회 시 배치 Job 구성은 어떻게 되어 있었나요?
    • 배치 Job 중 flush/clear 적용 기준은 어떻게 결정하셨나요?
  2. GC 로그를 기반으로 병목을 분석하셨다고 했는데, 어떤 도구를 활용하셨고 주요 인사이트는 무엇이었나요?

병렬 처리 및 분산 락 적용

  1. 대량 지분율 등록 작업에서 병렬 처리와 락을 결합하셨다고 했는데, 어떤 방식으로 트랜잭션 충돌을 방지하셨나요? → 꼬리 질문:
    • Redis 락의 만료시간 설정은 어떻게 하셨나요?
    • 동시에 여러 요청이 들어왔을 때 병렬성이 보장되도록 설계한 방식은?

이벤트 기반 외부 API 호출 설계

  1. @TransactionalEventListener를 사용해 외부 API 호출을 처리하셨다고 했는데, 이 방식의 장점과 트랜잭션과의 관계를 설명해주세요. → 꼬리 질문:
    • 비동기 호출로 인한 예외 상황은 어떻게 모니터링하거나 복구하셨나요?

ISMS 대응을 위한 로그 시스템 개선

  1. 감사 로그 설계를 하셨다고 했는데, 어떤 로그 항목과 포맷을 정의하셨고, 이를 어떻게 Kibana에서 조회 가능하도록 구성하셨나요? → 꼬리 질문:
    • 로그 수집 및 전송에서 Filebeat 외 대안은 고려하셨나요?
    • MDC를 통해 사용자 식별을 구성한 방식은?

기술 스택 및 의사결정 관련

  1. Package by Component 구조를 채택하셨다고 했는데, 기존 구조와 비교했을 때 어떤 장단점이 있었나요? → 꼬리 질문:
    • 각 도메인 간 의존성 문제는 어떻게 관리하셨나요?
  2. MapStruct, ArchUnit, SonarCloud를 함께 사용하면서 얻은 시너지는 어떤 부분이었나요?

꼬리질문 답변

좋아요! 아래는 사용자가 올린 “꼬리 질문 포함 기술면접 예상 질문”에 대한 질문 + 답변 정리입니다. 각 항목은 명확하고 실전 면접용으로 활용 가능한 형태로 구성되어 있습니다.


API 구조 개편 및 정적 타입 전환 관련

  1. 기존 JSP 기반 시스템을 DTO 중심의 정적 타입 구조로 전환하셨다고 했는데, 어떤 문제가 해결되었고 어떤 방식으로 접근하셨나요? JSP 기반 시스템에서는 프론트에 비즈니스 로직이 과도하게 집중되어 있고, 서버에서는 Map<String, Object> 형태로 데이터를 처리해 타입 안정성이 떨어지며, 유효성 검증이나 감사 로그 수집도 어려웠습니다. DTO를 도입해 정적 타입 구조로 전환하고, Swagger 기반 명세로 API 계약을 명확히 정의했으며, 서비스 계층을 도입하여 책임을 분리했습니다.

    꼬리 질문:

    • 유효성 검증은 어떤 계층에서 어떻게 수행하셨나요? → DTO 계층에서는 JSR-380 기반 @Valid를 사용하고, 도메인 계층에서는 커스텀 Validator 클래스를 통해 복잡한 비즈니스 검증을 수행했습니다.
    • Swagger 명세는 어떻게 관리하셨고, 실제 개발과 어떻게 연동하셨나요? → SpringDoc(OpenAPI 3) 기반 자동 문서를 사용했고, Swagger UI는 QA 환경에 배포하여 기획/QA 팀과 계약 기반 테스트를 수행했습니다.
  2. JSR-380 및 커스텀 유효성 검증을 도입하셨다고 했는데, 커스텀 검증이 필요한 사례와 구현 방법을 설명해주실 수 있나요? 예: 날짜 범위 유효성, 시작일 < 종료일 조건, 조건부 필드 필수화 등은 표준 애노테이션으로 검증이 어렵습니다. @ValidPeriod와 같은 커스텀 애노테이션을 만들고, ConstraintValidator<A, T> 인터페이스를 구현하여 복합 로직을 처리했습니다.

    꼬리 질문:

    • 복합 조건 (예: 날짜 유효성, 복수 필드 간 제약 등) 검증은 어떻게 구현하셨나요?Class-level constraint로 커스텀 애노테이션을 붙이고, 해당 Validator 내부에서 두 필드 값을 조합해 로직을 수행했습니다.

시퀀스 테이블 병목 및 키 생성 전략

  1. 시퀀스 테이블 병목 현상을 어떻게 진단하셨고, 해결을 위해 어떤 방식을 적용하셨나요? DB CPU 사용률이 높은 트랜잭션을 추적한 결과, 시퀀스 테이블의 for update 쿼리가 병목이었고, 락 경합이 다수 발생하고 있었습니다. 해결책으로는 미리 ID를 다량 확보한 후 메모리 캐시에 저장해두고, 실시간 사용 시 메모리에서 가져오는 구조로 변경했습니다. 갱신은 최소 트랜잭션 단위로 처리했습니다.

    꼬리 질문:

    • 낙관적 락 방식 적용 시, 충돌이 발생하면 어떻게 처리되나요?where current_value = expected_value 조건 실패 시 예외를 발생시키고, 재시도 로직을 통해 처리하도록 했습니다.
    • Redis 기반 키 생성은 어떤 이유로 도입되지 않았나요? → Redis incr도 고려했으나, DB 시퀀스와 일관된 값이 보장되어야 하는 정책이 있어 Redis 방식은 제외했습니다.

레거시 API 통합 및 응답 최적화

  1. 단편적인 API 호출을 도메인 기반 API로 통합하셨다고 했는데, 구조 재설계 과정에서 어떤 기준으로 API를 분리·통합하셨나요? 하나의 페이지에서 여러 API를 호출하던 구조를, 페이지 단위 또는 도메인 단위로 API를 통합했습니다. 예를 들어, 앨범 상세 페이지에서는 앨범 정보 + 트랙 리스트 + 권한 정보를 하나의 API로 응답하게 했습니다.

    꼬리 질문:

    • 통합 API에서 발생하는 데이터 응답량 증가 문제는 어떻게 해결하셨나요? → 클라이언트에서 실제 필요한 데이터만 선택할 수 있도록 필드 단위 DTO 구성과 projection 사용을 병행했고, 쿼리 범위를 ID 기준으로 제한하여 I/O 부하를 줄였습니다.

엑셀 대용량 처리 및 배치 최적화

  1. POI Streaming을 적용하셨다고 했는데, 기존 방식 대비 어떤 점이 개선되었고 어떤 제한사항이 있었나요? 기존에는 전체 데이터를 메모리에 올리는 방식이라 OOM이 자주 발생했습니다. POI Streaming은 한 행씩 디스크로 flush하면서 처리하므로 메모리 사용량이 획기적으로 줄었고, 처리 안정성이 높아졌습니다. 다만 스타일링이나 셀 병합 기능은 제한적이었습니다.

    꼬리 질문:

    • 청크 기반 조회 시 배치 Job 구성은 어떻게 되어 있었나요? → Spring Batch의 Step 구성에서 1000건 단위로 DB 조회 → DTO 변환 → POI Writer로 출력하는 구조였습니다.
    • flush/clear 적용 기준은 어떻게 결정하셨나요? → GC 로그 분석 결과 기준으로, 약 1000건마다 EntityManager.flush()/clear()를 적용하여 메모리 누수를 방지했습니다.
  2. GC 로그를 기반으로 병목을 분석하셨다고 했는데, 어떤 도구를 활용하셨고 주요 인사이트는 무엇이었나요? Eclipse MAT, VisualVM, GCViewer를 사용했습니다. Heap Dump를 통해 배치 Job 내 특정 엔티티의 과도한 유지 시간과 객체 수를 확인했고, Full GC 발생 주기가 flush 시점과 밀접하다는 점을 발견하여 조정했습니다.


병렬 처리 및 분산 락 적용

  1. 대량 지분율 등록 작업에서 병렬 처리와 락을 결합하셨다고 했는데, 어떤 방식으로 트랜잭션 충돌을 방지하셨나요? 배치 작업을 시작하기 전 Redis 분산 락을 선점하여 중복 실행을 방지했고, 데이터 단위를 나눠 병렬 실행하는 경우에도 상호 간섭이 없는 영역으로 분리해 충돌을 방지했습니다.

    꼬리 질문:

    • Redis 락의 만료시간 설정은 어떻게 하셨나요? → 10분 TTL을 설정하고 Redisson의 watchdog 기능으로 연장되도록 구성했습니다.
    • 동시에 여러 요청이 들어왔을 때 병렬성이 보장되도록 설계한 방식은? → 데이터 ID 범위를 기준으로 분할하고, 각 범위를 병렬 워커가 담당하도록 분배하여 락 간섭 없이 병렬 처리했습니다.

이벤트 기반 외부 API 호출 설계

  1. @TransactionalEventListener를 사용해 외부 API 호출을 처리하셨다고 했는데, 이 방식의 장점과 트랜잭션과의 관계를 설명해주세요. DB 트랜잭션이 커밋된 이후에만 외부 API가 호출되므로, 롤백 시에도 부정합이 발생하지 않습니다. 이벤트를 발행하고, 커밋 이후 이벤트 리스너가 동작하도록 @TransactionalEventListener(phase = AFTER_COMMIT)을 설정했습니다.

    꼬리 질문:

    • 비동기 호출로 인한 예외 상황은 어떻게 모니터링하거나 복구하셨나요? → 실패한 요청은 Dead Letter Queue 또는 재시도 큐에 넣고, Slack 알림과 Datadog Custom Event로 추적 가능하도록 구성했습니다.

ISMS 대응을 위한 로그 시스템 개선

  1. 감사 로그 설계를 하셨다고 했는데, 어떤 로그 항목과 포맷을 정의하셨고, 이를 어떻게 Kibana에서 조회 가능하도록 구성하셨나요? 로그 항목은 메뉴 ID, 사용자 ID, 요청 URI, HTTP 상태, 트랜잭션 ID, 수행 시간 등이며, JSON 포맷으로 표준화했습니다. 로그는 Filebeat로 수집하고 Elasticsearch에 저장한 후 Kibana에서 필터링과 시각화를 통해 감사 이력 확인이 가능하게 했습니다.

    꼬리 질문:

    • 로그 수집 및 전송에서 Filebeat 외 대안은 고려하셨나요? → Fluent Bit도 고려했지만, Elastic Stack과의 연동 편의성으로 Filebeat를 선택했습니다.
    • MDC를 통해 사용자 식별을 구성한 방식은? → 로그인 시점에 사용자 ID와 트랜잭션 ID를 MDC에 저장하고, Logback 패턴에서 이를 추출해 JSON 필드에 포함시켰습니다.

지인의 피드백

아래는 사용자가 작성하신 각 기술 면접 질문에 대한 답변입니다. 실무 맥락과 JVM/Spring 동작 원리를 바탕으로 구체적으로 정리했습니다.


ThreadDump, HeapDump 하실 때 사용하신 툴은 어떤 건가요?

ThreadDump:

  • VisualVM, JDK Mission Control, 또는 jstack 명령어를 사용했습니다.
  • 운영 중인 서버에서는 jstack -l <pid> 명령어로 추출하고, VisualVM에서 시각적으로 분석했습니다.

HeapDump:

  • jmap -dump:format=b,file=heap.hprof <pid> 명령어를 사용하거나,
  • -XX:+HeapDumpOnOutOfMemoryError 옵션으로 OOM 발생 시 자동 추출되도록 설정했습니다.
  • 분석 도구는 Eclipse MAT, VisualVM, 또는 JDK Flight Recorder를 사용했습니다.

OOM이 발생할 때 HeapDump 하도록 하는 JVM 옵션을 주셨나요?

네, 다음과 같은 JVM 옵션을 설정했습니다:

1
2
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/var/log/heap.hprof

이 옵션을 설정하면 OOM 발생 시 자동으로 heap dump가 지정된 경로에 생성되어 추후 분석에 사용됩니다.


JPA 대신 JPQL이나 nativeQuery를 사용하면 1차 캐시를 쓰지 않기 때문에 flush/clear 없이도 성능이 낫지 않을까요?

맞습니다. JPQL 또는 native query를 사용하는 경우 EntityManager의 1차 캐시를 거치지 않으므로,

  • 영속성 컨텍스트에 엔티티가 누적되지 않아 flush/clear가 필요 없는 경우가 많습니다.
  • 특히 읽기 전용 대용량 조회(batch) 의 경우 native query나 @Query(nativeQuery = true)로 수행하는 것이 훨씬 효율적입니다.

다만, 아래와 같은 조건에서는 여전히 JPA flush/clear 전략이 필요합니다:

  • 엔티티를 수정하거나 저장(persist)하는 경우
  • 트랜잭션 내에 수천 건 이상 처리하는 경우 (쓰기 작업 포함)

즉, 단순 조회라면 JPQL/nativeQuery를 사용하고 flush/clear 생략이 합리적입니다.


다른 세션에서 같은 row에 변경을 일으키면 Deadlock이 발생했을 것 같은데, service DB와 batch DB를 함께 쓴 상황인가요?

네, 맞습니다. 동일한 테이블을 서비스와 배치가 동시에 갱신하는 상황에서 다음 조건이 충족되면 Deadlock이 발생할 수 있습니다:

  • 서로 다른 트랜잭션에서 동일 row에 update/lock을 시도
  • InnoDB의 row-level locking 구조에 따라 lock 순서가 꼬일 경우

특히 다음 상황이 위험합니다:

  • 배치에서 다량의 데이터를 DELETE → INSERT 패턴으로 갱신
  • 서비스에서는 동일 row를 UPDATE 하거나 조회 시 FOR UPDATE를 수행

해결을 위해 다음을 적용했습니다:

  • 배치 실행 시 Redis 락을 통한 선점 처리
  • DB 레벨에서 분할 처리하거나 작업 시간대 조정
  • SELECT ... FOR UPDATE SKIP LOCKED 전략 고려

TransactionalEventListener는 활성화된 트랜잭션이 없으면 작동하지 않는데, 이런 케이스는 고려하셨나요?

네, @TransactionalEventListenerAFTER_COMMIT 시점의 트랜잭션 후크를 활용하므로, 트랜잭션이 없는 경우 이벤트가 동작하지 않습니다.

이를 고려해 아래와 같은 전략을 적용했습니다:

  • 트랜잭션이 존재하지 않을 수 있는 이벤트는 ApplicationEventPublisher 대신 별도의 서비스에서 직접 처리하거나 @EventListener로 fallback 처리
  • 이벤트 발행 전 TransactionSynchronizationManager.isActualTransactionActive()를 검사하여 트랜잭션 유무를 판단
  • 테스트 환경에서는 @Transactional(propagation = REQUIRES_NEW)를 강제로 부여하여 이벤트 리스너 활성화 여부를 검증

즉, “트랜잭션이 없을 경우 이벤트가 동작하지 않는다”는 특성을 정확히 인지하고, 설계 시 필터링 로직 또는 대체 전략을 마련했습니다. @TransactionalEventListener : 트랜잭션 유무에 따른 동작 원리와 실전 대응 전략


필요하시다면 각 답변을 이력서 기반 면접 대비용 정리 카드로 만들어드릴 수도 있어요. 더 다듬거나 확장하고 싶은 질문이 있으신가요?

This post is licensed under CC BY 4.0 by the author.