消息队列【开发实践】

1. 什么是消息队列

消息指两台计算机间传输的数据单元,可以包含任何类型的数据,如文本、JSON、XML等。

消息队列简称为MQ(Message Queue),指在消息传输过程中存放消息的容器,其本质是一个存放消息的队列,是介于消息发送源和消息接收者之间的中间件。

2. 消息队列中的相关概念

  • Producer:生产者,指消息的创建者,向消息队列发(即成产)消息。
  • Consumer:消费者,指消息的接收者,从消息队列取(即消费)消息。
  • Messeage:消息体,消息队列中存放的数据单元。
  • Queue:队列,消息队列中存放消息的具体容器,支持FIFO原则。
  • Topic:主题,在发布/订阅模式下使用,发布者发布消息到一个主题上,而所有订阅了这个主题的消费者都能收到该主题下的消息。将消息划分为不同的主题,将不同主题的消息发送到对应的Topic队列中,从而降低队列的竞争压力。
  • Partition:分区,队列中的更小的独立存取消息的区域。即使使用了主题来对消息分流,单个队列中的消息还是可能会过多,为减小多个消费者在单个队列中的竞争,可以将队列划分为多个分区,每个消费者仅使用其中的一个分区,从而大大降低了竞争,提升了消息队列的性能。
  • Broker:消息服务器。如果Partiton都在一个机器上,会导致单机CPU和内存使用率过高,影响整体系统性能。为此,我们可以使用多台机器,将Partition分散到不同的机器上,其中每台机器也被称为Broker。
  • 消息协议:定义消息的格式和通信规则,确保消息能够在不同的系统之间正确传输和解析。常见的消息协议有AMQP、MQTT、STOMP、Kafka协议等。

3. 消息队列的作用(前三个最重要)

  • 解耦(Decoupling):消息队列允许生产者和消费者应用程序之间松耦合。生产者无需直接与消费者交互,只需将消息放入队列,从而降低了系统的复杂度和相互依赖性,提高了模块间的独立性。
  • 异步处理(Asynchronous Processing):通过消息队列,生产者可以立即继续其任务而无需等待消费者处理消息的响应,这样提高了系统的响应速度和吞吐量。异步处理也使得系统能更有效地利用资源,处理更多并发操作。
  • 削峰填谷(Load Levelling):在高流量时段,消息队列作为缓冲区积累请求,随后在系统空闲时逐步处理,防止瞬间流量高峰压垮系统,实现了负载均衡。
  • 容错与可靠性(Fault Tolerance and Reliability):消息队列可以配置消息的持久化存储,确保即使系统崩溃,消息也不会丢失,增强了系统的稳定性和数据完整性。
  • 可扩展性(Scalability):随着系统负载的增长,可以动态添加更多的消息消费者来平行处理队列中的消息,从而水平扩展系统处理能力。
  • 顺序保证与消息分组(Ordering and Message Grouping):在某些场景下,消息队列可以确保消息按照特定顺序被处理,或者将相关消息分组处理,满足特定业务逻辑需求。
  • 灵活的路由与过滤(Flexible Routing and Filtering):消息队列支持根据消息内容或规则将其路由到不同的目标队列或消费者,实现灵活的消息分发和处理策略。

4. 消息队列的消费模型

4.1 点对点模型(单播)

生产者向队列发送消息,消费者从队列取出消息,队列中的消息只能被一个消费者取出并消费,当被消费后就会从队列中移除。

4.2 发布订阅模型(广播)

生产者和消费者通过主题建立订阅关系,生产者向主题队列发送消息,所有订阅了该主题的消费者都会收到该消息的拷贝。

发布订阅模型有两种订阅类型:

  • 持久订阅:持久订阅意味着无论订阅者当前是否在线或活跃,消息队列都会保存为其预定的所有消息。当订阅者重新连接后,它能够接收到在其离线期间发布的所有未读消息。
  • 非持久订阅:非持久订阅是指订阅者仅接收在线时发布的消息。一旦订阅者断开连接,任何在此期间发布的消息都将丢失,订阅者再次连接后不会收到这些错过的信息。

5. 使用消息队列时可能遇到的问题

