【システムアーキテクチャ】メッセージミドルウェアのアーキテクチャと原理

メッセージミドルウェアの役割は、非同期並行処理機能のキャリアとなることです。それだけでなく、アーキテクチャの多くの機能、高可用性、高い並行処理、スケーラビリティ、信頼性、整合性、順序保証などを確保する必要があります。これらはさまざまな設計者にとって頭痛の種です。消費が遅い、非反復的ななど、いくつかの異常なニーズがあります。費やす必要のある設計コストはかなり高いので、多くのメカニズムで、オープンソースのダニエルを盲目的に迷信にしないでください。再構築する必要があります。すべてのビジネスに適しており、使いやすく、普遍的なプライベートクラウドを構築することはそれほど簡単ではありません。

支払いシステムが毎日数十億件のビジネス注文を処理する場合、多くのシステムはミドルウェアのクラスタリング能力に依存しており、エラーが発生しないようにするため、メッセージミドルウェアの処理能力は少なくとも100億近くでなければなりません。アーキテクチャのいくつかの側面からミドルウェアを少し分析してみましょう。

高可用性(高可用性)

高可用性は永遠のトピックです。これは、金融の世界における信頼性の尺度でもあります。データの一部であっても、金融業界のアーキテクトはデータの損失を防ぐ方法を見つけることを知っておく必要がありますが、実際、これは理論的には、性格による。これはちらつきではありません。

例を挙げれば、インターネットデータアーキテクチャでは、データの少なくとも3つのコピーが高保証と呼ばれますが、実際には、Googleのベルギーのデータセンターは、8.13への落雷の影響で0.00001%(0.05未満)永久に失われましたディスクの%は修復されていません。ここで言いたいのは、適切なタイミングであり、状況が非常に重要であることです。極端な状況では不可能はありません。アーキテクチャの脆弱性があります。mq高可用性の一般的な方法を見てみましょう

次の図は、activemqのHAソリューションです。

1233356-702eb3dea716f13b.png

ActivemqのHAは、マスター/スレーブフェイルオーバーを介してホストされ、マスター/スレーブスイッチは複数の方法で切り替えることができます。

1:nfsまたは他の共有ディスクデバイスを使用して共有ロックを実行します。共有ファイルロックを使用してマスターの状態をマークします。mが電話を切ると、対応するスレーブがshared_lockを使用してマスターに変換します

2:飼育係によるクラスターの管理はより一般的であり、ここでは説明しません

次の図はmetaqのHAソリューションです

1233356-a908be28c6cd391e.png

上の図に示すように、zkを介してブローカーを管理するマスターノードとスレーブノードにも同じことが当てはまります。

もちろん、これはフェイルオーバーメカニズムの1つにすぎず、ブローカーが電話を切ったときにメッセージがスレーブに変換されることを保証するだけですが、プロセスの途中でメッセージが失われることは保証できません。

ブローカーからメッセージが送信される場合、ダウンタイムまたはその他のハードウェア障害が原因でメッセージが失われる可能性がありますが、現時点では、メッセージを保証するために関連する記憶媒体が必要です。

次に、カフカのストレージメカニズムを参照として使用します。メッセージミドルウェアをストレージに依存させるには、高速が必要であるだけでなく、IO要件のコストも非常に低く抑える必要があることを知っておく必要があります。カフカは、上記の要件を満たす一連のストレージメカニズムを設計しました。紹介します。

最初に、kafkaのトピックは、分散デプロイメントで複数のパーティションに分割されます。パーティションはメッセージの負荷に相当し、次に複数のマシンによってルーティングされます。例:トピック、debit_account_msgは、debit_account_msg_0、debit_account_msg_1に分割されます、debit_account_msg_2。N個のパーティションを待つと、各パーティションは/ debit_account_msg / topicなどのローカルディレクトリを生成します

内部のファイルは多くのセグメントに分割され、各セグメントは500MBのセグメントなどのサイズを定義し、ファイルは2つの部分のインデックスとログに分割されます

    00000000000000000.index
    00000000000000000.log
    00000000000065535.index
    00000000000065535.log

番号はmsgIdの値のインデックスの開始点を表し、対応するデータ構造は次のとおりです。

