消息队列应用场景


从上一章,大致已经知道消息队列是什么。
而本章,讲述消息队列在实际项目中的价值,即应用场景。

在合适的时候,引入消息队列,能让我们的服务架构可用性更高,能力更优秀。

下面,一起来了解消息队列的应用场景。

数据冗余

我们可能在看到“冗余”这个词的时候,觉得他是个贬义词。
但实际上,一定程度的冗余,会让我们的数据更加安全。
比如,数据库备份,就是一种数据冗余,mysql读写分离,亦是通过日志和轮询实现数据冗余。
这样,当我们某一份数据出现问题时,我们还有第二份数据,数据就更加安全。
那么,消息队列如何提供冗余功能呢?

常见的消息队列系统,会将数据保存在内存中,以提高数据读写效率。既然数据在内存中,就可能出现丢失的情况,所以,它们又提供持久化的功能,保证在队列系统崩溃后,数据仍然存在。 另外,消息队列内的每一条消息,都必然存在 reserved 和 deleted 两个状态,只有当消费者给队列系统发送处理成功的信号时,消息才会从队列中删除,并不会因为消息已接收,就删除消息。

可以说,消息队列,也是增对数据库层的一道输入向缓存,对数据有冗余作用。即,当有数据需要进入数据库,会先经过消息队列,再进入数据库。

解耦合

我们知道软件工程讲究高内聚低耦合,所以我们会想许多办法来控制耦合度,即解耦。
消息队列,也是一种解耦的方案。
按照普通流程,消费代码可能会直接跟在生产代码后面,那么,生产和消费就成了彼此的上下文,甚至连变量、作用域等都会有依赖,此时,你若对生产代码的某个变量进行修改,你必须仔细检查消费代码是否也使用了这个变量。

通过消息队列,我们将生产代码和消费代码拆分开来,它们不再互相依赖彼此的具体实现,只依赖于消息队列中消息的结构。只要消息结构不变,生产代码和消费代码如何修改,都不会影响到彼此。

这一点,我们可以联想到上一章《什么是消息队列?》中的下单功能辅助理解。

异步能力

有人说,高性能离不开异步,异步离不开队列
一定意义上来说,这句话是很有道理的。
异步,它让每一个调用都能及时返回,提升响应速度。在这里,可能需要理解一下异步:《关于异步的理解》
队列,保证了异步调用的处理不会丢失。这句话中的“处理”一词,指处理工作,是个名词。

我们知道,异步,它先返回的是调用动作是否成功的结果,而具体调用执行的逻辑和结果,并不在这里返回,而是以通知(回调)的形式进行。队列,是确保每一个调用的处理都会被执行数据结构。

这一点,我们可以在之后消息队列的实践中,体会到。
消息队列,能够让在架构上提供异步能力(注意,是架构上,而非代码层面如函数调用的异步能力)。
关于这个异步能力,还是可以参考上一章《什么是消息队列?》中的下单功能,

扩展性

当架构中加入消息队列,生产者和消费者就比较容易扩展。
仍然以下单功能举例,如果生产者和消费者的代码耦合在一起,互相严重依赖,当我们想对生产者产生内容进行不同的处理(消费)时,则需要在原有的源码中进行扩展,这对原有代码产生伤害,便不必说扩展性了。

但如果以消息队列将生产者和消费者进行解耦,则,我们只需要添加订阅消息的消费者程序即可,新的消费者对旧消费者没有任何伤害,它依旧依赖于消息队列,只需要确保它能收到消息即可。

顺序保证

队列本身具备“先进先出”的特性,消息队列是一种队列结构的中间件,则,消费者会根据消息进入的先后顺序,进行先后处理。
其本身就能解决顺序问题

削峰填谷

在某些高并发的场景下,流量突然激增,比如秒杀。
此时,数据库的压力很大,而数据库的读写处理能力普遍低于内存式的消息队列。
此时,可以将消息临时存储于消息队列中,减少数据库的压力,然后再由消费者按数据库能够接受的频率去读取消息,进行处理,因为数据库只在秒杀那一刻压力很大,平时会清闲一些。
这就是将山峰削掉,填补山谷