RabbitMQ学习

MQ入门总结(五)RabbitMQ的原理和使用
Spring Boot 中使用 RabbitMQ -- 很棒
CentOs7.3 搭建 RabbitMQ 3.6 Cluster 集群服务与使用
RabbitMQ实践

架构图:

一、rabbitmq重要的组件

  • Broker:简单来说就是消息队列服务器实体。
  • Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
  • Queue:消息队列载体,每个消息都会被投入到一个或多个队列。
  • Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。
  • Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
  • vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。每个virtual host本质上都是一个RabbitMQ Server,拥有它自己的queue,exchagne,和bings rule等等。这保证了你可以在多个不同的Application中使用RabbitMQ。
  • producer:消息生产者,就是投递消息的程序。
  • consumer:消息消费者,就是接受消息的程序。
  • channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。

为什么使用channel不实用tcp链接

1、tcp创建销毁有三次握手和四次挥手,开销太大
2、操作系统tcp链接有限制,如果使用tcp链接,高峰期每秒成千上万的链接造成资源浪费
3、channel的原理一个进程一条通道,多条进程多条通道公用一条tcp链接,一条tcp链接可以容纳无限的channel,不会有性能瓶颈。

二、特性

  • 投递
    多个消费者可以订阅同一个Queue,这时Queue中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。
  • 消息稳定性
    1、事务机制:(一般不采用,同步的,生产者发送消息会同步阻塞卡住等待你是成功还是失败。会导致生产者发送消息的吞吐量降下来)
    channel.txSelect
try {
    //发送消息
} catch(Exception e){
    channel.txRollback;
    //再次重试发送这条消息
} 
    channel.txCommit;

2、confirm机制:(一般采用这种机制,异步的模式,不会阻塞,吞吐量会比较高)

1)先把 channel 设置成 confirm 模式
2)发送一个消息到 rabbitmq
3)发送完消息后就不用管了
4)rabbitmq 如果接收到了这条消息,就会回调你生产者本地的一个接口,通知你说这条消息我已经收到了
5)rabbitmq 如果在接收消息的时候报错了,就会回调你的接口,告诉你这个消息接收失败了,你可以再次重发。

public void ack(String messageId){

}

public void nack(String messageId){
    //再次重发一次这个消息
}
  • 避免丢失
    消息持久化
    ACK确认机制
    设置集群镜像模式
    消息补偿机制

  • 持久化成功的条件
    声明队列和交换器必须设置持久化 durable 设置为 true.
    消息推送投递模式必须设置持久化,deliveryMode 设置为 2(持久)。
    消息已经到达持久化交换器。
    消息已经到达持久化队列。

以上四个条件都满足才能保证消息持久化成功。

rabbitmq 持久化缺点
持久化的缺地就是降低了服务器的吞吐量,因为使用的是磁盘而非内存存储,从而降低了吞吐量。可尽量使用 ssd 硬盘来缓解吞吐量的问题。

  • 延时消息
    RabbitMQ(七) -- 延迟队列实现

1、通过消息过期后进入死信交换器,再由交换器转发到延迟消费队列,实现延迟功能;
2、使用 RabbitMQ-delayed-message-exchange 插件实现延迟功能。

  • 保证顺序
    需要保证顺序的数据放到同一个queue里

  • 死信队列
    RabbitMQ系列(十三)RabbitMQ的死信队列

“死信--Dead Letter”是RabbitMQ中的一种消息机制。
“死信”消息会被RabbitMQ进行特殊处理,如果配置了死信队列,那么“死信”消息将会被丢进死信队列中,如果没有配置,则“死信”消息将会被丢弃。
死信出现的情况:
1、消息被否定确认(使用 channel.basicNack 或 channel.basicReject),并且requeue属性被设置为false;
2、消息在队列的存活时间超过设置的TTL时间;
3、消息队列的消息数量已经超过最大队列长度;
配置死信队列:
1、配置“业务队列”并绑定到“业务交换机”上;
2、为业务队列配置“死信交换机”和“路由key”;
3、为死信交换机配置“死信队列”;

三、广播类型

  • direct:
  • 把消息路由到那些Binding key与Routing key完全匹配的Queue中。
  • 如果找不到指定的exchange,就会报错。
  • 但routing key找不到的话,不会报错,这条消息会直接丢失
  • fanout:
  • 所有bind到此exchange的queue都可以接收消息,无视Binding key(纯广播,绑定到RabbitMQ的接受者都能收到消息);
  • 如果交换机没有绑定任何Queue,则消息就会被丢弃。
  • topic:
  • 所有符合routingKey(此时可以是一个表达式)的exchange所bind的queue可以接收消息;
  • 如果交换机没有匹配任何Queue,则消息会被丢弃。
  • 通配符规则:
    1、routingKey以.为分隔符,每一个分隔符的代表一个单词
    2、通配符*匹配一个单词、通配符#可以匹配多个单词
    3、' * '(星号)可以在routingKey和bindKey上使用,#只能用于RoutingKey中
  • headers:
    headers类型的Exchange不依赖于Routing Key与Binding Key的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。
    在绑定Queue与Exchange时指定一组键值对;当消息发送到Exchange时,RabbitMQ会取到该消息的headers(也是一个键值对的形式),对比其中的键值对是否完全匹配Queue与Exchange绑定时指定的键值对。如果完全匹配则消息会路由到该Queue,否则不会路由到该Queue。

