PHP 미드레벨 시스템 설계 면접

PHP 미드레벨 (3~7년) 시스템 설계 5문항 조회수 111 · 2026-05-07 (목) 19:11:05
1 API 설계 및 인증
Medium

Q. 마이크로서비스 아키텍처에서 서비스 간 인증을 위해 JWT(JSON Web Token)를 사용할 때, Access Token과 Refresh Token을 분리하여 설계하는 이유와 각각의 적절한 만료 시간 설정 전략을 설명해주세요. 또한 Token 탈취 시 보안 위험을 최소화하는 방법도 함께 제시해주세요.

A. 모범답안

Access Token은 짧은 만료 시간(15-30분)으로 설정하여 탈취 시 피해를 최소화하고, Refresh Token은 긴 만료 시간(7-30일)으로 설정하여 사용자 편의성을 보장합니다. Refresh Token은 HttpOnly 쿠키나 안전한 저장소에 보관하며, DB에 화이트리스트로 관리하여 필요 시 즉시 무효화할 수 있도록 합니다. Token Rotation 기법을 적용하여 Refresh Token 사용 시마다 새로운 토큰을 발급하고, IP 주소나 User-Agent 변경 감지 시 재인증을 요구하는 방식으로 보안을 강화합니다. Redis에 블랙리스트를 구현하여 로그아웃된 토큰의 재사용을 방지하고, 민감한 작업에는 추가 인증을 요구하는 단계별 보안 정책을 적용합니다.

핵심 포인트
  • • Access Token은 짧은 만료 시간, Refresh Token은 긴 만료 시간으로 보안과 편의성 균형
  • • Refresh Token을 DB에 저장하여 즉시 무효화 가능한 구조 구현
  • • Token Rotation, IP/User-Agent 검증, 블랙리스트 등 다층 보안 전략 적용
  • • HttpOnly 쿠키 사용으로 XSS 공격 방어
Follow-up 질문

JWT의 Stateless 특성과 Refresh Token을 DB에 저장하는 Stateful 방식의 트레이드오프는 무엇이며, 어떤 상황에서 각 방식을 선택해야 할까요?

2 데이터베이스 설계 및 샤딩
Hard

Q. 사용자 수가 수천만 명 이상인 소셜 미디어 플랫폼에서 게시글과 댓글 데이터를 관리하기 위한 데이터베이스 샤딩(Sharding) 전략을 설계해주세요. 샤딩 키 선택 기준, 데이터 분산 방식(Range-based, Hash-based, Directory-based), 그리고 샤드 간 조인이 필요한 쿼리를 처리하는 방법을 포함해서 설명해주세요.

A. 모범답안

사용자 ID를 기준으로 Hash-based 샤딩을 적용하여 데이터를 균등하게 분산시키며, Consistent Hashing을 사용하여 샤드 추가 시 재분배 비용을 최소화합니다. 게시글과 댓글은 작성자 기준으로 같은 샤드에 저장하여 단일 샤드 내에서 대부분의 쿼리를 처리할 수 있도록 설계합니다. 샤드 간 조인이 필요한 경우(예: 팔로워의 게시글 피드)는 Application Level에서 병렬 쿼리 후 병합하거나, Redis 같은 캐시 레이어에 비정규화된 데이터를 저장하여 성능을 최적화합니다. 글로벌 인덱스가 필요한 검색 기능은 Elasticsearch 같은 별도 검색 엔진을 활용하고, 샤드 메타데이터는 중앙 디렉토리 서비스에서 관리하여 라우팅 로직을 단순화합니다.

핵심 포인트
  • • Hash-based 샤딩과 Consistent Hashing으로 균등 분산 및 확장성 확보
  • • 사용자 ID 기준 샤딩으로 관련 데이터를 같은 샤드에 배치하여 조인 최소화
  • • 샤드 간 조인은 Application Level 병합 또는 캐시 레이어 비정규화로 해결
  • • 검색 등 글로벌 쿼리는 별도 검색 엔진 활용
Follow-up 질문

샤딩 환경에서 특정 샤드에 핫스팟(Hot Spot)이 발생했을 때 이를 감지하고 해결하는 방법은 무엇인가요?

3 캐싱 전략 및 일관성
Hard

Q. 전자상거래 시스템에서 상품 상세 정보를 캐싱할 때 Cache-Aside, Write-Through, Write-Behind 패턴의 차이점을 설명하고, 각 패턴이 적합한 시나리오를 제시해주세요. 또한 캐시와 DB 간 데이터 불일치를 방지하기 위한 Cache Invalidation 전략과 TTL 설정 방법도 함께 설명해주세요.

A. 모범답안

Cache-Aside는 애플리케이션이 캐시 미스 시 DB에서 데이터를 읽어 캐시에 저장하는 방식으로, 읽기 중심 워크로드에 적합하며 캐시 장애 시에도 서비스 가능합니다. Write-Through는 쓰기 시 캐시와 DB에 동시에 저장하여 데이터 일관성을 보장하지만 쓰기 지연이 발생할 수 있어 강한 일관성이 필요한 경우 적합합니다. Write-Behind는 캐시에 먼저 쓰고 비동기로 DB에 저장하여 쓰기 성능이 우수하지만 캐시 장애 시 데이터 손실 위험이 있어 로그나 분석 데이터에 적합합니다. Cache Invalidation은 DB 업데이트 시 해당 캐시 키를 삭제하는 방식과 이벤트 기반으로 관련 캐시를 무효화하는 방식을 병행하며, TTL은 데이터 변경 빈도에 따라 설정하되 Cache Stampede를 방지하기 위해 랜덤 지터를 추가합니다.