5.1 消息丢失

  • 避免在生产者丢失:使用发送者确认机制,若消息队列没有接收并确认消息,则由生产者重试。
  • 避免在消息队列丢失:使用持久化机制避免宕机丢失消息,使用多个节点来容灾和备份以提高可用性。
  • 避免在消费者丢失:使用消费者确认机制,消费者处理完消息后向消息队列发送确认(而不是取走消息后自动确认),队列收到确认后才从队列中移除消息。如果消费过程中出现异常,消息队列没有收到ACK,队列将在一段时间后重新投递该消息。
  • 事务消息:对于需要保证事务一致性的场景,使用事务消息功能。确保消息的发送与业务操作要么全部成功,要么全部失败,避免消息发送成功但业务操作失败导致的消息丢失。

5.2 消息重复消费

正常情况下,消费者在消费消息后,会给消息队列发送一个确认,消息队列接收后就知道消息已经被成功消费了,然后就从队列中删除该消息,也就不会将该消息再发送给其他消费者了。不同消息队列发出的确认消息形式不同,RabbitMQ是通过发送一个ACK确认消息。但是因为网络故障,消费者发出的确认并没有传到消息队列,导致消息队列不知道该消息已经被消费,然后就再次消息发送给了其他消费者,从而造成重复消费的情况。解决方案如下:

  • 保证操作的幂等性:幂等性意味着同一个操作执行多次产生的结果与执行一次的结果相同,即使消息被重复消费,也不会对系统状态造成影响。可以从业务逻辑上实现幂等性,如更新操作,更新多次的结果都是一致的。
  • 保证操作的唯一性:使用数据库或redis记录消息标识到消息处理状态的映射,处理消息之前先检查该消息是否处理过,处理过则不再处理。

5.3 消息顺序性

  • 使用支持顺序消息的队列服务:消息队列会确保同一分区内的消息按照发送顺序进行投递。
  • 单一消费者:多个消费者去消费同一队列的消息, 无法保证先读到消息的消费者一定先完成操作。为避免并发消费导致的错序执行的问题,我们可以让一个消费者来消费这个需要保证消息顺序性的队列。
  • 单线程处理:即使一个队列仅由一个消费者来消费,若该消费者使用了多线程来处理消息中的操作,由于多线程的并发性无法保证先处理的消息的操作先完成,也会导致错序执行的问题。此时我们可以限制该消费者只能用单线程处理。

5.4 消息积压问题

  • 迅速增加消费者实例数量,通过水平扩展来提高消费速率。(当消费者数量少于队列数量时有用)
  • 增加消费者的硬件资源,如CPU、内存和网络带宽,以提升单个消费者的处理能力。

6. 消息队列的选型

// to do

7. Spring + CMQ(公司内部封装过,仅供大家参考)

7.1 队列模式

7.1.1 发送消息(+删除消息)
	// 1. 注入Account对象
	@Autowired
	Account queueAccount;
	
	// 2. 获取指定队列
	Queue queue = queueAccount.getQueue("queueName");

	// 3. 向指定队列发送消息(还有一些重载方法)
	CmqResponse response = queue.send("msgBody");

	// 4. 删除指定队列中的消息
	CmqResponse response = queue.deleteMessage(receiptHandle);
7.1.2 接收消息
// 1. 创建指定队列的接收器
	// 实现IBaseQueueHandler接口
	// 使用@QueueListener(queueName = "queueName")自定队列
	// 使用@Component注册bean
@Component
@QueueListener(queueName = "queueName")
public class Test2QueueHandler implements IBaseQueueHandler {
 
 	// 2. 实现接收消息的方法
    @Override
    public boolean onMessage(String queueName, Message message) {
    	...
    	// 消息消费成功返回true,消费失败返回false
        return true;
    }
}

7.2 主题模式

7.2.1 发送消息
	// 1. 注入Account对象
	@Autowired
	Account queueAccount;
    
    // 2. 获取指定主题
    Topic topic = topicAccount.getTopic("topicName");

	// 3. 向主题队列发送消息(还有一些重载方法)
    topic.publishMessage("msgBody");
7.2.2 接收消息

主题下面会有响应的队列,接收就是从队列接收,和队列模式是一致的。

参考链接

深入消息队列MQ,看这篇就够了!
消息队列详解
b站视频资源:消息队列kafka是什么?架构是怎么样的?5分钟快速入门

  • 26
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值