3.1 生产者-生产阶段
在这个阶段,一般通过请求确认机制,来保证消息可靠性传输。 与TCP/IP协议里ACK机制有点像。
客户端发送消息到消息队列,消息队列给客户端一个确认响应,表示消息已经收到,客户端收到响应,表示一次正常消息发送完毕。
3.2 MQ-存储阶段
消息队列给客户端发送确认消息。存储完成后,才发送确认消息。
3.3 消费者-消费阶段
跟生产阶段相同,消费完了,给消息队列发送确认消息。
我们日常说的顺序性是什么呢?
比如说小孩早上上学过程,他先起床,然后洗漱,吃早餐,最后上学。我们认为他做的事情是有先后顺序的,及是时间的先后顺序,我们用时间来标记他的顺序。
更抽象的理解,这些发生的事件有一个相同的参考系,即他们的时间是对应同一个物理时钟的时间。
如果没有绝对的时间作为参考系,那他们之间还能确定顺序吗?
如果事件之间有因果关系,比如A、B两个事件是因果关系,那么A一定发生在B之前(前应后果)。相反,在没有一个绝对的时间的参考的情况下,若A、B之间没有因果关系,那么A、B之间就没有顺序关系。跟java里的happen before很像。
总结一下,我们说顺序时,其实说的是:
在有绝对时间作为参考系的情况下,事件发生的时间先后关系;
在没有绝对时间作为参考系的情况下,一种由因果关系推断出来的happening before的关系;
在分布式系统领域,有一篇关于时间,时钟和事件的顺序的很有名的一篇论文
Time, Clocks, and the Ordering of Events in a Distributed System,可以看一看,上面举例情况都是参考这篇论文。
参考上面的结论,在消息队列中,我们也是以时间作为参考系,让消息有序。
但是,在消息队列中,消息有序会遇到一些问题,下面让我们来讨论这些问题。
消息的顺序性的一些问题在计算机系统中,有一个比较棘手的问题是,它可以是多线程执行的,而且哪个线程先运行,哪个线程后运行,完全是由操作系统决定的,完全没有规律,是乱序执行。显然与消息队列中的消息有序相悖。
还有,在消息队列中,涉及到生产者,MQ,消费者,还有网络,这4者之间的关系。然后他们又涉及到消息的顺序性,就有很多种情况需要考虑。可以参考这篇文章
分布式开放消息系统(RocketMQ)的原理与实践(作者:CHUAN.CHEN),各种情况讨论的很全面。
最后的结论就是:消息的顺序性,不仅仅是MQ本身存储消息要保证顺序性,还需要生产者和消费者一同来保证顺序性。
顺序性保证在消息队列中,消息的顺序性需要3方面来保证:
1、生产者发送消息时要保证顺序
2、消息被消息队列存储时要保持和发送的顺序一致
3、消息被消费时保持和存储的顺序一致
生产者:发送时要求用户在同一个线程中采用同步的方式发送。
消息队列:存储保持和发送的顺序一致。一般是在一个分区中保持顺序性。
消费者:一个分区的消息由一个线程来处理消费消息。
https://www.hicsc.com/post/2020041566 这个链接中,作者分析了RocketMQ顺序消息的代码实现。
5.消息队列中消息延迟问题你说的 消息的延迟 是延迟消息队列吗? 啊,并不是,是完全2个不同的概念。延迟消息队列是MQ提供的一个功能。消息的延迟,是指消费端消费的速度跟不上生产端产生消息的速度,可能导致消费端丢失数据,也可能导致消息积压在MQ中。所以这里说的消息的延迟,指的是消费端消费消息的延迟。
消息队列的消费模型pull和push: 1、push模式这种模式是消息队列主动将消息推送给消费者。
优点:尽可能实时的将消息发送给消费者进行消费。
缺点:如果消费端消费能力弱,消费端的消费速度赶不上生产端,而MQ又不断的给消费端推送消息,消费端的缓存满了导致缓存溢出,就会产生错误或丢失数据的可能。
2、pull模式这种模式是由消费端主动向消息队列拉取消息。
优点:可以自主可控的拉取消息。
缺点:拉取消息的频率不好控制。