web-dev-qa-db-ja.com

複数のデータベース呼び出しは、Web APIのネットワーク呼び出しで本当に重要ですか?

私の雇用主の1つでは、REST(ただし、SOAPにも適用されます)APIに取り組んでいました。アプリケーションUIであるクライアントは、Web(通常の製品ではLAN)を介して呼び出しを行いますAPIへの展開)APIはデータベースを呼び出します。

私たちの議論で繰り返される1つのテーマはパフォーマンスです。チームの一部の人々は、パフォーマンスのために、単一のAPI呼び出しから複数のデータベース呼び出し(通常は読み取り)を行うべきではないと信じています。各API呼び出しが(正確に)1つのデータベース呼び出しのみを持つように、それらを最適化する必要があります。

しかし、それは本当に重要なのでしょうか? UIがAPIへのネットワーク呼び出しを行う必要があることを考慮してください。それはかなり大きい(ミリ秒の桁)。データベースは、物事をメモリに保持し、読み取りを非常に迅速に実行するように最適化されています(たとえば、SQL ServerはすべてをRAMにロードして保持し、ほとんどすべての空きを消費しますRAM =可能な場合)。

TLDR:すでにLAN経由でネットワーク呼び出しを行っているときに、複数のデータベース呼び出しを心配することは本当に重要ですか?ある場合、それはなぜですか?

明確にするために、私は桁違いの話をしています-それは仕様(マシンのハードウェア、APIとDBの選択など)に依存することを知っています。O(ミリ秒)を要する呼び出しがある場合、DBに対して最適化を行います桁違いに少ない呼び出し、実際には重要ですか?それともこれ以上の問題がありますか?

編集:後世のために、これらの状況下でデータベース呼び出しを組み合わせてパフォーマンスを改善する必要があると主張することは、特にプロファイリングの欠如を伴い、かなりおかしいと思います。ただし、これを行うかどうかは私の決定ではありません。これがWeb API呼び出しを最適化する正しい方法であると考える根拠の背後にあるものを知りたいです。

16
ashes999

しかし、それは本当に重要なのでしょうか? UIがAPIへのネットワーク呼び出しを行う必要があることを考慮してください。それはかなり大きい(ミリ秒の桁)。データベースは、物事をメモリに保持し、読み取りを非常に迅速に実行するように最適化されています(たとえば、SQL ServerはすべてをRAMにロードして保持し、ほとんどすべての空きを消費しますRAM =可能な場合)。

ロジック

理論的には、あなたは正しいです。ただし、この根拠にはいくつかの欠点があります。

  1. あなたが述べたことから、あなたが実際にあなたのアプリをテスト/プロファイルしたかどうかは不明です。つまり、アプリからAPIへのネットワーク転送が最も遅いコンポーネントであることを実際に知っていますか?それは直感的であるため、そうであると容易に想定できます。ただし、パフォーマンスについて議論するときは、決して想定するべきではありません。私の雇用主では、私が業績のリーダーです。私が最初に参加したとき、人々はボトルネックがどうあるべきかについての直感に基づいてCDNや複製などについて話し続けました。結局のところ、最大のパフォーマンスの問題は、データベースクエリのパフォーマンスの低下でした。

  2. データベースはデータの取得に優れているため、データベースは必ずピークパフォーマンスで実行されており、最適に使用されており、それを改善する方法はありません。つまり、データベースは高速に設計されているので、心配する必要はありません。別の危険な考え方。それは、車はすぐに動くようになっていると言っているようなものなので、オイルを交換する必要はありません。

  3. この考え方では、一度に1つのプロセスを想定するか、別の方法で並行性を想定しません。 1つの要求が別の要求のパフォーマンスに影響を与えることができないと想定しています。ディスクI/O、ネットワーク帯域幅、接続プール、メモリ、CPUサイクルなどのリソースが共有されます。したがって、1つのデータベース呼び出しで共有リソースを使用する回数を減らすと、他のリクエストの速度低下を防ぐことができます。私が現在の雇用主に初めて加入したとき、経営陣は3秒のデータベースクエリの調整は時間の無駄だと信じていました。 3秒はとても短いのに、なぜそれに時間を浪費するのですか? CDNや圧縮などのほうがいいのではないでしょうか。しかし、3秒のクエリを1秒で実行できる場合、たとえばインデックスを追加することで、ブロック化が2/3少なく、スレッドの占有にかかる時間が2/3少なくなり、さらに重要なことに、ディスクから読み取られるデータが少なくなります。つまり、 RAM内キャッシュからフラッシュされるデータが少なくなります。

理論

ソフトウェアのパフォーマンスは単にspeedであるという共通の概念があります。

純粋にスピードの観点から、あなたは正しいです。システムの速度は、最も遅いコンポーネントと同じです。コードのプロファイルを作成し、インターネットが最も遅いコンポーネントであることがわかった場合、他のすべてが明らかに遅い部分ではありません。

ただし、上記を踏まえて、リソースの競合、インデックス付けの欠如、不十分なコードの記述などにより、パフォーマンスに驚くほどの違いが生じることがわかると思います。

