一、简介
Rabbit MQ是一个消息代理-消息系统的媒介,它可以为应用提供一个通用的消息发送和接收平台,并且保证消息在传输过程中的安全 
二、多协议支持
amqp和stomp协议
Stomp:面向流文本的消息传输协议(Stream Text Oriented Messaging Protocol),是WebSocket通信标准。在通常的发布-订阅语义之上,它通过begin/publish/commit序列以及acknowledge机制来提供消息可靠性传递。
AMQP:
三、内部组件
3.1 ConnectionFactory(连接管理器)
应用程序和rabbit之间建立连接的管理器,程序代码中使用
3.2 Channel(信道)
消息推送使用的通道
3.3 Exchange(交换机)
AMQP 0-9-1的代理提供了四种交换机
Name(交换机类型) | Default pre-declared names(预声明的默认名称) |
---|
Direct exchange(直连交换机) | (Empty string) and amq.direct | Fanout exchange(扇型交换机) | amq.fanout | Topic exchange(主题交换机) | amq.topic | Headers exchange(头交换机) | amq.match (and amq.headers in RabbitMQ) |
1、直连direct routingkey和queue一对一精确匹配,当exchange不填,默认走空字符串的直连交换机
默认交换机属于直连交换机,绑定exchange为"":The default exchange is a direct exchange with no name(empty string) pre-declared by the broker.
2、主题topic 模糊匹配,*代表一个单词,#代表0或N个单词 3、广播fanout 无需routingkey,消息广播到所有的queue 4、头连head(可用topic代替) 请求头匹配,使用较少,大多数它能做到的topic都能做到
按照效率:fanout广播模式效率最高,其次direct直连,然后是topic 队列和交换机之间的绑定关系,放在控制台操作,避免业务代码混乱、方便管理
3.4 Queue
用于存储生产者的消息
3.5 RoutingKey(路由键)和BindingKey(绑定键)
BindingKey是Exchange和Queue绑定的规则描述,这个描述用来解析当Exchange接收到消息时,Exchange接收到的消息会带有RoutingKey这个字段,Exchange就是根据这个RoutingKey和当前Exchange所有绑定的BindingKey做匹配,如果满足要求,就往BindingKey所绑定的Queue发送消息,这样我们就解决了我们向RabbitMQ发送一次消息,可以分发到不同的Queue的过程
真实情况下参数名都是RoutingKey,没有BindingKey这个参数,为了区别用户发送的和我们绑定的概念,我们才说RoutingKey和BindingKey
3.7 Vhost(虚拟主机)
每个broker可以创建多个vhost,每个虚拟主机其实都是独立的rabbitMQ服务(共用一个broker进程)
四、pub-sub
1、生产者
connection.createChannel();
channel.queueDeclare(String queueName, bool durable, bool exclusive, bool autoDelete, 队列参数 arguments);
channel.basicAck(exchange, routingkey, props, message.getBytes());
2、消费者
- 创建连接,设置属性
- 创建channel信道,将队列绑定到信道(同生产者)
- 接收消息
channel.basicAck(message.getEnvelope.getDeliveryTag(), bool multiple);
3、broker
五、集群模式
1、cluster普通模式(不推荐)
多态机器启动多个rabbit实例,但创建的queue(元数据+实际数据)只会放在一个rabbit实例A上,其他实例都会同步queue的元数据
元数据:可以理解为queue的位置、信息,便于其他实例拉取数据
消费者消费消息时,实际连的是另一个实例B,B会根据元数据去到A上拉取数据
优点:快,效率高 缺点:没有做到分布式,就是普通集群。可能存在消息丢失,部分节点故障问题 ① 消费者每次随机连接一个实例拉取数据(增加拉取数据的开销) ② 消费者固定连接到queue所在的实例消费数据(导致单实例性能瓶颈) ③ 当A宕机(丢失数据),则其他实例无法拉取数据。即使开启消息实例化,让rabbit落地存储消息,也得等A恢复了才能继续拉取数据
总结:没有高可用可言,该方案主要是提高吞吐量,让集群中多个节点服务某个queue的读写操作(多个消费者消费单个实例中队列消息)
2、镜像模式
在cluster普通模式的基础上,rabbit管理台配置同步策略policy。 创建一个queue(元数据+实际数据),无论是queue的元数据还是消息,都存在于多个实例上。每次写消息到queue时,会自动把消息同步到多个实例的queue中。 优点:实现了高可用,不担心宕机,所有实例数据都是一样的 缺点:数据冗余,浪费资源。受限于最差的那台服务器 ① 性能开销大,消息同步所有机器导致网络带宽消耗很大 ② 无扩展性可言,若某queue负载很重,再加机器,新增的机器也包含了这个queue的所有数据,无法线性扩展queue的容量
3、additional:federation插件
应用于广域网,允许单台服务器上的交换机或队列接收发布到另一台服务器上交换机或队列的消息,可以是单独机器或集群。federation队列类似于单向点对点连接,消息会在联盟队列之间转发任意次,直到被消费者接受。通常使用federation来连接internet上的中间服务器,用作订阅分发消息或工作队列。 可以使rabbitMQ在不同broker节点间进行消息传递而无需建立集群,在以下场景非常有用:
- 各节点运行在不同版本的rabbitMQ
- 网络环境不稳定
4、shovel
连接方式与federation的连接方式类似,但它工作在更低层次。可以应用于广域网
六、持久化机制和内存、磁盘管理
1、持久化 rabbit分为队列持久化、消息持久化和交换机持久化。不管是持久化的消息还是非持久化的消息都可以被写入磁盘! 持久化 :消息存放在队列和内存中,并持久化到磁盘 非持久化 :消息存放在内存,当达到设置内存阈值时,写入磁盘(重启后无法加载)
2、内存、磁盘管理 rabbit中会有内存告警阈值(默认0.4),当超过这个阈值,消息会被阻塞、告警。 可以通过在配置文件中配置vm_memory_high_watermark_paging_ratio项来修改此值:
vm_memory_high_watermark.relative = 0.4
vm_memory_high_watermark_paging_ratio=0.75
以上配置将会在rabbit MQ内存使用率达到30%时进行换页动作,并在40%时阻塞生产者。当vm_memory_high_watermark_paging_ratio的值大于1时,相当于禁用了换页功能。
当磁盘剩余空间低于确定的阈值 时,rabbitMQ同样会阻塞生产者,这样可以避免因非持久化的消息持续换页而耗尽磁盘空间导致服务崩溃。
默认情况下,磁盘阈值为50MB,表示当磁盘剩余空间低于50MB时会阻塞生产者并停止内存中的消息换页动作。 这个阈值的设置可以减小,但不能完全消除因磁盘耗尽而导致崩溃的可能性。比如在两次磁盘空间检测期间内,磁盘空间从大于50MB被耗尽到0MB。 一个相对谨慎的做法是将磁盘阈值设置为与操作系统所显示的内存大小一致。
在某个broker节点触及内存并阻塞生产者之前,它会尝试将队列中的消息换页到磁盘以释放内存空间。持久化和非持久化的消息都会被转存到磁盘中,其中持久化的消息本身就在磁盘中有一份副本,这里会将持久化的消息从内存中清除掉。
默认情况下,在内存到达内存阈值的50%时会进行换页动作。 也就是说,在默认的内存阈值为0.4的情况下,当内存超过0.4*0.5=0.2 时会进行换页动作。
七、常见问题
1、rabbitMQ如何保证顺序消费? 通过消费者的deliveryTag,顺序递增的标识 // todo详细补充
2、rabbit如果有多个队列,无法实现顺序消费???(真伪待百度)
3、rabbit如何重复去消费一个队列中的消息?
4、rabbit集群中唯一一个磁盘节点崩溃了会发生什么情况? 唯一磁盘节点崩溃了,集群是可以保持运行的,但是不能更改任何东西。不能进行以下操作: ① 不能创建交换机、队列,不能创建绑定 ② 不能添加用户、更改权限,不能添加和删除集群节点
5、rabbit对集群节点停止顺序有要求吗? 有要求,应该先关闭内存节点,最后再关闭磁盘节点。若顺序相反,可能会造成消息的丢失。
6、rabbit怎么实现延迟消息队列? 延迟队列实现有两种方式: ① 通过消息过期后进入死信交换器,再由交换器转发到延迟消费队列,实现延迟功能; ② 使用rabbitMQ-delayed-message-exchange插件实现延迟功能
7、RabbitMq之怎么保证rabbitmq不丢消息和扩容 
https://www.jianshu.com/p/d33ada5ae346
8、扩容 单机版本的RabbitMQ实例不支持扩大存储空间。 集群版本的RabbitMQ实例不支持扩大存储空间,只支持扩节点。
9、发消息是否会绕过交换机? defalut 可以不用声明exchange但是不能绕过,还是要经过exchange,routingkey需要和queuename保持一致
|