消息中间件系列四、RabbiyMq初步

AMQP

AMQP(advanced message queuing protocol)是一个提供统一消息服务的应用层标准协议,基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同开发语言等条件的限制 。

一、AMQP的一些技术术语

  • AMQP模型(AMQP Model):一个由关键实体和语义表示的逻辑框架,遵从AMQP规范的服务器必须提供这些 实体和语义。为了实现本规范中定义的语义,客户端可以发送命令来控制AMQP服务器。
  • 连接(Connection):一个网络连接,比如TCP/IP套接字连接。
  • 会话(Session):端点之间的命名对话。在一个会话上下文中,保证“恰好传递一次”。
  • 信道(Channel):多路复用连接中的一条独立的双向数据流通道。为会话提供物理传输介质。虚拟的连接,建立在真实的tcp连接之上的。信道的创建没有限制的。
  • 交换器(Exchange):服务器中的实体,用来接收生产者发送的消息并将这些消息路由给服务器中的队列。
  • 消息队列(Message Queue):一个命名实体,用来保存消息直到发送给消费者。
  • 绑定器(Binding):消息队列和交换器之间的关联。
  • 绑定器关键字(Binding Key):绑定的名称。一些交换器类型可能使用这个名称作为定义绑定器路由行为的模式。
  • 路由关键字(路由键)(Routing Key):一个消息头,交换器可以用这个消息头决定如何路由某条消息。
  • 持久存储(Durable):一种服务器资源,当服务器重启时,保存的消息数据不会丢失。
  • 临时存储(Transient):一种服务器资源,当服务器重启时,保存的消息数据会丢失。
  • 持久化(Persistent):服务器将消息保存在可靠磁盘存储中,当服务器重启时,消息不会丢失。
  • 非持久化(Non-Persistent):服务器将消息保存在内存中,当服务器重启时,消息可能丢失。
  • 消费者(Consumer):一个从消息队列中请求消息的客户端应用程序。
  • 生产者(Producer):一个向交换器发布消息的客户端应用程序。
    消息处理过程:

队列通过路由键绑定到交换器,生产者把消息发送到了交换器,交换器根据绑定的路由键将消息路由到特定的队列,订阅了队列的消费者进行接收。

_1

说明

  • 如果消息达到无人订阅的队列会一直在队列中等待,rabbitmq会默认队列是无限长度的。
  • 如果多个消费者订阅到同一队列,消息会轮询的方式发送给消费者,每个消息只会发送给一个消费者
  • 消息路由到了不存在的队列,消息会忽略,当消息不存在,消息丢失了。

二、消息的确认机制

1、消费者收到的每一条消息都必须进行确认。(分为自动确认和消费者自行确认)

  消费者在声明队列时,指定autoAck参数,true自动确认,false时rabbitmq会等到消费者显示的发回一个ack信号才会删除消息。
  autoAck=false,有足够时间让消费者处理消息,直到消费者显示调用basicAck为止。Rabbitmq中消息分为了两部分:1、等待投递的消息;2、已经投递,但是还没有收到ack信号的。如果消费者断连了,服务器会把消息重新入队,投递给下一个消费者。
  未ack的消息是没有超时时间的。

2、如何明确拒绝消息

a、消费者断连,
b、消费者使用reject命令(requeue=true,重新分发消息,false移除消息),
c、nack命令(批量的拒绝)(rabbitMQ的特有命令)

三、创建队列

  生产者和消费者都可以调用declareQueue方法创建队列,当没有目标队列时才会创建,如果已经存在相同的队列了就不在重复创建。
  相关参数:exclusive 队列为应用程序私有,auto-delete 最后一个消费者取消订阅时,队列会自动删除,durable 队列持久化。
  如果消费者订阅了队列,就不能再声明队列了。

检测队列是否存在

可以通过调用方法QueueDeclarePassive判断队列是否存在,看方法名是“消极的声明创建”的意思,事实上它没有去声明队列,所谓消极,去看看有没有名为xxx的queue,如果有我就把名字什么的信息告诉你,没有就直接报错,用来确认queue是否存在。

四、四种交换器:

1、direct:

路由键完全匹配时,消息投放到对应队列。Amqp实现都必须有一个direct交换器(默认交换器),名称为空白字符。队列不声明交换器,会自动绑定到默认交换器,队列的名称作为路由键。

_2

2、Fanout:

可以理解为广播

_3

3、Topic:

主题,使来自不同源头的消息到达同一个队列

_4

路由键中的“*”和“#”

“.”会把路由键分为好几个标识符,“*”匹配一个标识符,“#”匹配一个或者多个;
例如:xxx.yyy.zzzz 可以: xxx.*. zzzz , xxx.# , #.zzzz

4、Headers:

匹配消息头,其余与direct一样,实用性不大

举例说明

日志处理场景:
1、有交换器(topic)log_exchange,日志级别有 error,info,warning,应用模块有 user,order,email,路由键的规则是 日志级别+“.”+应用模块名(例如info.user)
2、发送邮件失败,报告一个email的error,basicPublic(message,"log-exchange","error.email")
队列的绑定:queueBind("email-error-queue","log-exchange","error.email")
要监听email所有的日志怎么办?
queueBind("email-log-queue","log-exchange"," *.email")
监听所有模块所有级别日志?
queuebind(“all-log-queue”,"log-exchange","#")
“.”会把路由键分为好几个标识符,“*”匹配一个标识符,“#”匹配一个或者多个(xxx.yyy.zzzz 可以: xxx.*. zzzz , xxx.# , #.zzzz)。

五、虚拟主机

Vhost,真实rabbitmq服务器上的mini型虚拟的mq服务器。有自己的权限机制。Vhost提供了一个逻辑上的分离,可以区分客户端,避免队列和交换器的名称冲突。RabbitMq包含了一个缺省的vhost :“/”,用户名guest,口令 guest(guest用户只能在本机访问)。

未完待续。。。

猜你喜欢

转载自yq.aliyun.com/articles/647523