PHP 리드·아키텍트 트러블슈팅 면접

PHP 리드 · 아키텍트 (10년+) 트러블슈팅 5문항 조회수 41 · 2026-08-04 (화) 15:23:18
1 메모리 누수 장애
Hard

Q. 대규모 이커머스 사이트에서 PHP-FPM 프로세스들이 시간이 지날수록 메모리를 계속 점유하다가 결국 OOM Killer에 의해 강제 종료되는 현상이 반복됩니다. 주문 처리량이 많은 시간대에 특히 심각하며, 재시작 후 일시적으로 해결되지만 몇 시간 후 재발합니다. 이 장애의 원인을 어떻게 진단하고 해결하시겠습니까?

PHP의 메모리 관리 특성과 장기 실행 프로세스에서 발생할 수 있는 누적 문제를 중심으로 생각해보세요.

A. 모범답안

먼저 memory_get_usage()와 memory_get_peak_usage()를 활용한 로깅을 추가하여 메모리 증가 패턴을 파악합니다. PHP-FPM의 pm.max_requests 설정을 확인하여 워커 재시작 주기가 적절한지 점검하고, 순환 참조로 인한 가비지 컬렉션 실패 가능성을 조사합니다. XDebug나 Blackfire를 이용해 메모리 프로파일링을 수행하여 특정 함수나 객체에서 메모리가 해제되지 않는 부분을 식별합니다. 대용량 배열이나 객체를 unset()하지 않고 누적하는 코드, PDO 커넥션이나 파일 핸들을 명시적으로 닫지 않는 부분을 찾아 수정합니다. 장기적으로는 pm.max_requests를 적절히 낮춰 워커를 주기적으로 재시작하고, opcache 설정을 최적화하며, 모니터링 대시보드에 메모리 사용 추이를 추가하여 재발을 조기에 감지할 수 있도록 합니다.

핵심 포인트
  • • 메모리 사용 패턴 분석을 위한 프로파일링 도구 활용
  • • PHP-FPM pm.max_requests 설정을 통한 워커 재시작 주기 관리
  • • 순환 참조와 리소스 미해제 코드 식별 및 수정
  • • 모니터링 체계 구축을 통한 재발 방지
답변에 넣으면 좋은 키워드
PHP-FPM 메모리 누수 pm.max_requests 가비지 컬렉션 프로파일링 순환 참조
실무에서는

장기 실행되는 워커 프로세스나 대용량 데이터 처리 배치 작업에서 메모리 관리는 시스템 안정성의 핵심 요소입니다.

Follow-up 질문

pm.max_requests 값을 결정할 때 고려해야 할 요소들과, 이 값이 너무 낮거나 높을 때 발생할 수 있는 문제는 무엇인가요?

2 데이터베이스 연결 고갈
Hard

Q. 트래픽이 급증하는 이벤트 시간대에 갑자기 'Too many connections' 에러가 발생하며 서비스 전체가 응답하지 않습니다. MySQL max_connections는 500으로 설정되어 있고, PHP 애플리케이션 서버는 10대가 운영 중입니다. 평소에는 문제가 없다가 특정 임계치를 넘으면 급격히 악화됩니다. 이 상황을 어떻게 진단하고 즉각적/중장기적으로 해결하시겠습니까?

커넥션 풀 관리, 슬로우 쿼리, 트랜잭션 타임아웃 등 여러 레이어에서 원인을 찾아야 합니다.

A. 모범답안

즉각 대응으로는 SHOW PROCESSLIST를 실행하여 Sleep 상태나 장시간 실행 중인 쿼리를 식별하고, 필요시 kill 명령으로 정리합니다. 슬로우 쿼리 로그를 확인하여 인덱스 누락이나 비효율적인 쿼리가 커넥션을 오래 점유하는지 파악합니다. PHP 코드에서 명시적으로 커넥션을 닫지 않거나, 트랜잭션을 commit/rollback 없이 방치하는 부분이 있는지 검토합니다. PHP-FPM의 max_children 설정과 데이터베이스 max_connections의 균형이 맞는지 계산하여 조정합니다. 중장기적으로는 커넥션 풀링 미들웨어(ProxySQL, PgBouncer 등) 도입을 검토하고, 읽기 부하는 Read Replica로 분산하며, 캐싱 레이어(Redis)를 강화하여 DB 접근 자체를 줄입니다. 애플리케이션 레벨에서는 persistent connection 사용 여부를 재검토하고, 커넥션 타임아웃과 쿼리 타임아웃을 적절히 설정합니다.

