✅ 트러블 슈팅
🔸 단계
- 문제 인지: 장애 발생, 로그 에러, 성능 저하 탐지
- 원인 분석: 로그, 모니터링 툴, 코드 분석
- 해결 시도: 코드 수정, 설정 변경, 서버 튜닝 등
- 재발 방지: 문서화, 자동화, 테스트 강화
🔸 장애 대응 프로세스
1. 장애 감지 | - APM 알람 (Whatap, Pinpoint) - 모니터링 대시보드 CPU, Memory, Response Time 이상치 감지 - 사용자의 장애 신고 (예: 화면 멈춤, 거래 오류) |
2. 즉시 조치 | - 서비스 재기동 (임시 복구) - 임시 서비스 우회 (장애 회피) - 배치 중지, 트래픽 차단 등 |
3. 로그 및 상태 확인 | - WAS 로그 - Thread Dump - GC 로그 - API 요청/응답 로그 - DB Slow Query 로그 |
4. 원인 분석 | - DB 병목인지, API 병목인지, Thread Lock인지 판단 - 자원 부족인지 코드 문제인지 구분 |
5. 튜닝 및 근본 원인 해결 | - Thread Pool, DB 커넥션 풀 튜닝 - 쿼리 최적화 - 코드 리팩토링 - 인프라 확장 - 재배포 및 패치 |
🔸 트러블 슈팅 예시
1. API 응답 속도 저하 → 원인: N+1 쿼리 문제
- 상황: 특정 API 호출 시 초기에 빠르다가 데이터가 쌓이면서 점점 느려짐 (평균 5초 이상)
- 원인:
- JPA Lazy Loading으로 연관된 엔티티를 호출할 때마다 추가 쿼리가 발생 → N+1 문제
- 조치:
- @EntityGraph 사용하거나
- JPQL에서 fetch join 적용
- 결과: 응답 시간 5초 → 0.3초로 감소
2. 메모리 누수 및 OutOfMemoryError
- 상황: 배치 프로그램 실행 도중 메모리 부족으로 프로세스 다운
- 원인:
- 대용량 데이터를 한 번에 메모리에 로딩 (findAll() 등)
- 조치:
- Stream 또는 cursor 형태로 데이터를 페이징 처리하거나 스트리밍 처리
- 결과: 메모리 정상화, 배치 안정적 수행
3. 서버 다운 → 원인: 포트 충돌 및 WAS 중복 기동
- 상황: Spring Boot 서비스 배포 후 실행 안 됨
- 원인:
- 이전 버전 프로세스가 종료되지 않아 포트 충돌 (기본 8080)
- 조치:
- 프로세스 강제 종료 (kill -9)
- application.yml에 포트 변경 적용
4. 배포 후 장애 → 원인: 의존성 충돌
- 상황: Spring Boot 버전 업그레이드 후 특정 기능 500 오류
- 원인:
- 라이브러리 간 버전 충돌 (예: Spring Security + OAuth2)
- 조치:
- dependencyManagement로 버전 명시
- 불필요한 중복 의존성 제거
5. Kafka 메시지 유실 문제
- 상황: 이벤트 기반 MSA에서 데이터 누락
- 원인:
- Consumer Group 설정 오류
- Offset 관리 실수
- 조치:
- Kafka 설정 (enable.auto.commit=false)
- 수동 커밋 방식 적용
"저는 장애 발생 시 가장 먼저 로그를 확인하고, 트래픽 흐름을 파악합니다. 예를 들어 Spring Boot 프로젝트에서 배포 후 메모리 누수 이슈가 발생했던 경험이 있습니다. 데이터를 한번에 처리하는 구조로 인해 OOM이 발생했고, 이를 Stream 처리 방식으로 개선하여 문제를 해결했습니다. 이 과정에서 JVM Heap 관리와 GC 튜닝도 병행했고, 서비스 안정화에 성공했습니다. 이런 경험을 통해 장애 대응 뿐 아니라 사전 예방 관점에서도 꾸준히 노력하고 있습니다."
✅ 장애 발생 시 로그 확인 방법
🔸 1) WAS 로그 (Tomcat 기준)
- 경로: /logs/catalina.out, application.log
- 확인 포인트:
- Exception Stack Trace
- Error 발생 시각
- 요청 URI, API 경로
- 요청 처리 시간 (응답 지연 여부)
🔸 2) Thread Dump
- 확인 시점: CPU 100%, 서버 멈춤, 응답 불가 시
- 확인 포인트:
- RUNNABLE: 정상 실행 중
- BLOCKED: 락 대기 (동기화 문제)
- WAITING: 응답 대기 (DB, 외부 API 대기)
- 도구:
- 명령어 → jstack [PID] > threaddump.log
- 또는 Whatap, Pinpoint 자동 수집
🔸 3) GC 로그
- 경로: /logs/gc.log (설정 시)
- 확인:
- Full GC 빈도 급증 → 메모리 부족
- GC Pause Time → 멈춤 현상 발생
🔸 4) DB Slow Query 로그
- 실행 시간이 긴 쿼리 목록 → 응답 지연 주범
🔸 5) APM 로그 (Whatap, Pinpoint)
- 트랜잭션별 호출 흐름 확인
- 병목 메소드, API 탐지 가능
✅ 장애 원인별 튜닝 방법
Thread Pool 부족 | - WAS 설정 → maxThreads 증가 - 과도한 동시 요청 제한 (acceptCount) |
DB 커넥션 풀 부족 | - 커넥션 풀 (maximumPoolSize) 증가 - 불필요한 커넥션 점유 코드 개선 |
GC 잦음 (메모리 부족) | - JVM Heap 크기 증가 (-Xms, -Xmx) - GC 정책 변경 (CMS → G1GC) - 객체 생성 최소화, 메모리 누수 점검 |
쿼리 병목 | - 인덱스 추가 - 조인 최적화 - Batch 처리로 변경 - DB 파라미터 튜닝 |
외부 API 병목 | - 타임아웃 설정 - 비동기 처리 도입 - Circuit Breaker 패턴 적용 (Resilience4j 등) |
Thread Lock (동기화 문제) | - 동기화 범위 축소 - Concurrent 자료구조 사용 (예: ConcurrentHashMap) |
I/O 병목 (디스크, 네트워크) | - 캐싱 도입 (Redis) - API 결과 캐싱 - 리소스 압축 및 최적화 |
“신한투자증권 프로젝트에서 배치 프로그램 실행 중 응답 지연 장애가 발생했습니다. WAS 로그를 확인했더니 특정 시점에 Thread가 WAITING 상태로 몰려 있었고, DB 커넥션 풀 소진 문제가 확인되었습니다.
Thread Dump와 APM으로 확인한 결과, 대량 데이터 Insert 시 Connection 반환이 지연되는 문제가 있었습니다. DB Batch 처리 방식으로 변경하고, 커넥션 풀을 기존 10개 → 30개로 확장하여 해결했습니다.”
✅ WAS 로그 확인 방법 (Tomcat, WAS 기준)
Application 로그 | /logs/application.log 또는 /logs/catalina.out | - 비즈니스 로직 오류 (Exception) - API 요청/응답 흐름 - 에러 코드, 응답 지연 여부 |
Access 로그 (요청 로그) | /logs/localhost_access_log.[날짜].txt | - 누가, 언제, 어떤 API 호출 - 응답 시간, 상태 코드 (200, 500 등) |
Error 로그 | /logs/catalina.out | - 시스템 단 에러 - NullPointerException, DB Connection 오류 등 |
Thread Dump | 명령어 → jstack [PID] > threaddump.log | - Deadlock - Thread Block - 동시성 문제 |
🔥 장애 발생 시 확인 순서:
- catalina.out → Exception, Stack Trace 확인
- application.log → API 요청 흐름, Error 로그 확인
- Thread Dump → 서버 멈춤 원인 파악
- APM 툴 (Whatap, Pinpoint) 병행 확인
✅ WAS 로그 보는 도구
- 직접 서버 접속
→ tail -f catalina.out - ELK Stack (ElasticSearch + Logstash + Kibana)
→ 대부분의 금융사에서 도입
→ Kibana 대시보드로 실시간 조회 - APM (Application Performance Monitoring)
→ Whatap, Pinpoint, New Relic, Datadog
→ API별 응답 시간, 오류, 트랜잭션 추적
✅ Garbage Collection 로그
🔸 GC란?
- JVM의 메모리 자동 관리 기능
- 더 이상 참조되지 않는 객체를 메모리에서 자동으로 제거하는 기능
→ 메모리 누수를 막고 프로그램이 멈추지 않게 해줌
🔸 GC 로그란?
- JVM이 언제 메모리를 청소(정리)했는지 기록한 로그
🔸 GC 로그 예시:
- Young 영역에서 메모리 수집
- 소요 시간 0.012초
- 메모리 사용량 변화 기록
🔸 GC 로그로 무엇을 알 수 있나?
- Full GC 발생 빈도 → 빈번하면 서비스 멈춤
- GC Pause Time → 멈춤 현상 원인
- 메모리 부족 여부
🔸 실무에서 GC 로그 확인 이유:
CPU 급등 | Full GC 빈도 급증 확인 |
서버 멈춤 | GC Pause Time 과다 |
메모리 부족 | Old 영역 사용률 90% 이상 |
🔥 GC 튜닝 방법:
- JVM 힙 크기 조정 → -Xms, -Xmx
- GC 정책 변경 → CMS → G1GC
- 메모리 누수 점검 → 불필요 객체 제거
✅ 금융 시스템에서 발생할 수 있는 주요 장애 사례와 대응 방법을 설명해 주세요.
- 금융 시스템에서 발생하는 주요 장애는 데이터 정합성 오류, 트랜잭션 실패, 네트워크 지연 등이 있습니다.
- 예를 들어, 트랜잭션 처리 중 중복 결제 방지를 위해 트랜잭션 격리 수준을 조절하거나, 장애 발생 시 롤백 처리로 시스템 일관성을 유지합니다.
- 로그를 분석해 원인을 신속히 파악하고, 모니터링 시스템을 통해 조기 경보 체계를 운영합니다.
✅ 금융권 MSA 프로젝트 기반 시스템 장애 대응 사례 및 대응 방법
제가 참여했던 금융권 MSA 프로젝트에서는 여러 독립된 마이크로서비스들이 유기적으로 연동되어 하나의 금융 서비스를 제공하는 구조였습니다. 이 구조의 장점은 서비스별로 독립적인 배포와 확장이 가능하다는 점이지만, 반대로 서비스 간 통신 장애나 데이터 불일치가 발생할 경우 전체 시스템 장애로 이어질 수 있는 리스크도 있었습니다.
실제로 한 번은 결제 처리 서비스와 계좌 관리 서비스 간 API 호출 지연으로 인해, 결제 요청이 일정 시간 내에 처리되지 않는 장애가 발생했습니다. 이로 인해 사용자 결제 응답 지연과 트랜잭션 처리 실패가 보고된 상황이었죠.
이에 대응하기 위해 저는 다음과 같은 조치를 취했습니다.
- 장애 원인 분석:
- 로그 및 모니터링 도구를 활용해 어느 서비스 간 통신에서 병목이 발생했는지 신속히 파악했습니다.
- API 호출 지연과 타임아웃 설정 미흡이 주요 원인임을 확인했습니다.
- 예방 및 완화 대책 적용:
- 각 서비스 간 호출에 대해 타임아웃과 재시도(retry) 로직을 강화하여 일시적 네트워크 장애에도 안정적으로 대응할 수 있도록 했습니다.
- 장애 발생 시 장애 전파를 막기 위해 서킷 브레이커 패턴(Circuit Breaker)을 도입, 문제가 있는 서비스로의 호출을 자동 차단했습니다.
- 장애 알림 시스템을 개선하여 운영팀이 빠르게 인지하고 대응할 수 있도록 조치했습니다.
- 장애 대응 절차 문서화 및 테스트:
- 장애 대응 시나리오를 문서화하고 정기적으로 모의 장애 테스트를 진행하여, 실제 상황에서 신속히 대응할 수 있도록 준비했습니다.
✅ Failover (페일오버) 구조
✔️ 개념
- 장애 발생 시 자동으로 예비 시스템으로 전환
- 서비스가 중단되지 않고 즉시 복구됨
- Failover는 서버, DB, 시스템 등에 장애가 발생했을 때 자동으로 대체 시스템으로 전환해 서비스 중단을 막는 기술입니다.
✔️ 예시 구조도
✔️ 방식
- DB → Master-Slave 구조, Active-Standby
- WAS → 여러 인스턴스 중 장애 서버 제외
- 장애 감지 → Health Check, Heartbeat 모니터링
- 장애 발생 → 자동 IP 전환 (Virtual IP), 장애 서버 격리, Standby 서버 활성화
- 기술 예시:
- DB → Oracle RAC, PostgreSQL Patroni
- 네트워크 → L4 스위치, DNS 헬스체크
- 클라우드 → Auto Scaling Group + Health Check
Active-Active | 두 서버 모두 동작, 부하 공유. 하나 죽어도 나머지가 처리 |
Active-Standby | 메인 서버가 죽으면 대기 서버가 즉시 전환 |
✔️ 실무 적용 예시
- DB → Oracle RAC, PostgreSQL Patroni
- WAS → 이중화 (Nginx + Tomcat 2대 이상, Health Check 설정)
- 금융권 대부분은 Active-Active + Load Balancing + Failover 조합 사용
- 장애 발생 시 자동 Failover + 수동 확인 절차 추가
✅ Load Balancing (로드 밸런싱) 구조
✔️ 개념
- 여러 서버로 트래픽을 분산 처리
- 성능 향상, 장애 대응, 확장성 확보
- Load Balancing은 사용자 요청을 여러 서버에 고르게 분산해서 트래픽을 나누고 서버 과부하를 막는 기술입니다.
✔️ 동작 구조
✔️ 방식
- L4 (TCP/IP 기반) → IP, 포트 단위 분산
- L7 (HTTP/HTTPS 기반) → URL, 쿠키, 세션 기준으로 분산
분산 알고리즘:
- Round Robin
- Least Connection (가장 적은 연결 수)
- IP Hash (특정 사용자 유지)
기술:
- 하드웨어 → F5, A10
- 소프트웨어 → Nginx, HAProxy
- 클라우드 → AWS ALB/ELB, GCP Load Balancer
Round Robin | 순차 분배 | Nginx, HAProxy |
Least Connection | 현재 연결 적은 서버로 | 트래픽 불균형 최소화 |
IP Hash | 클라이언트 IP 기반 고정 서버 연결 | 세션 유지 필요시 |
Health Check 기반 | 서버 상태 체크 후 문제 있는 서버는 제외 | 장애 자동 대응 |
✔️ 사용되는 툴
- L4 스위치 (하드웨어) → 금융권 데이터 센터 주력
- Nginx, HAProxy → 소프트웨어 로드밸런서
- Kubernetes Ingress + Service → 클라우드 환경
✔️ 실무 적용
- 금융사 웹 서버 앞단에 F5 L7 Load Balancer
- Nginx로 API 서버 부하 분산 + 장애 시 자동 제외
- 백엔드 서버는 Least Connection 방식 적용
🔥 즉, Failover는 장애 시 전환,
Load Balancing은 평상시 부하 분산 + 장애 서버 자동 제외 기능도 포함.
"금융권 시스템은 고가용성이 필수이기 때문에 WAS와 DB 모두 이중화 구조를 사용합니다. WAS는 Nginx 기반의 로드 밸런싱을 적용해서 트래픽을 분산하고, 서버 장애 발생 시 Health Check를 통해 자동으로 장애 서버를 제외합니다. 또한 DB는 Oracle RAC 또는 PostgreSQL Patroni 클러스터를 활용해 Failover 시에도 서비스가 중단되지 않도록 구성합니다."
✅ DB 이중화 및 마스터-슬레이브 구조
✔️ 개념
- DB 이중화: 장애 발생 시에도 서비스가 중단되지 않도록 두 개 이상의 데이터베이스 인스턴스를 운영하는 구조.
- Master-Slave 구조:
→ Master DB는 데이터의 쓰기(Insert, Update, Delete) 전용
→ Slave DB는 데이터의 읽기(Select) 전용
→ Slave는 Master의 데이터를 실시간 복제(Replication) 함.
✔️ 필요성
- 장애 대비 → Master 장애 시 Slave가 자동 승격 (Failover)
- 읽기 부하 분산 → 대량 조회 트래픽을 Slave가 처리
- 데이터 백업 안전성 증가
→ 금융권 같이 실시간 안정성이 중요한 서비스에서 필수
✔️ 구성 방식
- Sync Replication: Master와 Slave가 항상 동일 (느리지만 안전)
- Async Replication: 약간의 지연 허용 (성능 ↑, 데이터 유실 가능성)
→ 대부분 금융권은 Semi-Sync 구조 채택
✔️ 구성 예시

✔️ 실무 적용 사례
- PostgreSQL → Patroni + Etcd 기반 이중화
- Oracle → RAC or Active-Standby 구성
- 신한투자증권에서는 리스크 관리 시스템 DB를 Master-Slave 구조로 읽기 분산, 장애 발생 시 자동 Failover 처리
- 우리FIS 퇴직연금도 DB 이중화가 기본, 업무 특성상 고가용성이 필수
'CS' 카테고리의 다른 글
CI/CD, DevOps (1) | 2025.06.27 |
---|---|
WAS 튜닝, 쿼리 성능 튜닝 (1) | 2025.06.27 |
Spring (2) | 2025.06.27 |
REST API (1) | 2025.06.27 |
MSA (1) | 2025.06.27 |