なぜキューとしてのデータベースがそんなに悪いのか?[閉まっている]


33

私はこの記事を読んだばかりで、混乱しています。

1つのwebappと1つの別個のアプリケーションが「ワーカー」として動作し、両方が同じデータベースを共有しているとしましょう。

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

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

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

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

ポイントは:

イベントデータをワーカーに渡す方法

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

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

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

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

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

しかし、なぜwebapp側で余分なスケジューラーが必要なのか、そしてところで:この場合RabbitMQが必要なのはなぜですか?

このソリューションでは、特にデータベースが共有されているため、RabbitMQは不要である可能性があります。
実際、どのような場合でも、即時一貫性にデータベースからのポーリングが含まれることがわかりました。
したがって、なぜワーカーはこのポーリングに直接責任を負わないのでしょうか?

したがって、なぜWeb上の多くの記事が、データベース指向のキューイングを批判しているのに、メッセージ指向のミドルウェアを宣伝しているのか疑問に思います。

記事の抜粋:

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

そして、即時の一貫性は無視されますか?

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

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

ありがとう


2
ほぼすべての主要なデータベースには、他のプロセスに非同期的に通知するためのメカニズムがあり、テーブルからいくつかの作業を引き出すためです。
Blrfl 14年

回答:


28

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

RabbitMqのようなキューベースのシステムは、中程度のハードウェア上で大規模に構築されています。そのアーキテクチャは、ACID準拠のデータベースシステムをその性質によって遅くするプロセスを回避することにより、これを達成できます。メッセージバスは、メッセージが保存されて正常に処理されることを確認するだけでよいため、トランザクションログのロックと書き込みに煩わされる必要はありません。これらの概念は両方ともACIDシステムに絶対に必要ですが、多くの場合、競合の原因です。

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

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

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

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


この場合、どのようにして即時のコンシステンシーを処理できますか 発行が行われた直後に、ドメインモデルの更新を担当するトランザクションがロールバックした場合...ミドルウェアはまったく認識されず、イベントを処理します。
Mik378 14年

あなたは書いた:「ロックを気にする必要はない」。しかし、ルーティングされたイベントの(ワーカーへの)昇順(時間内)を確保するために、確実に一種のロックがありますか?
Mik378 14年

@ Mik378 メッセージべき等性に関するこの記事をご覧ください。はい、技術的には一貫性の約束を失いますが、アプリケーションの稼働時間とパフォーマンスの信頼性の点であなたが得るものを見つけることは間違いないでしょう。また、メッセージの処理方法を変更して、損失を非常に簡単にすることもかなり簡単です。
brianfeucht

2
はい、順序を保証するためにロックが必要になります。一部のキューシステムは、パフォーマンスを犠牲にしてこれを提供できます。操作が順不同で発生することがあるという事実を受け入れ、それをプロセッサ側で処理する方法を見つけ出すことができれば、パフォーマンスの観点から指数関数的に得られます。
brianfeucht

1
@ Mik378-回答にユースケースを追加しました。私はそれが役立つことを願っています!
ブライアンフェウチ14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.