RocketMQ是消息中间件之一,要谈什么是RocketMQ,就需要先明确什么是消息中间件,消息中间件的存在是为了解决什么样的问题?
同样无需照本宣科,消息中间件就是在同一程序或不同程序间进行同步或者异步消息传递的第三方组建。那么消息中间件解决了什么样的问题,亦或者应用场景是什么?最出名的就是处理高并发场景下的流量削峰平谷。
举一个比较浅显的例子,大批量订单打入系统,系统是需要对应生成物流信息的,但是如果这两件事放到一起做,就会在同一时间内占用很多资源去做物流信息生成这件事,但这件事本身对于订单来说是无关紧要的。因此就可以通过消息中间件,订单成功生成后,向消息中间件发送消息,告知订单生成成功,需生成物流信息,这样,生成订单的线程就可以直接结束掉。至于物流信息,则是根据相应的监听策略,监听到消息再写入,延时消费,批量消费,都可以起到资源合理分配的作用。
此外,消息中间件还支持跨平台的数据信息传递,数据的分发和异步处理,分布式事务等。
回到RocketMQ,RocketMQ是消息中间件之一,市面上常见的消息中间件是3Q1K,分别是ActiveMQ,RabbitMQ,RocketMQ,Kafka。其中,RocketMQ由阿里孕育,具体对比可参考RocketMQ官网文档首页提供表格https://rocketmq.apache.org/docs/4.x/
RocketMQ基本消息发送接收
上文介绍RocketMQ的主要应用场景,关于RocketMQ的安装下载,互联网有很多资源,此处就不多做赘述。而关于RocketMQ的使用,主要推荐两处文档rocket官网中文文档,以及gitee中文使用指南,这两处资料都详实细致,笔者在此处就不多画蛇添足。
这里继续介绍的是笔者基于上述基础使用文档以及公司实际业务场景所搭建的一个简易的消息收发框架。先介绍业务场景,现有项目是一个共享HR类项目,涉及多系统协同及多目录报表文档,现就有一实际需求,当三方平台向共享中心发单时,该单除了正常在共享中心生成一张工单随流程引擎正常派单外,还需写入对应台账报表中。例如,工单A是一张当月工资核算的工单,则需要写入工资核算台账,工单B是一张员工删减工单,则需要写入员工删减台账,当然这只是简化说法,实际上这里真对各个字段都有较为复杂的取值逻辑。
在上述业务场景下,当时的解决方案是工单创建时就写入相应台账,放到一次调用一个线程中去做这件事,在前期业务量小且各台账取值逻辑不复杂的情况下,并未出现较大问题,但随着功能上线及后续逻辑完善,三方平台工单创建接口访问压力及响应压力就大了很多。因此笔者在此处提出一个优化假象,工单发起与生成台账之间的关系,和上文所述生成订单与生成物流信息,本身不存在强关联性,可以将之拆分为两件事来做。
工单成功发起之后,发送消息通知之后需要干什么,消费者监听到消息,分配到对应的实现类消费消息,也就是写入对应台账,且消息异步发送,这样一来,两部分代码解藕,各做各事,提高三方平台工单发起接口的响应效率。
由此笔者抽取出一个简单的消息发送与接收的模型,从使用层面来讲,只需要构建消息实体,配置发送模式与选定生产者,给定消息tag,发送消息即可;消费者在程序启动时,选定监听规则,启动监听组,监听既定的tag标签,拿到生产者发送的消息并消费。
从程序实现来讲,需要做如下考量
值得一提的是,我司已构建RocketMQ和Kafka的使用框架,创建全局唯一的生产者组也是由此得来的灵感与经验,但个人学习不能因为有就可以不用学了,因此手搓一个发送与接收的建议框架,且与之不同的是提供多规则发送与接收消息的实现类入口,并在应用的全生命周期中对外暴露生产者的关闭方法(可开启并使用临时生产者,虽然可能没啥用)。
简易收发框架代码
整个建议框架结构如图所示,包括常量枚举,消费者,生产者,工具类,以及消息实体。
动作枚举:消息接收到后究竟需要做什么事情,以及做事情的枚举类
消费者消费行为枚举:各消费行为及实现类。
生产者枚举:各消息发送方
生产者生产行为枚举:各生产行为及实现类
消费动作实现类:消费方接收到消息后的具体行为实现类
消费动作实现类:消费方接收到消息后的具体行为抽象类
消费者消费行为抽象类:
推送且广播消费模式:
消费者管理:系统启动时创建消费监听,建议根据不同tag并行消费
生产者消息发送行为抽象类:
异步发送:
单向发送:
同步发送:
生产者抽象类:
生产者实现类:
生产者管理:根据传入key判定全局有无待机生产者,若有则直接使用,若无则新建一个。这部分源码及思路参考了我司rocketmq-manager包。
配置文件工具类:
全局基础消息:所有消息都是基于该消息类创建,固定全局唯一topic
业务消息实体:传入需传入消息内容即可,serviceKind即为相应所需动作。
无关紧要的配置文件vo:
测试使用
在系统启动时就启动消费者监听,此处启动推送及广播消费者监听:
ConsumerManager.createConsumer(ConsumerEnum.CONSUMPTION_MESSAGE.getListener());
会自动根据生产者枚举,创建相应的监听,形成监听组:
发送消息,这里三个枚举类配置的分别是,接收到消息后的具体行为,发送消息的生产者(对应消费者监听的tag),消息发送模式,为异步发送
LedgerMessageVo ledgerMessageVo = new LedgerMessageVo();
ledgerMessageVo.setServiceKind(BaseServicesEnum.LEDGER_EVALUATION_BILL_FORM.getServicesKind());
ledgerMessageVo.setPackageName("aca");
List<Message> messageVos = new ArrayList<>();
messageVos.add(new BaseMessageVo(ProduceEnum.SERVICE_REQUEST_PRODUCE.getProduceCode(), ledgerMessageVo).baseMessageVo());
ProduceService produceService = new ProduceServiceImpl();
produceService.sent(messageVos,"BASE_SERVICE", ProducerEnum.ASYNCHRONOUS_TRANSMISSION.getMessageBehavior(),messageVos.size());
在mq控制台查看已经发送成功
消息已成功消费