消息队列
一、应用场景
(一)异步处理
- 在电商系统中,用户下单流程包含多个环节,如库存扣减、订单生成、支付处理、发票开具以及通知用户等操作。若采用同步处理方式,各环节顺序执行,以库存扣减为例,假设其平均处理时间为 3 秒(可能因数据库查询、数据一致性校验等操作导致延迟),订单生成需 2 秒,支付处理 5 秒,发票开具 4 秒,通知用户 1 秒,那么整个下单流程总耗时将达到 3 + 2 + 5 + 4 + 1 = 15 秒,这会使客户长时间等待,极大影响用户体验。
操作 同步处理时间(秒) 库存扣减 3 订单生成 2 支付处理 5 发票开具 4 通知用户 1 - 引入消息队列后,下单操作触发时,将各个任务封装成消息发送至消息队列。库存系统、订单系统、支付系统、发票系统和通知系统分别从队列中异步获取消息并处理。此时,用户下单后可快速收到响应,而后续任务在后台并行处理。假设各系统处理消息的平均耗时不变,但由于异步执行,整个下单流程的总耗时近似于处理时间最长的支付处理环节,即约 5 秒,大大提升了系统响应速度和用户体验。
(二)流量削峰
- 以电商平台的 “双 11” 促销活动为例,在活动高峰时段,每秒可能有高达 10 万笔订单请求涌入服务器。若没有消息队列作为缓冲,服务器直接处理这些请求,假设服务器的处理能力为每秒 1 万笔订单,那么大量请求将瞬间超出服务器负载,导致服务器响应缓慢甚至崩溃。
- 当采用消息队列时,所有订单请求先进入消息队列。消息队列按照先进先出的原则暂存请求,后端订单处理系统以每秒 1 万笔的处理能力从队列中获取订单消息进行处理。例如,在 10 秒的高峰期间,消息队列可接收 10 * 10 万 = 100 万笔订单请求,而后端系统在 100 秒内可逐步处理完这些请求,有效避免了服务器因瞬时高流量而崩溃,实现了流量的削峰填谷,保障了系统的稳定性。
(三)应用解耦
- 考虑一个在线教育平台,包含课程管理系统、学生管理系统、教师管理系统和作业管理系统等多个子系统。在传统架构下,如果课程管理系统在课程更新时需要通知学生管理系统更新学生课程信息、教师管理系统更新教学安排以及作业管理系统调整相关作业,它需要直接调用这些子系统的接口。
- 假设课程管理系统与学生管理系统的接口依赖关系如下:
课程管理系统操作 学生管理系统接口 课程添加 addCourseForStudent 课程删除 deleteCourseForStudent 课程修改 updateCourseForStudent - 当学生管理系统的接口发生变更,例如将参数结构调整,课程管理系统也需要相应修改代码。而采用消息队列后,课程管理系统只需将课程更新消息发送到消息队列,各子系统根据自己订阅的消息类型从队列中获取消息并处理。这样,各子系统之间的依赖关系被解耦,每个子系统可以独立演进,提高了整个系统的灵活性和可维护性。
二、发展历史
(一)早期简单消息传递机制
-
早期计算机系统中,进程间通信主要依赖简单方式。例如,管道通信可用于父子进程间数据传输。在一个简单的 Linux 系统中,父进程可以通过管道将数据传递给子进程,如下代码所示:
c语言为例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
int pipefd[2];
pid_t pid;
char buffer[256];
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
pid = fork();
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
} else if (pid == 0) { // 子进程
close(pipefd[1]); // 关闭写端
read(pipefd[0], buffer, sizeof(buffer));
printf("子进程收到消息: %s\n", buffer);
close(pipefd[0]);
} else { // 父进程
close(pipefd[0]); // 关闭读端
const char *message = "Hello from parent";
write(pipefd[1], message, strlen(message)+1);
close(pipefd[1]);
wait(NULL);
}
return 0;
}
- 共享内存则是将一块内存区域映射到多个进程地址空间。但这些方式在分布式系统中面临诸多限制,如管道难以跨网络通信,共享内存在不同操作系统下管理差异大,无法满足分布式环境复杂的消息传递需求。
(二)消息队列初步形成
- 20 世纪 80 年代,在金融和电信领域大型主机系统中消息队列概念兴起。以银行核心业务系统为例,转账业务涉及多个系统模块间消息传递。当客户发起转账时,源账户系统需向交易处理系统发送转账请求消息,交易处理系统处理后向目标账户系统发送转账指令消息,同时向日志系统发送交易记录消息。当时的消息队列主要确保这些消息可靠传递,功能相对单一,缺乏通用性和高级功能支持。
(三)面向互联网的发展阶段
- 随着互联网发展,企业应用架构转型。消息队列产品功能和开放性提升。例如 RabbitMQ 支持多种编程语言如 Java、Python 等。以一个电商系统为例,其订单处理模块用 Java 编写,库存管理模块用 Python 编写,它们都可以方便地与 RabbitMQ 集成。RabbitMQ 还支持 AMQP 等多种协议,使得不同类型客户端如移动应用客户端(可能采用 MQTT 协议)和服务器端应用(采用 AMQP 协议)都能与消息队列交互,并且具备消息持久化、事务处理等功能,满足电商系统复杂的业务需求。
(四)云原生时代的消息队列
- 近年来,云原生技术推动消息队列发展。以阿里云消息队列 RocketMQ 版为例,在云环境中,它可以方便地与其他云服务集成。在一个容器化的微服务架构电商应用中,各个微服务可以快速地与 RocketMQ 进行连接,利用其高吞吐量的特点处理大量订单消息。并且,它可以根据业务流量自动弹性伸缩,在促销活动期间自动增加资源以应对高流量,活动结束后自动减少资源,降低成本,同时保障系统的高可用性和高效性。
三、常见消息队列类型
(一)ActiveMQ
-
特点:
- 开源且基于 Java,具有良好的跨平台性,可在 Windows、Linux、Unix 等多种操作系统上运行。支持多种消息协议,如 AMQP、STOMP、MQTT 等。以一个物联网项目为例,其中既有传统的企业级设备管理系统(可能采用 AMQP 协议),又有大量的传感器设备(可能采用 MQTT 协议),ActiveMQ 可以很好地兼容这些不同协议的设备和系统,实现统一的消息管理。
- 提供丰富功能,包括消息持久化,可将消息存储到磁盘以防止数据丢失;事务支持,保证一组消息操作的原子性;消息优先级,确保重要消息优先处理等。
-
应用场景:适用于企业级 Java 应用系统,尤其是对多种消息协议有需求的场景。例如,在一个企业级的数字化工厂项目中,既有生产管理系统(Java 开发)需要与企业内部其他系统进行消息交互(采用 AMQP 协议),又有一些智能监控设备(采用 MQTT 协议)需要将数据传输到统一的消息平台进行处理,ActiveMQ 可以满足这种复杂的多协议消息传递需求。
(二)RabbitMQ
-
特点:
- 开源且用 Erlang 语言编写,Erlang 语言本身具有高并发和高可靠性的特点,这使得 RabbitMQ 具有很高的可靠性。例如,在金融交易系统中,每一笔交易消息都至关重要,RabbitMQ 通过消息确认机制,只有当消费者成功处理消息并反馈确认后,才会将消息从队列中删除,否则会重新发送消息,同时其持久化存储机制也能确保消息在服务器故障等情况下不丢失。
- 支持多种消息交换类型,如 direct 类型可实现一对一的消息精准投递,适合订单处理系统中特定订单的处理;topic 类型可根据主题进行消息的模糊匹配分发,如在日志系统中,不同类型的日志可以根据主题分类分发到不同的日志处理模块;fanout 类型可将消息广播到所有绑定的队列,适用于消息通知场景,如系统公告的推送。
- 易于部署和管理,提供了丰富的插件和直观的管理界面,方便管理员进行队列管理、监控消息流量等操作。
-
应用场景:在需要高可靠性消息传递的场景中广泛应用,如金融交易系统、企业内部的关键业务系统等。在金融交易场景中,如股票交易系统,订单的创建、成交、撤单等消息需要可靠地在各个系统模块之间传递,RabbitMQ 能够确保消息不丢失且按顺序处理。在企业的供应链管理系统中,订单信息、库存信息、物流信息等关键业务消息的传递也依赖于 RabbitMQ 的高可靠性和多种消息交换类型来实现灵活的消息分发。
(三)RocketMQ
-
特点:
- 阿里巴巴开源的分布式消息队列,具有高吞吐量的特点。在电商大促场景下,如 “双 11” 期间,每秒会产生海量的订单消息、物流消息等,RocketMQ 能够稳定地处理这些大量消息,保障系统的高效运行。
- 支持消息的顺序消费,这在一些对消息顺序有严格要求的场景下非常重要。例如在电商系统中,订单的创建、支付、发货、确认收货等消息必须按照顺序处理,否则会导致业务逻辑混乱。RocketMQ 通过特定的分区和队列机制来确保同一业务流程的消息顺序性。
- 提供了丰富的消息过滤功能,能够根据消息的属性等进行灵活过滤。比如在一个电商平台的营销系统中,可以根据用户的地域、消费等级等消息属性,过滤出特定目标用户的促销消息,提高营销的精准度。
-
应用场景:适合大规模的分布式系统和高并发的互联网应用场景,如电商平台的订单处理、物流消息处理等。在电商平台的订单处理流程中,从用户下单到订单完成的整个生命周期涉及多个系统和环节,RocketMQ 可以高效地传递和处理这些订单相关消息,并且其顺序消费和消息过滤功能能够很好地满足电商业务复杂的需求,如根据订单状态过滤出需要进行售后处理的订单消息。
(四)Kafka
-
特点:
- 最初由 LinkedIn 开发的分布式流处理平台,也可作为消息队列使用。具有高吞吐量和可扩展性,能够处理海量的消息数据。例如在一个大型互联网公司的日志收集与分析系统中,每天会产生数 TB 的日志数据,Kafka 可以轻松地接收、存储和传输这些日志消息,并且可以通过增加节点的方式水平扩展,以适应不断增长的业务需求。
- 基于日志结构存储消息,这种存储方式使得它在消息持久化和顺序读写方面具有优势。在大数据分析场景中,如用户行为分析,需要对大量用户的行为数据按照时间顺序进行分析,Kafka 的日志结构存储可以高效地支持这种顺序读写操作,并且能够长时间保存数据以便进行历史数据分析。
- 适合处理实时流数据,支持消息的分区存储和多副本机制,提高了数据的可靠性和可用性。在物联网领域,大量设备产生的实时数据,如传感器数据,可以通过分区存储在 Kafka 中,并且多副本机制确保了数据不会因为单点故障而丢失,同时可以被多个消费者并行处理,实现实时数据的快速分析和响应。
-
应用场景:主要用于大数据领域的实时数据处理,如日志收集与分析、用户行为分析等。在一个社交网络平台的用户行为分析项目中,Kafka 可以收集用户的登录、点赞、评论等行为消息,然后将这些消息传输给后续的数据分析系统进行实时分析,以便平台能够及时了解用户的喜好和行为模式,从而进行精准的个性化推荐。在物联网领域,用于处理大量设备产生的实时数据,如在智能交通系统中,道路上的传感器收集车辆流量、速度等数据,Kafka 负责接收和传输这些数据,为交通流量分析和智能调控提供数据支持。