rabbitmq基本原理详析

1.Exchange交换机

  exchange在rabbitmq中充当交换机的角色,当然也可以形象的理解为rabbitmq的过滤器;

rabbitmq应用图示:


Exchange type的四大类型:

fanout

      fanout类型不处理路由键,只需要简单的将队列绑定到交换机上;一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上

申明exchange类型:

Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");

生产者发布消息

 //循环发布消息
for(int i = 0 ; i < 5; i++){
   String message = "Hello World! " + i;
    channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
     System.out.println(" rabbitmq'" + message + "'");
}
      channel.close();
      connection.close();

消费者A


消费者B


②direct

       direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中。(在实际使用RabbitMQ的过程中并没有binding key这个参数,只有routing key,为了区分我们把交换机和队列绑定时传的参数叫binding key,把发送消息时带的这个参数叫routing key)

申明exchange类型:

  private static final String EXCHANGE_NAME = "direct_logs";
// 申明routingKeys
   private static final String[] routingKeys = new String[]{"info" ,"warning", "error"};
  Connection connection = factory.newConnection();
   Channel channel = connection.createChannel();
// 申明exchange类型
   channel.exchangeDeclare(EXCHANGE_NAME, "direct");

生产者发布消息

//循环发布
  for(String severity :routingKeys){
   String message = "Send the message level:" + severity;
   channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes());
   System.out.println(" [x] Sent '" + severity + "':'" + message + "'");
  }
  channel.close();
  connection.close();

消费者A:

rootingKeyS配置

// 交换器名称
private static final String EXCHANGE_NAME = "direct_logs";
// 路由关键字
private static final String[] routingKeys = new String[]{"info" ,"warning", "error"};

接收结果


消费者B

rootingKeys配置

// 交换器名称
private static final String EXCHANGE_NAME = "direct_logs";
// 路由关键字
private static final String[] routingKeys = new String[]{"error"};

接收结果


topic

     topic类型的Exchange在匹配规则上进行了扩展,它与direct类型的Exchage相似,也是将消息路由到binding key与routing key相匹配的Queue中,但direct是完全匹配,而通过topic可以进行模糊匹配,绝大数业务逻辑采用的就是这种类型。

申明exchange类型:

connection = factory.newConnection();
channel = connection.createChannel();
        //声明一个匹配模式的交换器
channel.exchangeDeclare(EXCHANGE_NAME, "topic");

待匹配的rootingKeys

String[] routingKeys = new String[]{"quick.orange.rabbit", 
                           "lazy.orange.elephant", 
                           "quick.orange.fox", 
                           "lazy.brown.fox", 
                           "quick.brown.fox", 
                           "quick.orange.male.rabbit", 
                           "lazy.orange.male.rabbit"};

生产者发送消息

 //发送消息
for(String severity :routingKeys){
   String message = "From "+severity+" routingKey' s message!";
   channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes());
   System.out.println("product Sent '" + severity + "':'" + message + "'");
}

消费者A

配置路由关键字

// 路由关键字
String[] routingKeys = new String[]{"*.orange.*"};

接收结果


消费者B

// 路由关键字
String[] routingKeys = new String[]{"*.*.rabbit", "lazy.#"};

接收结果


headers

    headers类型的Exchange不依赖于routing key与binding key的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。 在绑定Queue与Exchange时指定一组键值对;当消息发送到Exchange时,RabbitMQ会取到该消息的headers(也是一个键值对的形式),对比其中的键值对是否完全匹配Queue与Exchange绑定时指定的键值对;如果完全匹配则消息会路由到该Queue,否则不会路由到该Queue,这种用的比较少。

2.rabbitmq应用场景

①异步处理

场景:用户注册后,发送短信和邮箱通知;

1.串行逻辑耗时150s


2.并行逻辑耗时100s


3.mq消息队列处理耗时55s

发送注册短信及邮箱通知不是必须的逻辑,所以放在mq中慢慢的消费,提高了系统的整体的性能


②应用解耦

场景:双11购物节的时候,用户下单后,订单系统会及时通知库存系统

1.传统的做法:订单系统接口调用库存系统


设想下,如果订单系统正在调用库存系统的时候,库存系统发生崩溃了,那么这个订单就没有成功,直接的造成了成交单的损失。

2.mq逻辑解耦


订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功。

库存系统:订阅下单的消息,获取下单消息,进行库操作。 

这样即使库存系统发生崩溃,但是订单的下单信息仍然存在消息队列中,等库存系统恢复正常后,继续调用库存接口,消息不会丢失,保证了成交量。

③并发削峰

     针对高并发请求,比如双11并发量超大的情况下,可以将用户的下单消息先存到消息队列中,这就极大的削弱了请求的并发量,然后慢慢消费消息队列中的消息;很好的避免了卡着不动的局面,用户体验也会好很多

好了,我是张星,欢迎加入博主技术交流群,群号:313145288




猜你喜欢

转载自blog.csdn.net/zhangxing52077/article/details/79710277