仮定

最後に一つだけ。アプリからAPIへのネットワークコールと比較して、データベースコールは安価である必要があると述べました。ただし、アプリとAPIサーバーは同じLANにあるとも述べました。したがって、どちらもネットワーク呼び出しと同等ではありませんか?言い換えると、APIの転送がデータベースの転送よりも桁違いに遅く、両方の帯域幅が同じであると想定しているのはなぜですか?もちろん、プロトコルとデータ構造は異なりますが、それは桁違いであるという仮定に異議を唱えます。

どこが暗くなるか

この問題全体は、「複数」と「単一」のデータベース呼び出しに関するものです。しかし、その数が複数であるかは不明です。上記で述べたことから、一般的な経験則として、データベース呼び出しは必要最小限に抑えることをお勧めします。しかし、それは経験則にすぎません。

理由は次のとおりです。

  1. データベースはデータの読み取りに優れています。それらはストレージエンジンです。ただし、ビジネスロジックはアプリケーションに存在します。すべてのAPI呼び出しの結果、データベース呼び出しが1つだけになるというルールを作成すると、ビジネスロジックがデータベースで終了する可能性があります。多分それは大丈夫です。多くのシステムがそれを行います。しかし、そうでないものもあります。柔軟性についてです。
  2. 場合によっては、適切なデカップリングを実現するために、2つのデータベース呼び出しを分離する必要があります。たとえば、おそらくすべてのHTTPリクエストは、ユーザーが適切なアクセス権を持っていることをDBから検証する汎用セキュリティフィルターを介してルーティングされます。含まれている場合は、そのURLに適切な機能を実行します。その関数はデータベースと相互作用する場合があります。
  3. ループでデータベースを呼び出す。これが何が複数かを尋ねた理由です。上記の例では、2つのデータベース呼び出しがあります。 2で結構です。 3は大丈夫かもしれません。 Nは良くありません。ループでデータベースを呼び出すと、パフォーマンスが線形になりました。つまり、ループの入力が多いほど時間がかかります。したがって、断定的に言うと、APIネットワーク時間が最も遅いと言うことは、データベースを10,000回呼び出すまだ発見されていないループが原因で、トラフィックの1%が長時間かかるなどの異常を見落とすことです。
  4. いくつかの複雑な計算のように、アプリが得意な場合があります。データベースからいくつかのデータを読み取り、いくつかの計算を行い、その結果に基づいて、パラメーターを2番目のデータベース呼び出しに渡す必要がある場合があります(おそらくいくつかの結果を書き込むため)。データベースを1回だけ呼び出すためだけにこれらを1つの呼び出し(ストアドプロシージャのような)に組み合わせると、アプリサーバーが得意なものにデータベースを使用せざるを得なくなります。
  5. 負荷分散:1つのデータベース(おそらく)と複数の負荷分散されたアプリケーションサーバーがあります。そのため、アプリの作業が多くデータベースが少ないほど、データベースのレプリケーションをセットアップするよりもアプリサーバーを追加する方が一般的に簡単であるため、スケーリングは簡単です。前の箇条書きに基づいて、SQLクエリを実行し、複数のサーバーに分散されているアプリケーションですべての計算を実行し、終了時に結果を書き込むことは理にかなっています。これにより、スループット全体が向上する可能性があります(全体のトランザクション時間が同じであっても)。

TL; DR

TLDR:LAN経由で既にネットワーク呼び出しを行っている場合、複数のデータベース呼び出しについて心配することは本当に重要ですか?もしそうなら、なぜですか?

はい、しかしある程度までです。実用的な場合は、データベース呼び出しの数を最小限に抑えるようにしてください。ただし、相互に何の関係もない呼び出しを結合するために、それらを結合しないでください。また、絶対にループでデータベースを呼び出すことは避けてください。

25
Brandon

彼らが理由がある前にあなたのチームが最適化しているように聞こえます。これらのリクエストを実行する時間を測定しましたか? Webサーバーへの往復の待ち時間がWebサーバーからデータベースへの接続時間よりもはるかに長くなるため、このパラダイムがエンドユーザーのパフォーマンスを低下させる可能性があります。その上、ほとんどのWebブラウザーは単一のWebサーバーへの2つの同時接続しか行わないため、複雑なページの場合、そこでボトルネックが発生する可能性があります。

どちらの方法でも、データをバックアップすることなく最適化の決定を下すべきではありません。それを測定し、アプリケーションに最適なものを見つけます。

3
brianfeucht

お答えできません

クエリがどのように見えるかはわかりません。彼らが完了するまでにかかる時間はわかりません。 APIサーバーへの各リクエストにどのくらいのオーバーヘッドが関係しているかはわかりません。クライアントがどのように地理的に分散しているかはわかりません。 その他

これが最適化が必要なシナリオであり、できるシナリオコールを分割するか結合するかを決定します両方の方法でベンチマークする必要があります:最適化する対象(UIレイテンシ、サーバーCPU負荷、競合など)を決定し、1つを選択します最適化の目標をより適切に達成するもの。


