Rust로 Node.js Native Addon 만들어보기
배경
이미지 리사이징 서비스에서 대량의 썸네일을 생성하는 작업이 있었다. Sharp 라이브러리를 사용했지만, 특정 필터 처리 로직이 순수 JavaScript로 구현되어 있어 느렸다. C++로 작성할까 고민하다가 최근 관심있던 Rust를 시도해봤다.
Neon 설치
npm install -g neon-cli
neon new image-processor
Neon은 Rust로 Node.js Native Addon을 만들 수 있게 해주는 바인딩 라이브러리다. 기존 C++ Addon보다 메모리 안전성을 보장받을 수 있다는 점이 매력적이었다.
Rust 코드 작성
use neon::prelude::*;
fn process_pixels(mut cx: FunctionContext) -> JsResult<JsNumber> {
let buffer = cx.argument::<JsBuffer>(0)?;
let width = cx.argument::<JsNumber>(1)?.value() as usize;
let height = cx.argument::<JsNumber>(2)?.value() as usize;
let data = cx.borrow(&buffer, |data| {
data.as_slice::<u8>()
});
// 픽셀 처리 로직
let result = apply_filter(data, width, height);
Ok(cx.number(result as f64))
}
register_module!(mut cx, {
cx.export_function("processPixels", process_pixels)
});
벤치마크 결과
- Pure JS: 1,240ms
- Sharp (C++): 180ms
- Rust Addon: 165ms
성능은 C++ 수준으로 나왔고, 코드는 훨씬 안전하게 작성할 수 있었다. 다만 빌드 시간이 길고, neon-cli의 성숙도가 아직 낮다는 점이 아쉬웠다.
소감
Rust 자체의 러닝커브는 예상보다 높았다. Ownership과 Lifetime 개념이 익숙해지는데 시간이 걸렸다. 프로덕션 적용은 조금 더 고민이 필요하지만, 성능이 중요한 부분에서는 충분히 고려할만한 선택지라고 판단했다.