はじめに
普段はフリーランスエンジニアをしているRyuと言います!
今回は初めてBunを触った際、あまりにも動作が爆速で驚いたのでNode.jsとの比較をしてみました。
Bun とは
Bun は、最近注目を集めている次世代の JavaScript ランタイムです。Node.js や Deno と同様にサーバーサイドの JavaScript 実行環境を提供しますが、高速な起動や統合ツール群(バンドラー、トランスパイラー、パッケージマネージャ)が特徴です。Bun のコアは Zig という言語で実装されており、パフォーマンス面での優位性を発揮しています。
Bun のここがすごい
高速性
Node.js と比較して、サーバの起動時間やリクエスト処理速度が数倍高速です。
統合ツール群
Node.js 単体ではランタイムのみを提供し、パッケージ管理(npm や Yarn)、バンドラー(webpack、Rollup など)、トランスパイラー(Babel など)は別途導入する必要がありますが、Bun はそれらすべて Bun の中にまとまって提供されます。
TypeScript 対応
最新の ECMAScript 機能をサポートしており、TypeScript もネイティブに扱えます。TypeScript をトランスパイルなしで直接実行可能なので Node.js では ts-node などを追加でインストールする必要がありますが、Bun ならその手間が不要です。
ホットリロード対応
bun dev
コマンドを使って立ち上げた開発サーバに、コードの変更をリアルタイムで反映できます。
テストランナー実装
Node.js を使用する場合は Jest のような外部のテストフレームワークを使ってテストしますが、Bun 独自のテストランナーを備えているため高速かつシンプルにテストの実行が可能
用語解説
ランタイム
ランタイムとは、プログラムが「実行」される環境のことです。
たとえば、JavaScript のランタイムとしては、ブラウザ環境が挙げられますが、サーバサイドでは Node.js や Bun などがこれに該当します。これらは、JavaScript コードを実行するために、独自の API やシステムリソース管理の仕組みを備えています。
バンドラー
バンドラーとは、複数の JavaScript モジュールやその他のリソース(CSS、画像など)を解析し、1 つまたは少数のファイルにまとめるツールのことです。
トランスパイル
ソースコードを解析し、構文や機能を理解した上で、目的の環境に適したコードに再生成することです。例えば、型付けされた TypeScript コードを、ブラウザや Node.js で実行可能な JavaScript に変換すること。
前準備
Bun と Node.js の比較をするために、まずは Docker で Bun と Node.js のコンテナを作成していきます。
Bun の Dockerfile
FROM oven/bun:latest
WORKDIR /app
COPY package.json .
COPY server.ts .
RUN bun install
EXPOSE 3001
CMD ["bun", "run", "server.ts"]
Node.js の Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
COPY tsconfig.json ./
COPY server.ts ./
RUN npm install
EXPOSE 3002
CMD ["npm", "start"]
docker-compose.yml
version: "3"
services:
bun-server:
build:
context: ./bun-server
dockerfile: Dockerfile
ports:
- "3001:3001"
container_name: bun-server
node-server:
build:
context: ./node-server
dockerfile: Dockerfile
ports:
- "3002:3002"
container_name: node-server
Bun で HTTP サーバーを作成
では早速 Bun を使用して HTTP サーバーを立てていきましょう。
// server.ts
import { Server } from "bun";
const server: Server = Bun.serve({
port: 3001,
fetch(request: Request): Response {
return new Response("Hello from Bun Server!");
},
});
console.log(`Bun server listening on ${server.url}`);
非常にシンプルな記述で HTTP サーバーを立てることができました。
Node.js で HTTP サーバーを立ててみる
では次は Node.js を使用して HTTP サーバーを立てていきましょう。
// server.ts
import { createServer, IncomingMessage, ServerResponse } from "http";
const server = createServer((req: IncomingMessage, res: ServerResponse) => {
res.statusCode = 200;
res.setHeader("Content-Type", "text/plain");
res.end("Hello from Node.js Server!");
});
const PORT: number = 3002;
server.listen(PORT, () => {
console.log(`Node.js server listening on port ${PORT}`);
});
Bun と Node.js のパフォーマンス比較
コンテナの立ち上げ
まずは上記のコードをもとにコンテナを立てて HTTP サーバーを立ててみましょう。
docker-compose up -d
ブラウザでhttp://localhost:3001
とhttp://localhost:3002
にアクセスして以下のように各サーバーが立ち上がったら成功です。
ベンチマークテストツール
今回ベンチマークテストツールとしてautocannon
を使用します。
autocannon
は Node.js の HTTP サーバーのパフォーマンスを計測するためのツールです。(Bun にも使えます)
npm install -g autocannon
ベンチマークテスト
Bun サーバーと Node.js サーバーのベンチマークテストを実行してみましょう。
autocannon -c 100 -d 30 http://localhost:3001
autocannon -c 100 -d 30 http://localhost:3002
これは各対象の HTTP サーバーに 100 個の同時接続して 30 秒間リクエストを送信してパフォーマンスを計測するコマンドです。
結果を見てみましょう。
PS C:\project\Bun> autocannon -c 100 -d 30 localhost:3001
Running 30s test @ http://localhost:3001
100 connections
┌─────────┬──────┬───────┬───────┬───────┬──────────┬─────────┬────────┐
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
├─────────┼──────┼───────┼───────┼───────┼──────────┼─────────┼────────┤
│ Latency │ 8 ms │ 11 ms │ 17 ms │ 19 ms │ 11.76 ms │ 4.18 ms │ 251 ms │
└─────────┴──────┴───────┴───────┴───────┴──────────┴─────────┴────────┘
┌───────────┬────────┬────────┬─────────┬─────────┬─────────┬─────────┬────────┐
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
├───────────┼────────┼────────┼─────────┼─────────┼─────────┼─────────┼────────┤
│ Req/Sec │ 5,431 │ 5,431 │ 8,191 │ 9,095 │ 8,201.8 │ 659.22 │ 5,431 │
├───────────┼────────┼────────┼─────────┼─────────┼─────────┼─────────┼────────┤
│ Bytes/Sec │ 750 kB │ 750 kB │ 1.13 MB │ 1.25 MB │ 1.13 MB │ 90.9 kB │ 749 kB │
└───────────┴────────┴────────┴─────────┴─────────┴─────────┴─────────┴────────┘
Req/Bytes counts sampled once per second.
# of samples: 30
246k requests in 30.23s, 34 MB read
PS C:\project\Bun>
PS C:\project\Bun>
PS C:\project\Bun> autocannon -c 100 -d 30 localhost:3002
Running 30s test @ http://localhost:3002
100 connections
┌─────────┬───────┬───────┬───────┬───────┬──────────┬─────────┬────────┐
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
├─────────┼───────┼───────┼───────┼───────┼──────────┼─────────┼────────┤
│ Latency │ 11 ms │ 15 ms │ 30 ms │ 33 ms │ 15.95 ms │ 5.47 ms │ 158 ms │
└─────────┴───────┴───────┴───────┴───────┴──────────┴─────────┴────────┘
┌───────────┬────────┬────────┬─────────┬────────┬──────────┬────────┬────────┐
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
├───────────┼────────┼────────┼─────────┼────────┼──────────┼────────┼────────┤
│ Req/Sec │ 3,553 │ 3,553 │ 6,235 │ 6,847 │ 6,080.77 │ 577.53 │ 3,552 │
├───────────┼────────┼────────┼─────────┼────────┼──────────┼────────┼────────┤
│ Bytes/Sec │ 622 kB │ 622 kB │ 1.09 MB │ 1.2 MB │ 1.06 MB │ 101 kB │ 622 kB │
└───────────┴────────┴────────┴─────────┴────────┴──────────┴────────┴────────┘
Req/Bytes counts sampled once per second.
# of samples: 30
183k requests in 30.06s, 31.9 MB read
こちら上記結果をChatGPTくんに要約してもらったものです。
レイテンシー(応答時間):
3001(Bun): 平均11.76ms
3002(Node.js): 平均15.95ms
→ 3001の方が約35%速い
毎秒リクエスト処理数(Req/Sec):
3001(Bun): 平均8,201.8
3002(Node.js): 平均6,080.77
→ 3001の方が約35%多くのリクエストを処理
30秒間の総リクエスト数:
3001(Bun): 246,000リクエスト
3002(Node.js): 183,000リクエスト
→ 3001の方が約63,000リクエスト多く処理
こんな単純な処理を返すサーバーでもBunの方がNode.jsよりも高いパフォーマンスを発揮していることがわかりますね。
まとめ
BunはNode.jsよりも高速で、シンプルな記述でHTTPサーバーを立てることができます。
皆さんもぜひBunを使ってみてください!
もし記事に追記した方がいいことや誤り等ありましたらご連絡ください!
個人ブログでも記事投稿しているので暇な時にでも覗いてやってくださいm(._.)m
https://ryu-engineer.com/