rocketmq是一个轻量级,低延时,高可用,支持亿级消息处理的消息中间件。rocketmq使用起来方便简单,具备传统的消息中间件所不具备的特性,例如低延迟,高负载,事物消息等特性,受到越来越多的开发者喜爱。
这里引用 apache rocketmq官网的图
1.NameServer
NameServer 提供轻量级的服务发现和路由,支持主从。
生产者和消费者从Name Server获取对应的读,写服务。
2.broker Server
broker server 提供轻量级的TOPIC-queue的形式实现消息的存贮。消息支持push 和pull的模式。
3.producer
消息生产者,producer有个很重要的属性叫producer group ,一般一个业务一个group,大多数情况下一个生产者实例就已经足够了,如果想提高系统吞吐率,可以在group相同的前提下,设置instantName,这样同一个group可以拥有多个实例。
消息的发送支持同步,异步。消息种类在简单的消息的基础上,还支持顺序消息,事物消息。
4.consumer
消息消费者,消费者也有个重要的属性叫group,Cosumer里面可以设置消费线程池的大小。
producer
package com.ly.mq.producer;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import java.util.List;
@Data
@AllArgsConstructor
public class Producer {
private final String namesrvAddr;
private DefaultMQProducer producer;
public void syncProducer(String msg) throws Exception {
//消息创建需要指定topic ,topic底层可和一个或多个队列进行绑定,在topic下,还有tag 相当于一个子topic
Message message =
new Message("topic_test","TagA"
,msg.getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult result = producer.send(message);
System.out.println(result.toString());
//producer.shutdown();
}
public void asyncProducer(String msg) throws Exception {
Message message =
new Message("topic_test","TagA"
,msg.getBytes(RemotingHelper.DEFAULT_CHARSET));
producer.send(message, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.printf("OK %s %s", msg,
sendResult.getMsgId());
}
@Override
public void onException(Throwable e) {
}
});
//producer.shutdown();
}
public Producer(String namesrvAddr) throws Exception {
this.namesrvAddr = namesrvAddr;
producer =
new DefaultMQProducer("rocketmq_test");
producer.setNamesrvAddr(namesrvAddr);
//producer.
producer.start();
}
public void orderProducer() throws Exception {
for (int i = 0; i < 100; i++) {
int orderId = i % 10;
Message message =
new Message("topic_test", "TagA"
, ("hello ordered message,i:" + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult result = producer.send(message, new MessageQueueSelector() {
@Override
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
Integer id = (Integer) arg;
int index = id % mqs.size();
System.out.printf("id:%d,msqs's size:%d,index:%d", id, mqs.size(),index);
System.out.println();
return mqs.get(index);
}
}, orderId);
System.out.println(result);
//producer.shutdown();
}
}
public static void main(String[] args) throws Exception {
String namesrvAddr = "192.168.48.138:9876";
Producer producer = new Producer(namesrvAddr);
producer.orderProducer();
/*for(int i = 0;i<10;i++){
producer.syncProducer("hello rocketmq,"+i);
producer.asyncProducer("hello rocketmq,"+i);
}*/
}
}
consumer
package com.ly.mq.consumer;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.*;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import java.io.UnsupportedEncodingException;
import java.util.List;
@Data
@AllArgsConstructor
public class Consumer {
private final String namesrvAddr;
public void consumer() throws Exception {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer_test_group_1");
consumer.setNamesrvAddr(namesrvAddr);
//tag支持 || 分割订阅多个tag,或者以*为通配符
consumer.subscribe("topic_test","*");
//consumer.setConsumeThreadMin();
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
MessageExt ext = msgs.get(0);
try {
String content = new String(ext.getBody(), RemotingHelper.DEFAULT_CHARSET);
System.out.println(String.format("msgid:%s,msgcontent:%s",ext.getMsgId(),content));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
Thread.sleep(600000);
}
public void consumerOrderly() throws Exception {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer_test_group_1");
consumer.setNamesrvAddr(namesrvAddr);
consumer.subscribe("topic_test","TagA");
//consumer.setConsumeThreadMin();
consumer.registerMessageListener(new MessageListenerOrderly() {
@Override
public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
MessageExt messageExt = msgs.get(0);
try {
String content = new String(messageExt.getBody(),RemotingHelper.DEFAULT_CHARSET);
System.out.println("thread -number:"+Thread.currentThread().getId()+","
+"msgId:"+messageExt.getMsgId()+",content:"+content+",queueId:"+context.getMessageQueue().getQueueId());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return ConsumeOrderlyStatus.SUCCESS;
}
});
consumer.start();
Thread.sleep(600000);
}
public static void main(String[] args) throws Exception {
String namesrvAddr = "192.168.48.138:9876";
Consumer consumer = new Consumer(namesrvAddr);
//consumer.consumer();
consumer.consumerOrderly();
}
}
rocketmq只支持topic 模式,相对于rabbitmq来说,消息路由的种类会少点,但是topic模式已经支持大多数的使用场景了,而且我们不必关注了队列的绑定,一般一个group一个生产者实例就已经足够了,多个消费者订阅同一个topic,在默认的消费模式下,MessageModel.CLUSTERING多消费者,只会有一个消费者能消费到该消息,可以改成 MessageModel.BROADCASTING ,这样每个消费者都能消费了。