接下来将花费大概五分钟的时间来熟悉RocketMQ中比较重要的角色:生产者
- 消息类型:普通消息(并发消息)、顺序消息、事务消息
- 消息发送方式:同步发送、异步发送、单向发送
角色概括
在RocketMQ中,生产者是发送消息的一方。
-
生产者组:由一个及多个生产者实例组成,在使用时指定同一个组名,一个生产者组可以生产多个Topic的消息。
-
生产者实例:一个生产者组中的进程实例。
-
Topic:消息主题,一个Topic由一个或多个Queue组成。
生产者类
-
org.apache.rocketmq.client.producer.TransactionMQProducer :用于发送事务消息
-
org.apache.rocketmq.client.producer.DefaultMQProducer: 用于发送普通消息、顺序消息、批量消息等
消息结构
org.apache.rocketmq.common.message.Message
public class Message implements Serializable {
private static final long serialVersionUID = 8445773977080406428L;
private String topic;
private int flag;
private Map<String, String> properties;
private byte[] body;
private String transactionId;
- topic :消息主题
- flag :消息的标记,不做任何处理
- properties:存储tags、keys、延迟级别等属性
public void setTags(String tags) {
this.putProperty("TAGS", tags);
}
public void setKeys(String keys) {
this.putProperty("KEYS", keys);
}
public void setDelayTimeLevel(int level) {
this.putProperty("DELAY", String.valueOf(level));
}
- body:消息内容,字节数组,注意编解码格式。
- transactionId:事务Id
消息类型
RocketMQ支持普通(并发)消息、分区有序消息、事务消息、延迟消息。
- 普通消息:普通消息没有发送消费顺序,因此性能可达十万TPS。
- 分区有序消息:Topic中分多个分区对消息进行保存消费,在同一个分区的消息遵循FIFO原则。
- 事务消息:RocketMQ通过发送Half消息、处理本地事务、提交或回滚消息来实现分布式事务,参与的对象只有生产端,消费端失败会导致分布式事务失效。
- 延迟消息:可通过设置定时或者延迟多长时间消费消息。
示例
同步发送消息
不额外创建线程,阻塞调用,直到返回消息发送的结果
package mq.producer;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;
import java.io.UnsupportedEncodingException;
public class SyncProducer {
/**
* 同步消息发送
*
* @param args
* @throws MQClientException
* @throws MQBrokerException
* @throws RemotingException
* @throws InterruptedException
* @throws UnsupportedEncodingException
*/
public static void main(String[] args) throws MQClientException, MQBrokerException, RemotingException, InterruptedException, UnsupportedEncodingException {
System.out.println("SyncProducer start......");
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("pg_sync_01");
defaultMQProducer.setNamesrvAddr("localhost:9876");
defaultMQProducer.start();
SendResult sendResult = defaultMQProducer.send(new Message("message_sync_01",
"hello this is sync message!".getBytes(RemotingHelper.DEFAULT_CHARSET)));
System.out.println(sendResult);
defaultMQProducer.shutdown();
System.out.println("SyncProducer end......");
}
}
异步发送消息
额外创建线程,不阻塞,可通过回调方法处理消息发送的结果
package mq.producer;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
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.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;
import java.io.UnsupportedEncodingException;
public class AsyncProducer {
/**
* 异步消息发送
*
* @param args
* @throws MQClientException
* @throws MQBrokerException
* @throws RemotingException
* @throws InterruptedException
* @throws UnsupportedEncodingException
*/
public static void main(String[] args) throws MQClientException, MQBrokerException, RemotingException, InterruptedException, UnsupportedEncodingException {
System.out.println("AsyncProducer start......");
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("pg_async_01");
defaultMQProducer.setNamesrvAddr("localhost:9876");
defaultMQProducer.start();
defaultMQProducer.send(new Message("message_async_01",
"hello this is async message!".getBytes(RemotingHelper.DEFAULT_CHARSET)), new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.println("success " + sendResult);
}
@Override
public void onException(Throwable throwable) {
System.out.println("error " + throwable);
}
});
System.out.println("AsyncProducer end......");
}
}
分区有序消息
package mq.producer;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
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 org.apache.rocketmq.remoting.exception.RemotingException;
import java.io.UnsupportedEncodingException;
import java.util.List;
public class OrderProducer {
/**
* 分区有序消息发送
*
* @param args
* @throws MQClientException
* @throws MQBrokerException
* @throws RemotingException
* @throws InterruptedException
* @throws UnsupportedEncodingException
*/
public static void main(String[] args) throws MQClientException, MQBrokerException, RemotingException, InterruptedException, UnsupportedEncodingException {
System.out.println("OrderProducer start......");
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("pg_order_01");
defaultMQProducer.setNamesrvAddr("localhost:9876");
defaultMQProducer.start();
//根据arg来指定相同的分区
Integer arg = 313;
Message message = new Message("message_order_01",
"hello this is async message!".getBytes(RemotingHelper.DEFAULT_CHARSET));
defaultMQProducer.send(message, new MessageQueueSelector() {
@Override
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
Integer id = (Integer) arg;
int index = id % mqs.size();
return mqs.get(index);
}
}, arg);
System.out.println("OrderProducer end......");
}
}
单向消息发送
额外创建线程,不阻塞,不关注消息发送的结果
package mq.producer;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
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.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;
import java.io.UnsupportedEncodingException;
public class OnewayProducer {
/**
* 单向消息发送
*
* @param args
* @throws MQClientException
* @throws MQBrokerException
* @throws RemotingException
* @throws InterruptedException
* @throws UnsupportedEncodingException
*/
public static void main(String[] args) throws MQClientException, MQBrokerException, RemotingException, InterruptedException, UnsupportedEncodingException {
System.out.println("OnewayProducer start......");
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("pg_oneway_01");
defaultMQProducer.setNamesrvAddr("localhost:9876");
defaultMQProducer.start();
defaultMQProducer.sendOneway(new Message("message_oneway_01",
"hello this is oneway message!".getBytes(RemotingHelper.DEFAULT_CHARSET)));
System.out.println("OnewayProducer end......");
defaultMQProducer.shutdown();
}
}
发送延迟消息
可通过设置Message的DelayTimeLevel来指定消息消费的延迟级别
延迟级别从1开始对应1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
package mq.producer;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;
import java.io.UnsupportedEncodingException;
public class DelayProducer {
/**
* 延迟消息发送
*
* @param args
* @throws MQClientException
* @throws MQBrokerException
* @throws RemotingException
* @throws InterruptedException
* @throws UnsupportedEncodingException
*/
public static void main(String[] args) throws MQClientException, MQBrokerException, RemotingException, InterruptedException, UnsupportedEncodingException {
System.out.println("DelayProducer start......");
DefaultMQProducer defaultMQProducer = new DefaultMQProducer("pg_delay_01");
defaultMQProducer.setNamesrvAddr("localhost:9876");
defaultMQProducer.start();
Message message = new Message("message_delay_01",
"hello this is delay message!".getBytes(RemotingHelper.DEFAULT_CHARSET));
message.setDelayTimeLevel(3);
SendResult sendResult = defaultMQProducer.send(message);
System.out.println(sendResult);
System.out.println("DelayProducer end......");
defaultMQProducer.shutdown();
}
}
事务消息
- 发送Half消息到Broker,Broker将其queueOffset设置为0,消费者对这条消息不可见。
- 本地事务执行成功,发送COMMIT消息到Broker,Broker将queueOffset设置为正常值,此时消费者可以正常消费
- 处理失败则发送ROLLBACK给Broker,Broker将Half消息删除。
package mq.producer;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.*;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class TransactionProducer {
/**
* 事务消息发送
*
* @param args
* @throws MQClientException
* @throws MQBrokerException
* @throws RemotingException
* @throws InterruptedException
* @throws UnsupportedEncodingException
*/
public static void main(String[] args) throws MQClientException, MQBrokerException, RemotingException, InterruptedException, UnsupportedEncodingException {
System.out.println("TransactionProducer start......");
TransactionMQProducer transactionProducer = new TransactionMQProducer("pg_transaction_01");
TransactionListener transactionListener = new TransactionListener() {
private AtomicInteger transactionIndex = new AtomicInteger(0);
private ConcurrentHashMap<String, Integer> localTrans = new ConcurrentHashMap<>();
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
int value = transactionIndex.getAndIncrement();
int status = value % 3;
localTrans.put(msg.getTransactionId(), status);
return LocalTransactionState.UNKNOW;
}
@Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
Integer status = localTrans.get(msg.getTransactionId());
if (status == null) return LocalTransactionState.COMMIT_MESSAGE;
switch (status) {
case 0:
return LocalTransactionState.UNKNOW;
case 1:
return LocalTransactionState.COMMIT_MESSAGE;
case 2:
return LocalTransactionState.ROLLBACK_MESSAGE;
}
return LocalTransactionState.COMMIT_MESSAGE;
}
};
transactionProducer.setTransactionListener(transactionListener);
//线程池
ExecutorService executorService = new ThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2000), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "client-transaction-msg-check-thread");
}
});
transactionProducer.setExecutorService(executorService);
transactionProducer.setNamesrvAddr("localhost:9876");
transactionProducer.start();
Message message = new Message("message_transaction_01",
"hello this is transaction message!".getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult sendResult = transactionProducer.sendMessageInTransaction(message, 1);
SendResult sendResult2 = transactionProducer.sendMessageInTransaction(message, 2);
System.out.println(sendResult);
System.out.println(sendResult2);
for (int i = 0; i < 100000; i++) {
Thread.sleep(1000);
}
transactionProducer.shutdown();
}
}