术语
|
说明
|
约束
|
---|---|---|
app/应用 | 接入JMQ的系统或应用的名称,全局唯一 | 字母开头,字母、数字和下划线组合,控制在30个字符以内 |
broker | JMQ的服务端实例 | |
businessId/业务ID | 一条业务消息的ID,用于于归档查询) | 推荐每一条消息的businessId都唯一,方便精确查询(可以不唯一),长度须小于等于16个字符 |
message/消息体 | 业务方通过JMQ传递的消息内容,在发送时客户端会对消息进行压缩 | 压缩之后的消息体应小于2M |
queue/队列 | 一个topic 在一个broker上可以有一个或多个队列, 每个队列里的消息先进先出,不同队列间的消息无序 页面显示的队列数为单个broker上该主题的队列数。 | 每个topic默认的并发=queue*分组数量 |
topic/主题 | 消息的识别串,代表一种消息类型,全局唯一 | 字母开头,字母和数字组合,控制在20个字符以内 |
分组 | 一个分组包含两个broker, 一主一从。主从节点消息完全一致,页面只展示主节点。 分组名一般为jmq*** | |
连接数 | 客户端与broker间的TCP连接数。一个客户端会和每一个broker都建立一个连接,所以正常情况下连接数 等于客户端数量* broker数量。 在消费监控中,操作,消费详情里可以看到具体的连接信息 |
生产者:某个消息的发送端,称为生产者
消费者:某个消息的订阅端,称为消费者
生产者和消费者之间是通过topic建立联系的(值得特别注意的是生产者和消费者之间的app是相互独立的,相互之间没有任何关系)
1、首先在(
测试环境(
192.168.0.0/16
):
http://192.168.179.67/jmq-web/index.do
)进行接入申请,首先建立应用,然后在该应用下创建生产者和消费者topic,
参考文档:
http://jpcloud.jd.com/pages/viewpage.action?pageId=14364351
2、JAVA客户端
不依赖于第三方组件,只和Broker通信
内置管理和性能采集协议
较合理的超时时间设置
批量发送和消费,消费者为拉模式
支持两阶段事务
支持业务ID顺序消费
支持机房部署,就近发送和消费
默认数据压缩,更快的性能
支持流量分流控制
Spring 依赖:
<
dependency
>
<
groupId
>com.jd.jmq</
groupId
>
<
artifactId
>jmq-client-spring</
artifactId
>
<
version
>2.1.5-SNAPSHOT</
version
>
</
dependency
>
<
dependency
>
<
groupId
>com.jd.ump</
groupId
>
<
artifactId
>profiler</
artifactId
>
<
version
>3.2.0</
version
>
<!-- 必须3.2.0及以上!!! -->
</
dependency
>
|
schema配置(2.1.5-SNAPSHOT版本)
<beans ... xmlns:jmq="http://code.jd.com/schema/jmq"
xsi:schemaLocation="...
http://code.jd.com/schema/jmq
http://code.jd.com/schema/jmq/jmq-1.0.xsd">
JMQ配置项:
########### test environment ##########
jmq.user=b2bAfterSale
jmq.password=69754184
jmq.address=192.168.179.50:50088
jmq.producer.app=cdzhangfang
jmq.producer.topic=cdzhangfang_topic
jmq.consumer.app=cdzhangfang
jmq.consumer.topic=cdzhangfang_topic
jmq.epoll=true
生产端 Spring JMQ配置项:
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:conf/mq.properties</value>
</list>
</property>
</bean>
<jmq:transport address="${jmq.address}" user="${jmq.user}" password="${jmq.password}" app="${jmq.producer.app}"
epoll="false" channelMaxIdleTime="10000"/>
<jmq:producer id="producer" retryTimes="3" transport="jmq.transport"/>
transport配置说明:
属性
|
说明
|
默认值
|
---|---|---|
address | 目录服务地址 | JMQ接入地址 |
user | 用户 |
|
password | 密码 |
|
app | 接入的应用(系统)代码,此属性必须填写,和user完全一样 | nullAPP不同的TOPIC不能共用transport |
sendTimeout | 发送超时(毫秒) | 5000测试环境请适度改大 |
epoll | 是否使用epoll模式,会根据系统环境自动设置 | true |
属性
|
说明
|
默认值
|
---|---|---|
transport | 连接通道 | jmq.transport |
retryTimes | 发送失败后的重试次数 | 2 |
- 发送代码样例(请参考 demo里的ProducerTest.java)
//获取实例
Producer producer= (Producer) context.getBean(
"producer"
);
//普通发送方式
Message message =
new
Message(
"topic"
,
"消息内容"
,
"业务ID"
);
producer.send(message, timeout);
//批量发送方式
List<Message> messages =
new
ArrayList<Message>();
for
(
int
j =
0
; j < n; j++) {
Message message =
new
Message(
"topic"
,
"消息内容"
,
"业务ID"
);
messages.add(message);
}
producer.send(messages);
|
- 事物发送样例
transaction
/**
* 事务的单条发送
*/
protected
void
sendTransaction(
int
i)
throws
JMQException {
Message message =
new
Message(topic, topic +
"_test_"
+ i, topic +
"_rid_"
+ i);
Boolean ret = producer.send(message,
new
LocalTransaction<Boolean>() {
@Override
public
Boolean execute()
throws
Exception {
System.out.println(
"execute local transaction ok!"
);
return
true
;
}
@Override
public
int
getTimeout() {
return
50000
;
}
});
System.out.println(
"local transaction ret value:"
+ ret);
}
|
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:conf/mq.properties</value>
</list>
</property>
</bean>
<jmq:transport address="${jmq.address}" user="${jmq.user}" password="${jmq.password}" app="${jmq.consumer.app}" epoll="${jmq.epoll}"/>
<!-- pullTimeout must bigger than longPull !!!!!!! -->
<jmq:consumer id="consumer" transport="jmq.transport" longPull="10000" pullTimeout="11000" autoStart="true">
<jmq:listener topic="${jmq.consumer.topic}" listener="messageListener" maxConcurrent="10" minConcurrent="5"/>
</jmq:consumer>
<bean id="messageListener" class="com.jd.jmq.demo.DefaultMessageListener"/>
consumer配置说明:
属性
|
说明
|
默认值
|
---|---|---|
autoStart | 自动启动消费 | true,》=1.2.25以上版本支持,高级特性谨慎设置 |
longPull | 长轮询等待时间(一般不需要配置) | 5000ms |
maxConcurrent | 连接单组broker最大并发数,客户端实际线程数为单组运行的线程数*broker数(一般不需要配置,默认等于对列数) | topic索引分区数,管理端配置 》=1.3.1以上版本支持 |
minConcurrent | 连接单组broker最小并发数(一般不需要配置) | 0 自动调节》=1.3.1以上版本支持 |
pullTimeout | 长轮询超时时间(一般不需要配置) | 10000ms pullTimeout必须大于longPull时间,否则客户端会报"请求超时" |
transport | 连接工厂 | jmq.transport |
- 消息监听器属性说明
属性
|
说明
|
默认值
|
---|---|---|
topic | 消费者topic串,必须注入 | null |
listener | 消息监听器是MessageListener接口的实现类所创建的对象,用于处理收到的消息 抛出异常将回滚重试消息,否则成功消费并删除消息,所以如果认为消息处理失败还需重试请抛出异常 | null |
- 监听器模式配置样例(请参考demo里的spring-consumer.xml)
<
jmq:consumer
id
=
"consumer"
transport
=
"jmq.transport"
>
<
jmq:listener
topic
=
"${jmq.consumer.topic}"
listener
=
"messageListener"
/>
</
jmq:consumer
>
<
bean
id
=
"messageListener"
class
=
"com.jd.jmq.demo.DefaultMessageListener"
/>
|
监听器实现代码示例:
/**
* 消息监听器.
*/
public class DefaultMessageListener implements MessageListener {
private static final Logger logger = Logger.getLogger("consume");
/**
* 消费方法。注意: 消费不成功请抛出异常,MQ会自动重试
*
* @param messages
* @throws Exception
*/
@Override
public void onMessage(List<Message> messages) throws Exception {
if (messages == null || messages.isEmpty()) {
return;
}
for (Message message : messages) {
logger.info(String.format("收到一条消息,消息主题(队列名):%s,内容是:%s", message.getTopic(), message.getText()));
}
}
}