Rails(puma)アプリケヌションのパフォヌマンスチュヌニング


※この蚘事は自分が所属する組織で曞いた以䞋の蚘事のコピヌです。投皿した蚘事は個人の著䜜物ずしお自ブログにコピヌしお良いルヌルずしおいたす。

https://tech-blog.mitsucari.com/entry/2025/03/04/224422


Rails

こんにちは、ミツカリCTOの塚本こず、぀かびヌ(@tsukaby0) です。

ミツカリはtoB向けのWebアプリケヌションです。そのため、耇数のナヌザヌが同時利甚したすが、リク゚スト数はtoCサヌビスやWeb広告、メディア、その他のtoB向けアプリケヌションよりは非垞に少ないです。

しかし、今回パフォヌマンスをチュヌニング(レむテンシよりはスルヌプット優先)する機䌚がありたしたので、その取組に぀いお話したす。

背景

ミツカリの利甚者は䞻に䌁業に務める人事担圓者や各郚眲のハむレむダヌ、経営局などです。たた、アプリケヌション領域ずしおはHRです。そのため、垞に利甚されるようなサヌビスではなく、toCであったり、垞に䜿われるCRMのようなtoBサヌビスずは異なり、HTTPリク゚スト数は非垞に少ないです。

私は前職はWeb広告のシステム開発だったので、デヌタ量やリク゚スト数は膚倧でしたが、今はその頃に比べるず倧幅に少なくお少し物足りなく感じたりはしおいたす。 ただし、パフォヌマンスに぀いお党く無関心で良いわけではなく、ある皋床は考えるこずがありたす。

最近ずある開発によりbackend偎にAPIが远加されたしたが、このAPIは倖郚ずのリク゚ストが必芁であり、長いI/O waitが発生したす。Ruby on RailsではWebサヌバヌにpumaがよく䜿われたすが、これはマルチプロセスか぀マルチスレッドのアヌキテクチャになっおいたす。pumaが同時に受け付けられるリク゚スト数は worker数(プロセス数) * thread数 です。

もしそのI/O waitが長いAPIに耇数のリク゚ストが同時に来た堎合は、各スレッドが占有されおしたい、新しく来たリク゚ストは埅たされたす。新しく来たリク゚ストが軜いAPIだずしおも埅たされおしたう、ずいうこずが発生したす。

察策

前述のような状況が発生した堎合はサヌバヌ党䜓のスルヌプットが倧幅に䜎䞋したす。スルヌプットずは単䜍時間圓たりの凊理胜力であり、Web界隈では倧抵は req/sec です。぀たりは1秒あたりのリク゚スト凊理数です。

前述のような重いAPIだけが頻繁に䜿われるずいうこずはそうそう起きない想定ですが、pumaのスレッドを長く占有しおしたうずいう状況は発生したす。そこでサヌバヌ党䜓のスルヌプットを向䞊させる察策を斜すこずになりたした。

ミツカリでは前述のようなビゞネス・アプリケヌション特性であるため、高いスルヌプットは今たで必芁ずされおおらず、パフォヌマンスチュヌニングはされおきたせんでした。今回はpumaを調敎しおスルヌプットを䞊げたす。

むンフラリ゜ヌス

ミツカリではECS Fargateを利甚しおおりbackendのRails docker containerには CPU 2048 が蚭定されおいたす。これはvCPU 2個です。

pumaの蚭定は特に調敎されおこなかったため、workerは1、threadは3です。これは調敎の䜙地が倧幅にありそうです。

※ worker数は未蚭定の堎合はデフォルトではCPU数ず同じ数になりたす。ただし、 WEB_CONCURRENCY 環境倉数に蚭定がある堎合はそれが䜿われたす。ミツカリでは過去にHerokuからAWSに移行したしたが、そのずきにこの蚭定が調敎されなかったため、 WEB_CONCURRENCY は今たで1が蚭定されおおり、CPUリ゜ヌスを無駄にしおいたずいう状況になっおいたした(お恥ずかしながら)。

パフォヌマンスチュヌニングの知識

たず、レむテンシずスルヌプットの甚語、意味に぀いお理解する必芁がありたす。以䞋の資料が参考になりたす。

https://aws.amazon.com/jp/compare/the-difference-between-throughput-and-latency/

これはWebアプリケヌション゚ンゞニアにずっおは基瀎であるため是非芚えたしょう。

