[TIL] Spring Boot 기반의 MSA에서 오류 처리 방식
in TIL on Til, Spring, Project Last modified at:
2025-03-19 TIL
📝 TIL (Today I Learned)
🔗 원본 이슈: #29
📅 작성일: 2025-03-19
🔄 최종 수정: 2025년 04월 08일
🍀 새롭게 배운 것
- Spring Boot 기반의 MSA(마이크로서비스 아키텍처)에서 오류 처리 방식
💥 오류(Error)는 왜 발생할까?
- 데이터베이스(DB) 장애 → “내가 터질게!” (예: AWS RDS 다운)
- 외부 API 장애 → “FCM(푸시 서버) 안 돼요!” (예: 결제 서버 점검 중)
- 서버 자체 장애 → “레디스(캐시 DB)가 서버비 미납으로 종료”
- 네트워크 문제 → “WAS(웹 애플리케이션 서버) 연결 끊김”
- 트래픽 과부하 → “주식 거래 사이트 폭주!”
⚙️ 오류를 처리하는 방법 (AOP & MSA 관점)
1. “Plan B” 대체 시스템을 사용
서비스에서 DB나 API 장애가 발생하면, 다음과 같은 방법으로 처리합니다.
- 대체 DB/API 호출: 메인 DB가 죽으면 백업 DB 사용
- 캐시(Cache) 활용: Redis, Memcached 등으로 데이터를 빠르게 제공
- Failover 시스템: 다른 서버로 트래픽을 분산
예제: 데이터베이스 장애 발생 시 대체 DB 호출
try {
return mainDatabase.query("SELECT * FROM users");
} catch (DatabaseException e) {
return backupDatabase.query("SELECT * FROM users"); // 대체 DB 사용
}
2. 오류 감지 & 처리 (AOP, Exception Handling)
AOP(Aspect-Oriented Programming)로 공통 로직 처리 AOP를 사용하면, 각 서비스에서 일일이 예외처리를 할 필요 없이 한 곳에서 관리할 수 있습니다.
📌 예제: 오류를 자동 감지하고 로깅
@Aspect
@Component
public class LoggingAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object logErrors(ProceedingJoinPoint joinPoint) throws Throwable {
try {
return joinPoint.proceed();
} catch (Exception e) {
System.err.println("에러 발생: " + e.getMessage());
throw e; // 오류를 컨트롤러까지 던짐
}
}
}
3. 컨트롤러에서 최종 응답 처리
서비스에서 처리할 수 없는 심각한 오류가 발생하면 컨트롤러에서 최종 결정합니다.
📌 예제: HTTP 상태 코드 반환
@RestController
@RequestMapping("/api")
public class UserController {
@GetMapping("/user")
public ResponseEntity<String> getUser() {
try {
return ResponseEntity.ok(userService.getUserData());
} catch (DatabaseException e) {
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body("DB 장애 발생!");
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("서버 오류!");
}
}
}
🛠 결과:
- 정상: 200 OK
- DB 장애: 503 Service Unavailable
- 서버 장애: 500 Internal Server Error
4. 트래픽 증가 대응 (스케일링)
사용자가 많아지면 서버가 버티지 못할 수도 있습니다.
이럴 때 오토 스케일링(Auto Scaling)을 사용합니다.
- Kubernetes(K8s) 활용: 컨테이너 단위로 서버 자동 확장
- HPA(Horizontal Pod Autoscaler): CPU 사용량이 일정 수준 이상이면 자동으로 서버 개수를 늘림
- 로드 밸런서 (LB, Load Balancer): 트래픽을 여러 서버에 분산
📌 예제: K8s에서 HPA 설정
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
maxReplicas: 5 # 최대 5개 서버까지 확장
minReplicas: 2 # 최소 2개 유지
targetCPUUtilizationPercentage: 80 # CPU 사용량 80% 이상이면 서버 추가
🛠 결과:
- 사용자가 많아지면 → 서버 자동 증가
- 사용자가 줄어들면 → 서버 자동 축소
🔎 🔥 전체적인 오류 처리 흐름
📌 오류 발생 시 시스템이 어떻게 대처하는지 정리
(각 단계에서 어떻게 대응하는지 확인)
- 서비스 실행
- 사용자가 웹사이트에 접속
- 요청을 컨트롤러가 서비스로 전달
- 예기치 못한 장애 발생
- 데이터베이스 장애 발생!
- 결제 시스템 응답 없음!
- 서비스 대응
- 대체 API/DB 호출
- 대체할 게 없다면 → 오류 던짐
- 컨트롤러에서 최종 오류 처리
- 500 에러 반환
- 사용자가 알아볼 수 있도록 “잠시 후 다시 시도하세요” 메시지 출력
- 스케일링 및 복구
- K8s가 서버를 확장하여 복구 진행
- 시스템이 정상적으로 돌아옴
📌 한눈에 보는 아키텍처 개념도 (시각화)
📊 Spring Boot 3 & MSA 아키텍처에서 오류 처리 및 대응 과정
[ 시스템 오류 대응 흐름 ]
[User]
↓ 요청
[Controller]
↓
[Service] ----> [Database] ❌ 장애 발생!
↓ ↓
[대체 API/DB 호출] 🟢 정상 응답 or ❌ 대체 실패
↓
[Controller] ⚠️ 오류 처리
↓
[View] "오류가 발생했습니다. 다시 시도하세요."
🏁 결론: 오류를 어떻게 효과적으로 처리할까?
AOP를 활용해 예외처리를 한 곳에서 관리
- 모든 서비스에 일일이 if-else 조건을 넣지 않고, 공통으로 처리 가능
대체 시스템(Plan B) 준비
- DB 장애 시 백업 DB 사용
- API 장애 시 캐시/대체 API 활용
컨트롤러에서 최종 응답 제어
- 사용자에게 적절한 오류 메시지를 제공
트래픽 증가 시 자동 확장
- Kubernetes, HPA, 로드 밸런서를 활용하여 서버 자동 확장