핵심 포인트
  • • Cache-Aside는 읽기 중심, Write-Through는 강한 일관성, Write-Behind는 쓰기 성능 우선 시나리오에 적합
  • • 캐시 무효화는 명시적 삭제와 이벤트 기반 무효화 병행
  • • TTL에 랜덤 지터 추가로 Cache Stampede 방지
  • • 각 패턴의 장단점과 데이터 일관성, 성능 트레이드오프 이해
Follow-up 질문

상품 가격처럼 자주 변경되면서도 정확성이 중요한 데이터의 경우, 캐시 일관성과 성능을 동시에 확보하기 위한 설계 방법은 무엇인가요?

4 API Rate Limiting 및 보안
Medium

Q. 공개 API 서비스에서 사용자별 요청 횟수를 제한하는 Rate Limiting 시스템을 설계해주세요. Token Bucket, Leaky Bucket, Fixed Window, Sliding Window 알고리즘의 차이점과 각각의 장단점을 비교하고, PHP와 Redis를 사용하여 Sliding Window 방식을 구현할 때 고려해야 할 사항을 설명해주세요.

A. 모범답안

Token Bucket은 버스트 트래픽을 허용하면서도 평균 속도를 제한하며, Leaky Bucket은 일정한 처리 속도를 보장합니다. Fixed Window는 구현이 간단하지만 윈도우 경계에서 요청이 집중되는 문제가 있고, Sliding Window는 정확한 제한을 제공하지만 메모리 사용량이 많습니다. Redis의 Sorted Set을 사용한 Sliding Window 구현 시, 타임스탬프를 스코어로 하여 요청을 저장하고 ZREMRANGEBYSCORE로 만료된 요청을 제거한 후 ZCARD로 현재 윈도우의 요청 수를 확인합니다. Lua 스크립트를 사용하여 읽기-확인-쓰기 작업을 원자적으로 처리하여 동시성 문제를 해결하고, Redis의 EXPIRE를 설정하여 메모리 누수를 방지합니다. 사용자별로 다른 제한을 적용할 경우 키 네이밍 전략을 체계화하고, 분산 환경에서는 Redis Cluster를 활용합니다.

핵심 포인트
  • • Token Bucket은 버스트 허용, Sliding Window는 정확한 제한 제공
  • • Redis Sorted Set과 Lua 스크립트로 원자적 연산 보장
  • • ZREMRANGEBYSCORE로 만료 요청 제거, EXPIRE로 메모리 관리
  • • 사용자별 키 분리 및 분산 환경 고려
Follow-up 질문

분산 시스템에서 여러 API 서버가 동일한 사용자 요청을 처리할 때 정확한 Rate Limiting을 보장하면서도 Redis 부하를 최소화하는 방법은 무엇인가요?

5 이벤트 기반 아키텍처 설계
Hard

Q. 주문 처리 시스템에서 주문 생성, 결제 처리, 재고 차감, 배송 준비, 알림 발송 등 여러 단계가 있을 때, 이벤트 기반 아키텍처(Event-Driven Architecture)로 설계하는 방법을 설명해주세요. 특히 이벤트 순서 보장, 멱등성 처리, 부분 실패 시 보상 트랜잭션(Saga 패턴) 구현 방법을 포함해서 설명해주세요.

A. 모범답안

각 단계를 독립적인 서비스로 분리하고 메시지 큐(RabbitMQ, Kafka)를 통해 이벤트를 발행/구독하는 구조로 설계합니다. 주문 생성 시 OrderCreated 이벤트를 발행하면 결제 서비스가 이를 구독하여 처리하고, 성공 시 PaymentCompleted 이벤트를 발행하는 식으로 체인을 구성합니다. 이벤트 순서 보장을 위해 Kafka의 파티션 키를 주문 ID로 설정하거나, RabbitMQ의 단일 큐에 순차적으로 메시지를 전송합니다. 멱등성은 각 이벤트에 고유 ID를 부여하고 Redis나 DB에 처리 이력을 저장하여 중복 처리를 방지합니다. Saga 패턴으로 부분 실패 처리 시, Orchestration 방식(중앙 조정자)이나 Choreography 방식(각 서비스가 보상 이벤트 발행)을 선택하며, 결제 실패 시 PaymentFailed 이벤트로 재고 복구 등 보상 트랜잭션을 트리거합니다. 모든 이벤트는 Event Store에 저장하여 추적 가능성을 확보합니다.

핵심 포인트
  • • 메시지 큐를 통한 서비스 간 느슨한 결합 및 비동기 처리
  • • 파티션 키 또는 단일 큐로 이벤트 순서 보장
  • • 이벤트 ID와 처리 이력 저장으로 멱등성 보장
  • • Saga 패턴으로 분산 트랜잭션 및 보상 트랜잭션 구현
  • • Event Store로 모든 이벤트 추적 및 감사
Follow-up 질문

이벤트 기반 아키텍처에서 여러 서비스가 동일한 이벤트를 구독할 때, 한 서비스는 성공하고 다른 서비스는 실패하는 경우를 어떻게 처리해야 할까요?

댓글 0

로그인 후 댓글을 작성할 수 있습니다.

아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!