blog

RocketMQ メッセージストレージ

分散キューは高い信頼性が要求されるため、データを永続的に保存する必要があります。 Apacheは別のMQ - ActiveMQのオープンソースの下でメッセージの永続性を行うには、JDBCの方法を選択す...

Dec 1, 2020 · 6 min. read
シェア

I. 基本プロセス

分散キューは高い信頼性が要求されるため、データの永続的な保存が必要です。

  1. メッセージ・ジェネレーターはメッセージを
  2. MQはメッセージを受信し、メッセージを永続化し、新しいレコードをストアに追加します。
  3. プロデューサーにACKを返送
  4. MQはメッセージを対応するコンシューマにプッシュし、コンシューマがACKを返すのを待ちます。
  5. メッセージ・コンシューマが指定された時間内に ACK を正常に返した場合、MQ はメッ セージの消費に成功したとみなし、ストレージ内のメッセージを削除します。
  6. MQはメッセージを削除します。

II.記憶媒体

  • リレーショナル・データベース DB

別のMQ - ActiveMQの下でApacheのオープンソースは、簡単なxmlの設定情報をJDBCメッセージストレージを実現することができますを通じて、メッセージの永続JDBCの方法を行うことを選択することができます。に起因する、1000万レベルの単一のテーブルのデータ量の通常のリレーショナルデータベースは、そのIOの読み取りと書き込みのパフォーマンスがボトルネックになる傾向があります。信頼性の面では、プログラムは非常にDBに依存している、一度DBが失敗した場合、MQのメッセージは、ディスクストレージがオンライン障害につながる落下することはできません。

  • ファイルシステム

    現在、業界でより一般的に使用されている製品は、デプロイされたVM/物理マシンのファイルシステムにメッセージをブラッシングすることによって永続化を行うために使用されています。メッセージ・スワイピングは、メッセージ・ストレージに非常に効率的で信頼性が高く、高性能なデータ永続化手法を提供します。デプロイされたMQマシン自体やローカル・ディスクがハングアップしない限り、永続化できないという障害問題は通常発生しません。

  • 分散KVストレージ

memcachedに代表されるように、多くのWebアプリケーションはRDBMSにデータを保存し、そこからアプリケーションサーバーがデータを読み出してブラウザに表示しています。 しかし、データ量の増加やアクセスの集中に伴い、RDBMSの負荷の増大、データベースのレスポンス悪化、Webサイトの表示遅延など、大きな影響が出てきます。 memcachedは、高性能な分散型メモリキャッシュサーバです。 一般的な目的は、データベースのクエリ結果をキャッシュすることでデータベースへのアクセス回数を減らし、動的なWebアプリケーションのスピードとスケーラビリティを向上させることです。

コントラスト:

  • 貯蔵効率:

ファイルシステム > 分散KVストレージ > リレーショナルデータベースDB

  • 簡単な実装と迅速な統合

リレーショナルデータベース DB>分散KVストレージ>ファイルシステム

III.メッセージの保存と送信

1、メッセージストレージ

ディスクは適切に使用すれば、ネットワークのデータ転送速度に匹敵します。現在の高性能ディスクは、最大600MB/秒のシーケンシャル書き込み速度を達成することができ、これは一般的なネットワークカードの転送速度を上回ります。しかし、ディスクのランダム書き込み速度は100KB/秒程度で、シーケンシャル書き込み速度の2倍です!RocketMQのメッセージは逐次的に書き込まれるため、メッセージの保存速度が保証されます。

2、メッセージ送信

Linuxオペレーティングシステムは、ユーザー状態とカーネル状態に分割され、ファイル操作、ネットワーク操作は、必然的にデータのコピー、これらの2つのフォーム間の切り替えを伴う必要があります。

サーバーは、ローカルディスクファイルの内容を、一般的に2つのステップでクライアントに送信します:

1) read: ローカル・ファイルの内容を読みます;

2) WRITE:読み込んだ内容をネットワーク経由で送信。

一見単純に見えるこの2つの操作は、実際にはそれぞれ何回ものデータ複製を実行します:

  1. ディスクからカーネル状態のメモリにデータをコピーします;
  2. カーネル状態メモリからユーザー状態メモリへのコピー;
  3. その後、ユーザー状態のメモリーからネットワーク・ドライバーのカーネル状態のメモリーにコピーされます;
  4. 最後に、ネットワーク・ドライバーのカーネル・ステート・メモリーからネットワーク・カードにコピーされ、転送されます。

