Node.js에서 FFI로 Rust를 이용해보자

소개

Rust는 성능이 우수한 로우 레벨 프로그래밍 언어 중 하나입니다. 또한, 비용 없는 추상화, 메모리 안정성, 데이터 레이스 없는 스레딩 등등을 지원하며 C++에 비해 문법도 간결합니다. 이러한 장점의 Rust를 Node와 결합시켜 사용한다면, Node의 부족한 성능을 메꿀 수 있습니다. Node에서 Rust에서 작성한 함수를 호출하기 위해서는 FFI(Foreign function interface, 외부 함수 인터페이스)를 사용해야 합니다. 아래는 준비물입니다.

준비물

시작하기

우선 Node 프로젝트를 생성합시다.

npm init

FFI를 이용하기 위해서는 아래와 같은 패키지를 설치해야 합니다.

npm install node-gyp
npm install ffi

Node 패키지가 설치되었으면, Rust 프로젝트를 생성합니다.

cargo new --lib project_name

그리고 Cargo.tomlcrate-type=["dylib"]를 추가합니다.

[lib]
name="filename"
crate-type=["dylib"]

이제 기본적인 세팅이 완료되었습니다!

코딩하기

간단한 더하기 함수로 예제를 작성했습니다.

src/lib.rs 파일을 아래와 같이 수정해줍니다.

// src/lib.rs
#[no_mangle]
pub extern fn add(a: i64, b: i64) -> i64 {
    a + b
}

이 부분은 본인이 원하는 함수로 작성할 수 있습니다. 이때, #[no_mangle]pub extern은 FFI에서 꼭 필요한 부분이니 깜박하고 안 써주는 일이 없도록 합니다.

다음은 작성한 src/lib.rs 파일을 컴파일 해줘야 합니다.

cargo build --release

컴파일이 끝나면 파일은 target/release 위치에 .dll, .dylib, .so 확장자 중 하나로 출력되어 있을 것입니다.

그럼 다시 Node로 돌아와 봅시다.

index.js 파일을 하나 만들어 아래와 같이 작성해줍니다.

const ffi = require("ffi");

// 파일 경로는 Rust 바이너리 파일의 경로로 바꿔줄 것
const lib = ffi.Library('./target/release/your-file.so',{
    add: ['int64', ['int64', 'int64']],
    // 함수이름: [반환타입, [인자1타입, 인자2타입, ...]]
});

console.log(lib.add(1, 2)); // 3

전달할 수 있는 타입은 Ref 패키지를 참고해주세요.

이제 Node를 실행시켜 결과를 확인합니다.

node index.js

결과가 잘 나오셨다면 성공입니다.

결론

그렇다면 Rust FFI는 어디에 사용할까요? Rust의 우수한 성능을 이용해 CPU에 부하가 큰 작업이나 병렬로 연산을 해야 될 경우 요긴하게 사용될 수 있습니다.

KoreanDictionary 패키지의 경우 표준국어대사전을 병렬적으로 크롤링하기 위해 Rust FFI를 사용했습니다. 병렬 크롤링의 경우 GitHub의 소스를 참고해주세요.

이상입니다.

Comments

Windows 10에서 V8 빌드 환경 세팅하기

# Requirement - [Git for Windows](https://git-scm.com/downloads) - Visual Studio 2017 - [depot…

Node.js에서의 반복문 속도 비교

배열을 순회하는 반복문의 성능은 무엇이 가장 빠를까? benchmark.js를 이용하여 실험해보았습니다. 실험 const Benchmark = require('benchma…