gerbil httpdは遅いのか?
gerbilの組み込みHTTP Serverの速度が気になったのでベンチを取ってみた。
結論
(自分の実装で自分の期待よりかは)遅かった。
実装
code:lisp
(import :std/sugar
:std/net/httpd)
(export main)
(def (main . args)
(run "127.0.0.1:8080"))
(def (run address)
(let* ((mux (make-static-http-mux
(hash ("/" root-handler))))
(httpd (start-http-server! address mux: mux)))
(thread-join! httpd)))
(def (default-handler req res)
(http-response-write res 404 '(("Content-Type" . "text/plain"))
"Not found"))
(def (root-handler req res)
(http-response-write res 200 '(("Content-Type" . "text/plain"))
(string-append "hello" "\n")))
code:server.ts
import { Hono } from "jsr:@hono/hono";
const app = new Hono()
app.get('/', (c) => c.text('hello'))
Deno.serve(app.fetch)
ベンチマーク
gerbil HTTP Server:
code:txt
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.15ms 2.96ms 21.83ms 89.94%
Req/Sec 29.41k 4.37k 68.26k 81.09%
587837 requests in 10.10s, 57.18MB read
Requests/sec: 58202.46
Transfer/sec: 5.66MB
Hono in Deno:
code:txt
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 123.39us 84.43us 5.13ms 94.90%
Req/Sec 41.17k 5.67k 52.27k 68.32%
827024 requests in 10.10s, 112.79MB read
Requests/sec: 81882.84
Transfer/sec: 11.17MB
チューニング
gerbilの方が想像よりかなり遅くて驚いたのでちょっとチューニングをしてみた。
まず前提として、gerbilのhttpdでは Request Multiplexerというパスにハンドラをマップするオブジェクトをstart-http-server!に与えることでサーバーを起動できる。 このRequest Multiplexerはちょうど一般的なWebフレームワークにおけるルーティングに相当するもので、この箇所を高速なものに変えることで高速化できることが期待できる。
自分がWebサーバーを書く時に、ルーティングを動的に変更するケースは思い当たらないので、普通にサーバーを書く時にはmake-static-http-muxを使おうと思う。
思わぬ落し穴もありそうなので、その時はまた記事を書こうかと。
以下ベンチマーク。
code:txt
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.11ms 2.78ms 21.96ms 89.07%
Req/Sec 37.94k 5.29k 50.58k 69.00%
754945 requests in 10.00s, 73.44MB read
Requests/sec: 75491.31
Transfer/sec: 7.34MB
およそ0.04msの高速化に成功した。ほとんど誤差な気もする
今回はパスが1つのケースで行なったためそこまで差がでなかったが、複数パスにランダムにアクセスが飛んでくるケースなどでは確実に効いてくると思っている。
あと、今回ベンチマークに使用したwrkの影響か分からないけど、gerbil httpdで大量のリクエストエラーが発生したのでそのあたりも調査してみたい。