基本概念
Topic和MessageType
二者都是用来区别不同业务发送方发送的消息:
- Topic:一级消息类型(又名消息主题)。如TRADE,ic-common等不同的消息主题;
- MessageType:二级消息类型,区别同一Topic主题下的不同类型的消息; 如:TRADE(交易主题)下有2300-trade-created-done(交易创建),2300-trade-success(交易成功)等不同类型的消息
GroupId
又称组名, notify server根据groupId来识别客户端机器, 配置为同一groupId视为同一集群的机器.
因此, 各个业务之间,发送方和订阅方之间的GroupId不能重复.
MessageType和GroupId命名长度最大为64个字符, 且不能包含空格.
消息ID
消息ID是消息唯一标识.
发送方和订阅最好都在日志中记录消息ID,便于排查问题,获取消息ID方法
UniqId.getInstance().bytes2string(stringMessage.getMessageId())
如果可以建议同时记录下TOPIC、MessageType
订阅关系
订阅方的GroupId和Topic的映射关系.
一个GroupId可以对应多个Topic.
客户端通过spring配置文件配置订阅方需要订阅的消息,在应用启动时,订阅关系会推送到Notify Server.
Notify Server端将这份订阅关系保存,并根据保存在Server上的订阅关系将不断到达消息投给订阅方.
接入申请
申请须知
- 日常和线上分开申请。预发、线上环境会同时配置到位。
申请地址
日常申请地址 (新平台新规范)
线上申请地址 (线上配置自动同步到预发环境)
预发问题排查地址 (仅供问题排查,接入申请直接在线上完成,会自动同步到预发)
项目接入示例
maven依赖
maven依赖版本详见 (推荐使用Pandora容器2.x + notify-tr-client)
demo工程
- com.taobao.notify.example.publish.SimplePublisher 发送消息示例
- com.taobao.notify.example.subscribe.SimpleSubscriber 订阅消息示例
- com.taobao.notify.example.subscribe.HeaderSubscriber 订阅消息(消息属性过滤表达式订阅)示例
- com.taobao.notify.example.subscribe.unit.SimpleUnitSubscriber 单元化订阅示例
http://gitlab.alibaba-inc.com/middleware/notify-example
注意
如果是使用HSF1.x老版本,注意要使用com.taobao.hsf.notify.client.NotifyManagerBean
发消息
spring配置片段
<beans>
<bean id="notifyPublishManager" class="com.taobao.notify.remotingclient.NotifyManagerBean" init-method="init">
<property name="publishTopics"> <!-- 配置所需发布的topics -->
<list>
<value>TOPIC-01</value>
<value>TOPIC-02</value>
</list>
</property>
<property name="groupId" value="${GroupID}"/> <!-- 发送方的GroupId -->
</bean>
</beans>
java代码片段
private NotifyManagerBean notifyPublishManager;
public void sendMessage() {
StringMessage stringMessage = new StringMessage();
//必填属性
stringMessage.setBody("测试发送消息");
stringMessage.setTopic(topic);
stringMessage.setMessageType(messageType);
//可选属性
stringMessage.setStringProperty("customHeader", "customValue"); // 设置用户自定义的属性值
stringMessage.setStringProperty("bizOrderId", "业务主健、方便通过消息轨迹查询");//用long型数字,不支持字符串
SendResult result = notifyManager.sendMessage(stringMessage);
if (result.isSuccess()) {
// 发送成功后处理
System.out.println("消息发送成功");
}else {
log.warn("消息发送失败,原因:" + result.getErrorMessage()+"messageId:" + UniqId.getInstance().bytes2string(stringMessage.getMessageId()));
}
}
public NotifyManagerBean getNotifyPublishManager() {
return notifyPublishManager;
}
public void setNotifyPublishManager(NotifyManagerBean notifyPublishManager) {
this.notifyPublishManager = notifyPublishManager;
}
收消息
保证消息不丢 就必然可能出现重投的情况,需要订阅者在消息监听器里做好 幂等
,保证消息收到一次和收到多次的结果是一样的,需要对消息id去重 spring代码片段
<beans>
<bean id="notifySubscribeManager" class="com.taobao.notify.remotingclient.NotifyManagerBean" init-method="init">
<property name="subscribeMessages">
<map>
<entry key="Topic-01"> <!-- topic -->
<map>
<entry key="messageType-01"> <!-- messageType-->
<bean class="com.taobao.notify.config.SubscriptMsgDetailInfo" />
</entry>
</map>
</entry>
</map>
</property>
<property name="groupId" value="${GroupID}"/> <!-- 订阅方的GroupId -->
<property name="messageListener" ref="messageListener" /> <!-- 消息监听处理器 -->
</bean>
<bean id="messageListener" class="com.taobao.notify.comexample.SimpleMessageListener" />
</beans>
订阅方消息监听处理器 SimpleMessageListener.java
import com.taobao.notify.remotingclient.MessageListener;
import com.taobao.notify.remotingclient.MessageStatus;
import com.taobao.notify.message.BytesMessage;
import com.taobao.notify.message.Message;
import com.taobao.notify.message.StringMessage;
public class SimpleMessageListener implements MessageListener{
public void receiveMessage(Message message, MessageStatus status){
StringBuilder generalInfo = new StringBuilder();
generalInfo.append("收到消息");
generalInfo.append("messageId is:").append(UniqId.getInstance().bytes2string(message.getMessageId()));
generalInfo.append("topic is:").append(message.getTopic());
generalInfo.append("messageType is:").append(message.getMessageType());
generalInfo.append("用户自定义属性:").append(message.getStringProperty("customHeader"));
/**
* 只读属性
*/
generalInfo.append("消息在客户端产生时间:").append(message.getBornTime());
generalInfo.append("消息到达notify server时间:").append(message.getGMTCreate());
generalInfo.append("消息最后一次投递时间:").append(message.getGMTLastDelivery());
//消息 body 处理
if (message instanceof StringMessage) {
generalInfo.append("String消息body内容:");
StringMessage stringMessage = (StringMessage) message;
generalInfo.append(stringMessage.getBody());
}
else if (message instanceof BytesMessage) {
generalInfo.append("Byte消息body内容:");
BytesMessage bytesMessage = (BytesMessage) message;
generalInfo.append(new String(bytesMessage.getBody()));
}
System.out.println(generalInfo.toString());
if(业务处理失败,需要重投){
status.setRollbackOnly();
status.setReason("失败原因");
}
}
}
关于发送消息超时及重试次数
推荐不修改
1.默认是重试三次
在发送配置里可以配置重试次数
<property name="maxRetry" value="n"></property>
n为重试次数
2.超时时间是3秒
可以在发送消息手动设置超时时间:message.setClientPostTimeout(MILLISECONDS);