1233356-972f90ede17eaaa8.png

1,0はmsgIdが1のメッセージを表し、0はこのファイルのオフセットを表します。このファイルを読み取った後、対応するセグメントログファイルを見つけ、対応するmsg情報を読み取ります。対応する情報は固定ですメッセージ本文のフォーマット:

1233356-cbdd6229fc1c0ea4.png

明らかに、このメカニズムの単純なアプリケーションは、高い同時I / Oに確実に対応できません。最初に、segmentfileバイナリを検索し、次に、オフセットを介して対応するデータを見つけ、次にmsgsizeを読み取り、次にレポート本文を読み取ります。 、しかし、プル時に使用される順次読み取りは、基本的にほとんど効果がありません。

上記のクエリに加えて。実際、ディスクに書き込む前に、OSのページキャッシュで読み取りと書き込みが行われ、非同期スレッドを通じてハードディスクがフラッシュされます(LRU戦略)。特に、大量のデータの消費とバックログが遅い場合のデータの損失、ただしカフカの新しいmetaqは、この部分と、これらのパーティションファイルのレプリケーションメカニズム(Aliが使用)に多くの変更を加えているため、このレベルではインターネットの落雷によりメッセージが失われる可能性は比較的低くなりますが、ホストルームの光ケーブルが掘られたときに何が起こるかを排除するものではありません。

そんなに言ってみれば、より完璧で美しいように見えますが、実際には維持管理費が非常に高いようです。これらはファイルであるため、問題が発生すると、手動で処理するのは非常に面倒であり、1台のマシン上にあり、いくつかの操作とメンテナンスの仕様とAPI呼び出し機能を実行するには、比較的大きな操作とメンテナンスのコストが必要です。

したがって、この領域では、mongoDBなどの一部のnosqlにデータを変換して格納できます。もちろん、mysqlも可能ですが、強力なトランザクション処理メカニズムと財務機能がない限り、io機能とnosqldbは同じレベルではありません。 Liは確かにこの要件について非常に厳格です。Alipayの背後にあるmetaqの使用と同様に、以前のミドルウェアtbnotifyは、消費が遅い場合に非常にパッシブであり、metaqはこの領域で非常に有利になるため、後で分解を聞いてください。

高い並行性

最初は、mqを使用したエンジニアのほとんどが性能sum の問題を解決するために使用されました异步化。実際、同じ点についてio调度は、それほどリソースを消費しません。さらなる苦労をせずに、mqの高い同時実行ポイントのいくつかを見てみましょう。ここにいくつかの有名なミドルウェアの背景があります:

Activemqは当時、エンタープライズレベルの特殊なソリューションでした。jeeのjms仕様に準拠していました。実際、パフォーマンスは依然として良好でしたが、インターネットに引っ張られたとき、それはスイカを抱いたウサギであり、何もできませんでした。

Rabbitmqはerlang言語で記述され、AMQPプロトコル仕様に準拠しており、よりクロスプラットフォームです。モード転送モードはより豊富で、

rocketmq(今日のmetaq3.0の最新バージョン、kafkaはmetaqの前任者でもあり、当初はリンクされていたオープンソースのログメッセージシステムです)、metaqは基本的に、Javaでのkafkaの原理とメカニズムを記述しました。開発速度は非常に速く、アリと中国にはこのメンテナンスを行うのに非常に良いコミュニティがあります。

パフォーマンスを比較するために、参照用のインターネットからのデータを以下に示します。

1233356-9db0160ceb800c69.png

正直に言うと、これらのデータレベルでの違いはばかげていませんが、いくつかの共通点を分析できます。主なパフォーマンスの違いは何ですか。

Rocketmqはmetaqの後継です。いくつかの新機能とメカニズムの改善を除いて、パフォーマンスの原則は似ています。これらの高パフォーマンスのいくつかのハイライトを次に示します。

rocketmqの消費は主にプルメカニズムを使用するため、ブローカーの場合、多くの消費機能をブローカーに実装する必要はなく、コンシューマーを通じて関連データをプルするだけでよく、activemqと同様、rabbitmqは古いブローカーにメッセージをディスパッチさせる方法はもちろん、これらはjmsまたはamqpのいくつかの標準的な配信方法でもあります。

