Node.js 시니어 종합 기술면접
새 면접Q. Node.js 애플리케이션에서 클러스터 모드로 여러 워커 프로세스를 실행할 때, 마스터 프로세스가 들어오는 연결을 워커들에게 분배하는 방식(Round-Robin vs Shared Socket)을 설명하고, 각 방식의 장단점을 비교해주세요. 또한 특정 세션을 동일한 워커로 라우팅해야 하는 Sticky Session이 필요한 경우 어떻게 구현하시겠습니까?
Node.js 클러스터는 두 가지 로드 밸런싱 방식을 제공합니다. Round-Robin 방식은 마스터가 연결을 받아 순차적으로 워커에게 분배하며, OS별 편차 없이 균등 분배가 가능하지만 마스터가 병목이 될 수 있습니다. Shared Socket 방식은 모든 워커가 같은 포트를 공유하며 OS 커널이 분배를 담당해 오버헤드가 적지만, OS에 따라 불균등 분배가 발생할 수 있습니다. Sticky Session은 nginx의 ip_hash나 HAProxy의 source 옵션을 사용하거나, 애플리케이션 레벨에서 Redis 기반 세션 저장소를 활용하여 모든 워커가 세션을 공유하도록 구현할 수 있습니다.
- • Round-Robin: 마스터가 연결을 순차 분배, 균등하지만 마스터 병목 가능
- • Shared Socket: OS 커널이 분배, 오버헤드 적지만 불균등 가능성
- • Sticky Session: 외부 로드밸런서 설정 또는 Redis 세션 공유로 구현
- • Windows는 기본적으로 Round-Robin, Linux는 Shared Socket 사용
PM2나 다른 프로세스 매니저를 사용할 때 클러스터 모드 대비 어떤 추가 기능을 활용할 수 있으며, 무중단 배포(Zero-Downtime Deployment)는 어떻게 구현하시겠습니까?
Q. 대규모 트래픽을 처리하는 Node.js 애플리케이션에서 데이터베이스 연결 풀(Connection Pool)의 크기를 결정하는 전략을 설명해주세요. 특히 PostgreSQL에서 권장하는 공식(connections = ((core_count * 2) + effective_spindle_count))의 의미와, Node.js의 비동기 특성을 고려할 때 연결 풀 크기 설정 시 주의해야 할 사항을 설명해주세요.
데이터베이스 연결 풀 크기는 CPU 코어 수와 디스크 특성을 기반으로 설정하는데, PostgreSQL 공식은 CPU 병렬 처리 능력과 디스크 I/O 동시성을 고려합니다. 하지만 Node.js는 비동기 I/O 모델로 단일 스레드가 많은 요청을 처리하므로, 전통적인 멀티스레드 애플리케이션보다 적은 연결로도 높은 처리량을 달성할 수 있습니다. 과도한 연결 풀은 DB 서버의 컨텍스트 스위칭과 메모리 오버헤드를 증가시키므로, 실제 동시 쿼리 수를 모니터링하고 점진적으로 증가시키며 최적값을 찾아야 합니다. 일반적으로 워커 프로세스당 10-20개 연결로 시작하여 병목 지점을 분석하며 조정하는 것이 좋습니다.
- • 전통 공식은 멀티스레드 환경 기준, Node.js는 비동기 특성상 더 적은 연결로 효율적
- • 과도한 연결은 DB 서버의 컨텍스트 스위칭과 메모리 낭비 유발
- • 실제 동시 쿼리 수 모니터링하여 점진적 조정 필요
- • 연결 획득 대기 시간, 쿼리 실행 시간, DB CPU 사용률을 종합 분석
Read Replica를 활용하는 환경에서 마스터와 레플리카 간 복제 지연(Replication Lag)이 발생할 때, 애플리케이션 레벨에서 데이터 정합성을 보장하기 위한 전략은 무엇이 있을까요?
Q. Node.js 애플리케이션에서 SQL Injection, NoSQL Injection, Command Injection 등 다양한 인젝션 공격의 차이점과 각각의 방어 방법을 설명해주세요. 특히 ORM/ODM을 사용하더라도 인젝션 공격에 취약할 수 있는 경우와, 사용자 입력 검증 시 화이트리스트 방식과 블랙리스트 방식 중 어느 것을 선택해야 하는지 근거와 함께 설명해주세요.
SQL Injection은 쿼리 문자열에 악의적인 SQL을 삽입하는 공격으로 Prepared Statement나 ORM의 파라미터 바인딩으로 방어합니다. NoSQL Injection은 MongoDB 등에서 객체 형태로 쿼리 연산자($where, $gt 등)를 주입하는 공격으로, 입력값의 타입 검증과 쿼리 객체 생성 시 연산자 필터링이 필요합니다. Command Injection은 child_process 등에서 시스템 명령어를 실행할 때 발생하므로, shell 옵션을 false로 설정하고 인수를 배열로 전달해야 합니다. ORM 사용 시에도 raw 쿼리나 동적 필드명 사용 시 취약할 수 있으며, 입력 검증은 허용된 값만 통과시키는 화이트리스트 방식이 우회 공격을 원천 차단할 수 있어 안전합니다.
- • SQL Injection: Prepared Statement, 파라미터 바인딩 사용
- • NoSQL Injection: 타입 검증, 쿼리 연산자 필터링, Object.create(null) 활용
- • Command Injection: shell 옵션 비활성화, 인수 배열 전달
- • 화이트리스트 방식이 블랙리스트보다 안전 - 알려지지 않은 공격 패턴 차단
OWASP Top 10에서 Insecure Deserialization 취약점이 Node.js 환경에서 어떻게 발생할 수 있으며, JSON.parse 외에 직렬화 라이브러리를 사용할 때 주의해야 할 보안 사항은 무엇인가요?
Q. Node.js 기반 이벤트 드리븐 아키텍처에서 메시지 큐(RabbitMQ, Kafka 등)를 도입할 때 At-Most-Once, At-Least-Once, Exactly-Once 전송 보장 수준의 차이를 설명하고, 각 수준을 구현하기 위한 전략을 설명해주세요. 특히 Exactly-Once 시맨틱을 구현할 때 멱등성(Idempotency) 보장이 왜 중요한지 설명해주세요.
At-Most-Once는 메시지를 한 번만 전송하고 확인 없이 삭제하여 손실 가능성이 있지만 중복은 없습니다. At-Least-Once는 메시지 처리 확인(ACK) 후 삭제하여 손실은 방지하지만 재전송으로 중복 가능성이 있습니다. Exactly-Once는 메시지가 정확히 한 번만 처리되도록 보장하는데, 분산 환경에서는 네트워크 장애나 프로세스 재시작으로 완벽한 구현이 어렵습니다. 따라서 At-Least-Once 전송에 애플리케이션 레벨에서 멱등성을 보장하여 중복 처리를 허용하되 결과는 동일하게 만드는 방식이 현실적입니다. 멱등성은 고유 메시지 ID를 DB에 저장하거나, 자연스럽게 멱등한 연산(SET 연산, 절대값 업데이트 등)을 사용하여 구현합니다.
- • At-Most-Once: 손실 가능, 중복 없음 / At-Least-Once: 손실 없음, 중복 가능
- • Exactly-Once: 이론적 보장, 실무에서는 At-Least-Once + 멱등성으로 구현
- • 멱등성: 동일 메시지 여러 번 처리해도 결과 동일하게 설계
- • 메시지 ID 기반 중복 제거 테이블, 트랜잭션 아웃박스 패턴 활용
Kafka의 파티션 리밸런싱 중에 메시지 처리 순서가 보장되지 않을 수 있는데, 순서 보장이 중요한 이벤트 스트림을 처리할 때 어떤 전략을 사용하시겠습니까?
Q. 프로덕션 환경의 Node.js 애플리케이션에서 관찰성(Observability)을 확보하기 위한 세 가지 핵심 요소인 Metrics, Logs, Traces의 역할과 차이점을 설명하고, 각각을 수집하고 분석하기 위한 도구와 전략을 제시해주세요. 특히 분산 트레이싱에서 Trace ID와 Span ID의 개념과, 마이크로서비스 간 컨텍스트 전파(Context Propagation) 방법을 설명해주세요.
Metrics는 시스템의 정량적 지표(CPU, 메모리, 요청 수, 응답 시간 등)를 시계열로 수집하여 전체적인 건강도를 파악하는 데 사용하며, Prometheus나 Datadog으로 수집합니다. Logs는 개별 이벤트의 상세 정보를 기록하여 문제의 원인을 분석하는 데 사용하며, ELK Stack이나 Loki로 중앙화합니다. Traces는 요청이 여러 서비스를 거치는 전체 경로를 추적하여 병목 지점을 식별하는 데 사용하며, Jaeger나 Zipkin으로 시각화합니다. 분산 트레이싱에서 Trace ID는 전체 요청 흐름을 식별하고, Span ID는 각 서비스 내 작업 단위를 식별하며, HTTP 헤더나 메시지 메타데이터를 통해 서비스 간 컨텍스트를 전파합니다.
- • Metrics: 시계열 수치 데이터, 시스템 전체 건강도 모니터링
- • Logs: 이벤트 상세 기록, 문제 원인 분석 및 디버깅
- • Traces: 분산 요청 경로 추적, 병목 지점 식별
- • Trace ID로 전체 요청 추적, Span ID로 개별 작업 식별, HTTP 헤더로 컨텍스트 전파
고부하 상황에서 모든 요청을 트레이싱하면 오버헤드가 크므로 샘플링을 적용해야 하는데, Head-based Sampling과 Tail-based Sampling의 차이와 각각의 장단점을 설명해주세요.
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!