一般常用来进行业务异步解耦、解耦微服务、流量削峰填谷、消息分发、分布式事务的数据一致性等。
最常见的场景就是用户注册之后,需要发送注册短信、邮件通知,以告知相关信息。
正常做法,是要经过三大步处理:用户信息处理、发送邮件、发送短信,等这三步全部都完成之后,才返回前端,告诉你注册成功了。
使用MQ,只需要在处理完用户信息之后,给MQ发送两个消息即可,邮件服务、短信服务监听MQ的任务消息,根据消息进行发送即可。
还是用户注册的例子,将用户注册、邮件/短信发送理解为两个独立的微服务,就非常好理解
控制流量,也是MQ比较常用的一个场景,一般在秒杀、搞活动中使用广泛。这个时候一般用户请求量会激增,可能会远超当前系统的最大处理量,如果不做任何处理,系统可能就会宕掉。
使用MQ,可以将需要处理的消息全部放入其中,系统按照最大处理能力,去获取消息进行消费,这样就可以将一瞬间过来的请求,分散到一段时间内进行处理,避免了系统的崩溃。
多个系统对同一个数据感兴趣,只需要监听同一类消息即可。
例如付款系统,在付款成功之后,正常做法是通知外围系统这个单子付款成功了,或者是外围系统定时来拉取付款结果,使用MQ后,付款系统可以在付款成功之后,将消息放到MQ里面,想知道这个结果的系统订阅这个主题的消息即可,非常方便,也不需要定时去拉取数据了。
MQ(Message Queue)消息队列,是基础数据结构中先进先出的一种数据结构。指把要传递的数据(消息)放到队列中,用队列机制来实现消息传递 - 生产者产生消息并把消息放入队列,然后由消费者去处理。消费者可以到指定队列去拉取消息,或者订阅相应的队列,由MQ服务端给其推送消息。
经典的Producer,Broker,Consumer消费模型,不同类型的消息以不同的Topic来区分。为了解决性能问题,一个Topic下可以根据需求设置为一个或多个消息队列,Message Queue类似数据库中的分区。Producer按照负载均衡策略将消息发送到Topic不同的消息队列中,Consumer可以从队列中取出消息并发的去消费。
MetaQ通信组件直接使用Netty,在其上做了简单的封装。Netty是一个事件驱动的网络编程框架,它屏蔽了Java底层的复杂细节,具备高性能,高可靠性。
网络协议
MetaQ消息存储是由CommitLog和ConsumeQueue配合完成的,CommitLog真正存储消息,存储在实际CommitLog物理存储中,ConsumeQueue存储消息在CommitLog上的索引,类似于数据库的索引文件,存储的是消息在实际CommitLog物理存储中的偏移地址。每个Topic下的每个Queue都有一个ConsumeQueue文件,文件地址在{root}/consumequeue/{topicName}/{queueId}
CommitLog以物理文件存储,每个Broker上的CommitLog被该机器上的所有Queue共享(也就是说一个Broker上只有一个CommitLog文件)
优点
缺点
对于缺点的克服
metaq的所有消息都是持久化的,先写入系统page cache,然后刷盘,可以保证内存和磁盘都有一份数据
访问时,直接从内存读取。目前,metaq的刷盘策略使用的是异步刷盘等方式
异步刷盘
broker节点收到消息之后,将消息写入缓存便返回成功。当收到一定数量的消息条数或一定量大小的消息,再批量刷到磁盘
同步刷盘
broker节点收到消息,将消息写入缓存,并会当缓存中的数据落到磁盘之后,才会返回成功
对于指定的一个Topic,所有的消息严格按照先入先出的(FIFO)的顺序进行发布和消费
对于指定的一个Topic,所有的消息根据sharding key进行区块分区。同一个分区内的消息严格按照FIFO的顺序发布和消费。
将同一个Topic下的多个消息消息队列,进行分区
顺序消息的缺陷
事务消息发送对应步骤1,2,3,4 ,事务回查对应步骤5,6,7
1 对于生产者的负载均衡
主要在于生产者发送消息时,会发往broker里面topic分区。多个broker里对同一个topic有多个分区,生产者发送的消息需要确认发往那个分区。此处负载均衡策略是,将所有的broker里面的分区组成一个圈,按从头到位循环遍历选择topic分区发送消息。
2 对于消费者的负载均衡
主要是消费者在消费时,会选择consumer group的哪个consumer进行消费
此处策略是
引用文章 : https://blog.csdn.net/qq_48607414/article/details/125801014
发送普通消息的方式有三种,同步,异步,Oneway
代码示例 : https://help.aliyun.com/document_detail/29547.html?spm=a2c4g.11186623.2.11.56d6783eLPaTwZ#concept-2047086
● 同步发送 : 客户端提交消息到broker之后会等待返回结果,相对常用的方式
● 异步发送 : 调用发送接口时会注册一个callback类,发送线程继续其他业务逻辑,producer在收到消息之后回调。比较适合不想发送结果影响正常业务逻辑的情况
● Oneway : Producer提交消息之后,无论是broker是否真正常收到消息都不关心,适合追求高吞吐,能容忍消息丢失败的情况,比如日志收集
乱序重试消息
该重试是针对消息乱序消费的情况
何时重试
抛出运行时异常或者返回ConsumerConsurrentlyStatus.RECONSUME_LATER,metaq会自动重试
重试策略
会自动重试16次,超过16次还失败,则消息进入死信队列,不再提供重试机制。死信队列的消息不可以读取,每次消费失败,应用可以设置消息下次重试时间间隔,正常情况下,间隔时间比较准确,在broker压力比较大的情况下,间隔时间可能比设置时间要长
客户端代码(设置间隔时间)
如果重试16次还是失败后,先告警,然后可以考虑消息本地落地,然后使用定时任务取出消息然后再发送。
顺序重试消息
该重试是针对消息顺序消费的情况
何时重试
抛出运行时异常或者返回ConsumerOrderlyStatus.SUSPEND_CURRENT_QUWUW_A_MONENT , metaq会自动重试,知道返回成功才停止重试
重试策略
因为要保证消费的顺序性,所以某一个队列的某条消息消费失败,那么这个队列就暂停消费,知道该消息重试成功。其他队列不受影响,重试行为完全在客户端执行,不需要服务器参与
注意: 广播消费消息不支持失败重试,广播消费进度会在消费者本地磁盘五秒钟刷盘一次。
Producer最佳实践
Consumer最佳实践