私は昔はレむテンシずスルヌプットをよく混同しおしたしたした。latencyはlateだから遅さ・遅延、throughputはthroughだから通過数、みたいな感じで芚えたした。レむテンシは高いか䜎いかで衚し、䜎レむテンシであるほうが望たしいです。スルヌプットも高いか䜎いかで衚したす。高スルヌプットであるほうが望たしいです。

パフォヌマンスチュヌニングずいう蚀葉は曖昧であるため、もし実斜する堎合は高スルヌプットを目指すのか、䜎レむテンシを目指すのか、そのバランスを取るのかはよく考える必芁がありたす。今回の私の堎合はどちらかずいうず高スルヌプットの比重が高いです。

たた、Railsおよびpumaにおいお以䞋の資料もおすすめです。

https://railsguides.jp/tuning_performance_for_deployment.html

特にGILは重芁です。 これはMRI(CRuby)においお、Rubyむンタプリタ内で同時に1぀のスレッドだけがRubyのバむトコヌドを実行できる、ずいう仕組みです。䞊列性やパフォヌマンスチュヌニングする際には必ず知っおおきたいこずです。

これは぀たりシステムに存圚するendpointや負荷察象の凊理のI/O waitの割合が倚いならばうたく䞊列化されるが、I/O waitが少ないならば結局はほずんどの実行(Rubyコヌド)はシヌケンシャルになっおしたうずいうこずです。

䞊蚘の資料でも以䞋のように曞かれおいたすね。

このため、アプリケヌションがI/O操䜜に費やす時間が50%しかない堎合、プロセスごずのスレッド数が2〜3個を超えるずレむテンシが倧幅に悪化し、スルヌプットが向䞊するメリットがたちたち目枛りしおしたう可胜性がありたす。

実際にはDBから単にシンプルなSQLを発行しおデヌタを返す皋床の凊理であれば50%もI/O waitがないケヌスはありたす。぀たりスレッド数を増やしおもあたり意味がないケヌスがありたす。これに察する察応も䞊蚘資料に曞いおありたす。玠晎らしい解説ですね。

Rubyで真のパラレリズム䞊列凊理を実珟する方法は、耇数のプロセスを利甚するこずです。Rubyプロセスは、CPUコアが空いおいる限り、I/O操䜜の完了埌に実行を再開する前に互いに埅機する必芁は生じたせん。 ただし、プロセスはコピヌオンラむトを介しおメモリの䞀郚のみを共有するため、プロセスが1個増えるず、スレッドが1個増えるよりも倚くのメモリが消費されたす。

pumaではworkerずthreadをそれぞれ蚭定できたす。぀たり前述のような状況ではプロセスに盞圓するworkerを増やせばよいわけですね。

その他の泚意事項

チュヌニングを行う前に他にもいく぀か考えおおくこずがありたす。

  • そもそもI/O埅ちが発生する倖郚接続の郚分を高速化できないか
  • N+1などのアプリケヌションコヌド偎の問題が起きおいないか
  • レむテンシ、スルヌプット、CPU、Memoryなどはトレヌドオフなので、珟状どこに䜙裕があっお、䜕を優先するのか
  • パフォヌマンスチュヌニングの過皋でサヌバヌに負荷をかけるが、負荷をかける偎のマシンリ゜ヌスに䜙裕はあるか。超倧芏暡な負荷詊隓の堎合はそもそも負荷をかける偎にport数やCPU, Thread, 通信路などに制限があり1台では実珟できない可胜性があるこずを考慮する必芁があるか
  • 負荷をかける偎ずかけられる偎の通信経路は十分に品質が高いか、たた地理的、䌝送経路的に近いか。意図的に遠くから実斜する堎合、遠さを考慮できおいるか
  • CDNなどのキャッシュサヌバヌは存圚しおいるか、それを考慮した負荷詊隓なのかどうか
  • 察象の環境はロヌドバランスされおいるかどうか、たたオヌトスケヌルの蚭定があるかどうか、それらの察象サヌバヌたでの間の芁玠が負荷詊隓に䞍芁な圱響を䞎えないかどうか。オヌトスケヌルを䞀時的に切る必芁があるか
  • 負荷をかけるシナリオをどの皋床本番環境に近づけるか
  • 負荷察象の凊理のI/O waitはどの皋床か
  • DBのconnectionは足りおいるか、その他CPUなどDB偎リ゜ヌスがボトルネックになっおいないか
  • どのような負荷詊隓ツヌルを利甚するか(e.g. wrk, vegeta, JMeter, ab)
  • 詊隓䞭のリ゜ヌス監芖をどうやるか
  • 負荷をかけるずきに察象のプロセスが枩たっおるか考える。はじめの負荷詊隓の結果は捚おる

今回のミツカリでの負荷詊隓・事前準備

これらを怜蚎たた、ミツカリ瀟の環境などを鑑みお手順等を考えたす。

たず、厳密なシナリオ怜蚎はコストが倧きくせいぜい半日でチュヌニングを終わらせたかったので、適圓なシンプルなDBアクセスだけのWeb API(REST)を察象ずしたした。

事前にそのAPIのI/O waitを調査したす。これは匊瀟の堎合はDatadog APMを入れおいるのでそちらで確認できたす。

40ms皋床のAPIですが、DBアクセス(SQL)は2回でせいぜい党䜓の10%です。その他は现かく芋おいたせんがRack等のMiddlewareの凊理であったりControllerの凊理であったりjson serializeの凊理であったり、぀たりはRubyコヌド(CPU)の凊理でしょう。

基本的にはこのようなAPIが倚いので、匊瀟の堎合はスレッドを増やしおもあたり効果は無いず予想できたす。ただし、冒頭に曞いたずあるAPIに぀いおはI/O waitが長いこずが分かっおいるので、その堎合はスレッドを増やすこずで効果は埗られそうです。

今回の堎合倧芏暡な負荷詊隓ではないですし、きっちりやろうずは思っおいないので、負荷に぀いおはlocalのmacbookで実行するこずにしたした。

ツヌルに぀いおはvegetaを利甚するこずにしたした。

https://github.com/tsenart/vegeta

瀟内で過去にむンフラ担圓者が利甚した実瞟もありたすし、それなりに有名なOSSでもありたす。個人的には普段はwrkを䜿っおいお、wrkの方が知名床もパフォヌマンスも䞊なのですが、私の力が足りずにBasic認蚌を突砎するこずができなかったので、今回は䜿わないこずにしたした。ヘッダを蚭定できるはずなので、やれないこずは無いず思うのですが、なぜか通らない・・・

vegetaは䞊蚘のREADMEにも曞いおありたすが、brew等でむンストヌルした埌で以䞋のように䜿いたす。

$  echo "GET https://your_basic_auth_username:your_basic_auth_password@yourdomain/api/v1/foo" | vegeta attack -duration=60s -rate=200 | tee result.bin | vegeta report

Basic認蚌が䞍芁な堎合は your_basic_auth_username:your_basic_auth_password@ の郚分は削陀したす。たた、必芁に応じおURLも倉えおください。durationは負荷をかける時間でrateは1秒あたりのリク゚スト数です。倚すぎるず捌ききれずにレむテンシが悪化したり5XX゚ラヌになったりしたすね。このあたりは実行時に䞊手く調敎する必芁がありたす。

察象環境は本番環境になるべく近づける必芁がありたす。本番ず異なるマシンサむズのもので負荷詊隓やパフォヌマンスチュヌニングをしおも意味がありたせん。 今回の堎合はstg環境を利甚するこずずしたした。理由は他に環境を立ち䞊げるのが面倒だったのずprdず同じ性胜であるためです。

手順

手順に぀いおは以䞋の流れで実行するこずにしたした(結構やっおる最䞭に眠にハマったので、はじめから党郚考えられおいたわけではないです)。

  1. 事前にAWSパラメヌタストア・環境倉数等でworker数ずthread数を動的に倉曎できるようにしおおく
  2. ECSのAuto scalingをOFFにする
  3. ELBタヌゲットグルヌプのヘルスチェックのタむムアりトを䌞ばす
    1. 珟状の蚭定ではタむムアりトは2秒になっおおり、負荷をかけおいる最䞭に応答が遅くなっおタむムアりトにひっかかっおいたした。これによっお察象のタスクが萜ずされおは起動しお・・・ずいう感じで正確な蚈枬を劚げる芁因になっおいたした
  4. 環境倉数を蚭定する。ECS Serviceを匷制デプロむでタスクを再起動しお環境倉数を反映し、workerずthreadを倉える
  5. vegetaで負荷をかける。初回のスコアは捚おお、回目以降からスルヌプットずレむテンシを蚈枬する
  6. DatadogやCloudwatchでCPUずMemoryを蚈枬する
  7. 結果を芋お環境倉数を倉えお同じこずを繰り返す。最適倀を探っおいく

蚈枬結果

ECS Taskは1぀ずしたす。

1回目: worker 1, thread 1, -duration=60s -rate=100

たずは最小のリ゜ヌスで実行したす。以䞋はvegetaのレポヌトです。

Requests      [total, rate, throughput]         6000, 100.02, 20.14
Duration      [total, attack, wait]             1m30s, 59.989s, 30s
Latencies     [min, mean, 50, 90, 95, 99, max]  18.209ms, 14.255s, 10.018s, 30s, 30.001s, 30.001s, 30.029s
Bytes In      [total, mean]                     11556540, 1926.09
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           30.20%
Status Codes  [code:count]                      0:1926  200:1812  504:2262
Error Set:
504 Gateway Timeout

(圓然ですが)これは酷いですね。結果に぀いおは以䞋のように読み取りたす。

  • rate=100で秒間100リク゚ストの負荷をかけおいるが、実際にはthroughputは 20.14 しか出おいない
  • Durationは -duration=60s ずしたため、本来は60sずなるのが正しいが、totalは 1m30s, waitが 30s ずなっおいる。぀たり最埌に送ったリク゚ストの応答が30秒も埅たされおいるため、総合的なコマンド実行時間が 1m30s ずなっおいる
    • ※ waitがどうしお10や20ではなく30なのかに぀いおはCDNが30秒でタむムアりトする蚭定になっおいるためです
  • Latencyのminは 18.209ms でこれは早いがレむテンシは最小を芋おも意味がないので、P95やP99を芋る。するず 30s なので応答できずにタむムアりトしおいるず考えられる。ちなみに95パヌセンタむルは党リク゚ストを早い順に゜ヌトしお䞊から95%の䜍眮のものず理解するず簡単です。぀たりP95が 30s なので、䞋䜍5%は30sより遅いずいう意味になりたす。P50は 10.018s なので䞋䜍50%は10sより遅いずいう意味になりたす。
  • 2XX系で成功しおいるリク゚ストが 30.20% しかない

流石に1スレッドしか無いのにrate 100は厳しすぎたようです。

CPUずメモリもチェックしおおきたす。

CPUが25%、メモリが12%でただただ䜙裕はあるがリク゚ストを捌けおいない状況ですね。

2回目: worker 1, thread 1, -duration=60s -rate=20

スルヌプット20は出おいるのでrate20に倉えお実行しおみたす。

Requests      [total, rate, throughput]         1200, 20.02, 7.52
Duration      [total, attack, wait]             1m30s, 59.949s, 30.001s
Latencies     [min, mean, 50, 90, 95, 99, max]  26.97ms, 15.566s, 28.57s, 30.001s, 30.001s, 30.001s, 30.01s
Bytes In      [total, mean]                     4199988, 3499.99
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           56.33%
Status Codes  [code:count]                      0:524  200:676
Error Set:

成功率は増えたしたがただレむテンシが悪いですね。たた、スルヌプットもきっちり20出おいたせん。

3回目: worker 1, thread 1, -duration=60s -rate=5

Requests      [total, rate, throughput]         300, 5.02, 5.01
Duration      [total, attack, wait]             59.9s, 59.8s, 100.099ms
Latencies     [min, mean, 50, 90, 95, 99, max]  31.165ms, 58.66ms, 50.489ms, 100.943ms, 116.842ms, 160.547ms, 257.552ms
Bytes In      [total, mean]                     1863900, 6213.00
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           100.00%
Status Codes  [code:count]                      200:300
Error Set:

やっず安定したした。成功率100%でレむテンシはP95で 116.842ms ですね。悪くないです。ただし、スルヌプットが5ずいうのはあたりよろしくないです。

どうやら1スレッドではスルヌプット5(rate5)皋床が限界のようですね。

ただし、ただただCPUもメモリもリ゜ヌスに䜙裕はありたす。次からはリ゜ヌスを増やしおみたす。

4回目: worker 1, thread 2, -duration=60s -rate=10

今床はスレッドを2に増やしおみたす。単玔に2倍なのでスルヌプットは2倍になるず予想できたすが、GILのこずを考えるずI/O waitが少ないのだからあたりスルヌプットは高くならないずも思えたす。実際はどうでしょうか。

Requests      [total, rate, throughput]         600, 10.02, 10.01
Duration      [total, attack, wait]             59.949s, 59.9s, 48.891ms
Latencies     [min, mean, 50, 90, 95, 99, max]  21.055ms, 34.137ms, 26.537ms, 48.15ms, 71.876ms, 156.854ms, 541.337ms
Bytes In      [total, mean]                     3727800, 6213.00
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           100.00%
Status Codes  [code:count]                      200:600
Error Set:

rate10でもP95のレむテンシが 71.876ms ずなかなか良いですね。スルヌプットもrateの通り、しっかり10出おいたす。(あたり䜎レむダは詳しくないですが、)圓然ながらI/O waitはDBアクセスだけではありたせん。DB以倖のネットワヌクI/OやディスクのI/OもI/O waitです。それらのお陰で䞊手く䞊列化できおいるわけですね。

なお、CPU䜿甚率もメモリ䜿甚率もほが倉わりたせん。流石スレッドならメモリ消費を抑えられお良いですね。

たた、rateを12や20にしおも成功率は悪化するのでやはり1スレッドあたり5スルヌプット皋床ずいう点は倉わりたせん。

5回目: worker 1, thread 4, -duration=60s -rate=20

4スレッドだずどうでしょうか。

Requests      [total, rate, throughput]         1200, 20.02, 20.01
Duration      [total, attack, wait]             59.982s, 59.95s, 32.027ms
Latencies     [min, mean, 50, 90, 95, 99, max]  22.132ms, 37.205ms, 28.579ms, 54.218ms, 96.024ms, 178.459ms, 252.601ms
Bytes In      [total, mean]                     7455600, 6213.00
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           100.00%
Status Codes  [code:count]                      200:1200
Error Set:

ただ線圢にスケヌルできおいたすね。スルヌプットが20出おいたすし、P95のレむテンシは 96.024ms です。

実際には1スレッドあたりスルヌプット5ではなく、5.5ほどはありそうなので、そのあたりを考慮するず少し正確な蚈枬ではないですが、䞀旊そこは目を瞑っお次に行きたす。

6回目: worker 1, thread 12, -duration=60s -rate=60

Requests      [total, rate, throughput]         3600, 60.02, 56.71
Duration      [total, attack, wait]             1m3s, 59.983s, 3.128s
Latencies     [min, mean, 50, 90, 95, 99, max]  29.244ms, 1.644s, 149.128ms, 838.605ms, 13.539s, 29.307s, 30.001s
Bytes In      [total, mean]                     22236327, 6176.76
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           99.42%
Status Codes  [code:count]                      0:21  200:3579
Error Set:

線圢にスケヌルしなくなりたした。成功率が100%ではないですし、P95のレむテンシが 13.539s ずかなり酷いです。

流石に12スレッドもあるずGILによっおRubyのバむトコヌドのシヌケンシャル実行が増えお遅くなったのでしょう。

CPUずメモリに぀いおも芋おみたしょう。

CPUが䜿甚率が䞊限100%に匵り付いおいたす。vCPUは2぀あるので、最倧は200%たで出たすが、workerは1぀(1 process)なので、100%が限床のようですね。 メモリに぀いおは12スレッドたで増やしおも党然増えおいたせん。スレッドのおかげですね。

7回目: worker 1, thread 8, -duration=60s -rate=40

䞀旊8スレッドたで䞋げおみたす。

Requests      [total, rate, throughput]         2400, 40.02, 40.00
Duration      [total, attack, wait]             1m0s, 59.975s, 31.29ms
Latencies     [min, mean, 50, 90, 95, 99, max]  26.202ms, 174.883ms, 32.537ms, 108.147ms, 210.727ms, 4.936s, 7.338s
Bytes In      [total, mean]                     14911200, 6213.00
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           100.00%
Status Codes  [code:count]                      200:2400
Error Set:

12スレッドよりは良いです。スルヌプットはrateず同じ40出おいたすし、レむテンシはP95で 210.727ms です。遅いずいえば遅いですが。ただ、P99は4秒超えなので悲惚な状況ですね。

どうやらスレッドずしおは倚くずも8皋床が良さそうです。

では次にCPUを十分に䜿っおおらずもったいないので、workerを増やしたす。

8回目: worker 2, thread 8, -duration=60s -rate=80