mmapを使うことで、ユーザーランドへのメモリコピーをなくし、高速化することができます。この仕組みはJavaではMappedByteBufferで実装されています。

RocketMQは、「ゼロコピー」技術としても知られるこれらの機能を最大限に活用し、メッセージの保存とネットワーク配信の速度を向上させます。

ここで注意しなければならないのは、MappedByteBufferをメモリマッピングの方法として使用するにはいくつかの制限があるということです。そのうちの1つは、一度に1.5~2Gのファイルしかユーザーランドの仮想メモリにマッピングできないということです。

IV.メッセージ保存構造

RocketMQのメッセージの保存は、ConsumeQueueとCommitLogによって行われます。実際の物理的な保存ファイルはCommitLogで、ConsumeQueueはメッセージの論理的なキューで、トピックに関する情報を保存し、データベースのインデックスファイルに似ていて、物理的な保存場所を指すアドレスを保存します。各トピックの下にある各メッセージ・キューには、対応するConsumeQueueファイルがあります。

  • CommitLog: メッセージのメタデータを保存します。
  • ConsumerQueue: CommitLogにメッセージのインデックスを格納します。
  • IndexFile:メッセージを探すために、キーや時間間隔によってメッセージを照会する方法を提供します。IndexFileによってメッセージを探すこの方法は、メッセージの送受信の主要なプロセスには影響しません。

メッセージ保存の主なプロセス:

プロデューサがメッセージを送信した後、メッセージは保存されます:

コミットログファイルにメッセージの内容を保存します。

トピック、開始オフセット、メッセージ長などを含むトピック情報を consumerqueue ファイルに格納します。

インデックス・ファイルにインデックス情報を保存

コンシューマがメッセージを消費するとき、トピックに従ってコンシューマキューファイルに照会、対応するトピックを見つけ、メッセージの読み取りを開始します。このとき、読み取られるデータは、メッセージの開始オフセットとメッセージの長さです。メッセージの開始オフセットに従って、コミットログから対応するオフセットの位置を調べ、メッセージの長さに従って、コミットログのデータを取得します。つまり、指定されたメッセージの内容を取得します。つまり、指定されたメッセージの内容を取得します。

コンシューマが tag タグを使用してメッセージを取得した場合、インデックス・ファイルを使用し、上述 と同様の方法でメッセージの内容を取得します。

V. ブラシディスク機構

RocketMQのメッセージはディスクに保存されるため、停電が発生しても復旧でき、保存されるメッセージの量がメモリの上限を超えることはありません。RocketMQはパフォーマンスを向上させるために、ディスクへの書き込みを可能な限り順次行うようにしています。ProducerがRocketMQにメッセージを書き込む場合、ディスクへの書き込みには分散同期フラッシングと非同期フラッシングの2つの方法があります。

1) 同期ブラシプレート

同期スワイプ:メモリマップファイルはディスクに直接書き込まれます。

書き込み成功ステータスが返されると、メッセージがディスクに書き込まれたことになります。具体的な処理としては、メッセージがメモリ上のPAGECACHEに書き込まれた後、直ちにディスクのフラッシュを行うようフラッシングスレッドに通知し、フラッシングが完了するのを待ち、フラッシングスレッドがフラッシングの実行を終えると待ちのスレッドを起こし、メッセージが正常に書き込まれたステータスに戻ります。

2) 非同期ブラシプレート

非同期スワイプ:メモリマップされたファイルはオフヒープメモリに書き込まれ、非同期にスワイプされます。

書き込み成功状態に戻るとき、メッセージはメモリのPAGECACHEに書き込まれるだけかもしれません、書き込み動作の復帰は速く、スループットは大きいです。メモリ内のメッセージの量があるレベルまで蓄積されると、書き込みディスク動作が一律にトリガされ、迅速に書き込まれます。

3) コンフィギュレーション

ディスクを同期的にフラッシュするか非同期的にフラッシュするかは、Broker設定ファイルのflushDiskTypeパラメータによって設定されます。

Read next

デザインパターン・シリーズ - SOLID設計原則

S、O、L、I、Dは、オブジェクトの設計とコーディングの重要な原則と向き合うことを目的としています。これらの原則が使われると、プログラムの拡張や保守が容易になります。 上の単一責任原則の英語の説明から、単一責任原則の原則は比較的単純であることがわかります。つまり、クラスやモジュールは1つの機能だけを実行する責任を持つべきだということです。 言い換えれば、クラスやモジュールを設計する際には、大規模で包括的なクラスやモジュールを設計することは避けましょう。

Dec 1, 2020 · 11 min read