生产者概述
rocketMq中生产消息的一方称为生产者
生产者组:一个逻辑概念,在创建生产者实例的时候,需要指定一个生产者组名
//1. 创建消息生产者,并指定生产者组名
DefaultMQProducer producer = new DefaultMQProducer("async-producer");
RocketMQ客户端中的生产者有两个独立实现类:
org.apache.rocketmq.client.producer.DefaultMQProducer
org.apache.rocketmq.client.producer.TransactionMQProducer
前者用于生产普通消息、顺序消息、单向消息、批量消息、延迟消息,后者主要用于生产事务消息。
一个生产者组可以生产多个topic的消息。
生产者实例:一个生产者组中可以部署多个进程,每个进程都可以称为一个生产者实例。
Topic:主题名字,一个Topic由若干Queue组成。
消息类型和消息结构
rocketMq中message类
package org.apache.rocketmq.common.message;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class Message implements Serializable {
private static final long serialVersionUID = 8445773977080406428L;
//主题名字(必填):表示消息要到的发送主题 ,可以通过RocketMQ Console创建
private String topic;
//选填,消息的标记,完全由应用设置,RocketMQ不做任何处理,类似于memcached中flag的作用。
private int flag;
//消息属性,主要存储一些消息的元数据信息,消息扩展信息,Tag、keys、延迟级别都保存在这里
private Map<String, String> properties;
//消息体,字节数组。需要注意生产者使用什么编码,消费者也必须使用相同的编码解码,否则会产生乱码。
private byte[] body;
//事务id,仅在事务消息中使用到
private String transactionId;
public Message() {
}
public Message(String topic, byte[] body) {
this(topic, "", "", 0, body, true);
}
public Message(String topic, String tags, String keys, int flag, byte[] body, boolean waitStoreMsgOK) {
this.topic = topic;
this.flag = flag;
this.body = body;
if (tags != null && tags.length() > 0) {
this.setTags(tags);
}
if (keys != null && keys.length() > 0) {
this.setKeys(keys);
}
this.setWaitStoreMsgOK(waitStoreMsgOK);
}
public Message(String topic, String tags, byte[] body) {
this(topic, tags, "", 0, body, true);
}
public Message(String topic, String tags, String keys, byte[] body) {
this(topic, tags, keys, 0, body, true);
}
//setKeys():设置消息的key,多个key可以用MessageConst.KEY_SEPARATOR分隔或者直接用另一个重载方法。如果Broker中messageIndexEnable=true 则会根据key创建消息的hash索引,帮助用户进行快速查询。
public void setKeys(String keys) {
this.putProperty(MessageConst.PROPERTY_KEYS, keys);
}
void putProperty(final String name, final String value) {
if (null == this.properties) {
this.properties = new HashMap<String, String>();
}
this.properties.put(name, value);
}
void clearProperty(final String name) {
if (null != this.properties) {
this.properties.remove(name);
}
}
//putUserProperty():如果还有其他扩展信息,可以存放在这里,内部是一个Map,重复调用会覆盖旧值。
public void putUserProperty(final String name, final String value) {
if (MessageConst.STRING_HASH_SET.contains(name)) {
throw new RuntimeException(String.format(
"The Property<%s> is used by system, input another please", name));
}
if (value == null || value.trim().isEmpty()
|| name == null || name.trim().isEmpty()) {
throw new IllegalArgumentException(
"The name or value of property can not be null or blank string!"
);
}
this.putProperty(name, value);
}
public String getUserProperty(final String name) {
return this.getProperty(name);
}
public String getProperty(final String name) {
if (null == this.properties) {
this.properties = new HashMap<String, String>();
}
return this.properties.get(name);
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public String getTags() {
return this.getProperty(MessageConst.PROPERTY_TAGS);
}
//setTags():消息过滤的标记,用户可以订阅某个Topic的某些Tag,这样Broker只会吧订阅了topic-tag的消息发送个消费者。
public void setTags(String tags) {
this.putProperty(MessageConst.PROPERTY_TAGS, tags);
}
public String getKeys() {
return this.getProperty(MessageConst.PROPERTY_KEYS);
}
public void setKeys(Collection<String> keyCollection) {
String keys = String.join(MessageConst.KEY_SEPARATOR, keyCollection);
this.setKeys(keys);
}
public int getDelayTimeLevel() {
String t = this.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL);
if (t != null) {
return Integer.parseInt(t);
}
return 0;
}
//setDelayTimeLevel():设置延迟级别,延迟多久消费者可以消费。
public void setDelayTimeLevel(int level) {
this.putProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL, String.valueOf(level));
}
public boolean isWaitStoreMsgOK() {
String result = this.getProperty(MessageConst.PROPERTY_WAIT_STORE_MSG_OK);
if (null == result) {
return true;
}
return Boolean.parseBoolean(result);
}
public void setWaitStoreMsgOK(boolean waitStoreMsgOK) {
this.putProperty(MessageConst.PROPERTY_WAIT_STORE_MSG_OK, Boolean.toString(waitStoreMsgOK));
}
public void setInstanceId(String instanceId) {
this.putProperty(MessageConst.PROPERTY_INSTANCE_ID, instanceId);
}
public int getFlag() {
return flag;
}
public void setFlag(int flag) {
this.flag = flag;
}
public byte[] getBody() {
return body;
}
public void setBody(byte[] body) {
this.body = body;
}
public Map<String, String> getProperties() {
return properties;
}
void setProperties(Map<String, String> properties) {
this.properties = properties;
}
public String getBuyerId() {
return getProperty(MessageConst.PROPERTY_BUYER_ID);
}
public void setBuyerId(String buyerId) {
putProperty(MessageConst.PROPERTY_BUYER_ID, buyerId);
}
public String getTransactionId() {
return transactionId;
}
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
@Override
public String toString() {
return "Message{" +
"topic='" + topic + '\'' +
", flag=" + flag +
", properties=" + properties +
", body=" + Arrays.toString(body) +
", transactionId='" + transactionId + '\'' +
'}';
}
}
RocketMQ支持普通消息、分区有序消息、全局有序消息、延迟消息和事务消息
普通消息:普通消息也称为并发消息,和传统的队列相比,并发消息没有顺序,但是生产消费都是并行进行的,单机性能可达十万级别的TPS。
分区有序消息:与kafka中的分区类似,把一个Topic消息分为多个分区保存和消费,在一个分区内的消息就是传统的队列,遵循FIFO的原则。
全局有序消息:如果把一个topic的分区数设置为1,那么该topic中的消息就是单分区,所有消息都遵循FIFO的原则。
延迟消息:消息发送后,消费者要在一定时间后,或者指定某个时间点才可以消费。在没有延迟消息时,基本的做法是基于定时计划任务调度,定时发送消息。在RocketMQ中只需要在发送消息时设置延迟级别即可实现。
事务消息:主要涉及分布式事务,即需要保证在多个操作同时成功或者同时失败时,消费者才能消费消息。RocketMQ通过发送half消息、处理本地事务、提交消息或者回滚消息优雅地实现分布式事务。
生产者高可用
工作中不管Broker、Namesrv出现什么情况,我们都希望发送消息都不要出现未知状态或者消息丢失。在消息发送的过程中,客户端、Broker、Namesrv都有可能发生服务器损坏,掉电等各种故障。当这些故障发生时,RockerMQ是怎么处理的呢?
知乎文章中写的很全面,并附有代码,可以参考
https://zhuanlan.zhihu.com/p/434104817