Node.js 미드레벨 성능 최적화 면접

Node.js 미드레벨 (3~7년) 성능 최적화 5문항 조회수 53 · 2026-09-13 (일) 22:11:17
1 메모리 최적화
Medium

Q. Node.js 애플리케이션에서 대용량 CSV 파일(5GB)을 읽어 데이터베이스에 저장하는 배치 작업을 구현했는데, 메모리 사용량이 급증하며 OOM(Out of Memory) 에러가 발생합니다. 이 문제를 해결하기 위한 접근 방법과 Stream 기반 처리 시 고려해야 할 성능 최적화 포인트를 설명해주세요.

파일 전체를 메모리에 로드하는 방식과 청크 단위로 처리하는 방식의 차이를 생각해보세요.

A. 모범답안

fs.readFile 대신 fs.createReadStream을 사용하여 파일을 청크 단위로 읽고, csv-parser 같은 스트림 기반 파서와 조합합니다. 데이터베이스 삽입 시 개별 INSERT 대신 배치 삽입(bulk insert)을 사용하되, 메모리 제한을 고려해 적절한 배치 크기(예: 1000건)를 설정합니다. Transform 스트림을 활용해 데이터 변환 로직을 파이프라인에 추가하고, Backpressure를 적절히 처리하여 생산자-소비자 속도 차이를 관리합니다. highWaterMark 옵션을 조정해 내부 버퍼 크기를 최적화하고, pipeline 또는 stream.promises.pipeline을 사용해 에러 처리를 안전하게 구현합니다. 처리 중 메모리 사용량을 모니터링하여 process.memoryUsage()로 힙 사용량을 추적합니다.

핵심 포인트
  • • Stream 기반 처리로 메모리 사용량 제한
  • • 배치 삽입으로 데이터베이스 성능 향상
  • • Backpressure 처리로 안정적인 데이터 흐름 관리
  • • 적절한 청크 크기와 배치 크기 설정
답변에 넣으면 좋은 키워드
createReadStream Transform Stream Backpressure bulk insert highWaterMark pipeline
실무에서는

대용량 로그 파일 분석, ETL 파이프라인, 데이터 마이그레이션 작업에서 필수적으로 사용됩니다.

Follow-up 질문

배치 삽입 시 트랜잭션을 어떻게 관리하고, 중간에 실패했을 때 재시작 지점을 어떻게 추적할 수 있을까요?

2 API 응답 최적화
Medium

Q. Node.js REST API에서 사용자 목록 조회 API가 평균 2초 이상 소요되고 있습니다. 데이터베이스 쿼리 자체는 100ms인데, 응답 생성 과정에서 각 사용자마다 프로필 이미지 URL을 S3에서 생성하고 권한을 체크하는 작업이 순차적으로 실행되고 있습니다. 이 API의 응답 시간을 최적화하는 방법을 설명해주세요.

독립적인 비동기 작업들을 어떻게 처리하면 전체 실행 시간을 줄일 수 있을지 생각해보세요.

A. 모범답안

사용자별로 순차 실행되는 S3 URL 생성과 권한 체크를 Promise.all을 사용해 병렬로 처리합니다. 100명의 사용자가 있다면 순차 처리 시 200초가 걸리지만 병렬 처리하면 최대 2초로 단축됩니다. S3 presigned URL은 TTL이 있으므로 짧은 시간 동안 Redis에 캐싱하여 동일한 요청에 대한 반복 생성을 방지합니다. 권한 체크 로직도 사용자 역할별로 캐싱 가능하다면 메모리 캐시를 적용합니다. 또한 페이지네이션을 구현하여 한 번에 조회하는 사용자 수를 제한하고, 필요한 필드만 SELECT하여 데이터 전송량을 줄입니다. API 응답을 압축(compression 미들웨어)하여 네트워크 전송 시간도 개선합니다.

핵심 포인트
  • • Promise.all로 독립적인 비동기 작업 병렬 처리
  • • S3 URL과 권한 체크 결과 캐싱
  • • 페이지네이션으로 데이터량 제한
  • • 응답 압축으로 네트워크 전송 최적화
