RustによるRubyアプリケーションサーバー Flamboyant: version 0.1.0.rc
「なんとか動かせた」という世界の話なんですが、途中経過をメモしておきます。
先日Rustでgemをなるべくイマい形で書く方法をメモっていたんですが、一つは実用的なものを作ろうと思ってサーバを書いています。
Flamboyant という名前をつけました。
RubyGems 3.4.0.dev (今のgithub masterにあるやつ)を使っていればRuby自体は3系であれば動くようです。インストールは:
gem install flamboyant --pre
あるいはGemfileに:
# 2022/06/11 現在 gem "flamboyant", "0.1.0.rc2"
実装的にはTRPLの サーバ実装ワーク にほぼ近いようなコードで、さらにリクエストとレスポンスを構築するとこは生のstringをRubyに渡してWEBrickのコードをほぼそのまま使ってやっていってる感じなので、これは「書いた」と言っていいのでしょうか...?
しかしそれで Rack::Lint は通過させました。そう、Flamboyantは歴としたRack互換のアプリケーションサーバです。したがって最低限ベンチは流せるようになったと思います。
あとflamboyantの中ではcoffret使ってるんですが、当座はFlamboyantの中に置いてるようなRuby C APIラッパーコードもあって、その辺はなんかいい感じに整理します。
この実装ではこうなってしまうという記録を残しておきます。まずApache Benchで、WEBrick、Puma(いずれもデフォルト設定)との比較:
Rubyのアプリケーションはこういう config.ru を書いてます。
run lambda {|_env| return [200, {"Content-Type" => "text/plain"}, ["OK Rack"]] }
ABのパラメータはとりあえずソフトです。
$ ab -n 10000 -c 1 http://127.0.0.1:9292/
webrick
Concurrency Level: 1
Time taken for tests: 3.997 seconds
Complete requests: 10000
Failed requests: 0
Total transferred: 1740000 bytes
HTML transferred: 70000 bytes
Requests per second: 2501.79 [#/sec] (mean)
Time per request: 0.400 [ms] (mean)
Time per request: 0.400 [ms] (mean, across all concurrent requests)
Transfer rate: 425.11 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.8 0 64
Processing: 0 0 0.1 0 3
Waiting: 0 0 0.1 0 3
Total: 0 0 0.8 0 65
Percentage of the requests served within a certain time (ms)
50% 0
66% 0
75% 0
80% 0
90% 0
95% 0
98% 1
99% 1
100% 65 (longest request)
Puma
Concurrency Level: 1
Time taken for tests: 2.932 seconds
Complete requests: 10000
Failed requests: 0
Total transferred: 710000 bytes
HTML transferred: 70000 bytes
Requests per second: 3410.32 [#/sec] (mean)
Time per request: 0.293 [ms] (mean)
Time per request: 0.293 [ms] (mean, across all concurrent requests)
Transfer rate: 236.46 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 1
Processing: 0 0 0.1 0 4
Waiting: 0 0 0.1 0 4
Total: 0 0 0.1 0 5
Percentage of the requests served within a certain time (ms)
50% 0
66% 0
75% 0
80% 0
90% 0
95% 0
98% 0
99% 0
100% 5 (longest request)
Flamboyant
Concurrency Level: 1
Time taken for tests: 2.516 seconds
Complete requests: 10000
Failed requests: 0
Total transferred: 1100000 bytes
HTML transferred: 70000 bytes
Requests per second: 3974.32 [#/sec] (mean)
Time per request: 0.252 [ms] (mean)
Time per request: 0.252 [ms] (mean, across all concurrent requests)
Transfer rate: 426.93 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.5 0 249
Processing: 0 0 0.0 0 1
Waiting: 0 0 0.0 0 1
Total: 0 0 2.5 0 250
Percentage of the requests served within a certain time (ms)
50% 0
66% 0
75% 0
80% 0
90% 0
95% 0
98% 0
99% 0
100% 250 (longest request)
(よく考えたらヘッダが違うので、例えば「Total transferred」がかなり違うんですよね。あくまで参考レベルということで...)
で、Flamboyantはこのベンチは完走します(偉い!自画自賛する)。そして、単純にRPSだけ見るとなぜかPumaより少し優秀です。これは... サーバとして必要な機能が全然実装されていないこと、例えばそもそもログを出してないなどに起因してると思います...。ログってやっぱり影響あるんですかね...。
で、そもそもFlamboyantは他のサーバに比べ、レスポンスタイムにかなりばらつきがあることが示唆されていそうです。
次はwrkを使ってみます。こういうパラメータで。
$ wrk -t 1 -c 1 -d 5s --latency http://127.0.0.1:9292/
WEBrick
Running 15s test @ http://localhost:9292/
1 threads and 1 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 320.14us 127.40us 8.37ms 98.34%
Req/Sec 3.16k 137.43 3.55k 85.43%
Latency Distribution
50% 305.00us
75% 338.00us
90% 362.00us
99% 473.00us
47478 requests in 15.10s, 8.11MB read
Requests/sec: 3144.27
Transfer/sec: 549.64KB
Puma
Running 15s test @ http://localhost:9292/
1 threads and 1 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 190.04us 45.43us 1.89ms 93.72%
Req/Sec 5.28k 176.92 5.48k 96.03%
Latency Distribution
50% 176.00us
75% 193.00us
90% 228.00us
99% 342.00us
79377 requests in 15.10s, 5.37MB read
Requests/sec: 5256.73
Transfer/sec: 364.48KB
Flamboyant
Running 15s test @ http://localhost:9292/
1 threads and 1 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 427.75us 3.87ms 87.81ms 99.45%
Req/Sec 4.46k 1.05k 4.98k 88.89%
Latency Distribution
50% 156.00us
75% 192.00us
90% 211.00us
99% 317.00us
16337 requests in 15.05s, 1.71MB read
Socket errors: connect 0, read 16337, write 0, timeout 0
Requests/sec: 1085.75
Transfer/sec: 116.63KB
Flamboyantは明らかに完走していなくて、並行数1ですら、ちょっと負荷を上げると今今は刺さるということがわかります。〜完〜*1
むしろWEBRickって安定してて偉いんですね。
とはいえ、条件によってはちゃんと動くということを自画自賛して行きたくて、今後はまともな機能を実装しつつ、刺さる箇所を調査したり、どれくらい遅くなったり速くなったりしたか観察しながら手を動かすというのをやっていこうと思います。
というメモを残した。
比較した環境です:
GEM
remote: https://rubygems.org/
specs:
flamboyant (0.1.0.rc2)
rack
webrick
nio4r (2.5.8)
puma (5.6.4)
nio4r (~> 2.0)
rack (2.2.3.1)
webrick (1.7.0)
PLATFORMS
arm64-darwin-21
DEPENDENCIES
flamboyant (= 0.1.0.rc2)
puma
webrick
BUNDLED WITH
2.4.0.dev
$ ruby -v ruby 3.1.1p18 (2022-02-18 revision 53f5fc4236) [arm64-darwin21]
マシンはApple M1 Max(8+2 Core, メモリ64GB)です。