Next.js 리드·아키텍트 CS 기초 면접
새 면접Q. Next.js 서버에서 대용량 파일 업로드 처리 시 메모리 부족으로 프로세스가 종료되는 문제가 발생했습니다. Virtual Memory의 Page Fault 메커니즘과 Thrashing 현상을 설명하고, Node.js의 V8 힙 메모리 제약과 Buffer 메모리의 차이를 비교한 후, Stream 기반 처리로 메모리 사용량을 제어하는 원리와 백프레셔(Backpressure) 처리 전략을 제시해주세요.
가상 메모리 시스템에서 물리 메모리와 디스크 스왑 간의 페이지 이동과, Node.js에서 힙 외부 메모리를 다루는 방식을 고려해보세요.
Page Fault는 프로세스가 접근하려는 페이지가 물리 메모리에 없을 때 발생하며, OS가 디스크에서 해당 페이지를 로드합니다. Thrashing은 페이지 교체가 너무 빈번하게 발생해 실제 작업보다 페이징에 더 많은 시간을 소비하는 현상입니다. V8 힙은 JavaScript 객체를 위한 메모리로 --max-old-space-size로 제한되지만, Buffer는 힙 외부 메모리를 사용해 대용량 바이너리 데이터를 처리합니다. Stream은 데이터를 청크 단위로 처리해 전체 파일을 메모리에 적재하지 않으며, Readable Stream의 버퍼가 가득 차면 pause 이벤트로 읽기를 중단하고 Writable Stream이 drain 이벤트를 발생시킬 때 재개하는 백프레셔 메커니즘으로 메모리를 제어합니다. 실무에서는 pipeline API로 스트림을 연결하고 highWaterMark 옵션으로 버퍼 크기를 조정합니다.
- • Page Fault와 Thrashing의 메커니즘 이해
- • V8 힙 메모리와 Buffer의 메모리 영역 차이
- • Stream 기반 청크 처리로 메모리 사용량 분산
- • Backpressure를 통한 메모리 흐름 제어
대용량 파일 업로드, 비디오 트랜스코딩, 로그 파일 분석 등 메모리 제약이 있는 서버 환경에서 스트림 기반 처리가 필수적입니다.
대용량 파일 업로드 시 multipart/form-data 파싱 과정에서 메모리 사용량을 제어하기 위해 busboy 같은 스트리밍 파서를 사용할 때, 동시 업로드 수 제한과 Rate Limiting을 어떻게 설계하시겠습니까?
Q. Next.js 기반 실시간 협업 에디터에서 수백만 개의 문서 블록을 ID로 빠르게 조회하고 업데이트해야 합니다. 해시 테이블의 충돌 해결 방법인 Chaining과 Open Addressing(Linear Probing, Quadratic Probing, Double Hashing)의 동작 원리와 시간 복잡도를 비교하고, Load Factor가 성능에 미치는 영향을 설명한 후, JavaScript Map 객체와 일반 Object의 내부 구현 차이와 대용량 데이터 처리 시 선택 기준을 제시해주세요.
충돌 발생 시 체인을 따라가는 방식과 다른 빈 슬롯을 찾는 방식의 캐시 지역성과 메모리 사용 패턴을 비교해보세요.
Chaining은 충돌 시 연결 리스트로 연결하며 평균 O(1), 최악 O(n)이고, Open Addressing은 충돌 시 다른 빈 슬롯을 탐사하며 Linear Probing은 순차 탐색으로 클러스터링 문제가 있고, Quadratic Probing은 i² 간격으로 탐사하며, Double Hashing은 두 번째 해시 함수로 간격을 결정합니다. Load Factor가 0.7을 초과하면 충돌이 급증해 재해싱이 필요하며, Open Addressing은 캐시 지역성이 좋지만 삭제 시 tombstone 처리가 필요합니다. JavaScript Map은 해시 테이블로 구현되어 삽입 순서를 보장하고 모든 타입을 키로 사용할 수 있지만, Object는 프로토타입 체인을 가지며 문자열/Symbol만 키로 사용하고 속성 순서가 정의되지 않았습니다. 대용량 데이터에서는 Map이 메모리 효율과 성능이 우수하며, 특히 빈번한 추가/삭제 시 Object보다 빠릅니다.
- • Chaining과 Open Addressing의 충돌 해결 메커니즘
- • Load Factor와 재해싱의 성능 영향
- • 캐시 지역성과 클러스터링 트레이드오프
- • Map과 Object의 내부 구현 및 사용 사례 차이
실시간 협업 도구, 인메모리 캐시, 세션 스토어 등에서 빠른 키-값 조회와 대용량 데이터 처리가 필요한 상황에서 활용됩니다.
협업 에디터에서 Operational Transformation이나 CRDT를 구현할 때, 버전 벡터나 타임스탬프를 해시 키로 사용하는 경우 해시 함수 선택과 충돌 최소화 전략을 어떻게 설계하시겠습니까?
Q. Next.js 서버에서 CPU 집약적인 이미지 처리 작업과 I/O 집약적인 API 요청이 혼재된 환경을 운영 중입니다. OS의 프로세스 스케줄링 알고리즘인 FCFS, SJF, Round Robin, Priority Scheduling의 특성과 Convoy Effect, Starvation 문제를 설명하고, Node.js의 이벤트 루프에서 CPU 집약적 작업이 I/O 작업을 블로킹하는 원리를 분석한 후, Worker Threads와 Child Process를 활용한 작업 분리 전략과 우선순위 큐 기반 작업 스케줄링 설계 방안을 제시해주세요.
CPU 바운드 작업이 이벤트 루프를 독점하는 문제와, 멀티 프로세스/스레드 환경에서 작업을 분산하는 방식을 고려해보세요.
FCFS는 도착 순서대로 처리하지만 긴 작업이 짧은 작업을 지연시키는 Convoy Effect가 발생하고, SJF는 실행 시간이 짧은 작업을 우선 처리하지만 긴 작업이 무한 대기하는 Starvation이 발생할 수 있으며, Round Robin은 타임 슬라이스로 공평하게 분배하고, Priority Scheduling은 우선순위가 높은 작업을 먼저 처리하지만 Aging 기법으로 Starvation을 방지합니다. Node.js는 싱글 스레드 이벤트 루프로 동작하므로 CPU 집약적 작업이 이벤트 루프를 점유하면 I/O 콜백 처리가 지연됩니다. Worker Threads는 별도 V8 인스턴스에서 CPU 작업을 실행하고 메시지 패싱으로 통신하며, Child Process는 완전히 독립된 프로세스로 격리되지만 IPC 오버헤드가 있습니다. 실무에서는 Bull 같은 작업 큐에 우선순위를 설정하고, CPU 작업은 Worker Pool로 분산하며, I/O 작업은 메인 스레드에서 비동기로 처리하는 하이브리드 전략을 사용합니다.
- • 스케줄링 알고리즘별 Convoy Effect와 Starvation 이해
- • Node.js 싱글 스레드의 CPU 집약 작업 블로킹 메커니즘
- • Worker Threads와 Child Process의 격리 수준과 통신 방식
- • 우선순위 큐와 작업 분산을 통한 스케줄링 최적화
이미지/비디오 처리, PDF 생성, 데이터 집계 등 CPU 집약적 작업과 API 요청을 동시에 처리하는 서버에서 성능 최적화에 활용됩니다.
이미지 처리 작업을 Worker Pool로 분산할 때, 워커 수를 CPU 코어 수에 맞춰 설정하는 것과 오버프로비저닝하는 것의 트레이드오프를 설명하고, 동적으로 워커 수를 조정하는 전략을 제시해주세요.
Q. Next.js 애플리케이션에서 WebSocket 연결이 모바일 네트워크 환경에서 자주 끊어지는 문제가 발생했습니다. TCP의 3-way Handshake와 4-way Handshake 과정을 설명하고, NAT 환경에서 Keep-Alive 패킷의 역할과 타임아웃 설정이 연결 유지에 미치는 영향을 분석한 후, WebSocket over HTTP/2와 HTTP/3(QUIC)의 차이점을 비교하고, 불안정한 네트워크에서 재연결 전략과 Exponential Backoff 알고리즘을 설계해주세요.
TCP 연결 수립과 종료 과정에서 상태 전이와, NAT 타임아웃으로 인한 연결 끊김, 그리고 상위 프로토콜의 재연결 메커니즘을 고려해보세요.
TCP 3-way Handshake는 SYN, SYN-ACK, ACK 패킷으로 연결을 수립하고, 4-way Handshake는 FIN, ACK, FIN, ACK로 연결을 종료하며 TIME_WAIT 상태로 패킷 지연을 처리합니다. NAT는 일정 시간 동안 패킷이 없으면 매핑 테이블을 삭제하므로, TCP Keep-Alive는 주기적으로 빈 패킷을 보내 연결을 유지하며, 타임아웃이 NAT 타임아웃보다 짧아야 합니다. WebSocket over HTTP/2는 단일 TCP 연결에서 멀티플렉싱되지만 Head-of-Line Blocking이 발생하고, HTTP/3는 QUIC 프로토콜로 UDP 기반이라 패킷 손실 시 독립적으로 재전송되며 연결 마이그레이션을 지원합니다. 재연결 전략은 Exponential Backoff로 재시도 간격을 2배씩 증가시키고(1초, 2초, 4초), Jitter를 추가해 동시 재연결을 분산하며, 최대 재시도 횟수와 최대 대기 시간을 설정합니다.
- • TCP 연결 수립/종료 과정과 상태 전이
- • NAT 환경에서 Keep-Alive의 연결 유지 역할
- • HTTP/2와 HTTP/3의 멀티플렉싱과 재전송 메커니즘
- • Exponential Backoff와 Jitter를 활용한 재연결 전략
실시간 채팅, 주식 거래, 멀티플레이어 게임 등 지속적인 양방향 통신이 필요하고 네트워크 환경이 불안정한 모바일 앱에서 활용됩니다.
모바일 앱에서 네트워크가 Wi-Fi에서 LTE로 전환될 때 WebSocket 연결이 끊어지는데, HTTP/3의 Connection Migration 기능을 활용하면 어떻게 끊김 없는 전환이 가능한지 설명해주세요.
Q. Next.js API에서 수천만 건의 주문 데이터를 다루는데, 복합 조건 쿼리(날짜 범위 + 상태 + 사용자 ID)의 성능이 저하되고 있습니다. B+Tree 인덱스의 구조와 범위 검색에 유리한 이유를 설명하고, 복합 인덱스의 컬럼 순서가 쿼리 성능에 미치는 영향과 Index Skip Scan의 동작 원리를 분석한 후, Covering Index와 Include 컬럼을 활용한 최적화 전략과, 인덱스 유지 비용(쓰기 성능 저하, 스토리지 증가)을 고려한 인덱스 설계 원칙을 제시해주세요.
B+Tree의 리프 노드 연결 구조와, 복합 인덱스의 최좌측 컬럼부터 매칭되는 특성, 그리고 인덱스만으로 쿼리를 완성하는 방법을 고려해보세요.
B+Tree는 모든 데이터가 정렬된 리프 노드에 저장되고 리프 노드가 연결 리스트로 연결되어 범위 검색 시 순차 스캔이 가능하며, 내부 노드는 키만 저장해 메모리 효율이 높습니다. 복합 인덱스는 최좌측 컬럼부터 순서대로 정렬되므로, WHERE 절이 인덱스 컬럼 순서와 일치해야 효율적이며, Index Skip Scan은 선행 컬럼의 카디널리티가 낮을 때 중간 컬럼을 건너뛰고 검색합니다. Covering Index는 쿼리에 필요한 모든 컬럼을 인덱스에 포함시켜 테이블 접근 없이 인덱스만으로 결과를 반환하며, PostgreSQL의 INCLUDE 절이나 MySQL의 복합 인덱스로 구현합니다. 인덱스는 INSERT/UPDATE/DELETE 시 유지 비용이 발생하므로, 쿼리 빈도와 성능 향상을 측정해 선택적으로 생성하고, 사용되지 않는 인덱스는 주기적으로 제거하며, 쓰기가 많은 테이블은 인덱스를 최소화합니다.
- • B+Tree의 리프 노드 연결과 범위 검색 최적화
- • 복합 인덱스의 컬럼 순서와 Index Skip Scan
- • Covering Index로 테이블 접근 제거
- • 인덱스 유지 비용과 선택적 인덱스 설계
대용량 트랜잭션 데이터, 로그 분석, 검색 기능 등에서 복잡한 조건의 쿼리 성능을 최적화하고 인덱스 전략을 설계하는 데 활용됩니다.
주문 테이블에서 날짜 범위 조회가 대부분이고 상태 필터는 선택적일 때, (created_at, status, user_id) 순서의 복합 인덱스와 (status, created_at, user_id) 순서 중 어느 것이 더 효율적인지 설명하고, Partial Index를 활용한 대안을 제시해주세요.
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!