Puma を使ったアプリケーションを触っているのですが、Puma についてわかっていないので少しドキュメントを読んだり動かしたりしたメモです
Puma のアーキテクチャ
概要図は下記にあります。
Puma は、クラスターモードとシングルモードの 2 つのモードのいずれかで動作するようです。 シングルモードでは、1 つの Puma プロセス(ワーカー)のみが起動します。クラスターモードでは、マスタープロセスが起動され、それに対して、fork() システムコールを使用して 1 つ以上の子プロセス(ワーカー)が作成されます。
Puma 起動時に TCP または UNIX ソケットをリッスンします。
外部からのリクエストをバックログの値分までは受け付けられるようです。 スレッドがソケットからリクエストを読み取りスレッド内部で「todo」という配列に格納されるようです。
- puma/lib/puma/server.rb at v6.4.2 · puma/puma · GitHub
- puma/lib/puma/thread_pool.rb at v6.4.2 · puma/puma · GitHub
- puma/lib/puma/thread_pool.rb at v6.4.2 · puma/puma · GitHub
試す
Rails のサンプルアプリケーションを使って試してみます。
環境
Ruby はインストールされているものとします。
% cat /etc/os-release PRETTY_NAME="Debian GNU/Linux 12 (bookworm)" NAME="Debian GNU/Linux" VERSION_ID="12" VERSION="12 (bookworm)" VERSION_CODENAME=bookworm ID=debian HOME_URL="https://www.debian.org/" SUPPORT_URL="https://www.debian.org/support" BUG_REPORT_URL="https://bugs.debian.org/"
% ruby -v ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux-gnu]
bunlder インストール
% gem install bundler
% bundler -v Bundler version 2.3.7
Rails プロジェクト作成
bundler 用のディレクトリを作成します。
% mkdir -p /path/to/sandbox % cd !$
bundler を初期化します。Gemfileが生成されます。
% bundle init Writing new Gemfile to /path/to/sandbox/Gemfile
Gemfile を編集して、以下のようにします。
# frozen_string_literal: true source "https://rubygems.org" ruby "3.1.2" gem "rails", "~> 7.1.3", ">= 7.1.3.2" gem "puma", ">= 5.0" gem "sprockets-rails" gem "sqlite3", "~> 1.4" gem "importmap-rails" gem "turbo-rails" gem "stimulus-rails" gem "jbuilder" gem "tzinfo-data", platforms: %i[ mswin mswin64 mingw x64_mingw jruby ] gem "bootsnap", require: false group :development, :test do gem "debug", platforms: %i[ mri mswin mswin64 mingw x64_mingw ] end group :development do gem "web-console" gem "error_highlight", ">= 0.4.0", platforms: [:ruby] end group :test do gem "capybara" gem "selenium-webdriver" end
bundler を使ってインストールします。
Debianだとスーパーユーザー権限がないとデフォルトの場所にインストールできないので、インストールパスをプロジェクトディレクトリ内の vendor/bunlde にしておきます。
% bundle config set path 'vendor/bunlde' % bundle install
Rails プロジェクトを新規に作成します。
% bundle exec rails new .
Rails を起動します。
% bundle exec rails s
=> Booting Puma
=> Rails 7.1.3.2 application starting in development
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 6.4.2 (ruby 3.1.2-p20) ("The Eagle of Durango")
* Min threads: 5
* Max threads: 5
* Environment: development
* PID: 3850903
* Listening on http://127.0.0.1:3000
* Listening on http://[::1]:3000
top コマンドを使ってプロセスの状態を見てみます。
% top -p 3850903 -H
puma srv tp 00X がワーカースレッドで、5つ起動しています。
reactor などもスレッドとして起動しているようです。
top - 04:08:47 up 52 days, 17:16, 2 users, load average: 0.00, 0.00, 0.00
Threads: 13 total, 0 running, 13 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.3 us, 0.2 sy, 0.0 ni, 99.5 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 3928.8 total, 535.9 free, 2103.6 used, 1581.9 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 1825.2 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3850903 dshimizu 20 0 960064 102668 13916 S 0.0 2.6 0:02.89 ruby3.1
3850916 dshimizu 20 0 960064 102668 13916 S 0.0 2.6 0:00.03 DEBUGGER__::SES
3850920 dshimizu 20 0 960064 102668 13916 S 0.0 2.6 0:00.32 puma plgn bg 0
3850921 dshimizu 20 0 960064 102668 13916 S 0.0 2.6 0:00.44 puma srv tp 001
3850922 dshimizu 20 0 960064 102668 13916 S 0.0 2.6 0:00.00 puma srv tp 002
3850923 dshimizu 20 0 960064 102668 13916 S 0.0 2.6 0:00.00 puma srv tp 003
3850924 dshimizu 20 0 960064 102668 13916 S 0.0 2.6 0:00.00 puma srv tp 004
3850925 dshimizu 20 0 960064 102668 13916 S 0.0 2.6 0:00.00 puma srv tp 005
3850926 dshimizu 20 0 960064 102668 13916 S 0.0 2.6 0:00.02 puma reactor
3850927 dshimizu 20 0 960064 102668 13916 S 0.0 2.6 0:00.48 puma srv thread
3850928 dshimizu 20 0 960064 102668 13916 S 0.0 2.6 0:00.01 puma srv thread
3850929 dshimizu 20 0 960064 102668 13916 S 0.0 2.6 0:00.00 puma srv
3850935 dshimizu 20 0 960064 102668 13916 S 0.0 2.6 0:00.02 reaper.rb:42
処理中のPumaスレッド数を上回るHTTPリクエストを投げた時の動き
puma にはリクエストタイムアウトの仕組みがないようで、そのままの状態で使うと、大量のリクエストが来た場合に、スレッド数を上回るリクエストは、クライアント側のタイムアウト設定値だけ待機し、それを超えると接続が切られるようです。
この時、例えば、ECS で Rails/Puma を動かしている場合、 重いリクエストで空きのスレッドがなくなっている場合、ALB ヘルスチェックリクエストも滞留することになってヘルスチェックに失敗し、ECSタスクがターゲットとして登録されているALB上のターゲットノードのステータスがUnhealty状態になり、ECS タスクが停止する形になる、といった状態が発生する可能性があります。
試してみます。
config/routes.rb に resources :samples, only: [:index, :show] を追記します。
Rails.application.routes.draw do # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. # Can be used by load balancers and uptime monitors to verify that the app is live. get "up" => "rails/health#show", as: :rails_health_check # Defines the root path route ("/") # root "posts#index" resources :samples, only: [:index, :show] end
app/controllers/samples_controller.rb を作成し、samples エンドポイントで60秒待機するようにするため、以下のようにしておきます。
class SamplesController < ApplicationController def index puts 'Started to wait 60 seconds' sleep 60 puts 'Finished waiting' head :ok end def show end end
Railsを起動します。 puma が5スレッド起動してます。
% bundle exec rails s
=> Booting Puma
=> Rails 7.1.3.2 application starting in development
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 6.4.2 (ruby 3.1.2-p20) ("The Eagle of Durango")
* Min threads: 5
* Max threads: 5
* Environment: development
* PID: 1051532
* Listening on http://127.0.0.1:3000
* Listening on http://[::1]:3000
Use Ctrl-C to stop
10個のリクエストを並列で投げてみます。 Curlでのタイムアウト値を3秒にしています。
% para=10; seq $para | xargs -I{} -P$para curl -v --max-time 3 http://127.0.0.1:3000/samples
クライアント側(curl)の10リクエスト全てタイムアウトしました。
* Trying 127.0.0.1:3000... * Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0) * Trying 127.0.0.1:3000... * Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0) > GET /samples HTTP/1.1 > Host: 127.0.0.1:3000 > User-Agent: curl/7.88.1 > Accept: */* >> GET /samples HTTP/1.1 > Host: 127.0.0.1:3000 > User-Agent: curl/7.88.1 > Accept: */* > * Trying 127.0.0.1:3000... * Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0) > GET /samples HTTP/1.1 > Host: 127.0.0.1:3000 > User-Agent: curl/7.88.1 > Accept: */* > * Trying 127.0.0.1:3000... * Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0) > GET /samples HTTP/1.1 > Host: 127.0.0.1:3000 > User-Agent: curl/7.88.1 > Accept: */* > * Trying 127.0.0.1:3000... * Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0) > GET /samples HTTP/1.1 > Host: 127.0.0.1:3000 > User-Agent: curl/7.88.1 > Accept: */* > * Trying 127.0.0.1:3000... * Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0) > GET /samples HTTP/1.1 > Host: 127.0.0.1:3000 > User-Agent: curl/7.88.1 > Accept: */* > * Trying 127.0.0.1:3000... * Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0) > GET /samples HTTP/1.1 > Host: 127.0.0.1:3000 > User-Agent: curl/7.88.1 > Accept: */* > * Trying 127.0.0.1:3000... * Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0) > GET /samples HTTP/1.1 > Host: 127.0.0.1:3000 > User-Agent: curl/7.88.1 > Accept: */* > * Trying 127.0.0.1:3000... * Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0) > GET /samples HTTP/1.1 > Host: 127.0.0.1:3000 > User-Agent: curl/7.88.1 > Accept: */* > * Trying 127.0.0.1:3000... * Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0) > GET /samples HTTP/1.1 > Host: 127.0.0.1:3000 > User-Agent: curl/7.88.1 > Accept: */* > * Operation timed out after 3000 milliseconds with 0 bytes received * Closing connection 0 curl: (28) Operation timed out after 3000 milliseconds with 0 bytes received * Operation timed out after 3001 milliseconds with 0 bytes received * Closing connection 0 curl: (28) Operation timed out after 3001 milliseconds with 0 bytes received * Operation timed out after 3001 milliseconds with 0 bytes received * Closing connection 0 curl: (28) Operation timed out after 3001 milliseconds with 0 bytes received * Operation timed out after 3001 milliseconds with 0 bytes received * Closing connection 0 curl: (28) Operation timed out after 3001 milliseconds with 0 bytes received * Operation timed out after 3001 milliseconds with 0 bytes received * Closing connection 0 curl: (28) Operation timed out after 3001 milliseconds with 0 bytes received * Operation timed out after 3001 milliseconds with 0 bytes received * Closing connection 0 curl: (28) Operation timed out after 3001 milliseconds with 0 bytes received * Operation timed out after 3001 milliseconds with 0 bytes received * Closing connection 0 curl: (28) Operation timed out after 3001 milliseconds with 0 bytes received * Operation timed out after 3001 milliseconds with 0 bytes received * Closing connection 0 curl: (28) Operation timed out after 3001 milliseconds with 0 bytes received * Operation timed out after 3001 milliseconds with 0 bytes received * Closing connection 0 curl: (28) Operation timed out after 3001 milliseconds with 0 bytes received * Operation timed out after 3000 milliseconds with 0 bytes received * Closing connection 0 curl: (28) Operation timed out after 3000 milliseconds with 0 bytes received
Rails 側の出力は以下のようになりました。 5スレッド分のリクエストはサーバー側(Rails/Puma)の処理が行われましたが、残りの5リクエスト分はクライアント側でタイムアウトとなり、pumaのログには何も出力されませんでしたので、処理されずに終わったことになるかと思います。
Started GET "/samples" for 127.0.0.1 at 2024-04-28 02:51:09 +0000 ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC Processing by SamplesController#index as */* Started to wait 61 second waiting ends Completed 200 OK in 61003ms (ActiveRecord: 0.0ms | Allocations: 1248) Started GET "/samples" for 127.0.0.1 at 2024-04-28 02:56:03 +0000 Processing by SamplesController#index as */* Started to wait 61 second Started GET "/samples" for 127.0.0.1 at 2024-04-28 02:56:03 +0000 Processing by SamplesController#index as */* Started to wait 61 second Started GET "/samples" for 127.0.0.1 at 2024-04-28 02:56:03 +0000 Processing by SamplesController#index as */* Started to wait 61 second Started GET "/samples" for 127.0.0.1 at 2024-04-28 02:56:03 +0000 Processing by SamplesController#index as */* Started to wait 61 second Started GET "/samples" for 127.0.0.1 at 2024-04-28 02:56:03 +0000 Processing by SamplesController#index as */* Started to wait 61 second ## --- 最初の5リクエスト分のサーバー側(Rails/Puma)の処理完了のログ --- Finished waiting Completed 200 OK in 61001ms (ActiveRecord: 0.0ms | Allocations: 4077) Finished waiting Completed 200 OK in 61001ms (ActiveRecord: 0.0ms | Allocations: 3329) Finished waiting Completed 200 OK in 61001ms (ActiveRecord: 0.0ms | Allocations: 2686) Finished waiting Completed 200 OK in 61000ms (ActiveRecord: 0.0ms | Allocations: 1931) Finished waiting Completed 200 OK in 61001ms (ActiveRecord: 0.0ms | Allocations: 1163)
クラスターモードの起動
クラスターモードの起動を試してみます。
config/puma.rb に以下を worker 数の指定を追記して puma を再度起動します。
workers 2
ワーカーが2つ起動して、Cluster モードになっていることが確認できます。
% bundle exec rails s
=> Booting Puma
=> Rails 7.1.3.2 application starting in development
=> Run `bin/rails server --help` for more startup options
[506579] Puma starting in cluster mode...
[506579] * Puma version: 6.4.2 (ruby 3.1.2-p20) ("The Eagle of Durango")
[506579] * Min threads: 5
[506579] * Max threads: 5
[506579] * Environment: development
[506579] * Master PID: 506579
[506579] * Workers: 2
[506579] * Restarts: (✔) hot (✔) phased
[506579] * Listening on http://127.0.0.1:3000
[506579] * Listening on http://[::1]:3000
[506579] Use Ctrl-C to stop
[506579] - Worker 0 (PID: 506582) booted in 0.0s, phase: 0
[506579] - Worker 1 (PID: 506585) booted in 0.0s, phase: 0
5 スレッド * 2 worker と 10 スレッド * 1 worker の簡易負荷検証
以下のようなk6のリクエストシナリオを記述したファイルを準備します。
import http from 'k6/http';
import { sleep } from 'k6';
export default function () {
http.get('http://127.0.0.1:3000/up');
sleep(1);
}
100ユーザーを使って65秒間負荷テストを実行してみます。
100ユーザーや65秒は適当に決めた値で意味はありません。手元の環境では request timeout が結構発生しました。
% k6 run --vus 100 --duration 65s k6.js
5 スレッド * 2 worker の結果
### 1回目
:
data_received..................: 2.0 MB 30 kB/s
data_sent......................: 267 kB 4.0 kB/s
http_req_blocked...............: avg=230.52µs min=3.64µs med=5.2µs max=27.66ms p(90)=6.89µs p(95)=21.39µs
http_req_connecting............: avg=212.67µs min=0s med=0s max=27.61ms p(90)=0s p(95)=0s
http_req_duration..............: avg=1.02s min=11.69ms med=29.03ms max=1m0s p(90)=43.34ms p(95)=83.25ms
{ expected_response:true }...: avg=107.66ms min=11.69ms med=28.94ms max=4.98s p(90)=41.49ms p(95)=54.63ms
http_req_failed................: 1.53% ✓ 50 ✗ 3204
http_req_receiving.............: avg=55.39µs min=0s med=51.39µs max=558.18µs p(90)=70.4µs p(95)=78.59µs
http_req_sending...............: avg=42.76µs min=9.66µs med=14.04µs max=44.45ms p(90)=25.63µs p(95)=39.21µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=1.02s min=10.11ms med=28.96ms max=1m0s p(90)=43.28ms p(95)=83.19ms
http_reqs......................: 3254 48.541967/s
iteration_duration.............: avg=2.02s min=1.01s med=1.02s max=1m1s p(90)=1.04s p(95)=1.08s
iterations.....................: 3254 48.541967/s
vus............................: 6 min=6 max=100
vus_max........................: 100 min=100 max=100
running (1m07.0s), 000/100 VUs, 3254 complete and 0 interrupted iterations
default ✓ [======================================] 100 VUs 1m5s
### 2回目
:
data_received..................: 2.0 MB 30 kB/s
data_sent......................: 265 kB 4.0 kB/s
http_req_blocked...............: avg=497.09µs min=3.61µs med=5.08µs max=34.35ms p(90)=7.1µs p(95)=20.45µs
http_req_connecting............: avg=478.83µs min=0s med=0s max=34.29ms p(90)=0s p(95)=0s
http_req_duration..............: avg=1.03s min=9.5ms med=434.71ms max=1m0s p(90)=460.68ms p(95)=505.93ms
{ expected_response:true }...: avg=301.1ms min=9.5ms med=434.1ms max=5.02s p(90)=457.69ms p(95)=475.92ms
http_req_failed................: 1.23% ✓ 40 ✗ 3193
http_req_receiving.............: avg=54.67µs min=0s med=50.63µs max=364.8µs p(90)=69.36µs p(95)=77.79µs
http_req_sending...............: avg=77.91µs min=9.31µs med=13.79µs max=26.86ms p(90)=25.7µs p(95)=40.62µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=1.03s min=9.38ms med=434.65ms max=59.99s p(90)=460.61ms p(95)=505.87ms
http_reqs......................: 3233 48.209701/s
iteration_duration.............: avg=2.04s min=1.01s med=1.43s max=1m1s p(90)=1.46s p(95)=1.5s
iterations.....................: 3233 48.209701/s
vus............................: 1 min=1 max=100
vus_max........................: 100 min=100 max=100
running (1m07.1s), 000/100 VUs, 3233 complete and 0 interrupted iterations
default ✓ [======================================] 100 VUs 1m5s
### 3回目
:
data_received..................: 2.0 MB 30 kB/s
data_sent......................: 266 kB 4.0 kB/s
http_req_blocked...............: avg=272.63µs min=3.51µs med=5.28µs max=27.37ms p(90)=7.25µs p(95)=21.96µs
http_req_connecting............: avg=262.21µs min=0s med=0s max=27.33ms p(90)=0s p(95)=0s
http_req_duration..............: avg=1.03s min=7.69ms med=29.72ms max=59.99s p(90)=47.73ms p(95)=94.99ms
{ expected_response:true }...: avg=110.02ms min=7.69ms med=29.62ms max=5.03s p(90)=46.19ms p(95)=56.39ms
http_req_failed................: 1.53% ✓ 50 ✗ 3199
http_req_receiving.............: avg=55.25µs min=0s med=51.71µs max=301.38µs p(90)=71.41µs p(95)=80.62µs
http_req_sending...............: avg=43.85µs min=9.49µs med=14.17µs max=5.41ms p(90)=26.42µs p(95)=44.15µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=1.03s min=7.6ms med=29.64ms max=59.99s p(90)=47.66ms p(95)=94.91ms
http_reqs......................: 3249 48.437741/s
iteration_duration.............: avg=2.03s min=1s med=1.03s max=1m1s p(90)=1.04s p(95)=1.09s
iterations.....................: 3249 48.437741/s
vus............................: 6 min=6 max=100
vus_max........................: 100 min=100 max=100
running (1m07.1s), 000/100 VUs, 3249 complete and 0 interrupted iterations
default ✓ [======================================] 100 VUs 1m5s
10 スレッド * 1 worker の結果
### 1回目
:
data_received..................: 2.0 MB 30 kB/s
data_sent......................: 265 kB 3.9 kB/s
http_req_blocked...............: avg=420.98µs min=3.51µs med=5.25µs max=25.54ms p(90)=7.03µs p(95)=20.71µs
http_req_connecting............: avg=412.69µs min=0s med=0s max=25.49ms p(90)=0s p(95)=0s
http_req_duration..............: avg=1.04s min=266.61ms med=343.31ms max=1m0s p(90)=386.07ms p(95)=420.53ms
{ expected_response:true }...: avg=398.49ms min=266.61ms med=342.97ms max=4.97s p(90)=383.94ms p(95)=409.82ms
http_req_failed................: 1.08% ✓ 35 ✗ 3190
http_req_receiving.............: avg=58.08µs min=0s med=54.9µs max=641.59µs p(90)=72.39µs p(95)=80.78µs
http_req_sending...............: avg=32.46µs min=9.76µs med=14.3µs max=874.12µs p(90)=25.69µs p(95)=39.37µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=1.04s min=266.54ms med=343.25ms max=59.99s p(90)=385.99ms p(95)=420.46ms
http_reqs......................: 3225 48.129766/s
iteration_duration.............: avg=2.04s min=1.26s med=1.34s max=1m1s p(90)=1.38s p(95)=1.42s
iterations.....................: 3225 48.129766/s
vus............................: 5 min=5 max=100
vus_max........................: 100 min=100 max=100
running (1m07.0s), 000/100 VUs, 3225 complete and 0 interrupted iterations
default ✓ [======================================] 100 VUs 1m5s
### 2回目
:
data_received..................: 2.0 MB 30 kB/s
data_sent......................: 266 kB 4.0 kB/s
http_req_blocked...............: avg=584.55µs min=3.65µs med=5.28µs max=34.07ms p(90)=7.24µs p(95)=21.18µs
http_req_connecting............: avg=566.77µs min=0s med=0s max=32.53ms p(90)=0s p(95)=0s
http_req_duration..............: avg=1.03s min=8.53ms med=45.89ms max=59.99s p(90)=100.4ms p(95)=155.64ms
{ expected_response:true }...: avg=127.37ms min=8.53ms med=45.23ms max=5.07s p(90)=92.73ms p(95)=142.96ms
http_req_failed................: 1.50% ✓ 49 ✗ 3200
http_req_receiving.............: avg=58.99µs min=0s med=54.08µs max=5.22ms p(90)=73.6µs p(95)=82.74µs
http_req_sending...............: avg=36.37µs min=9.69µs med=14.03µs max=1.02ms p(90)=26.1µs p(95)=43.15µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=1.03s min=7.97ms med=45.81ms max=59.99s p(90)=100.32ms p(95)=155.57ms
http_reqs......................: 3249 48.405461/s
iteration_duration.............: avg=2.03s min=1.02s med=1.04s max=1m1s p(90)=1.1s p(95)=1.15s
iterations.....................: 3249 48.405461/s
vus............................: 4 min=4 max=100
vus_max........................: 100 min=100 max=100
running (1m07.1s), 000/100 VUs, 3249 complete and 0 interrupted iterations
default ✓ [======================================] 100 VUs 1m5s
### 3回目
:
data_received..................: 2.0 MB 30 kB/s
data_sent......................: 267 kB 4.0 kB/s
http_req_blocked...............: avg=95.1µs min=3.52µs med=5.27µs max=31.36ms p(90)=7.19µs p(95)=24.95µs
http_req_connecting............: avg=74.63µs min=0s med=0s max=14ms p(90)=0s p(95)=0s
http_req_duration..............: avg=1.02s min=6.04ms med=23.94ms max=1m0s p(90)=63.47ms p(95)=92.73ms
{ expected_response:true }...: avg=108.04ms min=6.04ms med=23.82ms max=5.06s p(90)=61.31ms p(95)=82.59ms
http_req_failed................: 1.53% ✓ 50 ✗ 3207
http_req_receiving.............: avg=55.68µs min=0s med=52.34µs max=280.71µs p(90)=71.26µs p(95)=82.13µs
http_req_sending...............: avg=121.33µs min=9.79µs med=14.14µs max=21.22ms p(90)=25.54µs p(95)=39.29µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=1.02s min=5.91ms med=23.86ms max=1m0s p(90)=63.4ms p(95)=92.68ms
http_reqs......................: 3257 48.540327/s
iteration_duration.............: avg=2.02s min=1s med=1.02s max=1m1s p(90)=1.06s p(95)=1.09s
iterations.....................: 3257 48.540327/s
vus............................: 8 min=8 max=100
vus_max........................: 100 min=100 max=100
running (1m07.1s), 000/100 VUs, 3257 complete and 0 interrupted iterations
default ✓ [======================================] 100 VUs 1m5s
この程度だとぱっと見あまり差はないように思いました。(多少5 スレッド * 2 workerの方が良さそうだが誤差かも)