それとは別に、私が比較的確実に追加できる唯一のoneことはこれです:

単一のリクエスト内で、応答を作成するために実行する必要があるすべてのクエリを実行する必要があります。

つまり、N個すべてのクエリが実行されるまで応答を生成できない場合、通常はそれらを分離しても意味がありません。中間か完全かにかかわらず、各クエリの後に意味のある結果を生成できる場合は、ベンチマークを開始します。

2
svidgen

2つの考え:

まず、APIを使用する消費者に対して、タスクを実行するために1回の呼び出しを行います。サーバーが要求を満たすための呼び出しを受け取った後に何が起こるかはそれほど厳格であってはなりません。コンシューマーからの1回の呼び出しで、データをまとめて返すために10個のサブワークアイテムが必要な場合は、それで問題ありません。

次に、問題のプロセスに実際のデータベースパフォーマンスの問題が発生していますか。私の経験では、データベース要求のすべての側面を1つの呼び出しにまとめようとすると、データに対して3つまたは4つの呼び出しを行うよりも、呼び出しの効率が低下することがわかっています。最新のデータベースは、キャッシングと実行計画において非常に効率的です。多くの場合、あまりにも多くのことを実行しようとすると、カーソルを使用した手順(一度に1つのセットとしてではなく、行ごとにデータが処理されるためパフォーマンスが非常に低下します)が発生し、コードが壊れた場合よりも効率の悪い計画になります。いくつかの小さな簡単なステップへの呼び出し。

コードの単純な構成から、私は各API呼び出しが単一のストアドプロシージャ(またはdb関数)を呼び出す可能性があることに同意します。手順には複数のステップがある場合があります。

1
Richard

データベースがRESTサービスとは異なるサーバー上にある場合、データベース呼び出しごとにネットワークラウンドトリップが発生し、canはパフォーマンスを大幅に低下させます。

単一のWebサービス呼び出しが約500のデータベースクエリに変換されることをかつて確認しました-Webサービスとデータベースの両方が同じマシン上にある場合、これはほとんど問題になりませんでしたが、それらが異なる場合、6〜7秒の応答時間に変わりましたマシン。

明らかに、データベースへの500回の往復はかなり極端です。私はあなたのパフォーマンス要件が何であるかはわかりませんが、経験則として、REST呼び出しごとに約10未満のデータベースクエリにとどまる場合、大きなパフォーマンスヒットは発生しないはずです。

1
Astrotrain

とてもおしゃべりなアプリケーションがいくつかあります。すべてに対してデータベース呼び出しがあります。シングル。リトル。こと。参照データを何度も提供することは、システムのワークロードの主要な部分です。実際のディスクI/Oがなくても、ワーカースレッドのスケジュール、ロックの取得と削除、キャッシュチェックの計画など、すべての結果が加算されます。トランザクションは複数のDB呼び出しにまたがってロックを保持する必要があるため、スループットは実際よりもはるかに低くなるため、競合はさらに高くなります。これらのチームは現在、このため、非常に高価な新しいDBサーバーを購入する必要があると考えています。

したがって、システムの現在の構成の経過時間の大部分はREST API呼び出しで取得されますが、DBレベルでのパフォーマンスを無視すると、将来の問題が保存されます。

1
Michael Green

提示された最適化パスは、物事を見るには間違った方法です。

API呼び出しはアトミックである必要があります。つまり、必要なアクションを実行するために1つのWeb API呼び出しを行うことができるはずです。それがデータをフェッチすることであろうと、レコードを更新することであろうと何であれ。アクションを実行するために、2つ以上の呼び出しを行わないでください。また、複数の呼び出しにまたがるトランザクションを活用しようとすることは、ペストのように回避する必要があります。

時々、単一のアクションはかなり複雑です。たとえば、複数のソースから結合されたデータをフェッチする場合も、これは1回の呼び出しでなければなりません。全体が機能するか、全体が失敗します。

さて、単一のAPI呼び出しが1つのDBクエリのみを実行するべきだと言うことは少しモロニックです。ご指摘のとおり、ネットワーク全体でコールをマーシャリングするためのオーバーヘッドは、多くの場合、全体の時間の点で数桁高くなります。

やや単一のクエリを実行すると複数のクエリよりも速くなるというステートメントを理解できます。ただし、DBとネットワークの合計負荷が無視されるため、これは誤った印象を与えます。 DBからデータを取り出すさまざまな方法をプロファイリングすることによってのみ、問題が実際に何であるかを理解できます。特定のクエリが予想よりも100倍頻繁に実行され、適切なインデックスが設定されるまでシステムを強制終了するという話は誰にもあると思います...

結局のところ、話しかけるだけでは説得することはできません。両方のアプローチのテストケースを設定し、プロファイリングします。必要なデータを取得するための合計時間、生成されたネットワークトラフィックの量、データベースコールの数とタイミングなどに注意してください。全体的なアプローチを取る-つまり、システム全体を調べることになります。カラスを食べるか、黄金の道を示すデータ。

0
NotMe