web-dev-qa-db-ja.com

なぜキューとしてのデータベースはとても悪いのですか?

私はこれを読んだところです 記事 、そして私は混乱しています。

1つのwebappと1つの異なるアプリケーションが「ワーカー」として機能し、両方が同じデータベースを共有していると想像してみてください。

ああ、私は「共有」と言いましたが、記事は何について警告していますか? :

第4に、アプリケーション(またはサービス)間でデータベースを共有することは悪いことです。不定形の共有状態をそこに置くのはあまりにも魅力的であり、それを知る前に巨大に結合したモンスターができます。

=>同意しない。個別のアプリケーションが同じユニットの一部である場合があるため、「カップリングの問題」の概念はこの場合意味がありません。

続けましょう:webappはクライアントHTTPリクエストを処理し、いつでもいくつかの集計(DDD用語)を更新して、対応するドメインイベントを生成します。
ワーカーの目標は、必要なジョブを処理してこれらのドメインイベントを処理することです。

ポイントは:

イベントデータをワーカーにどのように渡す必要がありますか?

最初の解決策は、読んだ記事が推進しているように、優れたメッセージ指向ミドルウェアであるRabbitMQを使用することです。

ワークフローは簡単です。

Web dynoがイベントを生成するときはいつでも、ワーカーにフィードするRabbitMQを介してそれを公開します。
欠点は、対処せずに、集約更新のコミットとイベントの発行の間の即時の一貫性を保証するものがないことです潜在的な送信エラー...またはハードウェアの問題。それは別の主要な問題です。

例:集計更新が成功せずにイベントが発行された可能性があります。その結果、ドメインモデルの誤った表現を表すイベントが発生します。
グローバルXA(2フェーズコミット)が存在すると主張することはできますが、これはすべてのデータベースまたはミドルウェアに適合するソリューションではありません。

では、この即時の一貫性を確保するための優れたソリューションは何でしょうか? :
IMO。イベントをデータベースに格納し、集約更新と同じローカルトランザクションで実行します。
単純な非同期スケジューラが作成され、データベースから現在の未公開イベントをクエリし、それらをRabbitMQに送信して、ワーカーにデータを投入します。

しかし、なぜwebapp側に、そしてちなみに追加のスケジューラが必要なのですか。なぜこの場合、RabbitMQが必要なのでしょうか。

このソリューションでは、特にデータベースが共有されているため、RabbitMQは不要であるように思われます。
実際、どのような場合でも、即時整合性はデータベースからのポーリングに関与することがわかりました。
このように、なぜ労働者はこの投票に直接責任を負わないのですか?

したがって、メッセージ指向のミドルウェアを宣伝しながら、ウェブ上の多くの記事がデータベースのキューイングをほとんど批判しないのはなぜでしょうか。

記事の抜粋:

シンプルで、仕事に適したツールを使用してください。このシナリオは、メッセージングシステムを求めています。上記のすべての問題を解決します。これ以上のポーリング、効率的なメッセージ配信、完了したメッセージをキューからクリアする必要、共有状態はありません。

そして即時整合性、無視されますか?

要約すると、実際には、データベースが共有されているかどうかにかかわらず、データベースポーリングが必要です。

私はいくつかの重要な概念を見逃しましたか?

ありがとう

34
Mik378

トラフィックの少ないシンプルなアプリケーションを構築している場合、別のコンポーネントをシステムに入れないようにすることについて注意すべきことがあります。メッセージバスを使用しないことが正しい答えである可能性が非常に高いです。ただし、データベースベースのキューシステムをミドルウェアソリューションに交換できる方法でシステムを構築することをお勧めします。私はその記事に同意します。データベースは、キューベースのシステムに適したツールではありませんが、それで十分かもしれません。

RabbitMqのようなキューベースのシステムは、適度なハードウェア上で大規模に構築されています。彼らのアーキテクチャは、本質的に [〜#〜] acid [〜#〜] 準拠のデータベースシステムを遅くするプロセスを回避することでこれを実現できます。メッセージバスは、メッセージが確実に格納されて正常に処理されることを確認する必要があるだけなので、トランザクションログのロックや書き込みに煩わされる必要はありません。これらの概念はどちらもACIDシステムには絶対に必要ですが、多くの場合、競合の原因となります。

パフォーマンスに関しては、SQLテーブルがあるということになります。たくさんの読み取りとたくさんの書き込み。どちらも、行、ページ、インデックスを更新するために、なんらかのロックが必要です。ポーリングメカニズムは、インデックスを常にロックしてインデックスを検索しています。これにより、書き込みが発生しなくなります。せいぜいキューに入れられます。処理を実行するコードもロックされ、完了または失敗したときにキューのステータスを更新します。はい、最適化の後にクエリ最適化を実行してこれを機能させることも、要求している作業負荷用に特別に設計されたシステムを使用することもできます。 RabbitMqはこのタイプのワークロードを、汗をかきさえすることなく使い果たします。さらに、データベースをワークロードから保存して、他のことを実行するための拡張の余地を与えることができます。

考慮すべきもう1つの点は、ほとんどのキューシステムは通常、ポーリング手法を使用しないことです(一部はHTTPを許可しますが、受信側には使用しないことをお勧めします)。 RabbitMqは [〜#〜] ampq [〜#〜] などのメッセージバス用に特別に設計されたネットワークプロトコルを使用します。

編集:使用例を追加します。

Rabbitを使用した方法は、頻繁に使用されるデータベーステーブルを必要とする変更を受け入れるAPIエンドポイントがあったことです。このテーブルは常に競合しているため、APIから変更をタイムリーに保存できない場合があります。代わりに、変更要求をキューに書き込み、これらのメッセージを可能な限り処理するサービスを用意します。データベースの競合が発生すると、キューが大きくなり、メッセージの処理が遅れます。通常、処理時間は14ミリ秒の範囲ですが、競合が激しい場合は最大2〜3秒かかります。

31
brianfeucht