手とメッセージングミドルウェア(3)を介してあなたを取る - のRabbitMQ

RabbitMQの公式サイト:http://www.rabbitmq.com/
アーランの公式ウェブサイト:https://www.erlang.org
ヒント:RabbitMQのErlangの言語発達に基づいて、RabbitMQのを使用するために、あなたはErlangの環境をインストールする必要があります

1.RabbitMQは何ですか

  RabbitMQのメッセージブローカーがある:それは受け入れて、メッセージを転送します。郵便局として見ることができます:あなたがメールボックスにメッセージを投稿するとき、メッセージが最終的に郵便配達あなたの受信者に配信されます。ように、RabbitMQのは、メールボックス、郵便局と郵便配達することができます。
  それは、紙を扱うが、データメッセージを格納および転送バイナリデータを受信していないことを郵便局とRabbitMQの間の主な違い。

いくつかの概念を理解するためにまず

  2.1プロデューサ(プロデューサ)と消費者(コンシューマ)
  プロデューサとコンシューマは、2つの重要な役割RabbitMQの通信処理、メッセージの送信者と受信者と同等であり、RabbitMQの役割は、メッセージを配信する第三者として機能することです、それはデータを生成することができないことを意味します。実際には、また、生産者と消費者の役割は、私たちがRabbitMQのサーバーアプリケーションに接続するときに、私は生産者や消費者のことが明らかでなければならない、お互いに変換することができます。

  2.2接続(コネクション)
  RabbitMQの前にリリース農産物ニュース、に生産した後、あなたがRabbitMQのサーバを接続する必要があり、RabbitMQのすべてのサポートされているプロトコルがTCPベースで、かつ効率性と長期的な接続(プロトコルごとの操作開かないの使用を改善するために、新しい接続)。クライアントライブラリは、単一のTCP接続を使用して接続されています。

  2.3チャネル(チャネル)
  接続を確立した後、上記TCP接続に基づいて、クライアントは、AMQPオープンチャネル、動作を行うチャネルで発生するクライアントの各プロトコルは、チャネルは、接続中に存在するのではなく、個人でありますそれは存在しています。すべてのチャネルもクローズされる上での接続を、閉じた後。
  我々はまた、AMQP接続における1つまたは複数のチャネルを開くことができ、各チャネルは、チャネル間の干渉しないことを確実にするためにユニークなIDを持っています

  2.4待ち行列(キュー)
  のキューは、メッセージをキャッシュすることができるボックスと同様エンドポイントRabbitMQのメッセージサーバ、である;ここで、メッセージの配信にプロデューサー、前記メッセージコンシューマ退避。

  2.5スイッチ(交換)
  :プロデューサによって送信されたメッセージを受信するためのスイッチ、及びメッセージを処理することができるが、例えば、すべてのキューに送信、メッセージ・キューに送信される、またはメッセージを破棄、それは主に三種類のアプリケーションである
 A、ファンアウト(ファン)放送、メッセージがバインドスイッチキューのすべてに送信される
 指定routing_key満たすメッセージキューに、向き(直接接続):B、直接
 C、トピック:ワイルドカードを(トピック)、メッセージが準拠しますパターンをルーティング(ルートパターン)キュー

追加:スイッチは、メッセージを転送するための唯一の責任を一切キューとExchangeバインドが存在しない場合は、ストアのメッセージへの能力を持っていない、またはルーティングキューの規則に従わない場合、メッセージが失われます!

3.RabbitMQメッセージパターン

  2.1シンプルシンプルモード

  1人の関係、メッセージへの1つとして、生産者と消費者のは、消費者によって消費することができ、消費者はこの時点ではない場合に消費されるまで、メッセージは一時的にキューにキャッシュされます

  2.2操作の作業モード

  作業モデルでは、生産者と消費者対多の関係、より多くの消費者がキューにバインドすることができ、メッセージの一般的な消費のキュー

