以前のmysql生死シリーズに続いて、私のタイトルが頻繁に使用されていることがわかりました。生死動物園の飼育係、生死マルチスレッドがたくさんあります。今回は、インタビューの質問シリーズMQトピック、一般的な日常使用の中間としてのメッセージキューを開始しました。面接も重要なポイントの1つです。MQ面接の質問を見てみましょう。
なぜmqを使うのですか?具体的な使用シナリオは何ですか?
mqの役割は非常に単純で、山を切り、谷を埋めます。eコマーストランザクションで注文を行うシナリオをとると、フォワードトランザクションのプロセスには、注文の作成、在庫の差し引き、アクティビティ予算の差し引き、ポイントの差し引きなどが含まれる場合があります。各インターフェースの時間が100msの場合、理論的には注文するためのリンク全体に400msかかりますが、これは明らかに長すぎます。
これらの操作がすべて同期的に処理される場合、第一に、呼び出しリンクが長すぎてインターフェースのパフォーマンスに影響を与えないこと、第二に、分散トランザクションの問題に対処することが困難です。現時点では、予算の控除やポイントなどのリアルタイムの一貫性に対する要件はそれほど高くありません。 mqによって非同期的に処理できます。同時に、非同期による不整合を考慮して、ジョブを使用して再試行し、インターフェイスコールが成功したことを確認できます。通常、企業には注文成功の問題などの検証プラットフォームがありますが、検証によるポイントの減点は検証できません。底への解決策。
mqを使用した後、リンクが単純になり、同時に、メッセージを非同期に送信するためのシステム全体のストレス耐性も向上しました。
どのmqを使用しますか?どのタイプの選択に基づいていますか?
主にいくつかの主流のmq、kafka、rabbitmq、rocketmq、activemqを調査しました。選択は、主に次の点に基づいています。
システムのqps圧力は比較的大きいため、パフォーマンスが主な考慮事項です。
開発言語、私たちの開発言語はjavaであるため、主に二次開発の便宜のためです。
同時実行性の高いビジネスシナリオでは必要であるため、分散アーキテクチャの設計をサポートする必要があります。
機能は包括的です。ビジネスシナリオが異なるため、シーケンシャルメッセージ、トランザクションメッセージなどが使用される場合があります。
上記の考慮事項に基づいて、最終的にRocketMQを選択しました。
カフカ | RocketMQ | RabbitMQ | ActiveMQ | |
---|---|---|---|---|
単一マシンのスループット | 100,000レベル | 100,000レベル | 万 | 万 |
開発言語 | Scala | Java | Erlang | Java |
高可用性 | 分散アーキテクチャ | 分散アーキテクチャ | マスタースレーブアーキテクチャ | マスタースレーブアーキテクチャ |
パフォーマンス | ミリ秒レベル | ミリ秒レベル | 私たちのクラス | ミリ秒レベル |
特徴 | メインのMQ機能のみをサポート | シーケンスメッセージやトランザクションメッセージなどの完全な機能 | 強力な同時実行性、優れたパフォーマンス、低遅延 | 成熟したコミュニティ製品、豊富なドキュメント |
上記の非同期送信についてお話しましたが、メッセージの信頼性を確保するにはどうすればよいですか?
メッセージの損失は、プロデューサーがメッセージを送信する、MQ自体がメッセージを失う、コンシューマーがメッセージを失うという3つの側面で発生する可能性があります。
プロデューサーが負けました
プロデューサーがメッセージを失う可能性のあるポイントは、プログラムが送信に失敗し、再試行せずに例外をスローするか、送信プロセスは成功したが、ネットワークフラッシュMQがプロセス中にメッセージを受信せず、メッセージが失われることです。
通常、同期送信はこのように表示されないため、同期送信の問題は考慮せず、非同期送信のシナリオに基づいています。
非同期送信は、コールバックありの非同期とコールバックなしの非同期、コールバックなしの2つの方法に分けられます。プロデューサーが送信した後、結果に関係なく、メッセージが失われる可能性があります。非同期送信+コールバック通知+ローカルメッセージテーブルの形式を使用します。解決策を作ることができます。次の注文のシナリオの例。
注文後、ローカルデータとMQメッセージテーブルを保存します。この時点で、メッセージのステータスは送信中です。ローカルトランザクションが失敗すると、注文は失敗し、トランザクションはロールバックします。
注文が成功すると、直接クライアントに正常に戻り、MQメッセージを非同期で送信します
更新データベースMQ送信ステータスに対応するMQコールバック通知メッセージ送信結果
JOBポーリングが特定の時間(ビジネス構成に応じた時間)を超え、再試行するための成功メッセージを送信していません
監視プラットフォームまたはJOBプログラムを構成して、失敗したメッセージ、アラーム、および手動介入を特定の回数以上処理します。
一般的に、ほとんどのシナリオでは、非同期コールバックの形式で十分であり、メッセージを失わないことを完全に保証する必要があるシナリオに対してのみ完全なソリューションを作成します。
MQがありません
プロデューサーがメッセージがMQに送信されることを保証し、メッセージを受信した後もMQがメモリ内にある場合、マシンはダウンしており、スレーブノードに同期する時間がないため、メッセージが失われる可能性があります。
たとえば、RocketMQ:
RocketMQは、同期フラッシュと非同期フラッシュの2つの方法に分けられます。デフォルトは非同期フラッシュです。これにより、ハードディスクにフラッシュする前にメッセージが失われる可能性があります。同期フラッシュの方法を設定して、メッセージの信頼性を確保できます。 、このようにして、MQがハングした場合でも、メッセージを復元するときにディスクからメッセージを復元できます。
たとえば、Kafkaは次のように構成することもできます。
acks=all 只有参与复制的所有节点全部收到消息,才返回生产者成功。这样的话除非所有的节点都挂了,消息才会丢失。
replication.factor=N,设置大于1的数,这会要求每个partion至少有2个副本
min.insync.replicas=N,设置大于1的数,这会要求leader至少感知到一个follower还保持着连接
retries=N,设置一个非常大的值,让生产者发送失败一直重试
構成によってMQ自体の高可用性という目的を達成することはできますが、すべてパフォーマンスが低下します。構成方法は、ビジネスに応じて検討する必要があります。
消費者が失った
消費者がメッセージを失うシナリオ:消費者はメッセージを受信したばかりで、サーバーはこの時点でダウンしています。MQは、消費者がすでにメッセージを消費していると見なし、メッセージを繰り返し送信しないため、メッセージが失われます。
デフォルトでは、RocketMQは消費者に確認応答への返信を要求しますが、Kafkaは手動で構成を有効にし、自動オフセットを無効にする必要があります。
消費者は確認応答を返しません。再送信メカニズムは、MQタイプの送信時間間隔と時間によって異なります。再試行が回数を超えると、デッドレターキューに入り、手動で処理する必要があります。(カフカにはこれらがありません)
消費者の消費の失敗の問題について話しましたが、消費の失敗がメッセージのバックログを引き起こした場合はどうなりますか?
消費者は常に消費を間違えるという問題があるため、以下の観点から考えることができます。
消費者のエラーは、プログラムまたはその他の問題が原因である必要があります。修正が簡単な場合は、最初に問題を修正して、消費者に通常の消費を再開させます。
時間が遅すぎて対処できない場合は、転送プロセスを実行し、一時的な消費者消費計画を作成し、最初にメッセージを消費してから、新しいトピックとMQリソースに転送します。この新しいトピックのマシンリソースは個別に申請され、それを実行できる必要があります。ニュースの現在のバックログ
バックログデータを処理した後、新しいMQおよび既存のMQデータを消費するようにコンシューマーを修復し、新しいMQの消費が完了した後に元の状態を復元します
メッセージバックログがディスク制限に達し、メッセージが削除された場合はどうなりますか?
この。。。私を削除するために何がありますか。。。落ち着いて、もう一度考えてください。。はい。
最初に、送信したメッセージレコードがデータベースに保存され、転送されたデータも保存されました。次に、データのこの部分を使用してデータの欠落している部分を見つけ、別のスクリプトを実行して再送信できます。転送されたプログラムがライブラリにない場合は、それを消費者の記録と比較しますが、プロセスは少し難しくなります。
以上のように、RocketMQの実装原理についてお話しいただけますか?
RocketMQは、NameServerレジストリクラスター、プロデューサープロデューサークラスター、コンシューマーコンシューマークラスター、およびいくつかのブローカー(RocketMQプロセス)で構成されます。そのアーキテクチャの原則は次のとおりです。
ブローカーは起動時にすべてのNameServerに登録し、長い接続を維持し、30秒ごとにハートビートを送信します
プロデューサーは、メッセージの送信時にNameServerからブローカーサーバーアドレスを取得し、負荷分散アルゴリズムに従ってメッセージを送信するサーバーを選択します。
Conusmerがメッセージを消費すると、NameServerからブローカーアドレスも取得し、メッセージをアクティブにプルして消費します。
RocketMQが登録センターとしてZookeeperを使用しないのはなぜですか?
zookeeperを使用しない理由はいくつかあると思います。
CAP理論によれば、最大2つのポイントを同時に満たすことができますが、動物園の飼育係はCPを満たしているため、飼育係はサービスの可用性を保証しません。飼育係が選挙を行う場合、選挙全体に時間がかかりすぎ、クラスター全体がサービス検出は可用性のために設計する必要があるため、レジストリには絶対に受け入れられない使用不可状態。
パフォーマンスの考慮事項に基づいて、NameServer自体の実装は非常に軽量であり、マシンを追加してクラスターの耐ストレス性を高めることで水平方向に拡張できます。zookeeperの記述はスケーラブルではなく、zookeeperはフィールドを分割することによってのみこの問題を解決できます。 、複数の動物園飼育員クラスターを分割して解決するには、まず操作が複雑すぎて、次にCAPのAの設計に違反し、サービス間の切断が発生します。
永続化メカニズムによって引き起こされる問題であるZooKeeperのZABプロトコルは、書き込み要求ごとに各ZooKeeperノードにトランザクションログを書き込み続け、同時に、メモリデータの定期的なスナップショットをディスクに追加してデータを確保します単純なサービス検出シナリオの場合、これは実際には必要ありません。この実装スキームは重すぎます。また、それ自体で保存されるデータは高度にカスタマイズする必要があります。
メッセージの送信はレジストリに弱く依存する必要があり、RocketMQの設計コンセプトはこれに基づいています。プロデューサーは、メッセージを初めて送信するときにNameServerからブローカーアドレスを取得し、ローカルにキャッシュします。NameServerのクラスター全体が利用できない場合は、短時間です。生産者や消費者にはあまり影響を与えません。
ブローカーはどのようにデータを保存しますか?
RocketMQの主なストレージファイルには、commitlogファイル、consumequeueファイル、およびindexfileファイルが含まれます。
ブローカーはメッセージを受信すると、メッセージをcommitlogファイルに保存します。同時に、分散ストレージでは、各ブローカーがトピックデータの一部を保存します。同時に、各トピックに対応するメッセージキューの下にconsumequeueファイルが生成されます。 commitlogの物理的な場所のオフセットを保存するために、キーとオフセットの間の対応する関係がインデックスファイルに保存されます。
CommitLogファイルは$ {Rocket_Home} / store / commitlogディレクトリに保存されます。図から、ファイル名のオフセットを明確に確認できます。各ファイルのデフォルトは1Gで、いっぱいになると新しいファイルが自動的に生成されます。
同じトピックのメッセージはcommitlogに継続的に保存されないため、消費者がcommitlogから直接メッセージを取得することは非常に非効率的です。したがって、commitlog内のメッセージのオフセットの物理アドレスは、consumequeueを介して保存され、消費者は最初に消費します。消費キューからのオフセットに基づいて特定のcommitlog物理ファイルを見つけ、特定のルール(オフセットとファイルサイズを法として)に従ってcommitlogですばやく見つけます。
マスターとスレーブ間でデータを同期する方法は?
マスターとスレーブ間のメッセージの同期は、raftプロトコルに従って実行されます。
ブローカーがメッセージを受信すると、コミットされていないものとしてマークされます
その後、メッセージはすべてのスレーブに送信されます
スレーブは、メッセージを受信した後、マスターにack応答を返します。
ackの半分以上を受信した後、マスターはメッセージをコミット済みとしてマークします
コミットされたメッセージをすべてのスレーブに送信すると、スレーブもステータスをコミット済みに変更します
RocketMQが速い理由を知っていますか?
これは、シーケンシャルストレージ、ページキャッシュ、および非同期フラッシュを使用しているためです。
commitlogを書き込むときは順次書き込むため、ランダム書き込みよりもパフォーマンスが大幅に向上します。
commitlogを書き込むときは、ディスクに直接書き込まれるのではなく、最初にオペレーティングシステムのPageCacheに書き込まれます。
最後に、オペレーティングシステムは、キャッシュ内のデータをディスクに非同期的にフラッシュします
トランザクションメッセージとセミトランザクションメッセージとは何ですか?どうやってそうなった?
トランザクションメッセージは、MQが提供するXAと同様の分散トランザクション機能です。分散トランザクションの最終的な一貫性は、トランザクションメッセージを通じて実現できます。
セミトランザクションメッセージは、MQがプロデューサーからメッセージを受信したが、2回目の確認を受信しておらず、配信できないメッセージです。
実現原理は次のとおりです。
プロデューサーは最初にセミトランザクションメッセージをMQに送信します
MQは、メッセージを受信した後、確認応答を返します
プロデューサーが現地業務を開始
トランザクションが正常に実行された場合は、コミットをMQに送信し、失敗した場合は、ロールバックを送信します
MQがプロデューサーの2回目の確認コミットまたはロールバックを長時間受信しない場合、MQはプロデューサーへのメッセージバックチェックを開始します
プロデューサーは、トランザクション実行の最終ステータスを照会します
クエリトランザクションステータスに応じて2番目の確認を送信します
最後に、MQが2番目の確認コミットを受信すると、メッセージをコンシューマーに配信できます。それ以外の場合、ロールバックの場合、メッセージは3日後に保存および削除されます。
<終了>
この記事が好きな友達は、公式アカウントプログラマーのXiaohuiをフォローして、 もっとエキサイティングなコンテンツを見てください。
点个[在看],是对小灰最大的支持!