답변에 넣으면 좋은 키워드
Promise.all 병렬 처리 Redis 캐싱 pagination compression presigned URL
실무에서는

대시보드 API, 목록 조회 API 등 여러 외부 리소스를 조합하는 엔드포인트에서 흔히 발생하는 성능 문제입니다.

Follow-up 질문

Promise.all 대신 Promise.allSettled를 사용해야 하는 경우는 언제이며, 일부 사용자의 권한 체크가 실패했을 때 어떻게 처리해야 할까요?

3 데이터베이스 연결 최적화
Hard

Q. Node.js 애플리케이션에서 트래픽이 급증하는 시간대에 데이터베이스 연결 풀이 부족해져서 'Too many connections' 에러가 발생합니다. 연결 풀 크기를 무작정 늘리는 것 외에 근본적으로 이 문제를 해결하고 연결 효율을 높이는 방법을 설명해주세요.

연결이 오래 점유되는 원인과 불필요하게 연결을 사용하는 패턴을 찾아보세요.

A. 모범답안

먼저 Long-running 쿼리를 식별하여 최적화하고, 트랜잭션 범위를 최소화하여 연결 점유 시간을 줄입니다. API 핸들러에서 데이터베이스 연결을 획득한 후 외부 API 호출이나 파일 처리 같은 I/O 작업을 하면 연결이 불필요하게 점유되므로, 연결이 필요한 구간만 트랜잭션으로 묶습니다. 읽기 전용 쿼리는 Read Replica로 분산하여 Master DB 연결 부담을 줄이고, 자주 조회되는 데이터는 Redis 같은 캐시 레이어를 추가해 데이터베이스 쿼리 자체를 줄입니다. 연결 풀 설정에서 acquireTimeout, idleTimeoutMillis를 적절히 조정하고, 연결 누수를 방지하기 위해 모든 쿼리 후 반드시 연결을 반환하는지 확인합니다. 애플리케이션 인스턴스가 여러 개라면 전체 연결 수가 데이터베이스 max_connections를 초과하지 않도록 계산하여 인스턴스당 풀 크기를 설정합니다.

핵심 포인트
  • • 트랜잭션 범위 최소화로 연결 점유 시간 단축
  • • Read Replica 활용으로 연결 분산
  • • 캐싱으로 데이터베이스 쿼리 횟수 감소
  • • 연결 풀 설정 최적화 및 연결 누수 방지
답변에 넣으면 좋은 키워드
Connection Pool Read Replica 트랜잭션 범위 acquireTimeout 연결 누수 Long-running query
실무에서는

트래픽이 많은 서비스에서 데이터베이스 연결 관리는 안정성과 직결되는 핵심 성능 이슈입니다.

Follow-up 질문

Sequelize나 TypeORM에서 연결 풀 메트릭을 모니터링하는 방법과, 연결 누수를 디버깅하는 구체적인 방법을 설명해주세요.

4 캐싱 전략
Medium

Q. Node.js 전자상거래 서비스에서 상품 상세 정보 API가 초당 1000건 이상 호출되어 데이터베이스 부하가 높습니다. Redis를 사용한 캐싱을 도입하려고 하는데, 상품 정보가 관리자에 의해 수시로 업데이트될 수 있는 상황입니다. 캐시 일관성을 유지하면서 성능을 최적화하는 전략과 캐시 무효화 방법을 설명해주세요.

캐시 갱신 시점과 TTL 설정, 그리고 업데이트 이벤트를 활용하는 방법을 고려해보세요.

A. 모범답안

