序文
私たちの前でのRabbitMQインストール、制御ステーション、クイックスタートのRabbitMQを使用して、すべての主要なメッセージングミドルウェア、AMQP中核となる概念を、比較します。この章では、RabbitMQのの高度な機能について説明します。二つの点(上/下)が導入されます。
- どのようにメッセージの配信は、100%の成功を保証しますか?
- 詳細なコンセプトべき等
- 大規模な受注により生成されたビジネスのピークでは、どのようにメッセージを費やしの重複の問題を回避するには?
- 受信確認メッセージを確認し、リターン・メッセージを返します。
100%1つのメッセージ配信の成功を保証するには?
1.1生産の送出端部の信頼性とは何ですか?
- 送信されたメッセージの成功を確認してください
- MQノードが正常に保護を受けます
- MQの送信者は、ノード(ブローカー)承認を受け、
- メッセージのための補償機構を改善
最初の3つのステップでは、メッセージの配信が100%成功することを保証することはできないかもしれません。そこで、第4工程を追加します
BATインターネットソリューションの/ TMDメーカー: - メッセージを送信するときに、メッセージのステータスをマーク、落下のメッセージ、メッセージがデータベースに永続化する必要があり、状態(未送信、送信を設定するには、このメッセージを与えて、到着)。メッセージステータスが変化したときに、メッセージは変更を加える必要があります。メッセージの操作は、回転中に到着し、再送信されていないでください。回転の回数も3-5倍の制限を行う必要があります。メッセージが正常に送信できることを確認してください。
- メッセージの配信が遅れ、二次確認を行い、コールバックをチェック
これは具体的な実施形態を採用するだけでなく、同時実行性とメッセージトラフィックの量によって異なります。
1.2第1の実施形態は:
生産終了 - 信頼性の配達
グラフィック:
青い部分は、前記:注文データベースMSG DB:プロデューサがブローカにメッセージを送信する責任があるビズDBを終了する小規模アプリケーションプラス取引方法のメッセージデータ面は、トランザクションの整合性を確保するために使用することができます。ただし、高い同時実行の顔でメーカー、およびは、トランザクションを増加させなかったトランザクションスプライシングのパフォーマンスは非常に深刻ですが、補償を行います。
たとえば、次の注文は、メッセージを送信します。
STEP1:ストレージ・注文メッセージ(順序の作成)、業務データストレージ、ストレージのニュース。短所:永続二回。(状況:0)STEP2:成功STEP1の前提の下でメッセージを送信するSTEP3:ブローカのメッセージを受信した後、私たちの生産終了に確認してください。リスナーがメッセージブローカー非同期ポストバックをリッスン確認してください。STEP4:指定されたメッセージ、更新(ステータス= 1)を把持し、メッセージが正常に配信されたことを示します。
STEP5:データをフェッチするために0に等しい場合、タスクタイミング取得ステータスメッセージを配布しました。STEP6:メッセージSTEP7を再送信:再試行限界は3回に設定されています。メッセージが3回失敗したか、そして(ステータス= 2)を再試行する場合、我々はニュースが失敗であると考えています。
なぜ、これらのメッセージが失敗したクエリは、手動で照会する必要があるかもしれません。
STEP2は、成功したネットワークの不具合に起因するSTEP3を実行したとします。たとえば:メッセージ・ウェアハウスは、5分以上後のしきい値タイムアウト= 5分を設定すると、このデータが出てクロールされますそれは、我々はルールを設定する必要があり、メッセージを確認して受け取ることはありません。5分ごとのタスクや書き込みのタイミングは、メッセージステータス= 0が出てクロールします。小さな問題がある可能性があります。メッセージは、二回のメッセージの実装につながる、定期的なタスクを送信し、ただ単に通常のタスクを実行しますが、まだ受け取っていない確認し、実行。細かい操作:メッセージタイムアウト許容限度。確認メッセージが再度送信され、2〜3分以内に受信されません。
- 我々は最初の配信の信頼性場合MQが考える保証、非常に同時シナリオで適切なのですか?
本実施形態は、2つのデータストレージ、データ・ストレージ・サービス、メッセージストレージを有します。このようなデータのストレージがボトルネックとなっています。実際には、我々は唯一のストレージ事業においておく必要があります。
- メッセージの配信が遅れ、二次確認を行い、コールバックをチェック
このアプローチは、必ずしも100%の成功を保証するものではありませんが、また、ニュースの99.99%の成功を確実にするために。あなたが特に極端なケースが発生した場合は、あなただけを補うために、または定期的なタスクを実行するために労働力を必要とすることができます。第二の方法は、データベースの操作を低減するために主にあります。
見て第二の方法:
グラフィック:
上流のサービス:制作側下流サービス:消費者側のコールバックサービス:コールバックサービス
STEP1:成功したストレージ・ビジネスニュースの後、最初のメッセージが送られました。STEP2:成功貯蔵した後、同じメッセージ、第2のメッセージを送信するには、これら二つのメッセージが同時に送信されます。2番目のメッセージは、遅延チェックです、あなたは、伝送遅延を5分、2分を提供することができます。STEP3:指定されたキュー上で待機消費者側。STEP4:最終消費者がメッセージを処理した後、新たに内部で生成されたメッセージは、確認を送信します。MQ Brokerに投稿してください。STEP5:あなたはダウンストリームサービスを送信されたメッセージを受信した場合、コールバックサービスコールバックサービスは、MQブローカーをリッスンし、あなたはMSG DBへのメッセージストアの実装の成功を決定するためにメッセージを送ることができます。STEP6:モニターSTEP2を確認詳細を確認し、メッセージの配信を延期しました。この時点で、2つが同じキューリスナーはありませんが、5分後に、コールバックサービスは、MSG DBを確認し、メッセージを受信しました。メッセージが正常に配信された前に、それが見つかった場合、あなたは他のことをする必要はありません。チェックが見つかっ失敗した場合、コールバック補償は、RPC通信を送信します。生産の上流端は、メッセージを再送信通知します。
目的:以下DBストレージを行います。懸念事項ではない百パーセント成功した配信が、パフォーマンス。
2.冪等のコンセプト
2.1どのようなセックスように力であると?
冪等(冪等、冪等)が、すなわち、F(F(X))=、数学およびコンピュータサイエンスの概念共通の抽象代数学であり、 F(X)。それは単に動作の結果生成された最初の性能に一貫性のある結果を生成するために複数回行います。
- 私たちは、データベースの楽観的ロック機構から学ぶことができます。
- 例えば、我々は在庫を更新するSQL文を実行します。
- UPDATE T_REPS SET COUNT = COUNT - 1、VERSION = VERSION + 1 VERSION = 1
冪等を確保するために、プラスバージョンのバージョンの方法を使用します。
推奨読書:インタビュー不可欠なデータベース悲観的ロックと楽観的ロック
2.2消費者エンド - 冪等の保証
大規模な受注により生成されたビジネスのピークでは、どのように問題のあるメッセージを支出の重複を避けるために?
高い同時実行の場合は、MQに到達するためにニュースがたくさんあるでしょう、消費者側は、ニュースの多くに耳を傾ける必要があります。そのような場合には、それが配信メッセージを繰り返すことは避けられない、ネットワークが点滅し、好きになるでしょう。あなたは冪等でない場合は、繰り返し消費メッセージが表示されます。 - 消費者側の実装の冪等、それは我々が同じメッセージの複数のを受けているにもかかわらず、私たちのメッセージが複数回に消費されることはありませんことを意味し、それは一度だけ実行されます。
ユニークID +指紋の再利用データベースの主キーへの権利メカニズム - :インターネットの巨大な冪等操作の主流を見てください。 - 他の技術の冪等を - Redisの原子を使用して実装しました
唯一ID +指紋コード機構2.2.1
- 唯一のID +指紋右のメカニズムは、再使用するデータベースの主キーを。唯一の保証
- SELECT COUNT(1)T_ORDER WHERE ID = ID +指紋固有のコードからのクエリが添加されていない場合。何もする必要はありません、消費者側は、メッセージを消費する必要はありません。
- 利点:シンプル
- 短所:パフォーマンスのボトルネックのデータベース書き込みは、高い同時実行の下にあります。
- ソリューション:フォローアップIDが分割されたルーティングアルゴリズムライブラリサブテーブル共有トラフィック圧力。
2.2.2 Redisの原子プロパティ
Redisの自己通電最も簡単な使用。
- Redisのは冪等を使用し、問題を考慮すべき。
- まず:ライブラリがオフの場合、私たちはその問題を解決する鍵は、データベースとキャッシュアトミックを行う方法で、ライブラリからデータを必要ですか?プラスの取引ではない、とのRedisデータベースのトランザクションが同時に故障しながら、成功を保証することはできません、同じではありません。あなたは、任意のより良い選択肢がありますか?
- 第二:落下のために、そのタイミング同期の戦略を設定する方法、キャッシュに格納されている場合ではありませんか?安定性、キャッシュされたデータを達成するためにどのように?
3.確認メッセージを確認します
メッセージの確認応答機構の理解を確認します。
- 確認メッセージは、メッセージの送達後プロデューサを指すブローカメッセージを受信した場合、生産者は私達の応答を与えます。
- 生産者は、メッセージが正常ブローカに送信されるかどうかを決定するために、応答を受信し、このアプローチの核心は、メッセージの配信の信頼性を保護することです!
青:赤プロデューサープロデューサー:MQブローカーサーバーは、
プロデューサーは、メッセージの受信後に戻っプロデューサーにブローカー、ブローカーを終了するためにメッセージを送信します。リスナーリスナーの応答を確認してください。
プロデューサーがメッセージを送った後、チューブを必要としないときの動作は、非同期です。リスナーは、MQ Brokerの応答をlistenし確認してください。
3.1どのように確認確認メッセージを達成するには?
ステップ:確認モードでオープンチャネル:channel.confirmSelect()第2の工程と、追加シャネルリッスン:addConfirmListener、成功と失敗のモニタは、ログの結果に応じて再送信されたメッセージの結果を返し、等フォローアップ治療!
3.2コーディング:
プロデューサー:
/**
*
* @ClassName: Producer
* @Description: 生产者
* @author Coder编程
* @date 2019年7月30日 上午21:27:02
*
*/
public class Producer {
public static void main(String[] args) throws Exception {
//1 创建ConnectionFactory
Connection connection = ConnectionUtils.getConnection();
//2 通过Connection创建一个新的Channel
Channel channel = connection.createChannel();
//3 指定我们的消息投递模式: 消息的确认模式
channel.confirmSelect();
String exchangeName = "test_confirm_exchange";
String routingKey = "confirm.save";
//4 发送一条消息
String msg = "Hello RabbitMQ Send confirm message!";
channel.basicPublish(exchangeName, routingKey, null, msg.getBytes());
//5 添加一个确认监听 用于发送消息到Broker端之后,回送消息的监听
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
System.err.println("-------no ack!-----------");
}
@Override
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
System.err.println("-------ack!-----------");
}
});
}
}
复制代码
消費者:
/**
*
* @ClassName: Consumer
* @Description: 消费者
* @author Coder编程
* @date 2019年7月30日 上午21:32:02
*
*/
public class Consumer {
public static void main(String[] args) throws Exception {
//1 获取一个连接
Connection connection = ConnectionUtils.getConnection();
//2通过Connection创建一个新的Channel
Channel channel = connection.createChannel();
String exchangeName = "test_confirm_exchange";
String routingKey = "confirm.#";
String queueName = "test_confirm_queue";
//3 声明交换机和队列 然后进行绑定设置, 最后制定路由Key
channel.exchangeDeclare(exchangeName, "topic", true);
channel.queueDeclare(queueName, true, false, false, null);
channel.queueBind(queueName, exchangeName, routingKey);
//4 创建消费者
QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
channel.basicConsume(queueName, true, queueingConsumer);
while(true){
Delivery delivery = queueingConsumer.nextDelivery();
String msg = new String(delivery.getBody());
System.err.println("消费端: " + msg);
}
}
}
复制代码
ツール:
/**
*
* @ClassName: ConnectionUtils
* @Description: 连接工具类
* @author Coder编程
* @date 2019年6月21日 上午22:28:22
*
*/
public class ConnectionUtils {
public static Connection getConnection() throws IOException, TimeoutException {
//定义连接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置服务地址
factory.setHost("127.0.0.1");
//端口
factory.setPort(5672);//amqp协议 端口 类似与mysql的3306
//设置账号信息,用户名、密码、vhost
factory.setVirtualHost("/vhost_cp");
factory.setUsername("user_cp");
factory.setPassword("123456");
// 通过工程获取连接
Connection connection = factory.newConnection();
return connection;
}
}
复制代码
まず「=消費者の終了を開始し、生産側を再起動します
3.3 Viewコントロールステーション:
3.4印刷結果:
生産側が再びコールバック情報を受信した後、最初のメッセージの消費者側は、受信されたことを観察することができます。ディスクがいっぱいの場合、RabbitMQの異常、キューの容量が限界に達している受信しない可能性のあるいかなるACKを
何のACKのACKとどれも前に言われたメッセージを受信しない場合。RabbitMQのネットワークグリッチは、上記採用することができる、発生メッセージ補償。
4.メッセージメカニズムを返します。
- 非ルートメッセージの一部を処理するためのリスナーを返します!
- 私たちのニュースのプロデューサー、そして行くために特定のキューにメッセージを配信するためには、Exchange Routingkeyを指定することで、その後、私たちは、キュー消費者を聞く処理動作を消費!
- 私たちは、メッセージを送信するための時間を持っている場合は、いくつかのケースでは、現在の為替が存在しないか、指定されたルートキーのルートよりも少ないしない、我々はリターンリスナーを使用して、このメッセージまで聞く必要がない場合は、この時間!
APIに基づいて重要なのCIがあります:
- 必須:trueの場合、リスナーはルート到達不能メッセージが表示され、その後のフォローアップ治療を、偽の場合は、ブローカーの終わりには、自動的にメッセージを削除します!
4.1戻りメッセージングプロセス
MQ Brokerの最後にメッセージを送信するが、NotFind取引所、送信された交換メッセージを表示するプロデューサーの制作側、エンド・ブローカーを見つけることができませんでした。それとも見つけましたが、指定されたルーティングキーのルーティングキューよりも少ないです。だから、間違ったメッセージです。今回は、生産面では、このメッセージが送信されることを知っている必要があり、処理されません。したがって戻りMQブローカは、生産側にこれらの到達不能メッセージを送信するためにこのメカニズムを提供し、この時点でリターンザリスナー到達不能メッセージを受信するように配置された端部を作り出す必要があります。そして、時間のログに、これらのメッセージを処理します。
4.2コードショー
プロデューサー:
/**
*
* @ClassName: Producer
* @Description: 生产者
* @author Coder编程
* @date 2019年7月30日 上午22:03:22
*
*/
public class Producer {
public static void main(String[] args) throws Exception {
//1 创建ConnectionFactory
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
String exchange = "test_return_exchange";
String routingKey = "return.save";
String routingKeyError = "abc.save";
String msg = "Hello RabbitMQ Return Message";
channel.addReturnListener(new ReturnListener() {
@Override
public void handleReturn(int replyCode, String replyText, String exchange,
String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.err.println("---------handle return----------");
//响应码
System.err.println("replyCode: " + replyCode);
//响应文本
System.err.println("replyText: " + replyText);
System.err.println("exchange: " + exchange);
System.err.println("routingKey: " + routingKey);
System.err.println("properties: " + properties);
System.err.println("body: " + new String(body));
}
});
//第三个参数mandatory=true,意味着路由不到的话mq也不会删除消息,false则会自动删除
channel.basicPublish(exchange, routingKey, true, null, msg.getBytes());
//修改routingkey,测试是否能够收到消息
//channel.basicPublish(exchange, routingKeyError, true, null, msg.getBytes());
}
}
复制代码
消費者:
/**
*
* @ClassName: Consumer
* @Description: 消费者
* @author Coder编程
* @date 2019年7月30日 上午22:33:34
*
*/
public class Consumer {
public static void main(String[] args) throws Exception {
//1 创建ConnectionFactory
Connection connection = ConnectionUtils.getConnection();
Channel channel = connection.createChannel();
String exchangeName = "test_return_exchange";
String routingKey = "return.#";
String queueName = "test_return_queue";
channel.exchangeDeclare(exchangeName, "topic", true, false, null);
channel.queueDeclare(queueName, true, false, false, null);
channel.queueBind(queueName, exchangeName, routingKey);
QueueingConsumer queueingConsumer = new QueueingConsumer(channel);
channel.basicConsume(queueName, true, queueingConsumer);
while(true){
Delivery delivery = queueingConsumer.nextDelivery();
String msg = new String(delivery.getBody());
System.err.println("消费者: " + msg);
}
}
}
复制代码
上記のコードでConnectionUtilsツール。
消費者側を起動し、制御局を表示します。
4.3ビューコントロールステーション
4.4印刷結果を表示
消費解放側コード:channel.basicPublish(交換、routingKey、真、ヌル、msg.getBytes());消費者側印刷結果:
通常の印刷結果を見ることができる、にコードを変更するには、この時間:channel.basicPublish(交換、routingKeyError、真、ヌル、msg.getBytes());
私たちは、生産が到達不能メッセージを受信見ることができます。文末
個人的なマイクロチャネル公衆番号へようこそ注意:Coderのプログラムの最新オリジナルな技術に関する記事と無料の学習教材のため、多くのブティックマインドマップ、インタビューデータ、PMPの準備資料あなたがリードするために、待っているあなたは、いつでも、どこでも技術的な知識を習得することができます!QQのグループを作成します:315 211 365を、私たちは一緒にグループ交換研究に歓迎します。ありがとうございます!また、必要としている友人の側に導入することができます。
記事のGithubに含ま:github.com/CoderMerlin ... Gitee:gitee.com/573059382/c ...歓迎の注意と星〜
参考記事:
「簡潔RabbitMQのメッセージング・ミドルウェア」
推奨読書:
メッセージミドルウェア--RabbitMQ(4)コマンドライン制御局の基本的な操作!
メッセージングミドルウェア--RabbitMQ(5)クイックスタート生産者と消費者、SpringBootはRabbitMQの統合します!