ファイルストレージは順番に保存されるため、メッセージをプルするときにセグメントデータを呼び出すだけでよく、コンシューマーは情報を消費するときに最大限に情報を消費します。バックログを生成することはほとんどなく、ioを設定できます。 noopモードのようなスケジューリングアルゴリズムは、一部の順次読み取りのパフォーマンスを向上させることができます。

pagecacheホット消費は、osキャッシュのデータをヒットすることで実現されます。

metaqのバッチディスクIOとネットワークIOは、データを1つのioで実行しようとします。メッセージはすべてバッチで処理されるため、ioのスケジューリングで多くのリソースを消費する必要はありません。

以下に示すように、NIO送信は、これが元のmetaqのアーキテクチャです。元のmetaqは、Taobaoの内部geckoと統合されたいくつかの高性能NIOフレームワークと通知リモーティングを使用してメッセージを配信しました。

1233356-fbc7dcdd0ded3c5d.png

コンシューマキューの軽量化。メッセージ機能がキューを通じて取得されることを知っている必要があります。

下の写真を見てください:

1233356-dde4266c8cd62300.png

metaq物理的に追加コンシューマ・キュー・ロジック・キューは、ディスクのデータに対応するキューをシリアル化され、キューがディスクを追加するために追加されることはありませんiowait、負担を順次書き込むことができますが、読み取りは、ランダム読み込みする必要性がまだあるとき最初の論理キューで、その後、ディスクを読んで、そうpagecache、メモリを大量に作ってみることが重要であり、この割り当ては完全に使用されます。

実際、上記は基本的に比較的高いレベルでのパフォーマンスを保証しますが、パフォーマンスは最も重要ではない場合があります。最も重要なことは、他のアーキテクチャ機能との最適なバランスを取ることです。結局のところ、他のメカニズムが満たされなければなりません。これは、業界で最も難しい3つの問題は、高い同時実行性、高可用性、一貫性です。

スケーラブル

これはよくある質問ですが、一般的なシステムやミドルウェアの場合は、より拡張することができますが、メッセージのミドルウェアでは常に面倒でした。

activemqの拡張にはビジネスの性質が必要であるため、最初にactivemqの拡張の制限について説明します。ブローカーとして、最初に送信元と宛先を知る必要がありますが、これらのメッセージが分散伝送の場合は複雑になります。では、activemqを見てみましょう。ロードの再生方法:

1233356-b24977e544400a1d.png

プロデューサーがtopicAメッセージを送信すると仮定します。通常の状況ですべてのコンシューマーが各ブローカーに接続されている場合、それは暑いですか?ブローカーにプロデューサーからのメッセージがある場合、対応するコンシューマーに転送できます。

しかし、図のbroker2に対応するメッセージがない場合、この場合はどうすればよいでしょうか。同じトピックのアプリケーションシステム(プロデューサー)ノードと依存システム(コンシューマー)ノードが多数あると想定されているため、容量を拡張するにはどうすればよいですか。Activemqは上の画像の通常の部分を実行できますが、プロデューサー、ブローカー、コンシューマーの対応する構成を変更する必要があり、これは非常に面倒です。

もちろん、activemqはマルチキャストを介して動的検索を行うこともできます(lvsまたはf5が負荷として使用されていると誰かが述べましたが、コンシューマーには大きな問題があり、この負荷構成はトピックの分散に実質的な影響を与えません)しかし、私が言った問題はまだあります、トピックが大きすぎる場合、各ブローカーはすべてのプロデューサーまたはコンシューマーを接続する必要があります。

metaqがこれをどのように行うかについて話しましょう。図を見て話してください。

1233356-888ca116dff81d84.png

Metaqはトピックごとにパーティション化されています。このレベルでは、できるだけ多くのトピックパーティションを構成する必要があります。このように、スライスはルーティングルールとして「ビジネス」の概念を持つことです。通常、ブローカーマシンには多くの構成があります。トピック、各トピックは通常、マシン上に1つのパーティションしかありません。マシンが十分でない場合、複数のパーティションをサポートすることもできます。通常、ビジネスIDを使用して、送信領域のパラメーターを取得することにより、カスタムパーティションをモデル化できます。それだけです。

