「なんとか動かせた」という世界の話なんですが、途中経過をメモしておきます。
先日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)です。