Skip to content

Instantly share code, notes, and snippets.

@jung-han
Created November 11, 2023 23:52
Show Gist options
  • Save jung-han/8ebe544287bba638e3af8fe63a30ddfd to your computer and use it in GitHub Desktop.
Save jung-han/8ebe544287bba638e3af8fe63a30ddfd to your computer and use it in GitHub Desktop.

Bun과 Node.js의 호환성 및 복잡한 애플리케이션에서의 속도 테스트

원문: https://techsparx.com/nodejs/bun/1st-trial.html

최근 새로운 자바스크립트 서버 사이드 런타임인 Bun이 발표되었습니다. Bun은 Node.js에 비해 엄청난 속도 향상을 약속했습니다. 이 글에서는 작은 애플리케이션 대신 복잡한 애플리케이션을 사용해 실제 성능을 확인해봤습니다.

main

Bun 웹사이트(https://bun.sh/)를 보면 Node.js 사용을 대체하는 흥미로운 대안처럼 보이게 합니다. Bun은 Node.js와 같은 아이디어이지만, 훨씬 더 나은 성능을 약속합니다. Node.js와 마찬가지로, Bun은 웹 브라우저에서 자바스크립트 엔진을 서버 사이드 자바스크립트 플랫폼으로 패키징하고 완전한 호환성을 위해 Node.js API를 구현할 것을 약속합니다.

크롬의 V8 엔진을 사용하는 대신 애플의 사파리 브라우저의 자바스크립트코어(JavaScriptCore) 엔진을 사용합니다. 이 엔진은 V8 보다 더 빠르다는 평가를 받고 있으며, 이 부분이 첫 번째 장점이라고 주장되고 있습니다. 또 다른 장점으로는 Bun 시스템이 C++나 Rust가 아닌 새로운 언어인 Zig으로 작성된다는 것입니다. Zig는 몇몇 기술적 사양 덕분에 더 빠를 것으로 예상합니다.

또 다른 흥미로운 지점은 타입스크립트와 JSX 트랜스파일러가 Bun에 내장되어 있어 타입스크립트 코드를 매우 쉽게 실행할 수 있다는 점입니다.

Bun팀은 N-API를 사용해 네이티브 코드 Node.js 패키지 실행을 지원하는 것을 포함해 Node.js 패키지와 90% 호환을 주장합니다. 또한, Node.js와 동일한 node_modules 인프라와 패키지 검색 알고리즘을 사용하므로 기존 Node.js 생태계와 즉시 호환됩니다.

대조적으로 (Node.js의 대안으로 불리는)Deno는 Node.js 패키지 생태계와 호환되지 않으므로 큰 단점이 있습니다.

Node.js 개발자들은 기존 생태계와 호환되지만, 훨씬 더 빠른 이 대안을 가지고 무엇을 할 수 있을까요?

간단한 성능 테스트의 함정

이미 유튜브에는 Bun을 처음 시도하는 여러 영상이 있습니다. 제가 본 모든 비디오는 몇 가지 간단한 명령을 실행하는 것을 보여줍니다. 그러고는 "맙소사. 정말 빠르군요!" 라고 합니다.

잘 알려진 지나치게 단순한 성능 테스트의 오류가 있습니다. Bun으로 간단한 스크립트를 실행하는 것이 실제 애플리케이션에서 Node.js보다 매우 빠르다는 것을 의미하나요? 그것이 오류입니다. Bun이 실제로 빠르다는 것을 확인하기 위해서는 몇 가지 간단한 예시보다 더 심층적인 테스트가 필요합니다.

제 생각에는 호환성과 성능을 모두 테스트하기 위해 복잡한 케이스에 Bun을 사용하는 것이 더 좋아 보입니다.

Bun을 사용한 복잡한 테스트 케이스

저는 이미 여러 웹 사이트를 구축한 정적 웹사이트 생성기(AkashaCMS)를 개발했습니다. 몇몇 웹사이트는 꽤 큽니다. 예를 들어 techsparx.com는 1600개가 넘는 웹 페이지 즉, 블로그 게시물이 있습니다. AkashaCMS는 여러 템플릿 엔진을 지원하며 서버 사이드 jQuery 같은 DOM 조작 및 기타 여러 가지 작업을 수행합니다.

제 노트북(Core i7 및 16GB 메모리가 탑재된 Dell Latitude E7250)으로 Node.js를 실행하면 배포될 준비가 된 HTML로 웹 사이트를 렌더링하는데 30분 정도 걸립니다. Bun이 주장한 대로라면 10분이면 되어야겠죠?

확인해야 할 두 가지 중요한 시나리오가 있습니다.

  • Bun이 AkashaCMS를 실행할 수 있나요? techsparx.com에 있는 모든 것을 렌더링할 수 있나요?
  • Bun은 Node.js를 사용할 때보다 더 빨리 웹사이트를 렌더링할 수 있나요?

첫번째 관찰

제 첫번째 테스트는 AkashaCMS 자체를 실행하는 것이 아닌, Node.js 패키지와 관련된 테스트 케이스를 실행하는 것이었습니다. 저는 Mocha를 사용해 테스트 케이스를 구축했는데, 아쉽게도 Bun은 일부 코드와 호환되지 않았습니다. 일부 패키지는 호환성을 확인하기 위해 process 객체에서 값을 찾고 있습니다. Bun은 예상 값을 제공하지 않았고 Mocha가 사용한 일부 패키지는 다양한 호환성 테스트에서 충돌했습니다. 저는 Bun 이슈 리스트에 이 내용을 보고 했고, 이미 해결이 진행중인 것 같습니다.

또 다른 이슈는 Bun이 Github에 존재한 패키지에 대해 package.json을 지원하지 않는다는 것입니다. 저는 npm에 굳이 배포할 필요가 없다고 생각되는 패키지를 Github 의존에 등록합니다. 이 이슈 또한 Bun에 이미 리포팅되어 있습니다. 저처럼 npm 배포하지 않고 Github을 직접 로드하는 경우에는 사용하지 못합니다.

Bun을 통해 npm을 사용해 패키지를 설치하고 코드를 실행하는 것이 완벽하게 동작한다는 것은 확인했습니다. 뭐가 됐든간에 Bun은 아직 "beta" 소프트웨어입니다..

Bun을 사용해 AkashaCMS 웹사이트 렌더링 하기

첫 번째 테스트 시나리오에서 Bun은 techsparx.com웹사이트를 거의 문제없이 렌더링 했습니다.

이 웹사이트는 몇몇 Github 의존을 사용합니다. 즉 npm install을 통해 의존을 다운로드 한다는 것 입니다.

일반적으로 이 경우 저는 빌드 프로세스에서도 사용하기 위해 package.jsonscripts를 사용합니다. 이 방법은 과정을 기록하기에 편리한 방법이며, 이전 글에서 논의한 내용은 다음과 같습니다. (어떻게 npm/yarn/Node.js package.json를 빌드 도구로 사용할 수 있을까요?)

Bun은 package.json의 빌드 스크립트를 직접 실행할 수 있지만, 아래 스크립트는 akasharender 명령을 실행하며, 이 명령은 node 명령을 사용하여 실행되는 스크립트 입니다. 저는 대신 이 명령을 손으로 실행했습니다.

$ bun run node_modules/akasharender/cli.js -- copy-assets config.js
$ bun run node_modules/akasharender/cli.js -- render config.js

이렇게 하면 cli.js를 직접 실행할 수 있습니다 --는 명령 매개변수가 Bun에 의해 수정되지 않고 akasharender에 전달되도록 합니다. 첫 번째 명령은 렌더링된 출력 디렉터리에 asset 파일을 복사하고, 두 번째 명령은 웹 페이지 및 기타 파일을 해당 디렉터리에 렌더링합니다.

Node.js에서 실행 동사는 명령에 필요하지 않으며 --도 필요하지 않습니다. 그렇지 않으면 동일한 명령어입니다.

첫 번째 시도는 훌륭하게 통과되었습니다. AkashaCMS를 올바르게 실행하고 techsparx.com 웹사이트를 렌더링했습니다.

첫 번째 Bun 성능 테스트 -- asset 파일 복사

제가 보여드릴 성능 수치를 이해하려면 AkashaCMS에 대해 이해하는 것이 조금은 도움이 될 수 있습니다.

AkashaCMS 프로젝트는 네 가지 종류의 입력 디렉터리, asset, 문서 및 두 가지 종류의 템플릿 디렉터리를 갖고 있습니다. asset 디렉터리의 파일은 렌더링된 출력 디렉터리에 복사되는 반면 문서 디렉터리의 파일은 렌더링 프로세스를 통해 실행됩니다. 생성된 출력 디렉터리에는 웹 사이트 작성자가 필요한 HTML/CSS/JS/Image 파일의 혼합된 결과가 포함됩니다.

따라서 copy-assets은 다음과 같은 단계를 따릅니다.

  1. asset 디렉터리에서 파일 찾기
  2. 효율적인 파일 복사 작업 사용(fs-extra 패키지의 fs.copy)

파일 복사 루프는 fastq패키지를 사용해 최대 10개의 동시 복사 작업을 실행합니다. 출력 디렉터리에 이미 있는 파일 복사는 건너뛰고 시도하지 않습니다.

이와 대조적으로 render 명령은 렌더링 코드, 템플릿 엔진 등 여러 작업을 실행합니다.

테스트 환경은 5세대 Core i5, 16GB 메모리 및 HDD에 저장된 파일을 갖춘 Intel NUC입니다.

측정은 time 명령을 사용해 수행했습니다. 아래 열은 실제 소요된 시간을 의미하는 real, 사용자 모드 코드의 CPU 소비를 의미하는 사용자 user, 커널 코드의 CPU 소비를 의미하는 sys가 있습니다.

아래 결과는 Bun 0.1.2 버전을 사용해 총 6번의 copy-assets를 수행했습니다.

real  0m7.326s  user  0m5.241s  sys  0m1.319s
real  0m4.445s  user  0m5.277s  sys  0m1.101s
real  0m4.847s  user  0m5.346s  sys  0m1.137s
real  0m4.874s  user  0m5.345s  sys  0m1.217s
real  0m4.847s  user  0m5.420s  sys  0m1.128s
real  0m4.867s  user  0m5.472s  sys  0m1.167s

그리고 Node.js 18.5.0 버전을 사용해 6번의 copy-assets를 한 결과를 보겠습니다.

real  0m4.686s  user  0m5.105s  sys  0m1.279s
real  0m4.549s  user  0m5.160s  sys  0m1.224s
real  0m4.659s  user  0m5.246s  sys  0m1.309s
real  0m4.884s  user  0m5.127s  sys  0m1.285s
real  0m4.658s  user  0m5.316s  sys  0m1.148s
real  0m4.968s  user  0m5.174s  sys  0m1.292s

다른 말로 하면, 결과는 거의 같습니다.

techsparx.com에서는 2000개 이상의 파일이 복사됩니다.

두 번째 Bun 성능 테스트 -- HTML 파일로 가득 찬 웹 사이트 렌더링하기

우리는 방금 파일 복사가 많은 테스트에서 Bun이 Node.js에 비해 더 좋은 결과를 보여주지 못한 것을 증명했습니다. 다음 단계는 마크다운 파일을 HTML로 렌더링한 다음 HTML에서 템플릿을 처리하는 더 복잡한 작업을 수행하는 방법을 확인할 것 입니다.

이 경우 사용되는 기본 패키지는 다음과 같습니다.

  • 마크다운은 markdown-it v12.x 를 사용해 렌더링합니다.
  • 서버 사이드 DOM 처리는 Cheerio v1.0.0-rc.10를 사용했습니다.
  • EJS (v3.1.x)와 Nunjucks (v3.2.x)를 혼합해 템플릿 처리를 수행합니다.

copy-assets 명령어와 마찬가지로, fastq는 한 번에 여러 렌더링을 병렬로 실행하는 데 사용됩니다.

Bun 0.1.2 버전을 사용해 techsparx.com를 렌더링한 결과는 다음과 같습니다.

real  26m1.263s   user  25m20.973s  sys  0m27.235s
real  25m50.435s  user  25m40.301s  sys  0m24.955s
real  25m53.489s  user  25m58.259s  sys  0m25.791s

Node.js 18.5.0 버전을 사용해 techsparx.com를 렌더링한 결과는 다음과 같습니다.

real  25m46.665s  user  25m42.305s  sys	0m26.839s
real  26m6.209s   user  27m38.675s  sys	0m25.880s
real  25m42.731s  user  27m29.677s  sys	0m25.977s

copy-assets과 비슷하게 두 플랫폼 모두 거의 동일한 시간이 소요되었습니다.

요약

이 워크로드(workload)의 경우 Bun은 Node.js와 거의 동일한 성능을 갖고 있습니다.

Bun 팀은 성능에 대해 큰 주장을 했기 때문에, 우리는 무슨 일이 일어나고 있는지 고려해야 합니다. Bun이 아직 Beta이고 버그가 한두개 있을 수 있다는 인식을 넘어서서 말입니다.

물론, 이것이 최고의 성능 테스트는 아닙니다. 거의 20년 전 저는 Sun Microsystems의 Java SE팀에서 일했고, 성능 향상을 위한 업무를 수행하는 그룹과 시간을 보냈습니다. 그들은 특정 워크로드에 대한 긴 테스트 목록을 갖고 있으며, 각 테스트는 하나의 특정 성능 측정에 초점을 맞췄습니다. 이런 식으로 팀은 릴리즈 N이 문자열 성능 n%를 향상했다고 말할 수 있습니다.

AkashaCMS 같은 애플리케이션을 실행하는 것은 플랫폼의 상당한 부분을 수행하지만, 깔끔한 집중 시나리오 테스트가 아닙니다. 오늘날 유튜브에서 발견되는 지나치게 단순한 Bun 시연은 우리가 Bun의 성과를 이해하는 데 도움이 되지 않듯이, 이 테스트 또한 그렇습니다. Node.js 팀 내에 벤치마킹 팀이 있었지만, 작업 공간은 수년간 유휴 상태였습니다. 하지만, 저는 그들이 성능을 측정하기 위해 정확한 테스트 집합을 개발했다고 생각합니다.

저는 Node.js에서 일련의 벤치마크를 수행하는 것으로 보이는 패키지(https://github.com/majimboo/node-benchmarks)를 발견했습니다. Node.js 18.5.0 버전을 사용해 이 패키지를 설치하려고 했지만 microtime패키지를 설치하지 못했습니다. 해당 패키지의 package.jsonmicrotime 버전을 3.1.x 버전을 사용하면 테스트를 실행할 수 있지만, 결과를 어떻게 해석해야 할지 모르겠습니다. 어떤 경우든 해당 제품의 테스트는 이런 목적에 적합한 정렬입니다.

Bun이 Node.js보다 정말 빠른지, 어떤 기능 영역에서 Bun이 더 빠르거나 느린지 이해하려면 적절한 벤치마크 테스트 비교가 필요합니다. 두 플랫폼 모두 정확히 동일한 코드를 실행하는 것을 목표하므로 각각에 대해 동일한 벤치마크/성능 테스트를 실행해 상대적 성능을 측정할 수 있습니다.

라이언 달이 2009년 Node.js를 처음 출시했을 때, 그는 다른 플랫폼과 비교한 성능 벤치마크를 제시하며 Node.js를 전 세계에 팔았습니다. IIRC의 테스트는 메모리 풋프린트와 초당 HTTP 작업 수와 같은 유용한 지표에 초점을 맞췄습니다.

끝으로, 저는 Bun에 깊은 인상을 받았습니다. Node.js를 복제하는 것을 목표로 하는 새로 발표된 프로젝트이며, 이미 다소 복잡한 애플리케이션을 처리할 수 있기 때문입니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment