零、定义:一个消息中间件,貌似是参考kafaka做的,是面向集群和大数据的
一、官网
- 由于已经是apache顶级项目了,直接前缀加apache.org,http://rocketmq.apache.org/
- 源码首页 https://github.com/apache/rocketmq/tree/master/docs/cn
二、部署
1、先看看这个quick start http://rocketmq.apache.org/docs/quick-start/
2、docker安装centos最新版,目前是8,参考,因为docker run 启动后没办法直接再修改端口,所以,我安装启动用的:docker run -it -p 9876:9876 -p 8080:8080 -p 10911:10911 centos /bin/bash
3、安装maven,并添加阿里源(参考https://www.cnblogs.com/gabin/p/13810848.html)
yum install maven
4、在/opt下载安装
4.1、下载:curl https://mirrors.tuna.tsinghua.edu.cn/apache/rocketmq/4.7.1/rocketmq-all-4.7.1-source-release.zip -o rocketmq.zip
4.2、没有zip的话,自己安装下:yum install zip
4.3、解压 unzip rocketmq.zip
4.4、进入目录 cd rocketmq-all-4.7.1-source-release
4.5、编译(没增加阿里云源的就看运气吧,哦对了还有网速,反正我执行了挺久,娃哈哈):mvn -Prelease-all -DskipTests clean install -U
4.6、进入编译好的文件目录:cd distribution/target
4.7、拷贝到/opt: cp -r rocketmq-4.7.1/* /opt/rocketmq
4.8、进入执行目录:cd /opt/rocketmq
4.9、后面直接参考 【三、启动】吧
三、启动
- nameserver:无状态的注册中心(注册中心结合微服务的Eureka理解,无状态是因为name server之间并不通信,也不保持同步)
-
nohup sh bin/mqnamesrv &
-
- broker:理解为微服务中的一个具体服务,可以有多个,多个broker连接nameserver就形成一个集群
-
# n代表name server的地址,9876是name server的默认端口 nohup sh bin/mqbroker -n localhost:9876 &
-
问题1:ps:broker启动失败,启动内存设置过大
vim /opt/rocketmq/bin/runbroker.sh
这行改一下:JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g -Xmn4g"
我是改成:JAVA_OPT="${JAVA_OPT} -server -Xms1g -Xmx1g -Xmn512m"
反正改到可以启动(改小值)
问题2:demo No route info of this topic
我用的是4.7.1的服务,然后客户端用4.7.0,4.7.1有问题
还有试一下这个:mqbroker -n localhost:9876 autoCreateTopicEnable=true
反正感觉坑还挺多的
示例参考 https://github.com/gabinlin/study/tree/master/rocketmq
四、安装监控系统
由于没有自带监控,需要自己下载一个扩展项目,监控后台部署:https://github.com/apache/rocketmq-externals,这下面的rocketmq-console,可以直接用spring-boot启动(application.properties修改下参数rocketmq.config.namesrv-addr=localhost:9876)
这边顺便补个安装到服务器上的步骤吧
1、先安装git:yum install git
2、下载源码(当然也可以直接下载文件,不一定要用git clone,说实话git clone还挺慢的。。。。但是好处就是有更新版本,可以直接更新后重新编译):git clone https://github.com/apache/rocketmq-externals
3、实在是慢,还是建议直接下源码文件吧。。。。
4、总算好了:cd rocketmq-externals/rocketmq-console
5、打包安装包:mvn package -Dmaven.test.skip=true
6、启动,cd target;:java -jar rocketmq-console-ng-2.0.0.jar --rocketmq.config.namesrv-addr=localhost:9876
7、好了访问本地8080端口,这个docker启动centos的时候已经映射好了
五、发送消息(Demo代码待补)
1、同步消息:简单来说就是A给Broker发送消息,需要同步收到Broker的回执
2、异步消息:简单来说就是A给Broker发送消息,可以异步收到Broker的回执(通过回调的方式),相当于n条消息发送完之后再来看发送的结果(这个描述并不严谨,但大致逻辑是这样的)
3、单向消息:简单来说就是A给Broker发送消息,不需要回执,不管收到没,反正我发了
4、事务消息:二阶段提交的一种做法,先举个例子:比如我去接我老婆下班,
场景1、
我:老婆,可以去接你了吗(发送一个HAFT Msg,待确认的消息)
老婆:可以,我今天不加班,可以准时下班(收到Broker的回复)
我:好的,那我出发了(收到回复之后执行本地方法)
我:老婆,我到了,你可以下来了(执行完本地方法后,给broker发送确认提交的消息)
老婆:那我下来了(broker获取到本地方法执行的结果后,执行不同的操作,这边是提交,下面再举个回滚的例子)
场景2、
我:老婆,可以去接你了吗(发送一个HAFT Msg,待确认的消息)
老婆:可以,我今天不加班,可以准时下班(收到Broker的回复)
我:好的,那我出发了(收到回复之后执行本地方法)
我:老婆,我这边领导临时安排任务过不去了(本地方法执行失败后,给broker发送回滚的消息)
老婆:那我自己打车回去(broker获取到本地方法执行的结果后,执行不同的操作,这边是回滚)
场景3、
我:老婆,可以去接你了吗(发送一个HAFT Msg,待确认的消息)
老婆:可以,我今天不加班,可以准时下班(收到Broker的回复)
我:好的,那我出发了(收到回复之后执行本地方法)
我:领导直接过来催任务了,没时间给老婆回信息(本地方法执行的结果一直没有发给broker)
老婆:打个电话问一下,怎么还没来,还没人接,等着跪搓衣板吧(事务消息的回查机制,查询本地事务的执行情况)
老婆:打了n次还没人接,算了我自己打车回家(多次查询不到结果,就放弃,这边其实也有可能得到的是:老婆,再等等,我也不确定什么时候可以下班,这种则属于消息回复状态中的UNKNOW状态)
场景4、
我:老婆,可以去接你了吗(发送一个HAFT Msg,待确认的消息)
老婆:可以,我今天不加班,可以准时下班(收到Broker的回复)
我:好的,那我出发了(收到回复之后执行本地方法)
我:领导直接过来催任务了,没时间给老婆回信息(本地方法执行的结果一直没有发给broker)
老婆:打个电话问一下,怎么还没来
我:来了来了,刚才领导临时有个事处理下,还好是个小问题,我三下五除二给解决了,我现在已经到你楼下了
老婆:那我下来了
六、对于事务消息的思考:
刚学用这个的时候我也很迷糊,这玩意咋用呀?
后面我突然想起来,以前系统里面用过一个东西。
就是比如我们支付成功,订单状态扭转,要给用户发送微信通知。这个时候,是有可能这个支付成功的代码提交失败的,那这个时候可能消息就发送出去了。咋办?
比较直接的做法就是注册个Commit事务的监听方法,在事务提交成功之后才发送消息,那又衍生另外一个问题:啊,万一我发送消息还没成功,服务器挂了怎么办
哈哈,我们之前的系统是不管消息发不发送成功的,因为觉得不重要,但这里要是个重要的事务性逻辑,那可不能这么干,所以呢,结合刚才的事务性消息的大致原理和流程,我们改进一下
我在本地方法开始执行前发送一个预提交的信息到broker,然后本地方法执行完成之后,给broker发送确认(如果失败,则做业务补偿方案:自动或人工都可以)。确认完我们干另外一件事情,如果此时broker一直收不到结果,那么会触发回查机制(这个就是一致性的重点了,回查机制确保这个消息最终会被发送出去,或者不需要发送就结束)。
这个流程其实像是TCC的一个流程,或者就是吧,不太确定。
反正经过这个改造,我们可以确认在订单确认支付成功之后才发送短信,而且也不会因为发送短信的时候服务器宕机而不再重新发送。
题外话:其实我们之前是直接存储一个本地事件表,如果提交成功,本地事件表就会有一条记录,根据这条记录继续操作发送微信通知,哈哈。就是需要另外扩展一个本地事件表的机制,还有就是实时性比不上监听的模式
暂时还有docker无法访问内部IP的问题,等有时间了解下,再弄