Rabbitmq

 Concept:

    什么是消息队列Message Queue(MQ)?从字面上看队列,先进先出FIFO,进进出出的是message消息。

 BackGround:

    1. 进程之间耦合严重,以消息的形式解耦。

    2. 进程处理消息的速度有限,必须合理安排消息的处理,MQ可以做到。

 Basic:

    AMQP:消息队列的一种协议,为面向消息的中间件而设计,提供统一消息服务的应用层标准高级消息队列协议,所以这个协议是在应用层的协议,类似HTTP协议。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。想象一下HTTP协议(应用层协议(application layer protocol)定义了运行在不同端系统上的应用程序进程如何相互传递报文。)。

    Erlang语言开发:

    Erlang原因是面向并发的编程语言,目的是创造一种可以应对大规模并发活动的编程语言和运行环境。顺序执行的erlang是一个及早求值,单词赋值和动态类型的函数式编程语言。

  主要端口说明:

    4369 -- erlang发现口

    5672 --client端通信口

    15672 -- 管理界面ui端口(需要开启)

    25672 -- server间内部通信口

**************************************************

  RPC?waht‘s RPC?one process needs another Service provider’services,then you needs RPC。RPC is a thought,rather than a protocol。so you can use any protocol to realize the RPC thought。the protocol of MQ is one of them。also MQ has other uses。

**************************************************

  AMQP协议的主要特征是面向消息,队列,路由。

  RabbitMQ是一个开源的AMQP实现。服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

 RabbitMQ'API : 

  ConnectionFactory、Connection、Channel都是RabbitMQ对外提供的API中最基本的对象。Connection是RabbitMQ的socket链接,它封装了socket协议相关部分逻辑。ConnectionFactory为Connection的制造工厂。Channel是我们与RabbitMQ打交道的最重要的一个接口,我们大部分的业务操作是在Channel这个接口中完成的,包括定义Queue、定义Exchange、绑定Queue与Exchange、发布消息等。

 🔺 队列(Queue)

  Queue队列是RabbitMQ的内部对象,用于存储消息,且消息只能存储在Queue中,消息最终被投放到Queue中,然后被消费者从Queue中拉取处理。 

Message acknowledgment

  在实际应用中,可能会发生消费者收到Queue中的消息,但没有处理完成就宕机(或出现其他意外)的情况,这种情况下就可能会导致消息丢失。为了避免这种情况发生,我们可以要求消费者在消费完消息后发送一个回执给RabbitMQ,RabbitMQ收到消息回执(Message acknowledgment)后才将该消息从Queue中移除;如果RabbitMQ没有收到回执并检测到消费者的RabbitMQ连接断开,则RabbitMQ会将该消息发送给其他消费者(如果存在多个消费者)进行处理。这里不存在timeout概念,一个消费者处理消息时间再长也不会导致该消息被发送给其他消费者,除非它的RabbitMQ连接断开。
这里会产生另外一个问题,如果我们的开发人员在处理完业务逻辑后,忘记发送回执给RabbitMQ,这将会导致严重的bug——Queue中堆积的消息会越来越多;消费者重启后会重复消费这些消息并重复执行业务逻辑…

Message durability

  如果我们希望即使在RabbitMQ服务重启的情况下,也不会丢失消息,我们可以将Queue与Message都设置为可持久化的(durable),这样可以保证绝大部分情况下我们的RabbitMQ消息不会丢失。但依然解决不了小概率丢失事件的发生(比如RabbitMQ服务器已经接收到生产者的消息,但还没来得及持久化该消息时RabbitMQ服务器就断电了),如果我们需要对这种小概率事件也要管理起来,那么我们要用到事务。由于这里仅为RabbitMQ的简单介绍,所以这里将不讲解RabbitMQ相关的事务。

Prefetch count

  前面我们讲到如果有多个消费者同时订阅同一个Queue中的消息,Queue中的消息会被平摊给多个消费者。这时如果每个消息的处理时间不同,就有可能会导致某些消费者一直在忙,而另外一些消费者很快就处理完手头工作并一直空闲的情况。我们可以通过设置prefetchCount来限制Queue每次发送给每个消费者的消息数,比如我们设置prefetchCount=1,则Queue每次给每个消费者发送一条消息;消费者处理完这条消息后Queue会再给该消费者发送一条消息。

  🔺 交换机(Exchange)

  交换机,负责将生产者生产的消息投递到Queue中,共有四种类型的交换机,分别为fanout、direct、topic、headers这四种。(AMQP规范里还提到两种Exchange Type,分别为system与自定义,这里不予以描述)。交换机类型决定了路由策略,路由策略决定了如何将一条消息投递到和它绑定(binding)的Queue中。

  🔺 绑定(binding)和绑定Key(binding key)和路由Key(routing key)

  Rabbitmq提供binding命令将交换机和队列关联起来,在绑定的时候一般会指定一个binding key,这个绑定key的作用是当交换机类型为direct和topic时,会和生产者发送的routing key进行匹配,从而决定消费将被投递到那个Queue中。

  (生产者在将消息发送给Exchange的时候,一般会指定一个routing key,来指定这个消息的路由规则,而这个routing key需要与Exchange Type及binding key联合使用才能最终生效。RabbitMQ为routing key设定的长度限制为255 bytes。)

**************************************************

fanout(简单):

  不依赖binding key和routing key,将会把所有发送到该交换机的消息投递到与之关联的Queue。

direct(简单):

  完全匹配binding key和routing key,不包括模糊匹配。然后和fanout一样。

topic(优化):

  使用direct类型机制,但是进行了优化(改为模糊匹配),规则就是‘.’分割的单个字符串作为模糊匹配的最小单位(即最小单位是分割后的单词),routing key和binding key都是以‘.’进行分割的,同时又以‘#’,‘’*这两个符号分别代表进行模糊匹配多个或一个单词。

