Microservices 면접 질문
마이크로서비스 인터뷰는 확장 가능하고 분산된 시스템을 설계하고 구축하는 능력을 평가합니다. 종종 분산 컴퓨팅, API 및 데이터 일관성에 대한 깊은 지식을 가진 시니어 엔지니어와 아키텍트를 대상으로 합니다. 아키텍처 논의, 트레이드오프 분석 및 실습 코딩 시나리오가 혼합되어 나옵니다.
Microservices 면접에서 다루는 내용
서비스 분해 및 설계
모놀리스를 서비스로 분할하는 방법, 경계 컨텍스트 및 도메인 주도 설계 원칙.
서비스 간 통신
동기 대 비동기 패턴, API 게이트웨이, 서비스 메시, 통신 프로토콜.
데이터 관리 및 일관성
분산 트랜잭션 처리, 최종 일관성, 사가, CQRS/이벤트 소싱.
배포 및 관찰 가능성
컨테이너화, 오케스트레이션(Kubernetes), 분산 시스템에서 모니터링, 로깅, 추적.
샘플 Microservices 면접 질문
- 대규모 모놀리스를 마이크로서비스로 어떻게 분해하겠습니까? 의사 결정 과정을 설명하세요.좋은 답변이 다루는 것
- 비즈니스 도메인 분석 및 경계 식별 (DDD, Bounded Context)
- 변경 빈도와 확장 요구사항 기반 서비스 분리
- 데이터 일관성과 트랜잭션 경계 고려
- 점진적 분해 전략 (Strangler Fig 패턴)
샘플 답변 보기
모놀리스를 마이크로서비스로 분해할 때는 먼저 도메인 주도 설계(DDD)를 적용하여 비즈니스 도메인과 bounded context를 식별합니다. 각 bounded context는 독립적인 마이크로서비스 후보가 됩니다. 다음으로, 변경 빈도가 높거나 독립적 확장이 필요한 기능을 분리합니다. 예를 들어, 주문 처리와 결제는 변경 주기가 다를 수 있습니다. 데이터 일관성 측면에서, 강한 일관성이 필요한 트랜잭션은 동일 서비스에 두거나 사가 패턴을 고려합니다. 실제 분해는 Strangler Fig 패턴을 사용하여 점진적으로 진행하며, 기존 모놀리스를 완전히 대체할 때까지 기능별로 라우팅합니다. 이 과정에서 분산 트랜잭션, 네트워크 지연, 데이터 중복 등의 복잡성이 발생하므로, 각 서비스의 경계를 명확히 하고 적절한 통신 방식을 선택하는 것이 중요합니다.
- 사가 패턴에서 오케스트레이션과 코레오그래피의 차이점을 설명하세요. 각각 언제 사용하나요?좋은 답변이 다루는 것
- 오케스트레이션: 중앙 코디네이터가 각 단계 호출 및 보상
- 코레오그래피: 각 서비스가 이벤트를 발행/구독하여 자율적 처리
- 오케스트레이션은 복잡한 워크플로에 적합
- 코레오그래피는 느슨한 결합과 확장성에 유리
샘플 답변 보기
사가 패턴은 분산 트랜잭션을 관리하는 방법으로, 오케스트레이션과 코레오그래피 두 가지 구현 방식이 있습니다. 오케스트레이션은 중앙 오케스트레이터가 각 로컬 트랜잭션을 순서대로 호출하고 실패 시 보상 트랜잭션을 실행합니다. 이 방식은 제어가 명확하고 복잡한 워크플로를 관리하기 쉽지만, 오케스트레이터가 단일 장애점이 될 수 있습니다. 반면, 코레오그래피는 각 서비스가 자신의 로컬 트랜잭션을 완료한 후 이벤트를 발행하고, 다른 서비스가 이를 구독하여 다음 단계를 수행합니다. 이는 느슨한 결합과 높은 확장성을 제공하지만, 분산 디버깅이 어렵고 이벤트 순서 보장이 필요할 수 있습니다. 일반적으로 워크플로가 단순하고 서비스 간 종속성이 적을 때는 코레오그래피가, 복잡한 보상 로직이 필요하거나 워크플로가 자주 변경될 때는 오케스트레이션이 선호됩니다.
- 선호하는 언어로 간단한 서킷 브레이커를 구현하세요(의사 코드 허용).좋은 답변이 다루는 것
- 서킷 브레이커는 실패가 임계치를 넘으면 호출을 차단
- 세 가지 상태: CLOSED, OPEN, HALF_OPEN
- 실패 카운터와 타임아웃을 기반으로 상태 전환
샘플 답변 보기
서킷 브레이커는 외부 서비스 호출 실패를 감지하고 시스템을 보호하는 패턴입니다. 아래는 Java로 간단한 구현 예시입니다. 시간 복잡도는 O(1) (상태 확인 및 카운터 업데이트), 공간 복잡도는 O(1)입니다.
참고 코드java import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; public class CircuitBreaker { private enum State { CLOSED, OPEN, HALF_OPEN } private final int failureThreshold; // 실패 임계치 private final long timeout; // OPEN 상태에서 HALF_OPEN으로 전환까지 대기 시간 (ms) private State state = State.CLOSED; private AtomicInteger failureCount = new AtomicInteger(0); private AtomicLong lastFailureTime = new AtomicLong(0); public CircuitBreaker(int failureThreshold, long timeout) { this.failureThreshold = failureThreshold; this.timeout = timeout; } // 호출 전 상태 확인 public boolean allowRequest() { if (state == State.OPEN) { // 타임아웃 지났는지 확인 if (System.currentTimeMillis() - lastFailureTime.get() > timeout) { state = State.HALF_OPEN; return true; } return false; } return true; } // 성공 시 호출 public void onSuccess() { failureCount.set(0); state = State.CLOSED; } // 실패 시 호출 public void onFailure() { failureCount.incrementAndGet(); lastFailureTime.set(System.currentTimeMillis()); if (failureCount.get() >= failureThreshold) { state = State.OPEN; } } } - 최종 일관성으로 분산 트랜잭션을 어떻게 처리하나요? 구체적인 예를 들어 설명하세요.좋은 답변이 다루는 것
- 최종 일관성: 모든 복제본이 결국 동일한 상태가 됨
- 보상 트랜잭션을 통한 분산 트랜잭션 처리
- 예: 이커머스 주문-재고-결제 시스템
샘플 답변 보기
최종 일관성을 이용한 분산 트랜잭션 처리는 사가 패턴을 기반으로 합니다. 예를 들어, 온라인 쇼핑몰에서 주문이 들어오면 주문 서비스는 주문을 생성하고 '주문 생성됨' 이벤트를 발행합니다. 재고 서비스는 이를 수신하여 재고를 차감하고, 성공하면 '재고 차감됨' 이벤트를 발행합니다. 결제 서비스는 이를 수신하여 결제를 진행합니다. 만약 재고가 부족하면 재고 서비스는 보상 이벤트를 발행하여 주문을 취소하도록 합니다. 이 과정에서 각 서비스는 로컬 트랜잭션을 커밋하고 이벤트를 통해 다음 단계를 트리거하므로 강한 일관성이 아닌 최종 일관성을 보장합니다. 이 방식은 시스템의 가용성과 성능을 높이지만, 일시적인 불일치와 보상 로직의 복잡성을 감수해야 합니다.
- 10개 이상의 마이크로서비스가 있는 시스템을 위한 API 게이트웨이를 설계하세요. 어떤 기능이 포함되어야 하나요?좋은 답변이 다루는 것
- 라우팅: 요청을 적절한 서비스로 전달
- 인증/인가: 중앙 집중식 보안 처리
- 속도 제한 및 버스트 제어: 과도한 트래픽 방지
- 로드 밸런싱 및 서비스 디스커버리 통합
- 로깅, 모니터링, 분산 추적 통합
샘플 답변 보기
10개 이상의 마이크로서비스를 위한 API 게이트웨이는 다음과 같은 기능을 포함해야 합니다. 첫째, 요청 라우팅: 게이트웨이는 클라이언트 요청을 받아 적절한 마이크로서비스로 전달합니다. 둘째, 인증 및 인가: 모든 요청에 대해 중앙에서 토큰 검증을 수행하여 보안을 강화합니다. 셋째, 속도 제한(rate limiting): 특정 클라이언트의 과도한 요청을 제한하여 다운스트림 서비스를 보호합니다. 넷째, 로드 밸런싱: 여러 인스턴스에 요청을 분산시키고, 서비스 디스커버리(예: Consul, Eureka)와 통합하여 동적 라우팅을 지원합니다. 다섯째, 로깅 및 모니터링: 모든 트래픽을 기록하고, 분산 추적(예: Jaeger)과 연동하여 문제를 진단합니다. 또한, 응답 캐싱, 요청 변환(protocol translation), API 버전 관리 등도 고려할 수 있습니다. 이러한 기능은 시스템의 확장성, 보안, 유지보수성을 크게 향상시킵니다.
- 서비스 간 통신을 위해 REST보다 gRPC를 선택하는 시나리오를 설명하세요.좋은 답변이 다루는 것
- gRPC는 HTTP/2 기반의 바이너리 프로토콜
- 낮은 지연시간과 높은 처리량이 필요한 경우
- 강력한 타입 계약과 스트리밍 지원
- 다양한 언어 지원으로 이질적 환경에 유리
샘플 답변 보기
gRPC는 REST보다 다음과 같은 시나리오에서 선호됩니다. 첫째, 내부 마이크로서비스 간 통신에서 낮은 지연시간과 높은 처리량이 요구될 때, gRPC는 HTTP/2와 Protocol Buffers를 사용하여 메시지 크기를 줄이고 속도를 높입니다. 둘째, 서비스 간 강력한 타입 계약이 필요할 때, gRPC는 .proto 파일을 통해 명확한 인터페이스를 정의하므로 오류 가능성을 줄입니다. 셋째, 스트리밍 데이터(예: 실시간 알림, 로그 전송)가 필요한 경우, gRPC는 단일 연결에서 양방향 스트리밍을 지원합니다. 넷째, 다중 언어 환경에서 gRPC는 다양한 언어를 공식 지원하므로 폴리글랏 아키텍처에 적합합니다. 반면, 외부 클라이언트(웹 브라우저 등)와의 통신은 REST가 더 편리할 수 있습니다.
- 마이크로서비스 전반에 걸쳐 분산 추적을 어떻게 구현하겠습니까? 어떤 도구를 사용하겠습니까?좋은 답변이 다루는 것
- 각 서비스 요청에 고유 ID(trace ID)를 할당
- 각 서비스 내 span ID를 생성하여 계층 구조 형성
- OpenTelemetry 표준을 사용하여 추적 데이터 수집
- Jaeger 또는 Zipkin을 통해 시각화
샘플 답변 보기
분산 추적을 구현하려면 먼저 각 요청에 고유한 trace ID를 할당하고, 각 서비스는 이 trace ID를 전파합니다. 각 서비스 내에서 수행되는 작업 단위(span)에 span ID를 생성하고, 부모 span을 참조하여 계층 구조를 만듭니다. 이를 위해 OpenTelemetry SDK를 사용하여 계측하고, 추적 데이터를 수집하여 Jaeger나 Zipkin 같은 분산 추적 시스템으로 전송합니다. 예를 들어, Spring Cloud Sleuth와 같이 프레임워크 레벨에서 자동 계측을 지원하는 도구를 사용하면 편리합니다. 또한, 각 서비스의 로그에도 trace ID를 포함시켜 로그와 추적을 연계할 수 있습니다. 이렇게 하면 요청이 여러 서비스를 거치는 경로와 지연 시간을 시각화하여 병목 지점을 식별할 수 있습니다.
- 다운스트림 종속성(예: 데이터베이스, 캐시, 기타 서비스)의 상태를 보고하는 상태 확인 엔드포인트를 코딩하세요.좋은 답변이 다루는 것
- 엔드포인트는 각 다운스트림 종속성을 개별적으로 확인
- 상태를 UP/DOWN 또는 JSON 응답으로 반환
- 타임아웃과 재시도 로직을 포함하여 외부 종속성 처리
- Spring Boot Actuator의 HealthIndicator 구현
샘플 답변 보기
상태 확인 엔드포인트는 각 다운스트림 종속성(DB, 캐시, 외부 서비스)의 상태를 확인하고 종합적인 상태를 반환합니다. 아래는 Java Spring Boot 예시입니다. 각 종속성에 대해 연결을 시도하고 성공 여부를 반환합니다. 타임아웃을 설정하여 응답이 없으면 DOWN으로 처리하며, 재시도는 단순화를 위해 생략했습니다. 시간 복잡도는 O(n) (n은 종속성 수), 공간 복잡도는 O(n)입니다.
참고 코드java import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.stereotype.Component; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; @Component public class CustomHealthIndicator implements HealthIndicator { private final DataSource dataSource; private final RedisTemplate<String, String> redisTemplate; // 가정 public CustomHealthIndicator(DataSource dataSource, RedisTemplate<String, String> redisTemplate) { this.dataSource = dataSource; this.redisTemplate = redisTemplate; } @Override public Health health() { boolean dbHealthy = checkDatabase(); boolean redisHealthy = checkRedis(); boolean externalServiceHealthy = checkExternalService(); if (dbHealthy && redisHealthy && externalServiceHealthy) { return Health.up().withDetail("database", "UP") .withDetail("redis", "UP") .withDetail("externalService", "UP").build(); } else { Health.Builder builder = Health.down(); if (!dbHealthy) builder.withDetail("database", "DOWN"); if (!redisHealthy) builder.withDetail("redis", "DOWN"); if (!externalServiceHealthy) builder.withDetail("externalService", "DOWN"); return builder.build(); } } private boolean checkDatabase() { try (Connection conn = dataSource.getConnection()) { return conn.isValid(1000); // 1초 타임아웃 } catch (SQLException e) { return false; } } private boolean checkRedis() { try { redisTemplate.getConnectionFactory().getConnection().ping(); return true; } catch (Exception e) { return false; } } private boolean checkExternalService() { try { // 외부 서비스 호출 (간단한 HTTP GET) RestTemplate restTemplate = new RestTemplate(); restTemplate.getForObject("http://external-service/health", String.class); return true; } catch (Exception e) { return false; } } }
준비 방법
- 분산 시스템 기초를 마스터하세요: CAP 정리, 일관성 모델, 내결함성.
- 도메인 주도 설계(엔티티, 애그리게이트, 경계 컨텍스트)를 사용한 서비스 분해를 연습하세요.
- 최종 일관성과 사가 패턴(예: 보상 트랜잭션 포함) 구현 방법을 이해하세요.
- 트레이드오프에 대해 논의할 준비를 하세요: 오케스트레이션 대 코레오그래피, 동기 대 비동기, 상태 저장 대 무상태.
- 시스템 설계 문제에 대비하세요: 통신, 데이터, 관찰 가능성에 초점을 맞춘 마이크로서비스 아키텍처를 화이트보드에 그리는 연습을 하세요.
자주 묻는 질문
마이크로서비스 인터뷰에서 가장 중요한 개념은 무엇인가요?
핵심 개념은 서비스 분해, 서비스 간 통신(REST, gRPC, 메시징), 데이터 일관성(사가, 최종 일관성), 관찰 가능성(로깅, 메트릭, 추적)입니다.
마이크로서비스 인터뷰를 위해 Kubernetes를 알아야 하나요?
네, Kubernetes는 종종 컨테이너를 오케스트레이션하는 데 사용됩니다. 파드, 서비스, 디플로이먼트를 이해하고 클러스터에서 마이크로서비스를 관리하는 방법을 알아야 합니다.
마이크로서비스 인터뷰는 일반 시스템 설계 인터뷰와 어떻게 다른가요?
마이크로서비스 인터뷰는 서비스 경계, 데이터 분배, 네트워크 복원력 같은 분산 아키텍처의 특정 도전에 초점을 맞추는 반면, 일반 시스템 설계는 모놀리스도 다룰 수 있습니다.
마이크로서비스 인터뷰에서 어떤 코딩 질문을 기대할 수 있나요?
서킷 브레이커, 재시도 메커니즘, 간단한 서비스 상태 엔드포인트를 구현하라는 요청을 받을 수 있습니다. 또한 API를 설계하거나 서비스 간 통신 코드를 작성해야 할 수도 있습니다.
프로덕션에서 마이크로서비스를 작업한 경험이 없는데 어떻게 경험을 증명할 수 있나요?
마이크로서비스 패턴을 사용한 작은 프로젝트를 구축하세요(예: Docker, Node.js/Spring Boot, 메시지 큐 사용). 트레이드오프와 교훈을 논의하세요. 이론적 지식과 개인 프로젝트의 조합이 설득력 있을 수 있습니다.
즉각적인 AI 피드백으로 Microservices 질문 연습하기
이력서를 업로드하고 맞춤형 모의 면접을 받아 무엇을 개선해야 할지 정확히 확인하세요 — 무료로 시작하세요.