핵심 포인트
  • • SHOW PROCESSLIST를 통한 실시간 커넥션 상태 분석
  • • 슬로우 쿼리와 트랜잭션 미처리 코드 식별
  • • PHP-FPM max_children과 DB max_connections 균형 조정
  • • 커넥션 풀링 미들웨어와 Read Replica 도입
답변에 넣으면 좋은 키워드
커넥션 풀 max_connections SHOW PROCESSLIST 슬로우 쿼리 ProxySQL persistent connection
실무에서는

트래픽 급증 시 데이터베이스 커넥션 고갈은 가장 흔한 장애 유형으로, 아키텍처 설계 단계에서 고려해야 합니다.

Follow-up 질문

persistent connection을 사용할 때의 장단점과, PHP-FPM 환경에서 이를 사용할 때 주의해야 할 점은 무엇인가요?

3 세션 스토리지 장애
Medium

Q. 멀티 서버 환경에서 Redis를 세션 스토리지로 사용 중입니다. 갑자기 사용자들이 로그인 상태가 풀리거나 장바구니 데이터가 사라지는 현상이 간헐적으로 발생합니다. Redis 서버는 정상 동작 중이며, 네트워크 연결도 안정적입니다. 어떤 원인들을 의심하고 어떻게 조사하시겠습니까?

Redis의 메모리 정책, 키 만료, 그리고 PHP의 세션 핸들러 설정을 살펴보세요.

A. 모범답안

먼저 Redis의 maxmemory 설정과 maxmemory-policy를 확인하여 메모리 부족으로 세션 키가 eviction되고 있는지 파악합니다. Redis CLI에서 INFO memory와 INFO stats를 실행하여 evicted_keys 지표를 모니터링합니다. PHP의 session.gc_maxlifetime과 Redis 키의 TTL 설정이 일치하는지, session.save_handler가 올바르게 redis로 설정되어 있는지 확인합니다. 로드밸런서의 세션 어피니티(sticky session) 설정이 꺼져있어 세션 ID는 유지되지만 다른 Redis 인스턴스를 참조하는 문제는 없는지 점검합니다. Redis Sentinel이나 Cluster 환경이라면 failover 시 세션 손실 가능성을 검토하고, Redis 백업/복제 설정을 확인합니다. 근본적으로는 Redis 메모리를 증설하고, allkeys-lru 대신 volatile-lru 정책을 사용하여 TTL이 있는 세션 키만 eviction 대상으로 하며, 중요 세션 데이터는 DB에도 백업하는 이중화 전략을 고려합니다.

핵심 포인트
  • • Redis maxmemory-policy와 evicted_keys 지표 분석
  • • PHP 세션 설정과 Redis TTL 일치 여부 확인
  • • 로드밸런서 세션 어피니티 설정 점검
  • • Redis 메모리 증설 및 정책 최적화
답변에 넣으면 좋은 키워드
Redis 세션 스토리지 maxmemory-policy eviction session.gc_maxlifetime sticky session
실무에서는

세션 관리는 사용자 경험에 직접 영향을 미치며, 특히 이커머스에서 장바구니나 결제 진행 중 세션 손실은 매출 손실로 이어집니다.

Follow-up 질문

Redis Cluster 환경에서 세션을 저장할 때 해시 슬롯 배치로 인해 발생할 수 있는 문제와 해결 방법은 무엇인가요?

4 Opcache 무효화 문제
Medium

Q. 무중단 배포를 위해 Blue-Green 방식으로 PHP 애플리케이션을 배포했는데, 새 버전 배포 후에도 일부 서버에서 이전 코드가 계속 실행되는 현상이 발생합니다. opcache.validate_timestamps는 0으로 설정되어 있으며, PHP-FPM 재시작 없이 배포하고 있습니다. 이 문제를 어떻게 해결하고 배포 프로세스를 개선하시겠습니까?

Opcache의 캐싱 메커니즘과 무효화 방법, 그리고 프로세스 수명주기를 고려해야 합니다.

A. 모범답안

