目录
主要角色
broker
- Broker面向producer和consumer接受和发送消息
- 向nameserver提交自己的信息
- 是消息中间件的消息存储、转发服务器。
- 每个Broker节点,在启动时,都会遍历NameServer列表,与每个NameServer建立长连接,注册自己的信息,之后定时上报。
broker集群
-
Broker高可用,可以配成Master/Slave结构,Master可写可读,Slave只可以读,Master将写入的数据同步给Slave。
- 一个Master可以对应多个Slave,但是一个Slave只能对应一个Master
- Master与Slave的对应关系通过指定相同的BrokerName,不同的BrokerId来定义BrokerId为0表示Master,非0表示Slave
-
Master多机负载,可以部署多个broker
- 每个Broker与nameserver集群中的所有节点建立长连接,定时注册Topic信息到所有nameserver。
producer
- 消息的生产者
- 通过集群中的其中一个节点(随机选择)建立长连接,获得Topic的路由信息,包括Topic下面有哪些Queue,这些Queue分布在哪些Broker上等
- 接下来向提供Topic服务的Master建立长连接,且定时向Master发送心跳
consumer
消息的消费者,通过NameServer集群获得Topic的路由信息,连接到对应的Broker上消费消息。
注意,由于Master和Slave都可以读取消息,因此Consumer会与Master和Slave都建立连接。
nameserver
底层由netty实现,提供了路由管理、服务注册、服务发现的功能,是一个无状态节点
nameserver是服务发现者,集群中各个角色(producer、broker、consumer等)都需要定时想nameserver上报自己的状态,以便互相发现彼此,超时不上报的话,nameserver会把它从列表中剔除
nameserver可以部署多个,当多个nameserver存在的时候,其他角色同时向他们上报信息,以保证高可用,
NameServer集群间互不通信,没有主备的概念
nameserver内存式存储,nameserver中的broker、topic等信息默认不会持久化
RocketMQ Hello World级别Demo
首先就是导包
<!-- rocketmq 因为我的服务器部署的是5.0.0的RocketMQ-client -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>5.0.0</version>
</dependency>
之后我们就建两个类,生产者,消费者
首先是生产者
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
public class Producer {
public static void main(String[] args) throws Exception {
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("llgp");
//设置发送的服务器地址和端口
defaultMQProducer.setNamesrvAddr("192.168.124.128:9876");
defaultMQProducer.start();
//第一个参数是发送的主题,第二个是消息体需要转换成字节
Message msg = new Message("mytopic","llgp".getBytes());
defaultMQProducer.send(msg);
}
}
此时我们可以进行测试,直接运行main方法,去可视化页面进行查看
刚刚创建的主题已经出现了
创建消费者
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import java.util.List;
public class Consumer {
public static void main(String[] args) throws Exception {
DefaultMQPushConsumer defaultMQPushConsumer = new DefaultMQPushConsumer("llcsm");
defaultMQPushConsumer.setNamesrvAddr("192.168.124.128:9876");
//订阅主题,一个消费者只能订阅一个主题
//第一个是主题,第二个参数是过滤条件
defaultMQPushConsumer.subscribe("mytopic","*");
//监听我们的队列,获取消息
defaultMQPushConsumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
for (MessageExt msg : list){
System.out.println(new String(msg.getBody()));
}
//一个消息只能被一个consumer消费
//通过返回状态,修改message的状态
//ack用来确认的
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
defaultMQPushConsumer.start();
}
}
运行消费者
此时我们重新运行我们的生产者,我们的这边消费者会持续打印
在控制台我们也能看到相应的消息
,此时还有一个问题就是我们生产者一直在运行没有关闭
public class Producer {
public static void main(String[] args) throws Exception {
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("llgp");
//设置发送的服务器地址和端口
defaultMQProducer.setNamesrvAddr("192.168.124.128:9876");
defaultMQProducer.start();
//第一个参数是发送的主题,第二个是消息体需要转换成字节
Message msg = new Message("mytopic","llgp".getBytes());
//同步消息发送,返回的消息是消费者那边return的
SendResult sendResult = defaultMQProducer.send(msg);
System.out.println(sendResult);
//停机
defaultMQProducer.shutdown();
}
}
在生产者关闭之后,我们在可视化页面也找不到生产者
以上就是RocketMQ入门级别的代码了,当然还有很多用法,比如TAG,SQL过滤种种还是需要自己的去摸索的了,我把一个简单的例子放在这里了,密码543r