概述
MQ的内容之前已经介绍了几次了,所以今天这里主要聊一聊消息队列(MQ),以RabbitMQ为例来做个总结。
01基础定义1. Broker
Broker的概念来自与Apache ActiveMQ,通俗的讲就是MQ的服务器。
2. 消息的生产者、消费者
消息生产者Producer:发送消息到消息队列。
消息消费者Consumer:从消息队列接收消息。
3. 点对点消息队列模型
消息生产者向一个特定的队列发送消息,消息消费者从该队列中接收消息;
消息的生产者和消费者可以不同时处于运行状态。
每一个成功处理的消息都由消息消费者签收确认(Acknowledge)。如图:
4. 发布订阅消息模型-Topic
发布订阅消息模型中,支持向一个特定的主题Topic发布消息,0个或多个订阅者接收来自这个消息主题的消息。在这种模型下,发布者和订阅者彼此不知道对方。实际操作过程中,
发布订阅消息模型中,支持向一个特定的主题Topic发布消息,0个或多个订阅者接收来自这个消息主题的消息。在这种模型下,发布者和订阅者彼此不知道对方。实际操作过程中,
必须先订阅,再发送消息,而后接收订阅的消息,这个顺序必须保证。
5. 消息的顺序性保证
基于Queue消息模型,利用FIFO先进先出的特性,可以保证消息的顺序性。
6. 消息的ACK确认机制
即消息的Ackownledge确认机制,
为了保证消息不丢失,消息队列提供了消息Acknowledge机制,即ACK机制,当Consumer确认消息已经被消费处理,发送一个ACK给消息队列,此时消息队列便可以删除这个消息了。如果Consumer宕机/关闭,没有发送ACK,消息队列将认为这个消息没有被处理,会将这个消息重新发送给其他的Consumer重新消费处理。
02适用的应用场景- 异步处理:例如短信通知、终端状态推送、App推送、用户注册等
- 数据同步:业务数据推送同步
- 重试补偿:记账失败重试
- 系统解耦:通讯上下行、终端异常监控、分布式事件中心
- 流量消峰:秒杀场景下的下单处理
- 发布订阅:HSF的服务状态变化通知、分布式事件中心
- 高并发缓冲:日志服务、监控上报
其实MQ比较适合异步传输,这里解释一下什么是异步和同步。
异步:发送方不关心消息有没有发送成功,只发送消息,不去获取消息是否发送成功。
同步:发送方关心消息是否发送成功,发送消息后,会等待接收方返回状态码,根据状态码来判断是否发送成功,然后执行相对于的动作。
下边以Http中的同步和异步为例:
如:普通的B/S架构客户端和服务器端之间的通信就是同步的,即提交请求 ---> 等待服务器处理完毕返回消息 ---> 拿到服务器返回的消息,处理完毕。
如:Ajax技术就是异步的,请求通过事件触发 ---> 服务器处理(浏览器不用等待,仍可以做其他的事情) ---> 处理完毕。
03RabbitMQ在消息队列中有很多类似的产品,前面我已经做了介绍了,不过今天主要以RabbitMQ(RabbitMQ是AMQP的一个标准实现)为例。
1. 角色概念
每个开源项目都有自己的设计方法以及模块角色,RabbitMQ也不例外。结构图如下:
Broker:即消息队列服务器实体
Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
Queue:消息队列载体,每个消息都会被投入到一个或多个队列。
Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。
Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
producer:消息生产者,就是投递消息的程序。
consumer:消息消费者,就是接受消息的程序。
channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。
2. 工作过程
1)消息生产者连接到RabbitMQ Broker,创建connection,开启channel。
2)生产者声明交换机类型、名称、是否持久化等。
3)发送消息,并指定消息是否持久化等属性和routing key。
4)exchange收到消息之后,根据routing key路由到跟当前交换机绑定的相匹配的队列里面。
5)消费者监听接收到消息之后开始业务处理,然后发送一个ack确认告知消息已经被消费。
6)RabbitMQ Broker收到ack之后将对应的消息从队列里面删除掉。
3. RabbitMQ的消息持久化
RabbitMQ支持数据持久化,也就是把数据写在磁盘上,可以增加数据的安全性。消息队列持久化包括三个部分:
- 消息交换机(exchange)持久化,在声明时指定durable为1
- 消息队列(queue)持久化,在声明时指定durable为1
- 消息持久化,在投递时指定delivery_mode为2(1是非持久化)
如果消息交换机(exchange)和消息队列(queue)都是持久化的话,那么他们之间的绑定(Binding)也是持久化的。如果消息交换机和消息队列之间一个持久化、一个非持久化,那么就不允许绑定。
持久化工作原理
Rabbit会将你的持久化消息写入磁盘上的持久化日志文件,等消息被消费之后,Rabbit会把这条消息标识为等待垃圾回收。
持久化的缺点
消息持久化的优点显而易见,但缺点也很明显,那就是性能,因为要写入硬盘要比写入内存性能较低很多,从而降低了服务器的吞吐量,尽管使用SSD硬盘可以使事情得到缓解,但他仍然吸干了Rabbit的性能,当消息成千上万条要写入磁盘的时候,性能是很低的。
所以使用者要根据自己的情况,选择适合自己的方式。
后面会分享更多devops和DBA方面的内容,感兴趣的朋友可以关注一下~