补充:消息一旦被消费者接收,队列中的消息就会被删除,所有不会存在消息重复消费的问题,即每条消息只能被多个消费者中的其中一个消费者消费
  问题1:在多个消费者的情况下,消息如何分配

  queue可以实现负载均衡,生产者将消息放入queue中后,RabbitMQ会通过轮询的方式,实现消息的分配

  问题2:RabbitMQ怎么知道消息被接收了呢

  通过消息确认机制(Acknowlege)实现。当消费者获取消息后,会向RabbitMQ发送回执ACK,告知消息已经被接收。不过这种回执ACK分两种情况:

  • 自动ACK:消息一旦被接收,消费者自动发送ACK
  • 手动ACK:消息接收后,不会发送ACK,需要手动调用

    问题3:如何使用自动和手动ACK?

      这就要取决于消息的重要性,如果消息不太重要,丢失也没有影响,那么自动ACK会比较方便,反之,如果消息非常重要,不容丢失。那么最好在消费完成后手动ACK,否则接收消息后就自动ACK,RabbitMQ就会把消息从队列中删除,如果此时消费者宕机,那么消息就丢失了。

  2.3 订阅模型-Fanout

  X表示交换机;在广播模式下,消息发送流程是这样的:

  • 1) 可以有多个消费者
  • 2) 每个消费者有自己的queue(队列)
  • 3) 每个队列都要绑定到Exchange(交换机)
  • 4) 生产者发送的消息,只能发送到交换机,交换机来决定要发给哪个队列,生产者无法决定。
  • 5) 交换机把消息发送给绑定过的所有队列
  • 6) 队列的消费者都能拿到消息。实现一条消息被多个消费者消费

  2.4 订阅模型-Direct
在Direct模型下:

  • 1) 队列与交换机的绑定,不能是任意绑定了,而是要指定一个routing_key(路由key)
  • 2) 消息的发送方在 向 Exchange发送消息时,也必须指定消息的 routing_key
  • 3) Exchange不再把消息交给每一个绑定的队列,而是根据消息的routing_key进行判断,只有队列的routing_key与消息的 routing_key完全一致,才会接收到消息

    图解:
  • P:生产者,向Exchange发送消息,发送消息时,会指定一个routing key。
  • X:Exchange(交换机),接收生产者的消息,然后把消息递交给 与routing_key完全匹配的队列
  • C1:消费者,其所在队列指定了需要routing_key 为 error 的消息
  • C2:消费者,其所在队列指定了需要routing_key 为 info、error、warning 的消息

  2.5 订阅模型-Topic
  Topic类型的Exchange与Direct相比,都是可以根据routing_key把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定routing_key的时候使用通配符!通配符规则:
  #:可以替代零个或多个单词。
  *:可以代替一个单词

解释:routing_key 一般都是有一个或多个单词组成,多个单词之间以”.”分割,例如: item.insert


图解:

  • C1:消费者,其所在队列Q1绑定了*.orange.*的routing_key,它能匹配到以orange为中心,前后各一个单词的路由,例如:item.orange.insert,但是该item.orange.insert.one路由就不能被匹配
  • C2:消费者,其所在队列Q2绑定了lazy.#的routing_key,它能匹配到任何以lazy.#开头的路由

    在上面交换机中,提到了消息丢失的问题,那么哪种情况下消息会丢失,如何处理
  • 1) 生产者弄丢了数据。生产者将数据发送到 RabbitMQ 的时候,可能数据就在半路给搞丢了,比如:因为网络问题。
    解决方案:使用发送方确认机制。发送方确认机制是指生产者将信道设置成confirm(确认)模式,一旦信道进入confirm模式,所有在该信道上面发布的消息都会被指派一个唯一的ID(从1开始),一旦消息被投递到RabbitMQ服务器之后,RabbitMQ就会发送一个确认(Basic.Ack)给生产者(包含消息的唯一ID),这就使得生产者知晓消息已经正确到达了目的地了。
  • 2) RabbitMQ 弄丢了数据。比如:MQ宕机了
    解决方案:RabbitMQ 的消息默认存放在内存上面,如果不特别声明设置,消息不会持久化保存到硬盘上面的,如果MQ宕机,消息就会丢失。
    我们可以对消息进行持久化处理,要将消息持久化,前提是:队列、Exchange都持久化
//获取连接
Connection connection = ConnectionUtil.getConnection();
//建立通道
Channel channel = connection.createChannel();
//交换机持久化 ,第三个参数代表是否持久化
channel.exchangeDeclare(EXCHANGE_NAME,"EXCHANGE_TYPE",true);
//队列持久化 ,第二个参数代表是否持久化
channel.queueDeclare(QUEUE_NAME,true,false,false,null);
//消息持久化 ,第三个参数代表是否持久化
channel.basicPublish(EXCHANGE_NAME,routing_key,MessageProperties.PERSISTENT_TEXT_PLAIN,MESSAGE_TEXT.getBYtes());
  • 3) 消费端弄丢了数据。刚接收到消息,还没处理,结果进程挂了,比如:重启了。
    解决方案:使用消费者的ACK机制。当消费者获取消息后,会向RabbitMQ发送回执ACK,告知消息已经被接收。如果这个消费者挂掉没有发送应答,RabbitMQ会理解为这个消息没有被处理,然后交给另一个消费者去重新处理。这样,你就可以确认即使消费者偶尔挂掉也不会丢失任何消息了。

おすすめ

転載: www.cnblogs.com/kaischoolmate/p/12104551.html