Laravel 미드레벨 CS 기초 기술면접
새 면접Q. MySQL에서 인덱스의 자료구조로 B-Tree와 Hash가 사용됩니다. 각각의 동작 원리와 장단점을 설명하고, WHERE 조건에 LIKE '%keyword%', LIKE 'keyword%', = 'exact' 가 각각 사용될 때 어떤 인덱스가 효율적인지 설명해주세요. Laravel에서 마이그레이션으로 인덱스를 생성할 때 고려해야 할 사항도 함께 설명해주세요.
B-Tree는 정렬된 트리 구조로 범위 검색과 정렬에 유리하며, Hash는 해시 함수를 사용해 동등 비교에 최적화되어 있습니다. LIKE '%keyword%'는 전체 스캔이 필요해 인덱스를 사용할 수 없고, LIKE 'keyword%'는 B-Tree 인덱스의 범위 검색으로 활용 가능하며, = 'exact'는 두 인덱스 모두 효율적이지만 B-Tree가 범용적입니다. Laravel 마이그레이션에서는 카디널리티가 높은 컬럼에 인덱스를 생성하고, 복합 인덱스의 경우 WHERE 조건에서 자주 사용되는 순서대로 컬럼을 배치해야 하며, 인덱스가 과도하면 INSERT/UPDATE 성능이 저하되므로 실제 쿼리 패턴을 분석해 선택적으로 적용해야 합니다.
- • B-Tree는 범위 검색과 정렬에 유리하고, Hash는 동등 비교에 최적화
- • LIKE 'keyword%'만 인덱스 활용 가능, '%keyword%'는 전체 스캔 필요
- • 복합 인덱스는 컬럼 순서가 중요하며, 카디널리티와 쿼리 패턴 고려 필요
- • 과도한 인덱스는 쓰기 성능을 저하시킴
커버링 인덱스(Covering Index)란 무엇이며, Laravel Eloquent 쿼리에서 이를 활용하는 방법과 성능 개선 효과를 설명해주세요.
Q. HTTP/1.1, HTTP/2, HTTP/3의 주요 차이점을 설명하고, 각 버전에서 해결하려고 했던 성능 문제를 설명해주세요. 특히 Head-of-Line Blocking 문제가 무엇이며, 각 버전에서 어떻게 해결되었는지 설명해주세요. Laravel API 서버에서 HTTP/2를 활용할 때 얻을 수 있는 이점은 무엇인가요?
HTTP/1.1은 요청마다 새로운 TCP 연결이 필요해 오버헤드가 크고, Keep-Alive로 개선했지만 HOL Blocking이 발생합니다. HTTP/2는 멀티플렉싱으로 하나의 TCP 연결에서 여러 요청을 동시에 처리하고 서버 푸시를 지원하지만, TCP 레벨의 HOL Blocking은 여전히 존재합니다. HTTP/3는 UDP 기반의 QUIC 프로토콜을 사용해 TCP HOL Blocking을 완전히 해결하고 연결 수립 시간을 단축합니다. Laravel API에서 HTTP/2를 사용하면 여러 리소스를 병렬로 전송할 수 있어 모바일 환경이나 레이턴시가 높은 환경에서 성능이 개선되며, 헤더 압축으로 대역폭도 절약됩니다.
- • HTTP/1.1은 연결당 하나의 요청만 처리해 HOL Blocking 발생
- • HTTP/2는 멀티플렉싱으로 애플리케이션 레벨 HOL Blocking 해결
- • HTTP/3는 QUIC(UDP)으로 TCP 레벨 HOL Blocking까지 해결
- • Laravel API에서 HTTP/2 사용 시 병렬 전송과 헤더 압축으로 성능 개선
Laravel에서 API 응답 시간을 측정하고 최적화하기 위해 어떤 도구와 방법을 사용할 수 있으며, Server Timing API를 활용한 성능 모니터링 전략을 설명해주세요.
Q. 운영체제에서 프로세스와 스레드의 차이를 메모리 구조 관점에서 설명하고, 컨텍스트 스위칭 비용이 왜 다른지 설명해주세요. PHP-FPM과 Laravel Octane(Swoole/RoadRunner)의 동작 방식을 프로세스/스레드 관점에서 비교하고, 각각의 메모리 관리와 성능 특성을 설명해주세요. 멀티 스레드 환경에서 발생할 수 있는 문제점과 Laravel에서의 해결 방법도 함께 설명해주세요.
프로세스는 독립적인 메모리 공간(Code, Data, Heap, Stack)을 가지며, 스레드는 같은 프로세스 내에서 Code, Data, Heap을 공유하고 Stack만 독립적으로 가집니다. 컨텍스트 스위칭 시 프로세스는 전체 메모리 맵을 교체해야 하지만 스레드는 레지스터와 스택만 교체하면 되어 비용이 낮습니다. PHP-FPM은 각 요청마다 별도 프로세스를 사용해 메모리 격리가 완벽하지만 부트스트래핑 오버헤드가 크고, Laravel Octane은 장기 실행 프로세스로 애플리케이션을 메모리에 유지하며 워커 스레드로 요청을 처리해 성능이 높지만 메모리 누수와 전역 상태 오염에 주의해야 합니다. Octane에서는 요청 간 싱글톤 객체 초기화, 정적 변수 리셋, 데이터베이스 연결 관리를 명시적으로 처리해야 합니다.
- • 프로세스는 독립 메모리 공간, 스레드는 Code/Data/Heap 공유
- • 스레드 컨텍스트 스위칭이 프로세스보다 가벼움
- • PHP-FPM은 프로세스 격리로 안전하지만 느리고, Octane은 빠르지만 상태 관리 필요
- • Octane에서는 메모리 누수, 전역 상태 오염, 싱글톤 초기화 문제 해결 필요
Laravel Octane 환경에서 메모리 누수를 탐지하고 디버깅하는 방법과, 장기 실행 프로세스에서 안전하게 싱글톤 객체를 관리하는 패턴을 설명해주세요.
Q. 데이터베이스 트랜잭션의 격리 수준(Isolation Level) 4가지를 설명하고, 각 수준에서 발생할 수 있는 문제(Dirty Read, Non-Repeatable Read, Phantom Read)를 설명해주세요. MySQL InnoDB의 기본 격리 수준과 MVCC(Multi-Version Concurrency Control) 동작 원리를 설명하고, Laravel에서 특정 트랜잭션에 대해 격리 수준을 변경해야 하는 실무 상황과 구현 방법을 제시해주세요.
Read Uncommitted는 커밋되지 않은 데이터를 읽을 수 있어 Dirty Read가 발생하고, Read Committed는 커밋된 데이터만 읽지만 Non-Repeatable Read가 발생하며, Repeatable Read는 트랜잭션 시작 시점의 스냅샷을 유지해 Phantom Read가 발생할 수 있고, Serializable은 모든 문제를 방지하지만 성능이 낮습니다. MySQL InnoDB는 Repeatable Read를 기본으로 사용하며, MVCC를 통해 각 트랜잭션에 고유 ID를 부여하고 언두 로그에 이전 버전을 저장해 읽기와 쓰기가 블로킹되지 않도록 합니다. Laravel에서는 재고 차감처럼 정확한 데이터가 중요한 경우 DB::transaction() 내에서 DB::statement('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE')로 격리 수준을 높이거나, SELECT FOR UPDATE로 비관적 락을 사용합니다.
- • 격리 수준: Read Uncommitted < Read Committed < Repeatable Read < Serializable
- • Dirty Read, Non-Repeatable Read, Phantom Read는 격리 수준에 따라 발생
- • InnoDB는 MVCC로 Repeatable Read를 구현하며 읽기/쓰기 동시성 제공
- • Laravel에서 격리 수준 변경이나 SELECT FOR UPDATE로 동시성 제어 가능
낙관적 락(Optimistic Locking)과 비관적 락(Pessimistic Locking)의 차이를 설명하고, Laravel Eloquent에서 각각을 구현하는 방법과 적합한 사용 시나리오를 제시해주세요.
Q. Big-O 표기법에서 O(1), O(log n), O(n), O(n log n), O(n²)의 시간복잡도를 가지는 대표적인 알고리즘과 자료구조 연산을 각각 설명해주세요. Laravel Collection에서 제공하는 메서드들(first, search, filter, sort, unique)의 시간복잡도를 분석하고, 대용량 데이터 처리 시 성능을 개선하기 위해 어떤 자료구조나 알고리즘으로 대체할 수 있는지 설명해주세요.
O(1)은 배열 인덱스 접근이나 해시 테이블 조회, O(log n)은 이진 탐색이나 균형 트리 탐색, O(n)은 배열 순회나 선형 탐색, O(n log n)은 병합 정렬이나 퀵 정렬, O(n²)은 버블 정렬이나 중첩 반복문이 해당합니다. Laravel Collection의 first는 O(1), search는 O(n), filter는 O(n), sort는 O(n log n), unique는 O(n²)(내부적으로 in_array 사용)입니다. 대용량 데이터에서는 search를 Redis나 Elasticsearch로 대체하고, unique는 배열을 해시 테이블(array_flip)로 변환해 O(n)으로 개선하며, 정렬된 데이터가 필요하면 데이터베이스 레벨에서 ORDER BY와 인덱스를 활용해야 합니다.
- • 시간복잡도: O(1) < O(log n) < O(n) < O(n log n) < O(n²)
- • Collection 메서드는 대부분 O(n) 이상이며 대용량 데이터에 비효율적
- • unique는 O(n²)이므로 해시 테이블로 O(n) 개선 가능
- • 대용량 처리는 DB 레벨 최적화, Redis, Elasticsearch 활용 필요
Laravel에서 10만 건 이상의 데이터를 필터링하고 정렬해야 할 때, Collection을 사용하는 것과 Eloquent 쿼리를 사용하는 것의 성능 차이를 메모리와 CPU 관점에서 비교하고, 최적의 접근 방법을 제시해주세요.
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!