😼

ベンチマークのスコアは、常に高ければ高いほど良いのでしょうか?

2024/01/08に公開

私の書籍やニュースレターを読まれている方なら、私がパフォーマンスエンジニアリングを支持していることをご存じかもしれません。パフォーマンスエンジニアリングとは、パフォーマンス作業を行う際、要件と制約を前もって明確にし、それらを満たすようにシステムを設計することをいいます。求められるもの以上に良く(もしくは悪く)システムを設計するのではなく、求められる仕様に忠実にシステムを設計するのがエンジニアリングです。求められるよりも 2 倍大きな箱を設計したとしても、顧客の棚にフィットせず、顧客が希望する倍のコストがかかり、構築に規定の倍の時間がかかるとしたら、それは「より良い」箱を設計したことにはなりません。間違った箱を設計しているのです。

あらゆる計算機システムには、性能要件があります。もしそうでなければ、世界が終わりを迎える寸前に仕事を終えるようなシステムですら、要件を満たすことになってしまいます。そのようなシステムにお金を払ってくれる顧客はいないでしょう(もしいたら、ぜひ紹介してください)。

では、性能要件として求められるレイテンシーやスループットを上回るのは、常に良いことと言えるでしょうか? 1 秒間に 1,000 リクエスト処理できるより、1 秒間に 10,000 リクエスト処理できる方が常に良いのでしょうか? ページの読み込みを 1 秒ではなく 0.5 秒で行えるのは?

たいていの場合、要件を上回るには制約を破るという代償を伴います。プログラミングには様々な制約があります。その中でも特に重要なのは時間とお金です。もちろん、制約を満たせるのであれば、要件を上回ることに通常問題はありません(ただし、顧客には確認した方が良いでしょう。例えば、2 倍速いシステムと 2 倍早く完成するシステムのどちらが良いかなど)。

要件を上回るのが有用かを判断する一番のコツは、分母と分子を反転させることです。例えば、1 秒あたりのリクエスト数ではなく、1 リクエストあたりの秒数で考えてみるのです。

実例:Puma

私は、Rack Web アプリケーションサーバーである Puma のプロジェクトメンテナーの一人です。私は、Puma に対し、すべてのリクエストに 1 ミリ秒以上のオーバーヘッドを追加してはならないという非公式な要件を設定しています。この要件は「ほとんどのアプリケーションはレスポンスを返すのに少なくとも 10 ミリ秒、通常は 100 ミリ秒以上かかる」という、HTTP ベースの Web アプリケーションへの私の理解から導き出したものです。つまり、ほとんどのアプリケーションで、Puma のオーバーヘッドをレスポンスタイム全体の 10%以下(通常は 1%以下)にするという要件です。私はこれを良い要件と感じています。もし、このオーバーヘッドを 1 ミリ秒から 0.1 ミリ秒に減らしたとしても、Puma を 10 ミリ秒以上の待ち時間がある HTTP アプリケーションに使っているユーザーにとって、それほど大きな違いはないでしょう。

しかしながら、Web サーバーでは、この要件の分母と分子を反転させ、レイテンシーではなくスループットをベンチマークとして使うのが一般的です。例えば、TechEmpower が測るのは「リクエスト/秒」という観点のベンチマークです。現在の Puma のスコアは、設定にもよりますが、10,000 ~ 15,000 リクエスト/秒となっています。

しかし、このベンチマークは、アプリケーションサーバーにとっては全く意味がありません。アプリケーションサーバーの仕事は、アプリケーションを提供することです。サーバーが 1 秒間に何回「hello world」を応答できるかは、アプリケーションサーバーの仕事にとって重要でしょうか? そうしたベンチマークに使われる「アプリケーション」は、比較に意味がないほど、ユーザーが実際に行っていることとあまりにもかけ離れてしまっています。

リクエストごとに 0.5 ミリ秒のオーバーヘッドを追加する機能を Puma に追加するか検討しているとしましょう。現在のベンチマークを見ると、Puma は 10,000 リクエスト/秒、つまり 0.1 ミリ秒/リクエストの処理をしています。この機能をマージすると、スループットベンチマークは大幅に悪化し、新しい結果は 1666 リクエスト/秒となり、84%の減少となってしまいます。この機能はマージすべきでしょうか?

次のように考えてみてください。現在、実際の Puma アプリケーションの 99%は、アプリケーションの処理に 10 ミリ秒強費やしています。すると、この変更を入れると、99%の Puma ユーザーのアプリは 6%遅くなってしまうことになります。この機能にはそれだけの価値があるのでしょうか? そうかもしれませんし、そうでないかもしれません。しかし、6%のパフォーマンスペナルティと引き換えにでも、私が Puma に組み込みたい機能や変更はたくさん考えられます!

ここでは、全てを左右しているのはフレームです。この機能を追加するということは、アプリケーションが約 2 ミリ秒以下でレスポンスを返す必要がある場合には Puma は使わないでくださいと言っていることになります。しかし、実際にその制約に引っかかる HTTP アプリケーションの数は、おそらくほとんどないはずです。

ともあれ、0.5 ミリ秒が重要になるシナリオやユースケースも確かに存在します。例えば、Puma が WebSocket のパフォーマンスを向上させたい場合には、アイドル接続のオーバーヘッドに注意する必要があります。アイドル接続に 0.5 ミリ秒のオーバーヘッドがあると、処理できる接続数に大きな影響を与えますし、Puma プロセスごとに 1,000 以上のアイドル接続があることは決して珍しくはありません。

アプリケーションの作者であるあなたは、そのアプリケーションに対するパフォーマンスとして何が期待されているかを誰よりもよく知っているはずです(そう望みます!)。スコアが高ければ高いほど良いという考えにはとらわれずに、どの程度のパフォーマンスで十分なのかを考えてみてください。

-Nate

Discussion