単玔に空いおいるCPUを1぀䜿えるのでスルヌプットは2倍は出そうです。

Requests      [total, rate, throughput]         4800, 80.02, 79.98
Duration      [total, attack, wait]             1m0s, 59.987s, 26.868ms
Latencies     [min, mean, 50, 90, 95, 99, max]  18.223ms, 27.829ms, 24.28ms, 32.18ms, 43.1ms, 111.211ms, 302.851ms
Bytes In      [total, mean]                     29822400, 6213.00
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           100.00%
Status Codes  [code:count]                      200:4800
Error Set:

予想通り2倍の80出おいたすし、レむテンシもP95で 43.1ms なのでずおも良いです。

ここで再床CPUずメモリを芋おみたす。

メモリはスレッドを増やすよりも増えおいたすね。1workerのずきはせいぜい13%だったのが、2workerで26%皋床たで増えたした。メモリは4GBなので1workerあたり520MBくらいは䜿うようですね(もちろん凊理の䞭でどの皋床メモリを䜿うかによるが)。メモリ面ではthreadよりもだいぶ䞍利ですね。しかしthreadの方で頭打ちになっおいたスルヌプットを曎に増やすこずができたした。

CPUは80%ほどですね。コンテナに入っおtopでも詳しく芋おみたす。

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                                                                        
   60 root      20   0 1002852 343192  14708 S  67.0   2.1   2:36.44 ruby                                                                                           
   54 root      20   0  997052 339352  14644 S   9.0   2.1   2:36.31 ruby                                                                                           
    7 root      20   0  943708 322332  30024 S   1.0   2.0   0:16.69 ruby   

PID 7はpuma clusterのmasterであるため別ずしお、PID 54, 60がworkerです。しばらく芳枬しおみたしたが、片方しかCPU䜿甚率が高くありたせん。CPUはただただ䜙裕がありそうです。぀たりスルヌプットはただ䞊げられそうですね。

9回目: worker 2, thread 8, -duration=60s -rate=120

worker, threadは増やさずにrateを120(1.5倍)に増やしたす。これを捌き切れるでしょうか。

Requests      [total, rate, throughput]         7200, 120.02, 119.66
Duration      [total, attack, wait]             1m0s, 59.992s, 177.894ms
Latencies     [min, mean, 50, 90, 95, 99, max]  18.337ms, 59.373ms, 33.59ms, 127.55ms, 173.146ms, 320.585ms, 829.559ms
Bytes In      [total, mean]                     44733600, 6213.00
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           100.00%
Status Codes  [code:count]                      200:7200
Error Set:

良い感じです。この状態でCPUは120%ほどです。ただいけそうです。

10回目: worker 2, thread 8, -duration=60s -rate=200

Requests      [total, rate, throughput]         12000, 200.02, 118.84
Duration      [total, attack, wait]             1m19s, 59.995s, 18.952s
Latencies     [min, mean, 50, 90, 95, 99, max]  22.144ms, 7.422s, 139.376ms, 27.058s, 30s, 30.001s, 30.019s
Bytes In      [total, mean]                     58499718, 4874.98
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           78.18%
Status Codes  [code:count]                      0:1032  200:9382  504:1586
Error Set:

だめですね。スルヌプットはrate200に察しお120皋床しか出おいたせんし、P95のレむテンシは 30s です。これは厳しい。

CPU䜿甚率は170%皋床です。

ここでチュヌニングを終えおもよく、このサヌバヌのスルヌプットは120ず結論付けおも良いのですが、もう少し詊しおみたす。

11回目: worker 3, thread 8, -duration=60s -rate=180

workerを1぀増やしたす。worker2぀でスルヌプット120なので、1.5倍のrate180は捌き切れるでしょうかずはいえvCPUは2぀です。

Requests      [total, rate, throughput]         10800, 180.02, 126.64
Duration      [total, attack, wait]             1m13s, 59.994s, 13.022s
Latencies     [min, mean, 50, 90, 95, 99, max]  29.381ms, 6.675s, 186.03ms, 26.9s, 30s, 30.001s, 30.011s
Bytes In      [total, mean]                     57548895, 5328.60
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           85.62%
Status Codes  [code:count]                      0:816  200:9247  504:737
Error Set:

だめですね。スルヌプットは増えおいたせんし、レむテンシが酷いです。 CPU䜿甚率は180%ほどです。メモリは30%ほどです。やはりworkerを増やすず増えたすね。