headers(特殊):

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

**************************************************

  MQ本身是基于异步的消息处理,前面的示例中所有的生产者(P)将消息发送到RabbitMQ后不会知道消费者(C)处理成功或者失败(甚至连有没有消费者来处理这条消息都不知道)。
但实际的应用场景中,我们很可能需要一些同步处理,需要同步等待服务端将我的消息处理完成后再进行下一步处理。这相当于RPC(Remote Procedure Call,远程过程调用)。在RabbitMQ中也支持RPC。

  RabbitMQ实现RPC机制的原理是:

  • 客户端发送请求(消息)时,在消息的属性(MessageProperties,在AMQP协议中定义了14中properties,这些属性会随着消息一起发送)中设置两个值replyTo(一个Queue名称,用于告诉服务器处理完成后将通知我的消息发送到这个Queue中)和correlationId(此次请求的标识号,服务器处理完成后需要将此属性返还,客户端将根据这个id了解哪条请求被成功执行了或执行失败)
  • 服务器端收到消息并处理
  • 服务器端处理完消息后,将生成一条应答消息到replyTo指定的Queue,同时带上correlationId属性
  • 客户端之前已订阅replyTo指定的Queue,从中收到服务器的应答消息后,根据其中的correlationId属性分析哪条请求被执行了,根据执行结果进行后续业务处理。

------------------------------------------------------------------

  RabbitMQ Server: 也叫broker server,它不是运送食物的卡车,而是一种传输服务。原话是RabbitMQisn’t a food truck, it’s a delivery service. 他的角色就是维护一条从Producer到Consumer的路线,保证数据能够按照指定的方式进行传输。但是这个保证也不是100%的保证,但是对于普通的应用来说这已经足够了。当然对于商业系统来说,可以再做一层数据一致性的guard,就可以彻底保证系统的一致性了。

    Client A & B: 也叫Producer,数据的发送方。createmessages and publish (send) them to a broker server (RabbitMQ).一个Message有两个部分:payload(有效载荷)和label(标签)。payload顾名思义就是传输的数据。label是exchange的名字或者说是一个tag,它描述了payload,而且RabbitMQ也是通过这个label来决定把这个Message发给哪个Consumer。AMQP仅仅描述了label,而RabbitMQ决定了如何使用这个label的规则。

    Client 1,2,3:也叫Consumer,数据的接收方。Consumersattach to a broker server (RabbitMQ) and subscribe to a queue。把queue比作是一个有名字的邮箱。当有Message到达某个邮箱后,RabbitMQ把它发送给它的某个订阅者即Consumer。当然可能会把同一个Message发送给很多的Consumer。在这个Message中,只有payload,label已经被删掉了。对于Consumer来说,它是不知道谁发送的这个信息的。就是协议本身不支持。但是当然了如果Producer发送的payload包含了Producer的信息就另当别论了。

     对于一个数据从Producer到Consumer的正确传递,还有三个概念需要明确:exchanges, queues and bindings。

        Exchanges are where producers publish their messages.

        Queuesare where the messages end up and are received by consumers

        Bindings are how the messages get routed from the exchange to particular queues.

   还有几个概念是上述图中没有标明的,那就是Connection(连接),Channel(通道,频道)。

   Connection: 就是一个TCP的连接。Producer和Consumer都是通过TCP连接到RabbitMQ Server的。以后我们可以看到,程序的起始处就是建立这个TCP连接。

   Channels: 虚拟连接。它建立在上述的TCP连接中。数据流动都是在Channel中进行的。也就是说,一般情况是程序起始建立TCP连接,第二步就是建立这个Channel。

    那么,为什么使用Channel,而不是直接使用TCP连接?

    对于OS来说,建立和关闭TCP连接是有代价的,频繁的建立关闭TCP连接对于系统的性能有很大的影响,而且TCP的连接数也有限制,这也限制了系统处理高并发的能力。但是,在TCP连接中建立Channel是没有上述代价的。对于Producer或者Consumer来说,可以并发的使用多个Channel进行Publish或者Receive。有实验表明,1s的数据可以Publish10K的数据包。当然对于不同的硬件环境,不同的数据包大小这个数据肯定不一样,但是我只想说明,对于普通的Consumer或者Producer来说,这已经足够了。如果不够用,你考虑的应该是如何细化split你的设计。

参考文章:https://www.cnblogs.com/williamjie/p/9481774.html

集群搭建文章:https://www.cnblogs.com/shihaiming/p/11014257.html

MQ验证管理:https://www.cnblogs.com/cwp-bg/p/10070467.html

------------------------------------------------------------------

  *第一次启动前,vim /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.5/ebin/rabbit.app 找到这个地方,并将<<"guest">>删除使之剩下[],目的是取消对guest用户的远程登陆限制。

  然后,通过 rabbitmq-plugins enable rabbitmq_management 开启管理插件,可以使用15672进行远程访问。最后启动服务器,启动命令在 /usr/lib/rabbitmq/bin,./rabbitmq-server start启动完成。

  最后,登陆15672,然后添加新的用户,并删除guest用户。另外新建用户时tag可以选择administrator(可以做任何事情)。

   *此时需要添加虚拟主机(虚拟主机可以理解为数据库,或者仓库),guest用户的虚拟主机是/,根目录,但是我们不能使用该虚拟主机,进入Virtual Hosts添加虚拟主机。点击添加后的虚拟主机的名字可以修改此虚拟主机的用户,以及用户的权限,还有删除此虚拟主机。默认不动。

posted @ 2020-03-18 19:50  永不熄灭的火  阅读(132)  评论(0编辑  收藏  举报