opcache.validate_timestamps가 0이면 PHP는 파일 변경을 감지하지 않으므로, 배포 후 반드시 opcache_reset()을 호출하거나 PHP-FPM을 재시작해야 합니다. 현재 문제는 opcache가 프로세스별로 독립적이어서 일부 워커 프로세스에만 캐시가 남아있기 때문입니다. 즉각적인 해결책으로는 배포 스크립트에 opcache_reset() API 호출을 추가하거나, systemctl reload php-fpm으로 graceful restart를 수행합니다. 더 안전한 방법은 배포 시 php-fpm을 완전히 재시작하되, 로드밸런서에서 헬스체크를 통해 준비된 서버만 트래픽을 받도록 합니다. opcache.validate_timestamps를 1로 변경하고 opcache.revalidate_freq를 짧게 설정하는 것도 고려할 수 있으나, 성능 저하가 있으므로 프로덕션에서는 권장하지 않습니다. 배포 파이프라인에 opcache 상태 확인 단계를 추가하여 opcache_get_status()로 캐시 히트율과 메모리 사용량을 모니터링하고, 배포 후 검증 단계에서 실제 새 코드가 실행되는지 확인하는 스모크 테스트를 포함시킵니다.

핵심 포인트
  • • opcache.validate_timestamps=0 환경에서는 명시적 캐시 무효화 필수
  • • 배포 스크립트에 opcache_reset() 또는 PHP-FPM graceful restart 포함
  • • 로드밸런서 헬스체크와 연계한 안전한 재시작 전략
  • • 배포 파이프라인에 opcache 상태 검증 단계 추가
답변에 넣으면 좋은 키워드
Opcache opcache_reset validate_timestamps PHP-FPM graceful restart 무중단 배포
실무에서는

Opcache 관리는 배포 전략의 핵심 요소로, 잘못 처리하면 구버전과 신버전 코드가 혼재되어 예측 불가능한 버그를 유발합니다.

Follow-up 질문

대규모 서버 환경에서 opcache_reset()을 모든 서버에 일괄 적용할 때 발생할 수 있는 위험과 이를 완화하는 방법은 무엇인가요?

5 외부 API 타임아웃 연쇄 장애
Hard

Q. 결제 처리를 위해 외부 PG사 API를 호출하는 시스템에서, PG사 API 응답이 느려지자 전체 웹 서버가 먹통이 되는 현상이 발생했습니다. PHP-FPM의 모든 워커가 PG API 응답을 기다리며 블로킹되어 다른 정상 요청도 처리하지 못합니다. 이 장애를 즉시 복구하고, 향후 외부 의존성 장애가 전체 시스템으로 전파되지 않도록 아키텍처를 어떻게 개선하시겠습니까?

타임아웃 설정, 서킷 브레이커 패턴, 비동기 처리를 중심으로 생각해보세요.

A. 모범답안

즉시 복구를 위해 해당 PG API를 호출하는 엔드포인트를 일시적으로 비활성화하거나, 방화벽/로드밸런서에서 해당 요청을 차단하여 워커를 해방시킵니다. PHP의 cURL 타임아웃 설정(CURLOPT_TIMEOUT, CURLOPT_CONNECTTIMEOUT)이 적절한지 확인하고, 없다면 즉시 추가합니다(예: 5초 연결, 10초 응답). 근본적으로는 외부 API 호출을 동기에서 비동기로 전환하여 메시지 큐(RabbitMQ, AWS SQS)를 통해 별도 워커가 처리하도록 분리합니다. 서킷 브레이커 패턴을 구현하여 PG API 실패율이 임계치를 넘으면 자동으로 호출을 차단하고 폴백 로직(예: 대기열 등록 후 나중에 재시도)을 실행합니다. PHP-FPM 워커 풀을 용도별로 분리하여 결제 처리용 워커와 일반 요청 처리용 워커를 독립적으로 운영하는 것도 고려합니다. 모니터링에는 외부 API 응답 시간과 에러율을 추적하는 지표를 추가하고, 임계치 초과 시 자동 알람을 발생시켜 조기 대응할 수 있도록 합니다. 장기적으로는 Guzzle의 Promise 기능이나 ReactPHP, Swoole 같은 비동기 런타임 도입을 검토합니다.

핵심 포인트
  • • 즉시 엔드포인트 차단 및 cURL 타임아웃 설정 추가
  • • 외부 API 호출을 메시지 큐 기반 비동기 처리로 전환
  • • 서킷 브레이커 패턴 구현으로 장애 전파 차단
  • • 워커 풀 분리 및 외부 API 모니터링 강화
답변에 넣으면 좋은 키워드
타임아웃 서킷 브레이커 비동기 처리 메시지 큐 cURL 장애 격리
실무에서는

외부 의존성 장애는 마이크로서비스 아키텍처에서 가장 흔한 장애 원인이며, 격리 전략 없이는 단일 장애점이 전체 시스템을 마비시킵니다.

Follow-up 질문

서킷 브레이커의 Half-Open 상태에서 외부 API가 복구되었는지 확인하는 전략과, 이때 발생할 수 있는 위험을 어떻게 관리하시겠습니까?

댓글 0

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

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