PHP 시니어 기술면접
새 면접Q. PHP에서 긴 실행 시간이 소요되는 배치 작업(예: 대용량 CSV 파싱, 이미지 리사이징)을 처리할 때 메모리 효율성을 위해 Generator를 활용하는 방법과 일반 배열 처리 방식과의 성능 차이를 설명해주세요. 또한 Generator를 사용할 때 예외 처리와 중단된 작업의 재시작 전략을 어떻게 구현할 수 있는지 실무 관점에서 설명해주세요.
Generator는 yield 키워드를 사용하여 데이터를 한 번에 하나씩 생성하므로 전체 데이터셋을 메모리에 로드하지 않아 메모리 효율적입니다. 일반 배열은 모든 데이터를 메모리에 적재하므로 대용량 처리 시 메모리 초과 위험이 있습니다. Generator 내부에서 try-catch로 예외를 처리하고, 처리된 마지막 레코드의 ID나 오프셋을 Redis나 DB에 저장하여 재시작 시 해당 지점부터 재개할 수 있습니다. Iterator 인터페이스를 구현하여 외부에서 send() 메서드로 제어 신호를 전달하거나, finally 블록에서 리소스 정리를 보장할 수 있습니다.
- • Generator는 yield로 데이터를 지연 생성하여 메모리 사용량을 O(1)로 유지
- • 배열 방식은 O(n) 메모리를 사용하며 대용량 데이터에서 메모리 부족 발생 가능
- • 체크포인트 패턴으로 마지막 처리 위치를 저장하여 재시작 지원
- • send()와 throw() 메서드로 Generator와 양방향 통신 가능
Generator를 사용할 때 발생할 수 있는 성능 오버헤드는 무엇이며, 어떤 경우에는 일반 배열 처리가 더 나을 수 있나요?
Q. MySQL에서 복합 인덱스(Composite Index)의 컬럼 순서가 쿼리 성능에 미치는 영향을 설명하고, Leftmost Prefix Rule의 개념과 동작 원리를 설명해주세요. 또한 WHERE, ORDER BY, GROUP BY 절이 혼합된 복잡한 쿼리에서 최적의 복합 인덱스를 설계하는 전략과 Index Condition Pushdown(ICP)이 성능에 미치는 영향을 설명해주세요.
복합 인덱스는 정의된 컬럼 순서대로 정렬되므로 첫 번째 컬럼부터 순차적으로 사용해야 인덱스를 활용할 수 있습니다. Leftmost Prefix Rule은 인덱스의 왼쪽 컬럼부터 연속적으로 사용된 조건만 인덱스를 탈 수 있다는 규칙입니다. 최적 설계는 카디널리티가 높은 컬럼을 앞에 배치하되, WHERE 절의 등호 조건 컬럼을 우선하고 범위 조건이나 ORDER BY 컬럼을 뒤에 배치합니다. ICP는 인덱스에 포함된 컬럼의 조건을 스토리지 엔진 레벨에서 필터링하여 테이블 액세스를 줄여 성능을 향상시킵니다.
- • Leftmost Prefix Rule: 인덱스 (A, B, C)는 A, (A,B), (A,B,C) 조건에만 사용 가능
- • WHERE 등호 조건 > WHERE 범위 조건 > ORDER BY 순으로 컬럼 배치
- • 카디널리티와 쿼리 패턴을 함께 고려한 인덱스 설계 필요
- • ICP는 MySQL 5.6+에서 불필요한 테이블 액세스를 줄여 성능 향상
복합 인덱스에서 Skip Scan 최적화는 무엇이며, MySQL에서 이를 활용할 수 있나요?
Q. PHP에서 비밀번호를 안전하게 해싱하기 위한 password_hash() 함수의 내부 동작 원리와 bcrypt 알고리즘의 cost factor가 보안성과 성능에 미치는 영향을 설명해주세요. 또한 Argon2i와 Argon2id의 차이점과 대규모 사용자 시스템에서 기존 bcrypt 해시를 Argon2로 마이그레이션하는 전략을 설명해주세요.
password_hash()는 기본적으로 bcrypt 알고리즘을 사용하며 자동으로 솔트를 생성하고 해시에 포함시킵니다. cost factor는 해싱 반복 횟수를 결정하며(2^cost), 값이 클수록 보안성은 높아지지만 CPU 사용량과 응답 시간이 증가합니다. Argon2i는 사이드채널 공격에 강하고, Argon2id는 타이밍 공격과 GPU 크래킹 모두에 강한 하이브리드 방식입니다. 마이그레이션은 로그인 시점에 기존 해시로 검증 후 성공하면 새로운 알고리즘으로 재해싱하는 점진적 방식을 사용하며, password_needs_rehash()로 업데이트 필요 여부를 판단합니다.
- • bcrypt의 cost factor는 10-12가 일반적이며, 하드웨어 성능에 따라 조정 필요
- • Argon2id는 메모리 하드 함수로 GPU 기반 공격에 더 강력한 저항성 제공
- • 점진적 마이그레이션으로 사용자 경험을 해치지 않고 보안 강화 가능
- • password_needs_rehash()로 알고리즘이나 cost 변경 시 자동 업데이트
대규모 시스템에서 로그인 시 해싱 연산으로 인한 CPU 부하를 분산시키기 위한 전략은 무엇이 있나요?
Q. RabbitMQ와 Kafka의 아키텍처 차이점을 설명하고, 각각의 메시지 전달 보장 방식(At-most-once, At-least-once, Exactly-once)을 비교해주세요. 또한 PHP 애플리케이션에서 이벤트 기반 아키텍처를 구현할 때 메시지 순서 보장, 중복 처리 방지, Dead Letter Queue 처리 전략을 실무 관점에서 설명해주세요.
RabbitMQ는 메시지 브로커로 라우팅과 큐 관리에 중점을 두며 메시지를 소비하면 삭제됩니다. Kafka는 분산 로그 시스템으로 메시지를 영구 저장하며 오프셋 기반으로 재처리가 가능합니다. RabbitMQ는 acknowledgment로 At-least-once를 보장하고, Kafka는 트랜잭션과 idempotent producer로 Exactly-once를 지원합니다. 메시지 순서는 단일 파티션/큐 사용이나 sequence number로 보장하고, 중복 방지는 idempotency key를 DB에 저장하여 처리합니다. DLQ는 재시도 횟수 초과나 처리 불가능한 메시지를 별도 큐로 라우팅하여 모니터링하고 수동 처리합니다.
- • RabbitMQ는 push 모델, Kafka는 pull 모델로 동작하며 처리량과 지연시간 특성이 다름
- • Exactly-once는 idempotent 연산 설계와 트랜잭션 처리가 필요
- • 메시지 순서 보장을 위해 파티셔닝 키나 단일 큐 전략 사용
- • DLQ와 재시도 메커니즘으로 장애 복구력 향상
PHP에서 장시간 실행되는 메시지 컨슈머 프로세스의 안정성을 보장하기 위한 모니터링과 자동 복구 전략은 무엇인가요?
Q. PHP에서 배열 함수(array_map, array_filter, array_reduce)와 반복문(foreach, for)의 성능 차이를 설명하고, 대용량 데이터 처리 시 어떤 방식을 선택해야 하는지 판단 기준을 제시해주세요. 또한 array_walk와 array_map의 차이점과 참조 전달을 사용한 메모리 최적화 방법을 설명해주세요.
배열 함수는 내부적으로 C로 구현되어 있어 일반적으로 PHP 반복문보다 빠르지만, 콜백 함수 호출 오버헤드가 있습니다. 단순 변환은 array_map이 빠르지만 복잡한 로직이나 조기 종료가 필요한 경우 foreach가 유리합니다. array_walk는 원본 배열을 참조로 수정하고 반환값이 boolean이며, array_map은 새 배열을 반환합니다. 대용량 데이터는 참조 전달(&$value)로 복사 오버헤드를 줄이고, 불필요한 중간 배열 생성을 피하기 위해 체이닝보다 단일 루프로 처리하는 것이 효율적입니다.
- • 배열 함수는 가독성이 좋지만 콜백 오버헤드 존재, 성능 크리티컬한 경우 foreach 고려
- • array_walk는 in-place 수정, array_map은 새 배열 생성으로 메모리 사용량 차이
- • 참조 전달(&)로 copy-on-write 방지하여 메모리 절약
- • 체이닝된 배열 함수는 중간 배열을 생성하므로 단일 루프로 통합 고려
PHP 8.0의 Named Arguments와 Array Unpacking을 활용하여 배열 처리 코드를 개선할 수 있는 방법은 무엇인가요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!