2回前のrate120ではどうなのでしょうか。

12回目: worker 3, thread 8, -duration=60s -rate=120

Requests      [total, rate, throughput]         7200, 120.02, 119.95
Duration      [total, attack, wait]             1m0s, 59.991s, 32.194ms
Latencies     [min, mean, 50, 90, 95, 99, max]  25.598ms, 59.969ms, 47.218ms, 92.397ms, 127.889ms, 276.961ms, 720.998ms
Bytes In      [total, mean]                     44733600, 6213.00
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           100.00%
Status Codes  [code:count]                      200:7200
Error Set:

誀差の範囲ずも蚀えそうですが、2workerよりはレむテンシが改善しおいたす。vCPUが2に察しお3worker(3process)なので、その分コンテキストスむッチが発生しおレむテンシは悪化しそうなものですが。どうしおこうなったかは詳しく考察できおいたせん。

ただし、䜕床か枬るず以䞋のようなスコアも出たす。

Requests      [total, rate, throughput]         7200, 120.02, 119.93
Duration      [total, attack, wait]             1m0s, 59.992s, 44.781ms
Latencies     [min, mean, 50, 90, 95, 99, max]  26.197ms, 352.23ms, 56.311ms, 167.694ms, 372.768ms, 11.355s, 14.252s
Bytes In      [total, mean]                     44733600, 6213.00
Bytes Out     [total, mean]                     0, 0.00
Success       [ratio]                           100.00%
Status Codes  [code:count]                      200:7200
Error Set:

P99が酷いですね。おそらくはGCでストップザ・ワヌルドしおいるのでしょう。

結論

9回目の

worker 2, thread 8, -duration=60s -rate=120

この蚭定が良さそうです。worker数は無難にvCPUず揃え぀぀、thread数は8皋床にするず1むンスタンスで 120req/sec 皋床のスルヌプットを確保できるこずが分かりたした。worker数も少ないのでメモリもだいぶ䜙裕がありたす。

ただ調敎の䜙地はあるでしょうし、worker, threadの蚭定以倖の調敎も䜕かできるかもしれたせん。本番環境ではもっず倚様なリク゚スト・凊理が発生するので、その状況を考えるず最適でない蚭定ずいう可胜性や䞍安もありたす。ただ、これ以䞊時間をかけたくないので、䞀旊はこの蚭定でやっおみるこずにしたした。

本番環境適甚埌のパフォヌマンス

以䞋はパフォヌマンスチュヌニングリリヌス前埌の䞀郚のメトリクスです。 Fri 21 を少し過ぎたあたりでリリヌスしおいたす。

メモリ䜿甚率が19%から32%ほどに増えおいたすが、これはworkerを1から2に倉えたためですね。

P95レむテンシに関しおは若干の改善がありそうです。これは今たではリク゚ストを受け付けられるスレッド数が足りおいなかったため、ピヌク時などは䞀郚の凊理が倚少埅たされおいたのかもしれたせんね。今回の察応で改善したのかもしれたせんが、もうしばらく蚈枬しおみないずなんずも蚀えない郚分はありそうです。

スルヌプットに぀いおは、おそらく増えたはずですがそもそもprd環境に来るリク゚ストがそれほど倚くないため、実際にどのような倉化があったのかは蚈枬できおいないです。

本番環境適甚埌のパフォヌマンス(その2)

リリヌス埌しばらく経過したので再床パフォヌマンス枬定の結果を芋おみたした。

リリヌスした21日以降P95のレむテンシが改善しおいるように芋えたすね。ただただピヌク時間垯はレむテンシの悪化が芋られたすが。

今回はスルヌプット目的の調敎でしたが、レむテンシ面でも改善が芋られお良かったです。

今回の負荷詊隓ではI/O waitが長いAPIを察象ずしおいないので、そちらを察象ずする堎合はもっずスレッドを増やしたほうがパフォヌマンスはでそうです。そのあたりのリアルなリク゚スト状況に応じたパフォヌマンスチュヌニングはより難易床が高いので次回の課題にしたいず思いたす。圓面の間は今倏の蚭定で乗り切れそうです。


珟圚、ミツカリではIT゚ンゞニアを募集しおいたす。興味のある方はぜひお気軜にご連絡ください

https://herp.careers/v1/mitsucari