1233356-53305f2951166b6d.png
1233356-8b0c266b9ca55e6d.png

信頼性

信頼性はメッセージミドルウェアの重要な機能です。mqがこれらのメッセージをどのように循環させるかを見てみましょう。最初にactivemqをリファレンスとして使用します。これはプッシュとプッシュのメカニズムに基づいています。

送信されたすべてのメッセージが確実に消費されるようにするにはどうすればよいですか?Activemqプロデューサーは、受信を確認するメッセージを送信した後、ブローカーのackを受信する必要があります。ブローカーには、コンシューマーに同じ保証が提供されます。

Metaqのメカニズムも同じですが、ブローカーからコンシューマーへのプルが行われるため、その到着保証はコンシューマーの能力に依存しますが、一般に、アプリケーションサーバークラスターが雪崩の影響を与えることはほとんどありません。

メッセージのべき等性を保証する方法は?現在、基本的にactivemqであり、metaqはメッセージのべき等性を保証できません。ブローカーがタイムアウトすると再試行されるため、再試行すると新しいメッセージが生成されます。ブローカーが着陸した可能性があるため、この場合、同じビジネスパイプラインが2つのメッセージを生成する保証はありません。

メッセージの信頼性を確保する方法は?この時点で、activemqとmetaqは基本的に同じメカニズムを持っています。

プロデューサー保証:ブローカーにデータを生成した後、ACKを返すために永続化する必要があります

ブローカーの保証:metaqサーバーはメッセージを受信した後、メッセージを定期的にハードディスクに更新し、同期/非同期でデータをスレーブにコピーして、ダウンタイム後に消費が影響を受けないようにします。

Activemqは、データベースまたはファイルを介してローカルに保存され、ローカルのリカバリを実行します

消費者保証:メッセージの消費者は次々にメッセージを消費します。メッセージの消費に成功した後にのみ、次のメッセージを消費し続けます。メッセージの消費に失敗した場合(例外など)、メッセージの消費を再試行します(デフォルトでは最大5回です)。最大回数を超えた後も消費できず、メッセージはバックグラウンドスレッドによってバックアップされたコンシューマーのローカルディスクに保存されますもう一度やり直してください。メインスレッドは引き続き後退し、後続のメッセージを消費します。したがって、MessageListenerが1つのメッセージの正常な消費を確認した後にのみ、メタコンシューマは引き続き別のメッセージを消費します。これにより、メッセージの確実な消費が保証されます。

一貫性

2つのシナリオについて説明するmqの一貫性:

1:メッセージが複数回送信/消費されないことを保証します
2:トランザクションを保証します

上で紹介したmqの一部は一貫性を保証できないので、どうしてですか?コストは比較的高く、これらはソースコードを変更することで保証できると言えます。また、スキームは比較的複雑ではありませんが、追加のオーバーヘッドは、一定の期間を確保するための追加のキャッシュクラスターなどによって比較的大きくなります。再現性、私はこの機能を備えたいくつかのmqがあるはずだと思います。

Activemqは2種類のトランザクションをサポートしています。1つはJMSトランザクション、もう1つはXA分散トランザクションです。トランザクションをもたらすと、ブローカーとの対話中にtransactionIdが生成されます。ブローカーは、TMを実装してトランザクション処理を分散します。 XA(JTA標準に準拠)activemqおよびmetaqトランザクションの保証はすべて、基本的に同じREDOログメソッドを通じて行われます。

ここでの分散トランザクションは、ブローカーステージの後でのみ保証されます。ブローカーがコミットする前に、準備メッセージがローカルファイルに保存され、コミットステージまでメッセージがキューに書き込まれます。最後に、第2ステージのコミットはTMを介して実装されます。


Kotlin開発者コミュニティ

1233356-4cc10b922a41aa80

中国で最初のKotlin開発者コミュニティの公開アカウント。主にKotlinプログラミング言語、Spring Boot、Android、React.js / Node.js、関数型プログラミング、プログラミングのアイデアなどの関連トピックを共有および交換しています。

世界が騒々しいほど、より平和な思考が必要です。

1665件のオリジナル記事が公開されました 1067件の賞賛 750,000回

おすすめ

転載: blog.csdn.net/universsky2015/article/details/105531346