RabbitMQ 详解(一)------基本概念

一.什么是MQ?

概念: 消息队列(MQ):又叫消息中间件。(书面概念不再赘述),通俗讲可以理解为邮局和邮差,用来帮我们存储和准发消息的。

特点:1.是一个独立运行的服务,生产者发生消息,消费者接收消费,需要先跟服务器建立连接。

           2.采用队列作为数据结构,有先进先出的特点

           3.具有发布订阅的模型,消费者可以获取自己需要的消息。

二.面试常见问题

 问题一:Java有许多队列的实现,可以解决消息消费的问题,为什么还需要消息中间件呢?

     这个问题可以类比有了HashMap,还要用Redis做缓存是一样的,队列不能跨进程,不能在分布式系统中使用,并且没有持久化机制等等。

 问题二:我们为什么要在项目中使用消息中间件?

 1.实现异步通信  

    对数据量大或者处理耗时长的操作,可以使用MQ实现异步通信,减少客户端的等待,提升响应速度。

ps: 同步通信:发出请求,等待返回。异步通信:发出请求,直接返回,被调用者通过状态、通知来通知调用者处理

  2.实现系统解耦

     对于改动影响较大的系统之间,引入MQ实现解耦,减少系统之间的直接依赖

      ps 耦合:系统内部或者系统之间存在相互作用,相互影响,相互依赖。

       以一个购物系统为例,使用传统的通信方式,订单系统发生退货时会依次调用下游系统。如下图一。但下游系统是并行关系。引入多线程也是可以实现的,但每一个需要并行执行的地方都引入线程,又会带来线程或者线程池的管理问题。引入消息队列后如图二。

    

   3.实现流量削峰

      MQ既然是队列就具备队列先进先出的特性,在系统一个特殊瞬间到达峰值时,可以把所有流量承接下来。比如天猫的双11,如果通过堆硬件的方式去解决,那么在流量峰值过去之后就会出现巨大的资源浪费。

三.RabbitMQ简介

  1.rabbitmq的工作模式:

(1)Broker

   RabbitMQ服务器,帮助我们存储、转发消息的代理/中介。

(2)Connection

  生产者发送消息/消费者接收消息,都需要跟Broker之间建立一个TCP的长连接

(3)channel

   所有的生产者发送消息和消费者接收消息,都直接创建和释放TCP长连接的话,对于Broker来说会造成很大的性能损耗。因此引入了Channel(通道)的概念,它是一个虚拟的连接,这样我们就可以在保持的TCP长连接里去创建和释放Channel,大大减少了资源消耗。

(4)Queue

     queue(队列)真正用来存储消息的,是一个独立运行的进程,有自己的数据库(Mnesia)。
     消费者获取消息有两种模式,一种是Push,只要生产者发到服务器,就马上推送给消费者。另一种是Pull,消息存放在服务端,只有消费者主动获取才能拿到消息。消费者不需要循环不断地从队列获取消息,可以基于事件机制,实现消费者对队列的监听。由于队列有FIFO的特性,只有确定前一条消息被消费者接收之后,才会把这条消息从数据库删除,继续投递下一条消息。

(5)Exchange
         在 RabbitMQ 里消息不会直接发送到队列的。而是通过交换机(Exchange)用来实现消息的灵活路由。交换机是一个绑定列表,用来查找匹配的绑定关系。队列使用绑定键(Binding Key)跟交换机建立绑定关系。生产者发送的消息需要携带路由键,交换机收到消息时会根据它保存的绑定列表,决定将消息路由到哪些与它绑定的队列上。
 ps:交换机与队列、队列与消费者都是多对多的关系。

(6)Vhost
          虚拟主机VHOST。VHOST 可以提高硬件资源的利用率之外,实现资源的隔离和权限的控制。不同的 VHOST中可以有同名的Exchange和Queue,它们是完全透明的。可以使自己的业务系统不跟别人混用一个系统。

2.路由方式

(1)直连 Direct
         队列与直连类型的交换机绑定,需指定一个精确的绑定键。生产者发送消息时会携带一个路由键。只有当路由键与其中的某个绑定键完全匹配时,这条消息才会从交换机路由到满足路由关系的此队列上。

                

                channel.basicPublish(“MY_DIRECT_EXCHANGE”,”spring”,”msg1”); 只有第一个队列能收到消息。

(2)主题 Topic
          队列与主题类型的交换机绑定时,可以在绑定键中使用通配符。两个通配符:# 0个或者多个单词,* 不多不少一个单词单词,单词用英文的点“.”隔开的字符。例如abc.def是两个单词。

           

           第一个队列支持路由键以junior 开头的消息路由,后面可以有单词,也可以没有。
           第二个队列支持路由键以netty开头,并且后面是一个单词的消息路由。
           第三个队列支持路由键以jvm结尾,并且前面是一个单词的消息路由

          channel.basicPublish("MY_TOPIC_EXCHANGE","junior.fjd.klj","msg 2"); 只有第一个队列能收到消息。
         channel.basicPublish("MY_TOPIC_EXCHANGE","junior.jvm", "msg 3"); 第一个队列和第三个队列能收到消息

(3)广播 Fanout

            主题类型的交换机与队列绑定时,不需要指定绑定键。因此生产者发送消息到广播类型的交换机上,也不需要携带路由键。消息达到交换机时,所有与之绑定了的队列,都会收到相同的消息的副本。

           

                 channel.basicPublish("MY_FANOUT_EXCHANGE","","msg 4"); 三个队列都会收到 msg 4。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章