四、集群

RabbitMQ集群原理介绍,元数据同步,必有磁盘节点;镜像队列原理,节点新增和宕机

1、RabbitMQ默认集群
集群会始终同步四种类型的内部元数据:
a. 队列元数据:队列名称和它的属性
b. 交换器元数据:交换器名称、类型和属性
c. 绑定元数据:一张简单的表格展示了如何将消息路由到队列
d. vhost元数据:为vhost内的队列、交换器和绑定提供命名空间和安全属性

因此,当用户访问其中任何一个RabbitMQ节点时,通过rabbitmqctl查询到的queue/user/exchange/vhost等信息都是相同的。

为何RabbitMQ集群仅采用元数据同步的方式?

第一,存储空间。如果每个集群节点都拥有所有Queue的完全数据拷贝,那么每个节点的存储空间会非常大,集群的消息积压能力会非常弱(无法通过集群节点的扩容提高消息积压能力);

第二,性能。消息的发布者需要将消息复制到每一个集群节点,对于持久化消息,网络和磁盘同步复制的开销都会明显增加。

总结
普通集群模式,并不保证队列的高可用性。尽管交换机、绑定这些可以复制到集群里的任何一个节点,但是队列内容不会复制。虽然该模式解决一项目组节点压力,但队列节点宕机直接导致该队列无法应用,只能等待重启。所以要想在队列节点宕机或故障也能正常应用,就要复制队列内容到集群里的每个节点,必须要创建镜像队列。

2、RabbitMQ镜像集群
RabbitMQ镜像队列原理分析

  • 镜像队列是基于普通的集群模式的,然后再添加一些策略,所以还是得先配置普通集群,然后才能设置镜像队列。镜像队列存在于多个节点。要实现镜像模式,需要先搭建一个普通集群模式,在这个模式的基础上再配置镜像模式以实现高可用。
  • 镜像队列集群模式中,对某个queue来说,只有master对外提供服务,而其他slave只提供备份服务,在master所在节点不可用时,选出一个slave作为新的master继续对外提供服务。
  • 无论客户端的请求打到master还是slave最终数据都是从master节点获取。当请求打到master节点时,master节点直接将消息返回给client,同时master节点会通过GM(Guaranteed Multicast)协议将queue的最新状态广播到slave节点。GM保证了广播消息的原子性,即要么都更新要么都不更新。
  • 当请求打到slave节点时,slave节点需要将请求先重定向到master节点,master节点将将消息返回给client,同时master节点会通过GM协议将queue的最新状态广播到slave节点。
  • 所以,多个客户端连接不同的镜像队列不会产生同一message被多次接受的情况。
  • 镜像队列不能作为负载均衡使用,因为每个声明和消息操作都要在所有节点复制一遍。镜像队列是用于节点之间同步消息的机制,避免某个节点宕机而导致的服务不可用或消息丢失,且针对排他性队列设置是无效的。很重要的一点,镜像队列机制不是负载均衡。
  • 关于node节点
  • queue有master节点和slave节点。 要强调的是,在RabbitMQ中master和slave是针对一个queue而言的,而不是一个node作为所有queue的master,其它node作为slave。一个queue第一次创建的node为它的master节点,其它node为slave节点。
  • 节点类型
    ram(内存)节点:将队列、交换机、绑定等数据存储在内存中,好处是存储和交换机生命之类的操作速度快,坏处是断电后数据会丢失。
    disk(磁盘)节点:将元数据存储在磁盘中,单节点的RabbitMQ只允许磁盘节点,防止重启RabbitMQ的时候,丢失配置信息。
  • RabbitMQ要求在集群中至少有一个磁盘节点,所有其他节点可以是内存节点,当节点加入或者离开集群时,必须要将该变更通知到至少一个磁盘节点。如果集群中唯一的一个磁盘节点崩溃的话,集群可以继续路由消息,但是无法进行其他操作(增删改查队列、交换机、权限等),直到节点恢复。
  • 对集群节点停止顺序的要求
    RabbitMQ 对集群的停止的顺序是有要求的,应该先关闭内存节点,最后再关闭磁盘节点。如果顺序恰好相反的话,可能会造成消息的丢失。

你可能感兴趣的:(RabbitMQ学习)