Cache-Aside 패턴을 기본으로 사용하되, 상품 정보 조회 시 Redis에서 먼저 확인하고 없으면 데이터베이스에서 조회 후 캐싱합니다. TTL은 5~10분 정도로 설정하여 장시간 stale 데이터가 서빙되는 것을 방지합니다. 상품 정보가 업데이트될 때는 해당 상품의 캐시 키를 명시적으로 삭제(Cache Invalidation)하여 다음 조회 시 최신 데이터가 캐싱되도록 합니다. 동시성 문제를 방지하기 위해 캐시 갱신 시 Redis의 SET NX 또는 Redlock 같은 분산 락을 활용합니다. 캐시 키 설계는 product:id:상품ID 형태로 명확하게 하고, 관련된 여러 캐시를 무효화해야 한다면 태그 기반 무효화나 pub/sub을 활용합니다. 캐시 hit rate를 모니터링하여 효과를 측정하고, Thundering Herd 문제를 방지하기 위해 캐시 만료 시간에 랜덤 jitter를 추가합니다.

핵심 포인트
  • • Cache-Aside 패턴과 적절한 TTL 설정
  • • 업데이트 시 명시적 캐시 무효화
  • • 분산 락으로 동시성 제어
  • • Thundering Herd 방지를 위한 jitter 적용
답변에 넣으면 좋은 키워드
Cache-Aside Cache Invalidation TTL Redis Thundering Herd 분산 락
실무에서는

읽기가 많고 쓰기가 적은 데이터(상품 정보, 사용자 프로필 등)를 다루는 대부분의 웹 서비스에서 필수적입니다.

Follow-up 질문

여러 서버 인스턴스에서 동시에 같은 상품을 업데이트할 때 캐시 무효화 이벤트를 모든 인스턴스에 전파하는 방법은 무엇인가요?

5 부하 테스트 및 모니터링
Hard

Q. Node.js API 서버를 프로덕션에 배포하기 전에 성능 테스트를 진행하려고 합니다. 목표는 초당 500 RPS를 안정적으로 처리하는 것인데, 어떤 도구와 메트릭을 사용해 부하 테스트를 수행하고, 어떤 지표들을 기준으로 성능 병목을 진단하며, 프로덕션 환경에서 지속적으로 모니터링해야 할 핵심 메트릭은 무엇인지 설명해주세요.

부하 테스트 도구 선택, 측정할 메트릭, 그리고 병목 지점 파악 방법을 단계별로 생각해보세요.

A. 모범답안

부하 테스트는 Artillery, k6, Apache JMeter 같은 도구를 사용하며, 점진적으로 부하를 증가시키는 ramp-up 테스트와 지속 부하 테스트를 모두 수행합니다. 측정할 핵심 메트릭은 응답 시간(p50, p95, p99), 처리량(RPS), 에러율, CPU/메모리 사용률입니다. 응답 시간이 급증하는 지점을 찾아 병목을 식별하고, Node.js의 Event Loop Lag을 측정하여 이벤트 루프가 블로킹되는지 확인합니다. 데이터베이스 연결 풀 사용률, 활성 연결 수, 슬로우 쿼리를 모니터링하여 DB 병목을 파악합니다. 프로덕션에서는 APM 도구(New Relic, DataDog, Elastic APM)를 사용해 실시간 메트릭을 수집하고, 알림 임계값을 설정합니다. 특히 메모리 누수 감지를 위해 힙 사용량 추이를 추적하고, 가비지 컬렉션 빈도와 pause time을 모니터링합니다. 로그 집계(ELK Stack)를 통해 에러 패턴을 분석하고, 분산 추적(Distributed Tracing)으로 마이크로서비스 간 지연을 파악합니다.

핵심 포인트
  • • Artillery, k6 같은 도구로 점진적 부하 테스트 수행
  • • 응답 시간(p95, p99), RPS, 에러율, Event Loop Lag 측정
  • • 데이터베이스 연결 풀과 슬로우 쿼리 모니터링
  • • APM 도구로 실시간 메트릭 수집 및 알림 설정
답변에 넣으면 좋은 키워드
Artillery k6 p95/p99 Event Loop Lag APM Distributed Tracing 슬로우 쿼리
실무에서는

서비스 출시 전 성능 검증과 트래픽 증가에 대비한 용량 계획 수립에 필수적입니다.

Follow-up 질문

부하 테스트 중 CPU는 50%인데 응답 시간이 급증한다면 어떤 원인들을 의심해볼 수 있나요?

댓글 0

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

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