2.11日学习打卡
一. RocketMQ整合springboot
首先配置pom.xml文件
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>annotationProcessor</scope></dependency><dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>2.2.3</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency>
其次在配置application.yml文件
spring:application:name: RocketMqrocketmq:name-server: 192.168.66.100:9876(自己的地址监听9876端口)producer:group: my-group
编写测试类
生产者
package com.jjy.rocketmq;import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;//@RunWith(SpringRunner.class)
//@SpringBootTest(classes = {RocketMqApplication.class})
@SpringBootTest
class RocketMqApplicationTests {@Autowiredprivate RocketMQTemplate rocketMQTemplate;@Testvoid testSendMessage() {//向broker发送消息//第一个参数是主题(当时自己创建的主题)//第二个参数是消息内容rocketMQTemplate.convertAndSend("topicWarning","hello,RocketMQ");}}
消费者(新建一个springboot项目)
pom.xml文件同producer工程
application.yml配置
spring:application:name: RocketMQConsumer(自己的项目名字)rocketmq:name-server: 192.168.66.100:9876
消息监听器
package com.jjy.rocketmqconumers.consumer;import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;@Slf4j
@Component
@RocketMQMessageListener(topic="topicWarning",consumerGroup="myconsumer")
//consumerGroup(里面的参数随便写就行自己编个名字)
public class Consumer implements RocketMQListener<String> {@Overridepublic void onMessage(String message) {//使用日志的形式写出来 也开始使用控制台log.info("Received messsge:" + message);//使用控制台System.out.println(message);}
}
二. RocketMQ架构
技术架构
RocketMQ架构上主要分为四部分,如上图所示:
- Producer:消息发布的角色,支持分布式集群方式部署。
- Consumer:消息消费的角色,支持分布式集群方式部署。支持以push推,pull拉两种模式消费消息。
- NameServer:管理Broker代理服务器。
- BrokerServer:RocketMQ的核心,负责消息的接收和转发。
部署架构
RocketMQ 网络部署特点:
- NameServer是一个几乎无状态节点,可集群部署,节点之间无
任何信息同步。 - Broker部署相对复杂,Broker分为Master与Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master,Master与Slave 的对应关系通过指定相同的BrokerName,不同的BrokerId 来定义,BrokerId为0表示Master,非0表示Slave。Master也可以部署多个。每个Broker与NameServer集群中的所有节点建立长连接,定时注册Topic信息到所有NameServer。
- Producer与NameServer集群中的其中一个节点(随机选择)建立长连接,定期从NameServer获取Topic路由信息,并向提供Topic 服务的Master建立长连接,且定时向Master发送心跳。Producer完全无状态,可集群部署。
- Consumer与NameServer集群中的其中一个节点(随机选择)建立长连接,定期从NameServer获取Topic路由信息,并向提供Topic服务的Master、Slave建立长连接,且定时向Master、Slave发送心跳。Consumer既可以从Master订阅消息,也可以从Slave订阅消息。
- 结合部署架构图,集群工作流程可作如下描述:
- 启动NameServer,通过监听端口,等待Broker、Producer、Consumer连上来,相当于一个路由控制中心。
- Broker启动,跟所有的NameServer保持长连接,定时发送心跳包。心跳包中包含当前Broker信息(IP+端口等)以及存储所有Topic信息。注册成功后,NameServer集群中就有Topic跟Broker的映射关系。
- 收发消息前,先创建Topic,创建Topic时需要指定该Topic要存储在哪些Broker上,也可以在发送消息时自动创建Topic。
- Producer发送消息,启动时先跟NameServer集群中的其中一台建立长连接,并从NameServer中获取当前发送的Topic存在哪些Broker上,包含Topic中所有队列列表然后选择一个队列,与队列所在的Broker建立长连接再向Broker发消息。
- Consumer跟Producer类似,跟其中一台NameServer建立长连接,获取当前订阅Topic存在哪些Broker上,然后直接跟Broker建立连接通道,开始消费消息。
三.RocketMQ高级特性
消息存储
- 存储介质
- 关系型数据库
ActiveMQ(默认采用的KahaDB做消息存储)可选用JDBC的方式来做消息持久化,通过简单的xml配置信息即可实现JDBC消息存储。由于,普通关系型数据库(如Mysql)在单表数据量达到千万级别的情况下,其IO读写性能往往会出现瓶颈。在可靠性方面,该种方案非常依赖DB,如果一旦DB出现故障,则MQ的消息就无法落盘存储会导致线上故障。 - 文件
目前业界较为常用的几款产品(RocketMQ/Kafka/RabbitMQ)均采用的是消息刷盘至所部署虚拟机/物理机的文件系统来做持久化(刷盘一般可以分为异步刷盘和同步刷盘两种模式)。消息刷盘为消息存储提供了一种高效率、高可靠性和高性能的数据持久化方式。除非部署MQ机器本身或是本地磁盘损坏,否则一般是不会出现无法持久化的故障问题
同步的可靠性高 异步的效率高
同步:就是假如你是老板让员工区送邮件在员工送完邮件向你报告的期间一直属于等待状态;
异步: 在等待报告期间回去做其他事情 - 性能对比
文件系统 > 关系型数据库DB
- 关系型数据库
负载均衡
RocketMQ中的负载均衡都在Client端完成,具体来说的话,主要可以分为Producer端发送消息时候的负载均衡和Consumer端订阅消息的负载均衡
Producer的负载均衡
如图所示,5 个队列可以部署在一台机器上,也可以分别部署在 5 台不同的机器上,发送消息通过轮询队列的方式 发送,x每个队列接收平均的消息量。通过增加机器,可以水平扩展队列容量。 另外也可以自定义方式选择发往哪个队列。
Consumer的负载均衡
如图所示,如果有 5 个队列,2 个 consumer,那么第一个Consumer 消费 3 个队列,第二consumer 消费 2 个队列。 这样即可达到平均消费的目的,可以水平扩展 Consumer 来提高消费能力。但是 Consumer 数量要小于等于队列数 量,如果 Consumer超过队列数量,那么多余的Consumer 将不能消费消息 。
事务消息
Apache RocketMQ在4.3.0版中已经支持分布式事务消息,这里RocketMQ采用了2PC的思想来实现了提交事务消息,同时增加一个补偿逻辑来处理二阶段超时或者失败的消息,如下图所示。
事务消息发送步骤如下:
-
生产者将半事务消息发送至消息队列RocketMQ服务端。
-
消息队列RocketMQ服务端将消息持久化成功之后,向生产者返回Ack确认消息已经发送成功,此时消息为半事务消息。
-
生产者开始执行本地事务逻辑。
-
生产者根据本地事务执行结果向服务端提交二次确认结果(Commit或是Rollback),服务端收到确认结果后处理逻辑如下:
- 二次确认结果为Commit:服务端将半事务消息标记为可投递,并投递给消费者。
- 二次确认结果为Rollback:服务端不会将该消息投递给消费者,并按照如下逻辑进行回查处理。
-
事务消息回查步骤如下:
- 在断网或者是生产者应用重启的特殊情况下,上述步骤4提交的二次确认最终未到达服务端,经过固定时间后,服务端将对消息生产者即生产者集群中任一生产者实例发起消息回查。
- 生产者收到消息回查后,需要检查对应消息的本地事务执行的最终结果。
- 生产者根据检查得到的本地事务的最终状态再次提交二次确认,服务端仍按照步骤4对半事务消息进行处理。
顺序消息
消息有序指的是按照消息的发送顺序来消费(FIFO)。RocketMQ可以保证消息有序,消息有序分为部分有序和全局有序。全局有序是指某个Topic下的所有消息都要保证顺序;部分顺序消息只要保证每一组消息被顺序消费即可。
如果要实现全局顺序消息,那么只能使用一个队列,一个生产者,这会严重影响性能。
因此,我们常说的顺序消息通常指部分顺序消息。
顺序消费的原理解析,在默认的情况下消息发送会采取轮询方式把消息发送到不同的分区队列;而消费消息的时候从多个queue上拉取消息,这种情况发送和消费是不能保证顺序。但是如果控制发送的顺序消息只依次发送到同一个queue中,消费的时候只从这个queue上依次拉取,则就保证了顺序。当发送和消费参与的queue
只有一个,则是全局有序;如果多个queue参与,则为分区有序,即相对每queue,消息都是有序的。