Rust로 Node.js Native Addon 만들어보기

문제 상황

이미지 처리 API에서 대량의 메타데이터를 파싱하고 변환하는 작업이 병목이었다. JavaScript로 처리하니 CPU 사용률은 높은데 처리 속도가 느렸다. 특히 10MB 이상의 JSON 파일을 다룰 때 응답 시간이 3초를 넘었다.

Rust + napi-rs 선택

C++로 작성하는 것도 고려했지만, napi-rs를 사용하면 Rust의 안전성과 성능을 모두 가져갈 수 있었다. 메모리 안정성이 컴파일 타임에 보장되는 점이 매력적이었다.

use napi::bindgen_prelude::*;
use serde_json::{Value, from_str};

#[napi]
pub fn parse_and_transform(json_str: String) -> Result<String> {
  let data: Value = from_str(&json_str)
    .map_err(|e| Error::from_reason(e.to_string()))?;
  
  // 변환 로직
  let transformed = transform_data(data);
  
  Ok(serde_json::to_string(&transformed)
    .map_err(|e| Error::from_reason(e.to_string()))?)
}

빌드 및 통합

Cargo.toml에 napi 의존성을 추가하고, package.json에 빌드 스크립트를 설정했다.

{
  "scripts": {
    "build:native": "napi build --platform --release"
  }
}

Node.js에서는 일반 모듈처럼 불러서 사용할 수 있다.

const { parseAndTransform } = require('./index.node');

const result = parseAndTransform(largeJsonString);

성과

  • 10MB JSON 파싱: 3.2초 → 0.9초
  • CPU 사용률은 비슷하지만 처리 시간 70% 단축
  • 메모리 사용량도 약간 감소

CI/CD 파이프라인에 각 플랫폼별 빌드를 추가하는 작업이 필요했지만, 성능 개선 효과가 확실해서 만족스러웠다. Rust 학습 곡선이 있지만, 성능이 중요한 부분에는 충분히 투자할 가치가 있다고 판단했다.