RocketMQ-消息队列
消息队列概述
消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。目前使用较多的消息队列有ActiveMQ
,RabbitMQ
,ZeroMQ
,Kafka
,MetaMQ
,RocketMQ
核心概念
- Topic:消息主题,一级消息类型,生产者向其发送消息。
- 生产者:也称为消息发布者,负责生产并发送消息至Topic。
- 消费者:也称为消息订阅者,负责从Topic接收并消费消息。
- 消息:生产者向Topic发送并最终传送给消费者的数据和(可选)属性的组合。
- 消息属性:生产者可以为消息定义的属性,包含Message Key和Tag。
- Group:一类生产者或消费者,这类生产者或消费者通常生产或消费同一类消息,且消息发布或订阅的逻辑一致。
应用场景
消息队列作为高并发系统的核心组件之一,能够帮助业务系统解构提升开发效率和系统稳定性。主要具有以下优势:
-
削峰填谷(主要解决瞬时写压力大于应用服务能力导致消息丢失、系统奔溃等问题)
诸如秒杀、抢红包、企业开门红等大型活动时皆会带来较高的流量脉冲,或因没做相应的保护而导致系统超负荷甚至崩溃,或因限制太过导致请求大量失败而影响用户体验,消息队列
RocketMQ
版可提供削峰填谷的服务来解决该问题。 -
异步解耦(解决不同重要程度、不同能力级别系统之间依赖导致一死全死)
交易系统作为淘宝和天猫主站最核心的系统,每笔交易订单数据的产生会引起几百个下游业务系统的关注,包括物流、购物车、积分、流计算分析等等,整体业务系统庞大而且复杂,消息队列
RocketMQ
版可实现异步通信和应用解耦,确保主站业务的连续性。 -
提升性能(当存在一对多调用时,可以发一条消息给消息系统,让消息系统通知相关系统)
-
蓄流压测(线上有些链路不好压测,可以通过堆积一定量消息再放开来压测)
适用场景
消息队列RocketMQ
版作为分布式系统中的重要组件,可用于应对这些挑战,例如解决应用的异步解耦。
异步解耦
传统处理
最常见的一个场景是用户注册后,需要发送注册邮件和短信通知,以告知用户注册成功。传统的做法有以下两种:
-
串行方式
串行方式下的注册流程如下图所示。
-
数据流动如下所述:
- 您在注册页面填写账号和密码并提交注册信息,这些注册信息首先会被写入数据库。
- 注册信息写入数据库成功后,再发送请求至邮件注册。邮件注册收到请求后向用户发送邮件通知。
- 注册邮件接收注册请求后再向下游的短信注册发送请求。短信注册收到请求后向用户发送短信通知。
以上三个任务全部完成后,才返回注册结果到客户端,用户才能使用账号登录。
假设每个任务耗时分别为50 ms,则用户需要在注册页面等待总共150 ms才能登录。
-
并行方式
并行方式下的注册流程如下图所示。
数据流动如下所述:
- 用户在注册页面填写账号和密码并提交注册信息,这些注册信息首先会被写入数据库。
- 注册信息写入数据库成功后,再同时发送请求至邮件注册和短信注册。邮件和短信注册收到请求后分别向用户发送邮件和短信通知。
以上两个任务全部完成后,才返回注册结果到客户端,用户才能使用账号登录。
假设每个任务耗时分别为50 ms,其中,邮件和短信通知并行完成,则用户需要在注册页面等待总共100 ms才能登录。
以下就注册场景中使用了消息队列RocketMQ
版的效果进行说明。
异步解耦
对于用户来说,注册功能实际只需要注册系统存储用户的账户信息后,该用户便可以登录,后续的注册短信和邮件不是即时需要关注的步骤。
对于注册系统而言,发送注册成功的短信和邮件通知并不一定要绑定在一起同步完成,所以实际当数据写入注册系统后,注册系统就可以把其他的操作放入对应的消息队列RocketMQ
版中然后马上返回用户结果,由消息队列RocketMQ
版异步地进行这些操作。
数据流动如下所述:
- 用户在注册页面填写账号和密码并提交注册信息,这些注册信息首先会被写入数据库。
- 注册信息写入数据库成功后,再发送消息至消息队列。消息队列会马上返回响应给注册系统,注册完成。用户可立即登录。
- 下游的邮件和短信注册订阅消息队列的此类注册请求消息,即可向用户发送邮件和短信通知,完成所有的注册流程。
用户只需在注册页面等待注册数据写入注册系统和消息队列RocketMQ
版的时间,即等待55 ms即可登录。
异步解耦是消息队列RocketMQ
版的主要特点,主要目的是减少请求响应时间和解耦。主要的适用场景就是将比较耗时而且不需要即时(同步)返回结果的操作作为消息放入消息队列。同时,由于使用了消息队列RocketMQ
版,只要保证消息格式不变,消息的发送方和接收方并不需要彼此联系,也不需要受对方的影响,即解耦。
削峰填谷
流量削峰也是消息队列RocketMQ版的常用场景,一般在秒杀或团队抢购活动中使用广泛。
在秒杀或团队抢购活动中,由于用户请求量较大,导致流量暴增,秒杀的应用在处理如此大量的访问流量后,下游的通知系统无法承载海量的调用量,甚至会导致系统崩溃等问题而发生漏通知的情况。为解决这些问题,可在应用和下游通知系统之间加入消息队列RocketMQ
版。
秒杀处理流程如下所述:
- 用户发起海量秒杀请求到秒杀业务处理系统。
- 秒杀处理系统按照秒杀处理逻辑将满足秒杀条件的请求发送至消息队列。
- 假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面。
- 用户收到秒杀成功的通知。
Linux 安装和部署RocketMQ
Linux 配置环境:
JDK: jdk-8u271-linux-x64.tar.gz
RocketMQ: rocketmq-all-4.7.1-bin-release
RocketMQ控制台: rocketmq-externals
安装RocketMQ
-
传入 Linux 服务器
-
解压 rocketmq-all-4.7.1-bin-release
unzip rocketmq-all-4.7.1-bin-release.zip
注意:解压文件的时候说没有zip的命令
安装命令: yum install zip #提示输入时,请输入y;
安装命令:yum install unzip #提示输入时,请输入y; -
配置 jvm 参数
cd bin vim runserver.sh
cd bin vim runbroker.sh
-
启动 NameServer
在bin目录下启动
启动之前需要编辑配置文件,修改 JVM 内存设置,默认给的内存 4 GB,超过我们的 JVM 了。
上面已经修改过了
#打印日志启动 ./mqnamesrv #后台启动 nohup ./mqnamesrv &
-
检查是否启动成功
netstat -an | grep 9876
-
启动 Broker
在bin目录下启动
nohup ./mqbroker -n [虚拟机端口/服务端口]:9876 &
-
查看结果
netstat -nlet
-
测试 RocketMQ
消息发送
在 bin 目录下进行操作
export NAMESRV_ADDR=localhost:9876 ./tools.sh org.apache.rocketmq.example.quickstart.Producer
消息接收
在 bin 目录下进行操作
export NAMESRV_ADDR=localhost:9876 ./tools.sh org.apache.rocketmq.example.quickstart.Consumer
-
关闭 RocketMQ
在 bin 目录下进行操作
./mqshutdown broker ./mqshutdown namesrv
安装 RocketMQ 控制台
-
解压缩包
-
进入rocketmq-externals-rocketmq-console-1.0.0\rocketmq-externals-rocketmq-console-1.0.0\rocketmq-console\src\main\resources 目录修改 application.properties 配置
-
打包项目
#查看是否配置maven mvn -v
配置环境变量
配置成功
打包项目
mvn clean package -Dmaven.test.skip=true
-
进入 target 启动 jar
java -jar rocketmq-console-ng-1.0.0.jar
打开浏览器访问 localhost:9898,如果报错
这是因为我们的 RocketMQ 安装在 Linux 中,控制台在 windows,Linux 需要开放端口才能访问,开放 10909 和 9876 端口
#放行 firewall-cmd --zone=public --add-port=10909/tcp --permanent firewall-cmd --zone=public --add-port=9876/tcp --permanent firewall-cmd --zone=public --add-port=10911/tcp --permanent #重启 systemctl restart firewalld.service firewall-cmd --reload
成功运行
Java 实现消息发送
-
在 provider 提供者 导入依赖
<!-- Spring Boot Rocketmq --> <dependency> <groupId>org.apache.rocketmq</groupId> <artif