提交 2bf133be 编写于 作者: O odbozhou

Merge branch 'develop' into 5.0.0-preview

# Conflicts:
#	.travis.yml
#	acl/pom.xml
#	broker/pom.xml
#	broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java
#	broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
#	broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java
#	client/pom.xml
#	client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java
#	client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
#	client/src/test/java/org/apache/rocketmq/client/impl/MQClientAPIImplTest.java
#	common/pom.xml
#	common/src/main/java/org/apache/rocketmq/common/MQVersion.java
#	common/src/main/java/org/apache/rocketmq/common/protocol/RequestCode.java
#	distribution/pom.xml
#	example/pom.xml
#	filter/pom.xml
#	logappender/pom.xml
#	logging/pom.xml
#	namesrv/pom.xml
#	namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
#	namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java
#	openmessaging/pom.xml
#	pom.xml
#	remoting/pom.xml
#	srvutil/pom.xml
#	store/pom.xml
#	store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java
#	test/pom.xml
#	tools/pom.xml
#	tools/src/main/java/org/apache/rocketmq/tools/command/MQAdminStartup.java
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
name: Little RocketMQ
on: [pull_request_target, issues]
uses: actions/first-interaction@v1.1.0
with:
# Token for the repository. Can be passed in using {{ secrets.GITHUB_TOKEN }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
# Comment to post on an individual's first issue
issue-message: 'Make sure your issue is not the existence through the issue search. Follow the issue template, make more details for us. But please be aware that Issue should not be used for FAQs: if you have a question or are simply not sure if it is really an issue or not, please contact [us](https://rocketmq.apache.org/about/contact/) first before you create a new issue.'
# Comment to post on an individual's first pull request
pr-message: 'We always welcome new contributions, whether for trivial cleanups, [big new features](https://github.com/apache/rocketmq/wiki/RocketMQ-Improvement-Proposal) or other material rewards, more details see [here](http://rocketmq.apache.org/docs/how-to-contribute/).'
......@@ -15,7 +15,7 @@ It offers a variety of features:
* Messaging patterns including publish/subscribe, request/reply and streaming
* Financial grade transactional message
* Built-in fault tolerance and high availability configuration options base on [DLedger](https://github.com/openmessaging/openmessaging-storage-dledger)
* A variety of cross language clients, such as Java, C/C++, Python, Go
* A variety of cross language clients, such as Java, [C/C++](https://github.com/apache/rocketmq-client-cpp), [Python](https://github.com/apache/rocketmq-client-python), [Go](https://github.com/apache/rocketmq-client-go), [Node.js](https://github.com/apache/rocketmq-client-nodejs)
* Pluggable transport protocols, such as TCP, SSL, AIO
* Built-in message tracing capability, also support opentracing
* Versatile big-data and streaming ecosytem integration
......
......@@ -206,64 +206,35 @@ public class AclUtils {
}
public static String expandIP(String netaddress, int part) {
boolean compress = false;
int compressIndex = -1;
String[] strArray = StringUtils.split(netaddress, ":");
ArrayList<Integer> indexes = new ArrayList<>();
for (int i = 0; i < netaddress.length(); i++) {
if (netaddress.charAt(i) == ':') {
if (indexes.size() > 0 && i - indexes.get(indexes.size() - 1) == 1) {
compressIndex = i;
compress = true;
}
indexes.add(i);
netaddress = netaddress.toUpperCase();
// expand netaddress
int separatorCount = StringUtils.countMatches(netaddress, ":");
int padCount = part - separatorCount;
if(padCount > 0){
StringBuilder padStr = new StringBuilder(":");
for(int i = 0; i < padCount; i++){
padStr.append(":");
}
netaddress = StringUtils.replace(netaddress, "::", padStr.toString());
}
// pad netaddress
String[] strArray = StringUtils.splitPreserveAllTokens(netaddress, ":");
for (int i = 0; i < strArray.length; i++) {
if (strArray[i].length() < 4) {
strArray[i] = "0000".substring(0, 4 - strArray[i].length()) + strArray[i];
if(strArray[i].length() < 4){
strArray[i] = StringUtils.leftPad(strArray[i], 4, '0');
}
}
// output
StringBuilder sb = new StringBuilder();
if (compress) {
int pos = indexes.indexOf(compressIndex);
int index = 0;
if (!netaddress.startsWith(":")) {
for (int i = 0; i < pos; i++) {
sb.append(strArray[index]).append(":");
index += 1;
}
}
int zeroNum = part - strArray.length;
if (netaddress.endsWith(":")) {
for (int i = 0; i < zeroNum; i++) {
sb.append("0000");
if (i != zeroNum - 1) {
sb.append(":");
}
}
} else {
for (int i = 0; i < zeroNum; i++) {
sb.append("0000").append(":");
}
for (int i = index; i < strArray.length; i++) {
sb.append(strArray[i]);
if (i != strArray.length - 1) {
sb.append(":");
}
}
}
} else {
for (int i = 0; i < strArray.length; i++) {
sb.append(strArray[i]);
if (i != strArray.length - 1) {
sb.append(":");
}
for (int i = 0; i < strArray.length; i++) {
sb.append(strArray[i]);
if (i != strArray.length - 1) {
sb.append(":");
}
}
return sb.toString().toUpperCase();
return sb.toString();
}
public static <T> T getYamlDataObject(String path, Class<T> clazz) {
......@@ -308,7 +279,7 @@ public class AclUtils {
JSONObject yamlDataObject = null;
try {
yamlDataObject = AclUtils.getYamlDataObject(fileName,
JSONObject.class);
JSONObject.class);
} catch (Exception e) {
log.error("Convert yaml file to data object error, ", e);
return null;
......
......@@ -18,13 +18,6 @@ package org.apache.rocketmq.acl.plain;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.acl.common.AclConstants;
import org.apache.rocketmq.acl.common.AclException;
......@@ -39,6 +32,14 @@ import org.apache.rocketmq.logging.InternalLogger;
import org.apache.rocketmq.logging.InternalLoggerFactory;
import org.apache.rocketmq.srvutil.FileWatchService;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class PlainPermissionManager {
private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.COMMON_LOGGER_NAME);
......@@ -130,6 +131,7 @@ public class PlainPermissionManager {
log.error("Parameter value plainAccessConfig is null,Please check your parameter");
throw new AclException("Parameter value plainAccessConfig is null, Please check your parameter");
}
checkPlainAccessConfig(plainAccessConfig);
Permission.checkResourcePerms(plainAccessConfig.getTopicPerms());
Permission.checkResourcePerms(plainAccessConfig.getGroupPerms());
......@@ -193,9 +195,9 @@ public class PlainPermissionManager {
"The secretKey=%s value length should longer than 6",
plainAccessConfig.getSecretKey()));
}
newAccountsMap.put(AclConstants.CONFIG_SECRET_KEY, (String) plainAccessConfig.getSecretKey());
newAccountsMap.put(AclConstants.CONFIG_SECRET_KEY, plainAccessConfig.getSecretKey());
}
if (!StringUtils.isEmpty(plainAccessConfig.getWhiteRemoteAddress())) {
if (plainAccessConfig.getWhiteRemoteAddress() != null) {
newAccountsMap.put(AclConstants.CONFIG_WHITE_ADDR, plainAccessConfig.getWhiteRemoteAddress());
}
if (!StringUtils.isEmpty(String.valueOf(plainAccessConfig.isAdmin()))) {
......@@ -207,10 +209,10 @@ public class PlainPermissionManager {
if (!StringUtils.isEmpty(plainAccessConfig.getDefaultGroupPerm())) {
newAccountsMap.put(AclConstants.CONFIG_DEFAULT_GROUP_PERM, plainAccessConfig.getDefaultGroupPerm());
}
if (plainAccessConfig.getTopicPerms() != null && !plainAccessConfig.getTopicPerms().isEmpty()) {
if (plainAccessConfig.getTopicPerms() != null) {
newAccountsMap.put(AclConstants.CONFIG_TOPIC_PERMS, plainAccessConfig.getTopicPerms());
}
if (plainAccessConfig.getGroupPerms() != null && !plainAccessConfig.getGroupPerms().isEmpty()) {
if (plainAccessConfig.getGroupPerms() != null) {
newAccountsMap.put(AclConstants.CONFIG_GROUP_PERMS, plainAccessConfig.getGroupPerms());
}
......@@ -251,12 +253,6 @@ public class PlainPermissionManager {
}
public boolean updateGlobalWhiteAddrsConfig(List<String> globalWhiteAddrsList) {
if (globalWhiteAddrsList == null) {
log.error("Parameter value globalWhiteAddrsList is null,Please check your parameter");
return false;
}
Map<String, Object> aclAccessConfigMap = AclUtils.getYamlDataObject(fileHome + File.separator + fileName,
Map.class);
if (aclAccessConfigMap == null || aclAccessConfigMap.isEmpty()) {
......@@ -266,9 +262,10 @@ public class PlainPermissionManager {
if (globalWhiteRemoteAddrList != null) {
globalWhiteRemoteAddrList.clear();
globalWhiteRemoteAddrList.addAll(globalWhiteAddrsList);
// Update globalWhiteRemoteAddr element in memeory map firstly
if (globalWhiteAddrsList != null) {
globalWhiteRemoteAddrList.addAll(globalWhiteAddrsList);
}
// Update globalWhiteRemoteAddr element in memory map firstly
aclAccessConfigMap.put(AclConstants.CONFIG_GLOBAL_WHITE_ADDRS, globalWhiteRemoteAddrList);
if (AclUtils.writeDataObject(fileHome + File.separator + fileName, updateAclConfigFileVersion(aclAccessConfigMap))) {
return true;
......@@ -362,15 +359,19 @@ public class PlainPermissionManager {
this.globalWhiteRemoteAddressStrategy.clear();
}
public PlainAccessResource buildPlainAccessResource(PlainAccessConfig plainAccessConfig) throws AclException {
public void checkPlainAccessConfig(PlainAccessConfig plainAccessConfig) throws AclException {
if (plainAccessConfig.getAccessKey() == null
|| plainAccessConfig.getSecretKey() == null
|| plainAccessConfig.getAccessKey().length() <= AclConstants.ACCESS_KEY_MIN_LENGTH
|| plainAccessConfig.getSecretKey().length() <= AclConstants.SECRET_KEY_MIN_LENGTH) {
|| plainAccessConfig.getSecretKey() == null
|| plainAccessConfig.getAccessKey().length() <= AclConstants.ACCESS_KEY_MIN_LENGTH
|| plainAccessConfig.getSecretKey().length() <= AclConstants.SECRET_KEY_MIN_LENGTH) {
throw new AclException(String.format(
"The accessKey=%s and secretKey=%s cannot be null and length should longer than 6",
plainAccessConfig.getAccessKey(), plainAccessConfig.getSecretKey()));
"The accessKey=%s and secretKey=%s cannot be null and length should longer than 6",
plainAccessConfig.getAccessKey(), plainAccessConfig.getSecretKey()));
}
}
public PlainAccessResource buildPlainAccessResource(PlainAccessConfig plainAccessConfig) throws AclException {
checkPlainAccessConfig(plainAccessConfig);
PlainAccessResource plainAccessResource = new PlainAccessResource();
plainAccessResource.setAccessKey(plainAccessConfig.getAccessKey());
plainAccessResource.setSecretKey(plainAccessConfig.getSecretKey());
......
......@@ -167,7 +167,7 @@ public class RemoteAddressStrategyFactory {
String[] strArray = StringUtils.split(remoteAddr, ".");
if (analysis(strArray, 1) || analysis(strArray, 2) || analysis(strArray, 3)) {
AclUtils.verify(remoteAddr, index - 1);
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
for (int j = 0; j < index; j++) {
sb.append(strArray[j].trim()).append(".");
}
......
......@@ -202,6 +202,7 @@ public class AclUtilsTest {
@Test
public void expandIPTest() {
Assert.assertEquals(AclUtils.expandIP("::", 8), "0000:0000:0000:0000:0000:0000:0000:0000");
Assert.assertEquals(AclUtils.expandIP("::1", 8), "0000:0000:0000:0000:0000:0000:0000:0001");
Assert.assertEquals(AclUtils.expandIP("3::", 8), "0003:0000:0000:0000:0000:0000:0000:0000");
Assert.assertEquals(AclUtils.expandIP("2::2", 8), "0002:0000:0000:0000:0000:0000:0000:0002");
......
......@@ -19,6 +19,7 @@ package org.apache.rocketmq.acl.plain;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
......@@ -524,7 +525,7 @@ public class PlainAccessValidatorTest {
// Verify the dateversion element is correct or not
List<Map<String, Object>> dataVersions = (List<Map<String, Object>>) readableMap.get(AclConstants.CONFIG_DATA_VERSION);
Assert.assertEquals(1,dataVersions.get(0).get(AclConstants.CONFIG_COUNTER));
// Restore the backup file and flush to yaml file
AclUtils.writeDataObject(targetFileName, backUpAclConfigMap);
}
......@@ -566,6 +567,16 @@ public class PlainAccessValidatorTest {
plainAccessValidator.updateAccessConfig(plainAccessConfig);
}
@Test(expected = AclException.class)
public void createAndUpdateAccessAclNullSkExceptionTest() {
PlainAccessConfig plainAccessConfig = new PlainAccessConfig();
plainAccessConfig.setAccessKey("RocketMQ33");
// secret key is null
PlainAccessValidator plainAccessValidator = new PlainAccessValidator();
plainAccessValidator.updateAccessConfig(plainAccessConfig);
}
@Test
public void updateGlobalWhiteAddrsNormalTest() {
System.setProperty("rocketmq.home.dir", "src/test/resources");
......@@ -606,4 +617,44 @@ public class PlainAccessValidatorTest {
Assert.assertEquals(aclConfig.getPlainAccessConfigs().size(), 2);
}
@Test
public void updateAccessConfigEmptyPermListTest(){
PlainAccessValidator plainAccessValidator = new PlainAccessValidator();
PlainAccessConfig plainAccessConfig = new PlainAccessConfig();
String accessKey = "updateAccessConfigEmptyPerm";
plainAccessConfig.setAccessKey(accessKey);
plainAccessConfig.setSecretKey("123456789111");
plainAccessConfig.setTopicPerms(Collections.singletonList("topicB=PUB"));
plainAccessValidator.updateAccessConfig(plainAccessConfig);
plainAccessConfig.setTopicPerms(new ArrayList<>());
plainAccessValidator.updateAccessConfig(plainAccessConfig);
PlainAccessConfig result = plainAccessValidator.getAllAclConfig().getPlainAccessConfigs()
.stream().filter(c->c.getAccessKey().equals(accessKey)).findFirst().orElse(null);
Assert.assertEquals(0, result.getTopicPerms().size());
plainAccessValidator.deleteAccessConfig(accessKey);
}
@Test
public void updateAccessConfigEmptyWhiteRemoteAddressTest(){
PlainAccessValidator plainAccessValidator = new PlainAccessValidator();
PlainAccessConfig plainAccessConfig = new PlainAccessConfig();
String accessKey = "updateAccessConfigEmptyWhiteRemoteAddress";
plainAccessConfig.setAccessKey(accessKey);
plainAccessConfig.setSecretKey("123456789111");
plainAccessConfig.setWhiteRemoteAddress("127.0.0.1");
plainAccessValidator.updateAccessConfig(plainAccessConfig);
plainAccessConfig.setWhiteRemoteAddress("");
plainAccessValidator.updateAccessConfig(plainAccessConfig);
PlainAccessConfig result = plainAccessValidator.getAllAclConfig().getPlainAccessConfigs()
.stream().filter(c->c.getAccessKey().equals(accessKey)).findFirst().orElse(null);
Assert.assertEquals("", result.getWhiteRemoteAddress());
plainAccessValidator.deleteAccessConfig(accessKey);
}
}
......@@ -53,6 +53,11 @@ public class ManyMessageTransfer extends AbstractReferenceCounted implements Fil
return transferred;
}
@Override
public long transferred() {
return transferred;
}
@Override
public long count() {
return byteBufferHeader.limit() + this.getMessageResult.getBufferTotalSize();
......@@ -76,6 +81,28 @@ public class ManyMessageTransfer extends AbstractReferenceCounted implements Fil
return 0;
}
@Override
public FileRegion retain() {
super.retain();
return this;
}
@Override
public FileRegion retain(int increment) {
super.retain(increment);
return this;
}
@Override
public FileRegion touch() {
return this;
}
@Override
public FileRegion touch(Object hint) {
return this;
}
public void close() {
this.deallocate();
}
......
......@@ -47,6 +47,11 @@ public class OneMessageTransfer extends AbstractReferenceCounted implements File
return transferred;
}
@Override
public long transferred() {
return transferred;
}
@Override
public long count() {
return this.byteBufferHeader.limit() + this.selectMappedBufferResult.getSize();
......@@ -65,6 +70,28 @@ public class OneMessageTransfer extends AbstractReferenceCounted implements File
return 0;
}
@Override
public FileRegion retain() {
super.retain();
return this;
}
@Override
public FileRegion retain(int increment) {
super.retain(increment);
return this;
}
@Override
public FileRegion touch() {
return this;
}
@Override
public FileRegion touch(Object hint) {
return this;
}
public void close() {
this.deallocate();
}
......
......@@ -53,6 +53,11 @@ public class QueryMessageTransfer extends AbstractReferenceCounted implements Fi
return transferred;
}
@Override
public long transferred() {
return transferred;
}
@Override
public long count() {
return byteBufferHeader.limit() + this.queryMessageResult.getBufferTotalSize();
......@@ -76,6 +81,28 @@ public class QueryMessageTransfer extends AbstractReferenceCounted implements Fi
return 0;
}
@Override
public FileRegion retain() {
super.retain();
return this;
}
@Override
public FileRegion retain(int increment) {
super.retain(increment);
return this;
}
@Override
public FileRegion touch() {
return this;
}
@Override
public FileRegion touch(Object hint) {
return this;
}
public void close() {
this.deallocate();
}
......
......@@ -185,8 +185,8 @@ public abstract class AbstractPluginMessageStore implements MessageStore {
}
@Override
public boolean appendToCommitLog(long startOffset, byte[] data) {
return next.appendToCommitLog(startOffset, data);
public boolean appendToCommitLog(long startOffset, byte[] data, int dataStart, int dataLength) {
return next.appendToCommitLog(startOffset, data, dataStart, dataLength);
}
@Override
......
......@@ -21,11 +21,14 @@ import com.google.common.collect.Maps;
import io.netty.channel.ChannelHandlerContext;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map;Optional
import java.util.concurrent.ThreadLocalRandom;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.LongAdder;
......@@ -74,7 +77,6 @@ public abstract class AbstractSendMessageProcessor extends AsyncNettyRequestProc
protected final static int DLQ_NUMS_PER_GROUP = 1;
protected final BrokerController brokerController;
protected final Random random = new Random(System.currentTimeMillis());
protected final SocketAddress storeHost;
private List<SendMessageHook> sendMessageHookList;
......@@ -125,7 +127,7 @@ public abstract class AbstractSendMessageProcessor extends AsyncNettyRequestProc
final SendMessageRequestHeader requestHeader, final byte[] body, TopicConfig topicConfig) {
int queueIdInt = requestHeader.getQueueId();
if (queueIdInt < 0) {
queueIdInt = Math.abs(this.random.nextInt() % 99999999) % topicConfig.getWriteQueueNums();
queueIdInt = ThreadLocalRandom.current().nextInt(99999999) % topicConfig.getWriteQueueNums();
}
int sysFlag = requestHeader.getSysFlag();
......@@ -274,8 +276,8 @@ public abstract class AbstractSendMessageProcessor extends AsyncNettyRequestProc
try {
final SendMessageRequestHeader requestHeader = parseRequestHeader(request);
String namespace = NamespaceUtil.getNamespaceFromResource(requestHeader.getTopic());
if (null != requestHeader) {
String namespace = NamespaceUtil.getNamespaceFromResource(requestHeader.getTopic());
context.setNamespace(namespace);
context.setProducerGroup(requestHeader.getProducerGroup());
context.setTopic(requestHeader.getTopic());
......@@ -305,9 +307,7 @@ public abstract class AbstractSendMessageProcessor extends AsyncNettyRequestProc
switch (request.getCode()) {
case RequestCode.SEND_BATCH_MESSAGE:
case RequestCode.SEND_MESSAGE_V2:
requestHeaderV2 =
(SendMessageRequestHeaderV2) request
.decodeCommandCustomHeader(SendMessageRequestHeaderV2.class);
requestHeaderV2 = decodeSendMessageHeaderV2(request);
case RequestCode.SEND_MESSAGE:
if (null == requestHeaderV2) {
requestHeader =
......@@ -322,6 +322,79 @@ public abstract class AbstractSendMessageProcessor extends AsyncNettyRequestProc
return requestHeader;
}
static SendMessageRequestHeaderV2 decodeSendMessageHeaderV2(RemotingCommand request)
throws RemotingCommandException {
SendMessageRequestHeaderV2 r = new SendMessageRequestHeaderV2();
HashMap<String, String> fields = request.getExtFields();
if (fields == null) {
throw new RemotingCommandException("the ext fields is null");
}
String s = fields.get("a");
checkNotNull(s, "the custom field <a> is null");
r.setA(s);
s = fields.get("b");
checkNotNull(s, "the custom field <b> is null");
r.setB(s);
s = fields.get("c");
checkNotNull(s, "the custom field <c> is null");
r.setC(s);
s = fields.get("d");
checkNotNull(s, "the custom field <d> is null");
r.setD(Integer.parseInt(s));
s = fields.get("e");
checkNotNull(s, "the custom field <e> is null");
r.setE(Integer.parseInt(s));
s = fields.get("f");
checkNotNull(s, "the custom field <f> is null");
r.setF(Integer.parseInt(s));
s = fields.get("g");
checkNotNull(s, "the custom field <g> is null");
r.setG(Long.parseLong(s));
s = fields.get("h");
checkNotNull(s, "the custom field <h> is null");
r.setH(Integer.parseInt(s));
s = fields.get("i");
if (s != null) {
r.setI(s);
}
s = fields.get("j");
if (s != null) {
r.setJ(Integer.parseInt(s));
}
s = fields.get("k");
if (s != null) {
r.setK(Boolean.parseBoolean(s));
}
s = fields.get("l");
if (s != null) {
r.setL(Integer.parseInt(s));
}
s = fields.get("m");
if (s != null) {
r.setM(Boolean.parseBoolean(s));
}
return r;
}
private static void checkNotNull(String s, String msg) throws RemotingCommandException {
if (s == null) {
throw new RemotingCommandException(msg);
}
}
public void executeSendMessageHookAfter(final RemotingCommand response, final SendMessageContext context) {
if (hasSendMessageHook()) {
for (SendMessageHook hook : this.sendMessageHookList) {
......
......@@ -154,6 +154,7 @@ import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
import org.apache.rocketmq.remoting.protocol.LanguageCode;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
import org.apache.rocketmq.remoting.protocol.RemotingSysResponseCode;
import org.apache.rocketmq.srvutil.ConcurrentHashMapUtil;
import org.apache.rocketmq.store.ConsumeQueue;
import org.apache.rocketmq.store.ConsumeQueueExt;
......@@ -282,10 +283,8 @@ public class AdminBrokerProcessor extends AsyncNettyRequestProcessor implements
case RequestCode.MIGRATE_TOPIC_LOGICAL_QUEUE_NOTIFY:
return migrateTopicLogicalQueueNotify(ctx, request);
default:
break;
return getUnknownCmdResponse(ctx, request);
}
return null;
}
@Override
......@@ -365,8 +364,8 @@ public class AdminBrokerProcessor extends AsyncNettyRequestProcessor implements
accessConfig.setWhiteRemoteAddress(requestHeader.getWhiteRemoteAddress());
accessConfig.setDefaultTopicPerm(requestHeader.getDefaultTopicPerm());
accessConfig.setDefaultGroupPerm(requestHeader.getDefaultGroupPerm());
accessConfig.setTopicPerms(UtilAll.string2List(requestHeader.getTopicPerms(), ","));
accessConfig.setGroupPerms(UtilAll.string2List(requestHeader.getGroupPerms(), ","));
accessConfig.setTopicPerms(UtilAll.split(requestHeader.getTopicPerms(), ","));
accessConfig.setGroupPerms(UtilAll.split(requestHeader.getGroupPerms(), ","));
accessConfig.setAdmin(requestHeader.isAdmin());
try {
......@@ -439,7 +438,7 @@ public class AdminBrokerProcessor extends AsyncNettyRequestProcessor implements
try {
AccessValidator accessValidator = this.brokerController.getAccessValidatorMap().get(PlainAccessValidator.class);
if (accessValidator.updateGlobalWhiteAddrsConfig(UtilAll.string2List(requestHeader.getGlobalWhiteAddrs(), ","))) {
if (accessValidator.updateGlobalWhiteAddrsConfig(UtilAll.split(requestHeader.getGlobalWhiteAddrs(), ","))) {
response.setCode(ResponseCode.SUCCESS);
response.setOpaque(request.getOpaque());
response.markResponseType();
......@@ -507,6 +506,13 @@ public class AdminBrokerProcessor extends AsyncNettyRequestProcessor implements
return null;
}
private RemotingCommand getUnknownCmdResponse(ChannelHandlerContext ctx, RemotingCommand request) {
String error = " request type " + request.getCode() + " not supported";
final RemotingCommand response =
RemotingCommand.createResponseCommand(RemotingSysResponseCode.REQUEST_CODE_NOT_SUPPORTED, error);
return response;
}
private RemotingCommand getAllTopicConfig(ChannelHandlerContext ctx, RemotingCommand request) {
final RemotingCommand response = RemotingCommand.createResponseCommand(GetAllTopicConfigResponseHeader.class);
// final GetAllTopicConfigResponseHeader responseHeader =
......@@ -1513,7 +1519,7 @@ public class AdminBrokerProcessor extends AsyncNettyRequestProcessor implements
java.io.File commitLogDir = new java.io.File(this.brokerController.getMessageStoreConfig().getStorePathRootDir());
if (commitLogDir.exists()) {
runtimeInfo.put("commitLogDirCapacity", String.format("Total : %s, Free : %s.", MixAll.humanReadableByteCount(commitLogDir.getTotalSpace(), false), MixAll.humanReadableByteCount(commitLogDir.getFreeSpace(), false)));
runtimeInfo.put("commitLogDirCapacity", String.format("Total : %s, Free : %s.", MixAll.humanReadableByteCount(commitLogDir.getTotalSpace(), false), MixAll.humanReadableByteCount(commitLogDir.getUsableSpace(), false)));
}
return runtimeInfo;
......
......@@ -45,6 +45,8 @@ import org.apache.rocketmq.store.MessageExtBrokerInner;
import org.apache.rocketmq.store.PutMessageResult;
import org.apache.rocketmq.store.stats.BrokerStatsManager;
import java.util.concurrent.ThreadLocalRandom;
public class ReplyMessageProcessor extends AbstractSendMessageProcessor implements NettyRequestProcessor {
private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
......@@ -125,7 +127,7 @@ public class ReplyMessageProcessor extends AbstractSendMessageProcessor implemen
TopicConfig topicConfig = this.brokerController.getTopicConfigManager().selectTopicConfig(requestHeader.getTopic());
if (queueIdInt < 0) {
queueIdInt = Math.abs(this.random.nextInt() % 99999999) % topicConfig.getWriteQueueNums();
queueIdInt = ThreadLocalRandom.current().nextInt(99999999) % topicConfig.getWriteQueueNums();
}
MessageExtBrokerInner msgInner = new MessageExtBrokerInner();
......
......@@ -21,6 +21,7 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadLocalRandom;
import io.netty.channel.ChannelHandlerContext;
import org.apache.rocketmq.broker.BrokerController;
......@@ -48,6 +49,7 @@ import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader;
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
import org.apache.rocketmq.common.sysflag.MessageSysFlag;
import org.apache.rocketmq.common.sysflag.TopicSysFlag;
import org.apache.rocketmq.common.topic.TopicValidator;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
import org.apache.rocketmq.remoting.netty.RemotingResponseCallback;
......@@ -140,7 +142,7 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
}
String newTopic = MixAll.getRetryTopic(requestHeader.getGroup());
int queueIdInt = Math.abs(this.random.nextInt() % 99999999) % subscriptionGroupConfig.getRetryQueueNums();
int queueIdInt = ThreadLocalRandom.current().nextInt(99999999) % subscriptionGroupConfig.getRetryQueueNums();
int topicSysFlag = 0;
if (requestHeader.isUnitMode()) {
topicSysFlag = TopicSysFlag.buildSysFlag(false, true);
......@@ -178,22 +180,27 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
int maxReconsumeTimes = subscriptionGroupConfig.getRetryMaxTimes();
if (request.getVersion() >= MQVersion.Version.V3_4_9.ordinal()) {
maxReconsumeTimes = requestHeader.getMaxReconsumeTimes();
Integer times = requestHeader.getMaxReconsumeTimes();
if (times != null) {
maxReconsumeTimes = times;
}
}
if (msgExt.getReconsumeTimes() >= maxReconsumeTimes
|| delayLevel < 0) {
newTopic = MixAll.getDLQTopic(requestHeader.getGroup());
queueIdInt = Math.abs(this.random.nextInt() % 99999999) % DLQ_NUMS_PER_GROUP;
queueIdInt = ThreadLocalRandom.current().nextInt(99999999) % DLQ_NUMS_PER_GROUP;
topicConfig = this.brokerController.getTopicConfigManager().createTopicInSendMessageBackMethod(newTopic,
DLQ_NUMS_PER_GROUP,
PermName.PERM_WRITE, 0);
PermName.PERM_WRITE | PermName.PERM_READ, 0);
if (null == topicConfig) {
response.setCode(ResponseCode.SYSTEM_ERROR);
response.setRemark("topic[" + newTopic + "] not exist");
return CompletableFuture.completedFuture(response);
}
msgExt.setDelayTimeLevel(0);
} else {
if (0 == delayLevel) {
delayLevel = 3 + msgExt.getReconsumeTimes();
......@@ -277,15 +284,24 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
msgInner.setBody(body);
msgInner.setFlag(requestHeader.getFlag());
MessageAccessor.setProperties(msgInner, MessageDecoder.string2messageProperties(requestHeader.getProperties()));
msgInner.setPropertiesString(requestHeader.getProperties());
Map<String, String> origProps = MessageDecoder.string2messageProperties(requestHeader.getProperties());
MessageAccessor.setProperties(msgInner, origProps);
msgInner.setBornTimestamp(requestHeader.getBornTimestamp());
msgInner.setBornHost(ctx.channel().remoteAddress());
msgInner.setStoreHost(this.getStoreHost());
msgInner.setReconsumeTimes(requestHeader.getReconsumeTimes() == null ? 0 : requestHeader.getReconsumeTimes());
String clusterName = this.brokerController.getBrokerConfig().getBrokerClusterName();
MessageAccessor.putProperty(msgInner, MessageConst.PROPERTY_CLUSTER, clusterName);
msgInner.setPropertiesString(MessageDecoder.messageProperties2String(msgInner.getProperties()));
if (origProps.containsKey(MessageConst.PROPERTY_WAIT_STORE_MSG_OK)) {
// There is no need to store "WAIT=true", remove it from propertiesString to save 9 bytes for each message.
// It works for most case. In some cases msgInner.setPropertiesString invoked later and replace it.
String waitStoreMsgOKValue = origProps.remove(MessageConst.PROPERTY_WAIT_STORE_MSG_OK);
msgInner.setPropertiesString(MessageDecoder.messageProperties2String(msgInner.getProperties()));
// Reput to properties, since msgInner.isWaitStoreMsgOK() will be invoked later
origProps.put(MessageConst.PROPERTY_WAIT_STORE_MSG_OK, waitStoreMsgOKValue);
} else {
msgInner.setPropertiesString(MessageDecoder.messageProperties2String(msgInner.getProperties()));
}
LogicalQueueContext logicalQueueContext = super.buildLogicalQueueContext(msgInner.getTopic(), msgInner.getQueueId(), response);
CompletableFuture<RemotingCommand> future = logicalQueueContext.hookBeforePut(ctx, requestHeader, request, response);
......@@ -294,7 +310,6 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
}
CompletableFuture<PutMessageResult> putMessageResult = null;
Map<String, String> origProps = MessageDecoder.string2messageProperties(requestHeader.getProperties());
String transFlag = origProps.get(MessageConst.PROPERTY_TRANSACTION_PREPARED);
if (transFlag != null && Boolean.parseBoolean(transFlag)) {
if (this.brokerController.getBrokerConfig().isRejectTransactionMessage()) {
......@@ -348,13 +363,14 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
int reconsumeTimes = requestHeader.getReconsumeTimes() == null ? 0 : requestHeader.getReconsumeTimes();
if (reconsumeTimes >= maxReconsumeTimes) {
newTopic = MixAll.getDLQTopic(groupName);
int queueIdInt = Math.abs(this.random.nextInt() % 99999999) % DLQ_NUMS_PER_GROUP;
int queueIdInt = ThreadLocalRandom.current().nextInt(99999999) % DLQ_NUMS_PER_GROUP;
topicConfig = this.brokerController.getTopicConfigManager().createTopicInSendMessageBackMethod(newTopic,
DLQ_NUMS_PER_GROUP,
PermName.PERM_WRITE, 0
PermName.PERM_WRITE | PermName.PERM_READ, 0
);
msg.setTopic(newTopic);
msg.setQueueId(queueIdInt);
msg.setDelayTimeLevel(0);
if (null == topicConfig) {
response.setCode(ResponseCode.SYSTEM_ERROR);
response.setRemark("topic[" + newTopic + "] not exist");
......@@ -370,6 +386,82 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
return true;
}
private RemotingCommand sendMessage(final ChannelHandlerContext ctx,
final RemotingCommand request,
final SendMessageContext sendMessageContext,
final SendMessageRequestHeader requestHeader) throws RemotingCommandException {
final RemotingCommand response = RemotingCommand.createResponseCommand(SendMessageResponseHeader.class);
final SendMessageResponseHeader responseHeader = (SendMessageResponseHeader)response.readCustomHeader();
response.setOpaque(request.getOpaque());
response.addExtField(MessageConst.PROPERTY_MSG_REGION, this.brokerController.getBrokerConfig().getRegionId());
response.addExtField(MessageConst.PROPERTY_TRACE_SWITCH, String.valueOf(this.brokerController.getBrokerConfig().isTraceOn()));
log.debug("receive SendMessage request command, {}", request);
final long startTimstamp = this.brokerController.getBrokerConfig().getStartAcceptSendRequestTimeStamp();
if (this.brokerController.getMessageStore().now() < startTimstamp) {
response.setCode(ResponseCode.SYSTEM_ERROR);
response.setRemark(String.format("broker unable to service, until %s", UtilAll.timeMillisToHumanString2(startTimstamp)));
return response;
}
response.setCode(-1);
super.msgCheck(ctx, requestHeader, response);
if (response.getCode() != -1) {
return response;
}
final byte[] body = request.getBody();
int queueIdInt = requestHeader.getQueueId();
TopicConfig topicConfig = this.brokerController.getTopicConfigManager().selectTopicConfig(requestHeader.getTopic());
if (queueIdInt < 0) {
queueIdInt = ThreadLocalRandom.current().nextInt(99999999) % topicConfig.getWriteQueueNums();
}
MessageExtBrokerInner msgInner = new MessageExtBrokerInner();
msgInner.setTopic(requestHeader.getTopic());
msgInner.setQueueId(queueIdInt);
if (!handleRetryAndDLQ(requestHeader, response, request, msgInner, topicConfig)) {
return response;
}
msgInner.setBody(body);
msgInner.setFlag(requestHeader.getFlag());
MessageAccessor.setProperties(msgInner, MessageDecoder.string2messageProperties(requestHeader.getProperties()));
msgInner.setBornTimestamp(requestHeader.getBornTimestamp());
msgInner.setBornHost(ctx.channel().remoteAddress());
msgInner.setStoreHost(this.getStoreHost());
msgInner.setReconsumeTimes(requestHeader.getReconsumeTimes() == null ? 0 : requestHeader.getReconsumeTimes());
String clusterName = this.brokerController.getBrokerConfig().getBrokerClusterName();
MessageAccessor.putProperty(msgInner, MessageConst.PROPERTY_CLUSTER, clusterName);
msgInner.setPropertiesString(MessageDecoder.messageProperties2String(msgInner.getProperties()));
PutMessageResult putMessageResult = null;
Map<String, String> oriProps = MessageDecoder.string2messageProperties(requestHeader.getProperties());
String traFlag = oriProps.get(MessageConst.PROPERTY_TRANSACTION_PREPARED);
if (traFlag != null && Boolean.parseBoolean(traFlag)
&& !(msgInner.getReconsumeTimes() > 0 && msgInner.getDelayTimeLevel() > 0)) { //For client under version 4.6.1
if (this.brokerController.getBrokerConfig().isRejectTransactionMessage()) {
response.setCode(ResponseCode.NO_PERMISSION);
response.setRemark(
"the broker[" + this.brokerController.getBrokerConfig().getBrokerIP1()
+ "] sending transaction message is forbidden");
return response;
}
putMessageResult = this.brokerController.getTransactionalMessageService().prepareMessage(msgInner);
} else {
putMessageResult = this.brokerController.getMessageStore().putMessage(msgInner);
}
return handlePutMessageResult(putMessageResult, response, request, msgInner, responseHeader, sendMessageContext, ctx, queueIdInt);
}
private RemotingCommand handlePutMessageResult(PutMessageResult putMessageResult, RemotingCommand response,
RemotingCommand request, MessageExt msg,
SendMessageResponseHeader responseHeader, SendMessageContext sendMessageContext, ChannelHandlerContext ctx,
......@@ -434,6 +526,11 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
String owner = request.getExtFields().get(BrokerStatsManager.COMMERCIAL_OWNER);
if (sendOK) {
if (TopicValidator.RMQ_SYS_SCHEDULE_TOPIC.equals(msg.getTopic())) {
this.brokerController.getBrokerStatsManager().incQueuePutNums(msg.getTopic(), msg.getQueueId(), putMessageResult.getAppendMessageResult().getMsgNum(), 1);
this.brokerController.getBrokerStatsManager().incQueuePutSize(msg.getTopic(), msg.getQueueId(), putMessageResult.getAppendMessageResult().getWroteBytes());
}
this.brokerController.getBrokerStatsManager().incTopicPutNums(msg.getTopic(), putMessageResult.getAppendMessageResult().getMsgNum(), 1);
this.brokerController.getBrokerStatsManager().incTopicPutSize(msg.getTopic(),
putMessageResult.getAppendMessageResult().getWroteBytes());
......@@ -550,6 +647,7 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
}
}
@Override
public SocketAddress getStoreHost() {
return storeHost;
}
......@@ -587,7 +685,7 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
}
private int randomQueueId(int writeQueueNums) {
return (this.random.nextInt() % 99999999) % writeQueueNums;
return ThreadLocalRandom.current().nextInt(99999999) % writeQueueNums;
}
private RemotingCommand preSend(ChannelHandlerContext ctx, RemotingCommand request,
......
......@@ -17,7 +17,6 @@
package org.apache.rocketmq.broker.transaction;
import io.netty.channel.Channel;
import java.util.Random;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.message.MessageConst;
......@@ -40,7 +39,6 @@ public abstract class AbstractTransactionalMessageCheckListener {
//queue nums of topic TRANS_CHECK_MAX_TIME_TOPIC
protected final static int TCMT_QUEUE_NUMS = 1;
protected final Random random = new Random(System.currentTimeMillis());
private static ExecutorService executorService = new ThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2000), new ThreadFactory() {
@Override
......
......@@ -30,6 +30,8 @@ import org.apache.rocketmq.store.MessageExtBrokerInner;
import org.apache.rocketmq.store.PutMessageResult;
import org.apache.rocketmq.store.PutMessageStatus;
import java.util.concurrent.ThreadLocalRandom;
public class DefaultTransactionalMessageCheckListener extends AbstractTransactionalMessageCheckListener {
private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.TRANSACTION_LOGGER_NAME);
......@@ -58,7 +60,7 @@ public class DefaultTransactionalMessageCheckListener extends AbstractTransactio
private MessageExtBrokerInner toMessageExtBrokerInner(MessageExt msgExt) {
TopicConfig topicConfig = this.getBrokerController().getTopicConfigManager().createTopicOfTranCheckMaxTime(TCMT_QUEUE_NUMS, PermName.PERM_READ | PermName.PERM_WRITE);
int queueId = Math.abs(random.nextInt() % 99999999) % TCMT_QUEUE_NUMS;
int queueId = ThreadLocalRandom.current().nextInt(99999999) % TCMT_QUEUE_NUMS;
MessageExtBrokerInner inner = new MessageExtBrokerInner();
inner.setTopic(topicConfig.getTopicName());
inner.setBody(msgExt.getBody());
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.broker.processor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeaderV2;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.junit.Assert;
import org.junit.Test;
public class AbstractSendMessageProcessorTest {
@Test
public void testDecodeSendMessageHeaderV2() throws Exception {
Field[] declaredFields = SendMessageRequestHeaderV2.class.getDeclaredFields();
List<Field> declaredFieldsList = new ArrayList<>();
for (Field f : declaredFields) {
if (f.getName().startsWith("$")) {
continue;
}
f.setAccessible(true);
declaredFieldsList.add(f);
}
RemotingCommand command = RemotingCommand.createRequestCommand(0, null);
HashMap<String, String> m = buildExtFields(declaredFieldsList);
command.setExtFields(m);
check(command, declaredFieldsList);
}
private HashMap<String, String> buildExtFields(List<Field> fields) {
HashMap<String, String> extFields = new HashMap<>();
for (Field f: fields) {
Class<?> c = f.getType();
if (c.equals(String.class)) {
extFields.put(f.getName(), "str");
} else if (c.equals(Integer.class) || c.equals(int.class)) {
extFields.put(f.getName(), "123");
} else if (c.equals(Long.class) || c.equals(long.class)) {
extFields.put(f.getName(), "1234");
} else if (c.equals(Boolean.class) || c.equals(boolean.class)) {
extFields.put(f.getName(), "true");
} else {
throw new RuntimeException(f.getName() + ":" + f.getType().getName());
}
}
return extFields;
}
private void check(RemotingCommand command, List<Field> fields) throws Exception {
SendMessageRequestHeaderV2 o1 = (SendMessageRequestHeaderV2) command.decodeCommandCustomHeader(SendMessageRequestHeaderV2.class);
SendMessageRequestHeaderV2 o2 = AbstractSendMessageProcessor.decodeSendMessageHeaderV2(command);
for (Field f : fields) {
Object value1 = f.get(o1);
Object value2 = f.get(o2);
if (value1 == null) {
Assert.assertNull(value2);
} else {
Assert.assertEquals(value1, value2);
}
}
}
}
......@@ -60,10 +60,6 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>io.opentracing</groupId>
<artifactId>opentracing-api</artifactId>
......
......@@ -60,6 +60,8 @@ public class ClientConfig {
private boolean useTLS = TlsSystemConfig.tlsEnable;
private int mqClientApiTimeout = 3 * 1000;
private LanguageCode language = LanguageCode.JAVA;
public String buildMQClientId() {
......@@ -178,7 +180,7 @@ public class ClientConfig {
}
public String getNamesrvAddr() {
if (StringUtils.isNotEmpty(namesrvAddr) && NameServerAddressUtils.validateInstanceEndpoint(namesrvAddr.trim())) {
if (StringUtils.isNotEmpty(namesrvAddr) && NameServerAddressUtils.NAMESRV_ENDPOINT_PATTERN.matcher(namesrvAddr.trim()).matches()) {
return NameServerAddressUtils.getNameSrvAddrFromNamesrvEndpoint(namesrvAddr);
}
return namesrvAddr;
......@@ -298,6 +300,13 @@ public class ClientConfig {
this.accessChannel = accessChannel;
}
public int getMqClientApiTimeout() {
return mqClientApiTimeout;
}
public void setMqClientApiTimeout(int mqClientApiTimeout) {
this.mqClientApiTimeout = mqClientApiTimeout;
}
@Override
public String toString() {
......@@ -305,6 +314,6 @@ public class ClientConfig {
+ ", clientCallbackExecutorThreads=" + clientCallbackExecutorThreads + ", pollNameServerInterval=" + pollNameServerInterval
+ ", heartbeatBrokerInterval=" + heartbeatBrokerInterval + ", persistConsumerOffsetInterval=" + persistConsumerOffsetInterval
+ ", pullTimeDelayMillsWhenException=" + pullTimeDelayMillsWhenException + ", unitMode=" + unitMode + ", unitName=" + unitName + ", vipChannelEnabled="
+ vipChannelEnabled + ", useTLS=" + useTLS + ", language=" + language.name() + ", namespace=" + namespace + "]";
+ vipChannelEnabled + ", useTLS=" + useTLS + ", language=" + language.name() + ", namespace=" + namespace + ", mqClientApiTimeout=" + mqClientApiTimeout + "]";
}
}
......@@ -535,7 +535,9 @@ public class DefaultLitePullConsumer extends ClientConfig implements LitePullCon
private void setTraceDispatcher() {
if (isEnableMsgTrace()) {
try {
this.traceDispatcher = new AsyncTraceDispatcher(consumerGroup, TraceDispatcher.Type.CONSUME, customizedTraceTopic, null);
AsyncTraceDispatcher traceDispatcher = new AsyncTraceDispatcher(consumerGroup, TraceDispatcher.Type.CONSUME, customizedTraceTopic, null);
traceDispatcher.getTraceProducer().setUseTLS(this.isUseTLS());
this.traceDispatcher = traceDispatcher;
this.defaultLitePullConsumerImpl.registerConsumeMessageHook(
new ConsumeMessageTraceHookImpl(traceDispatcher));
} catch (Throwable e) {
......
......@@ -242,11 +242,11 @@ public class DefaultMQPushConsumer extends ClientConfig implements MQPushConsume
private boolean unitMode = false;
/**
* Max re-consume times. -1 means 16 times.
* </p>
* Max re-consume times.
* In concurrently mode, -1 means 16;
* In orderly mode, -1 means Integer.MAX_VALUE.
*
* If messages are re-consumed more than {@link #maxReconsumeTimes} before success, it's be directed to a deletion
* queue waiting.
* If messages are re-consumed more than {@link #maxReconsumeTimes} before success.
*/
private int maxReconsumeTimes = -1;
......@@ -431,7 +431,15 @@ public class DefaultMQPushConsumer extends ClientConfig implements MQPushConsume
public void createTopic(String key, String newTopic, int queueNum) throws MQClientException {
createTopic(key, withNamespace(newTopic), queueNum, 0);
}
@Override
public void setUseTLS(boolean useTLS) {
super.setUseTLS(useTLS);
if (traceDispatcher != null && traceDispatcher instanceof AsyncTraceDispatcher) {
((AsyncTraceDispatcher) traceDispatcher).getTraceProducer().setUseTLS(useTLS);
}
}
/**
* This method will be removed in a certain version after April 5, 2020, so please do not use this method.
*/
......
......@@ -163,6 +163,8 @@ import org.apache.rocketmq.common.protocol.header.UpdateGlobalWhiteAddrsConfigRe
import org.apache.rocketmq.common.protocol.header.ViewBrokerStatsDataRequestHeader;
import org.apache.rocketmq.common.protocol.header.ViewMessageRequestHeader;
import org.apache.rocketmq.common.protocol.header.filtersrv.RegisterMessageFilterClassRequestHeader;
import org.apache.rocketmq.common.protocol.header.namesrv.AddWritePermOfBrokerRequestHeader;
import org.apache.rocketmq.common.protocol.header.namesrv.AddWritePermOfBrokerResponseHeader;
import org.apache.rocketmq.common.protocol.header.namesrv.DeleteKVConfigRequestHeader;
import org.apache.rocketmq.common.protocol.header.namesrv.GetKVConfigRequestHeader;
import org.apache.rocketmq.common.protocol.header.namesrv.GetKVConfigResponseHeader;
......@@ -370,8 +372,8 @@ public class MQClientAPIImpl {
requestHeader.setDefaultGroupPerm(plainAccessConfig.getDefaultGroupPerm());
requestHeader.setDefaultTopicPerm(plainAccessConfig.getDefaultTopicPerm());
requestHeader.setWhiteRemoteAddress(plainAccessConfig.getWhiteRemoteAddress());
requestHeader.setTopicPerms(UtilAll.list2String(plainAccessConfig.getTopicPerms(), ","));
requestHeader.setGroupPerms(UtilAll.list2String(plainAccessConfig.getGroupPerms(), ","));
requestHeader.setTopicPerms(UtilAll.join(plainAccessConfig.getTopicPerms(), ","));
requestHeader.setGroupPerms(UtilAll.join(plainAccessConfig.getGroupPerms(), ","));
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UPDATE_AND_CREATE_ACL_CONFIG, requestHeader);
......@@ -1736,6 +1738,28 @@ public class MQClientAPIImpl {
throw new MQClientException(response.getCode(), response.getRemark());
}
public int addWritePermOfBroker(final String nameSrvAddr, String brokerName, final long timeoutMillis)
throws RemotingCommandException,
RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, InterruptedException, MQClientException {
AddWritePermOfBrokerRequestHeader requestHeader = new AddWritePermOfBrokerRequestHeader();
requestHeader.setBrokerName(brokerName);
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.ADD_WRITE_PERM_OF_BROKER, requestHeader);
RemotingCommand response = this.remotingClient.invokeSync(nameSrvAddr, request, timeoutMillis);
assert response != null;
switch (response.getCode()) {
case ResponseCode.SUCCESS: {
AddWritePermOfBrokerResponseHeader responseHeader =
(AddWritePermOfBrokerResponseHeader) response.decodeCommandCustomHeader(AddWritePermOfBrokerResponseHeader.class);
return responseHeader.getAddTopicCount();
}
default:
break;
}
throw new MQClientException(response.getCode(), response.getRemark());
}
public void deleteTopicInBroker(final String addr, final String topic, final long timeoutMillis)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
DeleteTopicRequestHeader requestHeader = new DeleteTopicRequestHeader();
......
......@@ -109,32 +109,12 @@ public class ConsumeMessageConcurrentlyService implements ConsumeMessageService
@Override
public void incCorePoolSize() {
// long corePoolSize = this.consumeExecutor.getCorePoolSize();
// if (corePoolSize < this.defaultMQPushConsumer.getConsumeThreadMax())
// {
// this.consumeExecutor.setCorePoolSize(this.consumeExecutor.getCorePoolSize()
// + 1);
// }
// log.info("incCorePoolSize Concurrently from {} to {}, ConsumerGroup:
// {}",
// corePoolSize,
// this.consumeExecutor.getCorePoolSize(),
// this.consumerGroup);
}
@Override
public void decCorePoolSize() {
// long corePoolSize = this.consumeExecutor.getCorePoolSize();
// if (corePoolSize > this.defaultMQPushConsumer.getConsumeThreadMin())
// {
// this.consumeExecutor.setCorePoolSize(this.consumeExecutor.getCorePoolSize()
// - 1);
// }
// log.info("decCorePoolSize Concurrently from {} to {}, ConsumerGroup:
// {}",
// corePoolSize,
// this.consumeExecutor.getCorePoolSize(),
// this.consumerGroup);
}
@Override
......@@ -417,11 +397,11 @@ public class ConsumeMessageConcurrentlyService implements ConsumeMessageService
}
status = listener.consumeMessage(Collections.unmodifiableList(msgs), context);
} catch (Throwable e) {
log.warn("consumeMessage exception: {} Group: {} Msgs: {} MQ: {}",
log.warn(String.format("consumeMessage exception: %s Group: %s Msgs: %s MQ: %s",
RemotingHelper.exceptionSimpleDesc(e),
ConsumeMessageConcurrentlyService.this.consumerGroup,
msgs,
messageQueue);
messageQueue), e);
hasException = true;
}
long consumeRT = System.currentTimeMillis() - beginTimestamp;
......
......@@ -493,11 +493,11 @@ public class ConsumeMessageOrderlyService implements ConsumeMessageService {
status = messageListener.consumeMessage(Collections.unmodifiableList(msgs), context);
} catch (Throwable e) {
log.warn("consumeMessage exception: {} Group: {} Msgs: {} MQ: {}",
log.warn(String.format("consumeMessage exception: %s Group: %s Msgs: %s MQ: %s",
RemotingHelper.exceptionSimpleDesc(e),
ConsumeMessageOrderlyService.this.consumerGroup,
msgs,
messageQueue);
messageQueue), e);
hasException = true;
} finally {
this.processQueue.getConsumeLock().unlock();
......
......@@ -100,7 +100,7 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner {
private static final String NOT_RUNNING_EXCEPTION_MESSAGE = "The consumer not running, please start it first.";
private static final String SUBSCRIPTION_CONFILCT_EXCEPTION_MESSAGE = "Subscribe and assign are mutually exclusive.";
private static final String SUBSCRIPTION_CONFLICT_EXCEPTION_MESSAGE = "Subscribe and assign are mutually exclusive.";
/**
* the type of subscription
*/
......@@ -198,8 +198,9 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner {
}
private void checkServiceState() {
if (this.serviceState != ServiceState.RUNNING)
if (this.serviceState != ServiceState.RUNNING) {
throw new IllegalStateException(NOT_RUNNING_EXCEPTION_MESSAGE);
}
}
public void updateNameServerAddr(String newAddresses) {
......@@ -207,10 +208,11 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner {
}
private synchronized void setSubscriptionType(SubscriptionType type) {
if (this.subscriptionType == SubscriptionType.NONE)
if (this.subscriptionType == SubscriptionType.NONE) {
this.subscriptionType = type;
else if (this.subscriptionType != type)
throw new IllegalStateException(SUBSCRIPTION_CONFILCT_EXCEPTION_MESSAGE);
} else if (this.subscriptionType != type) {
throw new IllegalStateException(SUBSCRIPTION_CONFLICT_EXCEPTION_MESSAGE);
}
}
private void updateAssignedMessageQueue(String topic, Set<MessageQueue> assignedMessageQueue) {
......@@ -470,7 +472,7 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner {
public synchronized void subscribe(String topic, String subExpression) throws MQClientException {
try {
if (topic == null || topic.equals("")) {
if (topic == null || "".equals(topic)) {
throw new IllegalArgumentException("Topic can not be null or empty.");
}
setSubscriptionType(SubscriptionType.SUBSCRIBE);
......@@ -489,7 +491,7 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner {
public synchronized void subscribe(String topic, MessageSelector messageSelector) throws MQClientException {
try {
if (topic == null || topic.equals("")) {
if (topic == null || "".equals(topic)) {
throw new IllegalArgumentException("Topic can not be null or empty.");
}
setSubscriptionType(SubscriptionType.SUBSCRIBE);
......@@ -539,8 +541,9 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner {
public synchronized List<MessageExt> poll(long timeout) {
try {
checkServiceState();
if (timeout < 0)
if (timeout < 0) {
throw new IllegalArgumentException("Timeout must not be negative");
}
if (defaultLitePullConsumer.isAutoCommit()) {
maybeAutoCommit();
......@@ -552,8 +555,9 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner {
if (endTime - System.currentTimeMillis() > 0) {
while (consumeRequest != null && consumeRequest.getProcessQueue().isDropped()) {
consumeRequest = consumeRequestCache.poll(endTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
if (endTime - System.currentTimeMillis() <= 0)
if (endTime - System.currentTimeMillis() <= 0) {
break;
}
}
}
......@@ -595,8 +599,19 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner {
}
final Object objLock = messageQueueLock.fetchLockObject(messageQueue);
synchronized (objLock) {
assignedMessageQueue.setSeekOffset(messageQueue, offset);
clearMessageQueueInCache(messageQueue);
PullTaskImpl oldPullTaskImpl = this.taskTable.get(messageQueue);
if (oldPullTaskImpl != null) {
oldPullTaskImpl.tryInterrupt();
this.taskTable.remove(messageQueue);
}
assignedMessageQueue.setSeekOffset(messageQueue, offset);
if (!this.taskTable.containsKey(messageQueue)) {
PullTaskImpl pullTask = new PullTaskImpl(messageQueue);
this.taskTable.put(messageQueue, pullTask);
this.scheduledThreadPoolExecutor.schedule(pullTask, 0, TimeUnit.MILLISECONDS);
}
}
}
......@@ -677,8 +692,9 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner {
public long committed(MessageQueue messageQueue) throws MQClientException {
checkServiceState();
long offset = this.offsetStore.readOffset(messageQueue, ReadOffsetType.MEMORY_FIRST_THEN_STORE);
if (offset == -2)
if (offset == -2) {
throw new MQClientException("Fetch consume offset from broker exception", null);
}
return offset;
}
......@@ -689,8 +705,9 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner {
}
Iterator<ConsumeRequest> iter = consumeRequestCache.iterator();
while (iter.hasNext()) {
if (iter.next().getMessageQueue().equals(messageQueue))
if (iter.next().getMessageQueue().equals(messageQueue)) {
iter.remove();
}
}
}
......@@ -718,16 +735,29 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner {
public class PullTaskImpl implements Runnable {
private final MessageQueue messageQueue;
private volatile boolean cancelled = false;
private Thread currentThread;
public PullTaskImpl(final MessageQueue messageQueue) {
this.messageQueue = messageQueue;
}
public void tryInterrupt() {
setCancelled(true);
if (currentThread == null) {
return;
}
if (!currentThread.isInterrupted()) {
currentThread.interrupt();
}
}
@Override
public void run() {
if (!this.isCancelled()) {
this.currentThread = Thread.currentThread();
if (assignedMessageQueue.isPaused(messageQueue)) {
scheduledThreadPoolExecutor.schedule(this, PULL_TIME_DELAY_MILLS_WHEN_PAUSE, TimeUnit.MILLISECONDS);
log.debug("Message Queue: {} has been paused!", messageQueue);
......@@ -741,10 +771,11 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner {
return;
}
if (consumeRequestCache.size() * defaultLitePullConsumer.getPullBatchSize() > defaultLitePullConsumer.getPullThresholdForAll()) {
if ((long) consumeRequestCache.size() * defaultLitePullConsumer.getPullBatchSize() > defaultLitePullConsumer.getPullThresholdForAll()) {
scheduledThreadPoolExecutor.schedule(this, PULL_TIME_DELAY_MILLS_WHEN_FLOW_CONTROL, TimeUnit.MILLISECONDS);
if ((consumeRequestFlowControlTimes++ % 1000) == 0)
if ((consumeRequestFlowControlTimes++ % 1000) == 0) {
log.warn("The consume request count exceeds threshold {}, so do flow control, consume request count={}, flowControlTimes={}", consumeRequestCache.size(), consumeRequestFlowControlTimes);
}
return;
}
......@@ -784,7 +815,7 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner {
long offset = 0L;
try {
offset = nextPullOffset(messageQueue);
} catch (MQClientException e) {
} catch (Exception e) {
log.error("Failed to get next pull offset", e);
scheduledThreadPoolExecutor.schedule(this, PULL_TIME_DELAY_MILLS_ON_EXCEPTION, TimeUnit.MILLISECONDS);
return;
......@@ -796,11 +827,10 @@ public class DefaultLitePullConsumerImpl implements MQConsumerInner {
long pullDelayTimeMills = 0;
try {
SubscriptionData subscriptionData;
String topic = this.messageQueue.getTopic();
if (subscriptionType == SubscriptionType.SUBSCRIBE) {
String topic = this.messageQueue.getTopic();
subscriptionData = rebalanceImpl.getSubscriptionInner().get(topic);
} else {
String topic = this.messageQueue.getTopic();
subscriptionData = FilterAPI.buildSubscriptionData(topic, SubscriptionData.SUB_ALL);
}
......
......@@ -297,7 +297,7 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner {
long offset = -1L;
try {
offset = this.rebalanceImpl.computePullFromWhereWithException(pullRequest.getMessageQueue());
} catch (MQClientException e) {
} catch (Exception e) {
this.executePullRequestLater(pullRequest, pullTimeDelayMillsWhenException);
log.error("Failed to compute pull offset, pullResult: {}", pullRequest, e);
return;
......
......@@ -696,7 +696,7 @@ public abstract class RebalanceImpl {
long nextOffset = -1L;
try {
nextOffset = this.computePullFromWhereWithException(mq);
} catch (MQClientException e) {
} catch (Exception e) {
log.info("doRebalance, {}, compute offset failed, {}", consumerGroup, mq);
continue;
}
......
......@@ -102,7 +102,8 @@ public class RebalanceLitePullImpl extends RebalanceImpl {
try {
result = this.mQClientFactory.getMQAdminImpl().maxOffset(mq);
} catch (MQClientException e) {
result = -1;
log.warn("Compute consume offset from last offset exception, mq={}, exception={}", mq, e);
throw e;
}
}
} else {
......
......@@ -499,7 +499,7 @@ public class MQClientInstance {
if (addr != null) {
try {
this.getMQClientAPIImpl().checkClientInBroker(
addr, entry.getKey(), this.clientId, subscriptionData, 3 * 1000
addr, entry.getKey(), this.clientId, subscriptionData, clientConfig.getMqClientApiTimeout()
);
} catch (Exception e) {
if (e instanceof MQClientException) {
......@@ -606,7 +606,7 @@ public class MQClientInstance {
}
try {
int version = this.mQClientAPIImpl.sendHearbeat(addr, heartbeatData, 3000);
int version = this.mQClientAPIImpl.sendHearbeat(addr, heartbeatData, clientConfig.getMqClientApiTimeout());
if (!this.brokerVersionTable.containsKey(brokerName)) {
this.brokerVersionTable.put(brokerName, new HashMap<String, Integer>(4));
}
......@@ -667,7 +667,7 @@ public class MQClientInstance {
TopicRouteData topicRouteData;
if (isDefault && defaultMQProducer != null) {
topicRouteData = this.mQClientAPIImpl.getDefaultTopicRouteInfoFromNameServer(defaultMQProducer.getCreateTopicKey(),
1000 * 3);
clientConfig.getMqClientApiTimeout());
if (topicRouteData != null) {
for (QueueData data : topicRouteData.getQueueDatas()) {
int queueNums = Math.min(defaultMQProducer.getDefaultTopicQueueNums(), data.getReadQueueNums());
......@@ -676,7 +676,7 @@ public class MQClientInstance {
}
}
} else {
topicRouteData = this.mQClientAPIImpl.getTopicRouteInfoFromNameServer(topic, 1000 * 3, true, logicalQueueIdsFilter);
topicRouteData = this.mQClientAPIImpl.getTopicRouteInfoFromNameServer(topic, clientConfig.getMqClientApiTimeout(), true, logicalQueueIdsFilter);
}
if (topicRouteData != null) {
TopicRouteData old = this.topicRouteTable.get(topic);
......@@ -950,7 +950,7 @@ public class MQClientInstance {
}
}
public boolean registerConsumer(final String group, final MQConsumerInner consumer) {
public synchronized boolean registerConsumer(final String group, final MQConsumerInner consumer) {
if (null == group || null == consumer) {
return false;
}
......@@ -964,27 +964,9 @@ public class MQClientInstance {
return true;
}
public void unregisterConsumer(final String group) {
public synchronized void unregisterConsumer(final String group) {
this.consumerTable.remove(group);
this.unregisterClientWithLock(null, group);
}
private void unregisterClientWithLock(final String producerGroup, final String consumerGroup) {
try {
if (this.lockHeartbeat.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
try {
this.unregisterClient(producerGroup, consumerGroup);
} catch (Exception e) {
log.error("unregisterClient exception", e);
} finally {
this.lockHeartbeat.unlock();
}
} else {
log.warn("lock heartBeat, but failed. [{}]", this.clientId);
}
} catch (InterruptedException e) {
log.warn("unregisterClientWithLock exception", e);
}
this.unregisterClient(null, group);
}
private void unregisterClient(final String producerGroup, final String consumerGroup) {
......@@ -999,7 +981,7 @@ public class MQClientInstance {
String addr = entry1.getValue();
if (addr != null) {
try {
this.mQClientAPIImpl.unregisterClient(addr, this.clientId, producerGroup, consumerGroup, 3000);
this.mQClientAPIImpl.unregisterClient(addr, this.clientId, producerGroup, consumerGroup, clientConfig.getMqClientApiTimeout());
log.info("unregister client[Producer: {} Consumer: {}] from broker[{} {} {}] success", producerGroup, consumerGroup, brokerName, entry1.getKey(), addr);
} catch (RemotingException e) {
log.error("unregister client exception from broker: " + addr, e);
......@@ -1014,7 +996,7 @@ public class MQClientInstance {
}
}
public boolean registerProducer(final String group, final DefaultMQProducerImpl producer) {
public synchronized boolean registerProducer(final String group, final DefaultMQProducerImpl producer) {
if (null == group || null == producer) {
return false;
}
......@@ -1028,9 +1010,9 @@ public class MQClientInstance {
return true;
}
public void unregisterProducer(final String group) {
public synchronized void unregisterProducer(final String group) {
this.producerTable.remove(group);
this.unregisterClientWithLock(group, null);
this.unregisterClient(group, null);
}
public boolean registerAdminExt(final String group, final MQAdminExtInner admin) {
......@@ -1182,7 +1164,7 @@ public class MQClientInstance {
if (null != brokerAddr) {
try {
return this.mQClientAPIImpl.getConsumerIdListByGroup(brokerAddr, group, 3000);
return this.mQClientAPIImpl.getConsumerIdListByGroup(brokerAddr, group, clientConfig.getMqClientApiTimeout());
} catch (Exception e) {
log.warn("getConsumerIdListByGroup exception, " + brokerAddr + " " + group, e);
}
......
......@@ -28,14 +28,14 @@ import java.util.List;
import java.util.Locale;
import java.util.Random;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
......@@ -88,7 +88,6 @@ import org.apache.rocketmq.common.message.MessageId;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.common.message.MessageType;
import org.apache.rocketmq.common.protocol.NamespaceUtil;
import org.apache.rocketmq.common.protocol.ResponseCode;
import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader;
import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader;
import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader;
......@@ -118,7 +117,12 @@ public class DefaultMQProducerImpl implements MQProducerInner {
private final RPCHook rpcHook;
private final BlockingQueue<Runnable> asyncSenderThreadPoolQueue;
private final ExecutorService defaultAsyncSenderExecutor;
private final Timer timer = new Timer("RequestHouseKeepingService", true);
private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "RequestHouseKeepingService");
}
});
protected BlockingQueue<Runnable> checkRequestQueue;
protected ExecutorService checkExecutor;
private ServiceState serviceState = ServiceState.CREATE_JUST;
......@@ -238,16 +242,23 @@ public class DefaultMQProducerImpl implements MQProducerInner {
this.mQClientFactory.sendHeartbeatToAllBrokerWithLock();
this.timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
try {
RequestFutureTable.scanExpiredRequest();
} catch (Throwable e) {
log.error("scan RequestFutureTable exception", e);
this.startScheduledTask();
}
private void startScheduledTask() {
if (RequestFutureTable.getProducerNum().incrementAndGet() == 1) {
this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
RequestFutureTable.scanExpiredRequest();
} catch (Throwable e) {
log.error("scan RequestFutureTable exception", e);
}
}
}
}, 1000 * 3, 1000);
}, 1000 * 3, 1000, TimeUnit.MILLISECONDS);
}
}
private void checkConfig() throws MQClientException {
......@@ -277,7 +288,9 @@ public class DefaultMQProducerImpl implements MQProducerInner {
if (shutdownFactory) {
this.mQClientFactory.shutdown();
}
this.timer.cancel();
if (RequestFutureTable.getProducerNum().decrementAndGet() == 0) {
scheduledExecutorService.shutdown();
}
log.info("the producer [{}] shutdown OK", this.defaultMQProducer.getProducerGroup());
this.serviceState = ServiceState.SHUTDOWN_ALREADY;
break;
......@@ -640,20 +653,14 @@ public class DefaultMQProducerImpl implements MQProducerInner {
log.warn(String.format("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e);
log.warn(msg.toString());
exception = e;
switch (e.getResponseCode()) {
case ResponseCode.TOPIC_NOT_EXIST:
case ResponseCode.SERVICE_NOT_AVAILABLE:
case ResponseCode.SYSTEM_ERROR:
case ResponseCode.NO_PERMISSION:
case ResponseCode.NO_BUYER_ID:
case ResponseCode.NOT_IN_CURRENT_UNIT:
continue;
default:
if (sendResult != null) {
return sendResult;
}
if (this.defaultMQProducer.getRetryResponseCodes().contains(e.getResponseCode())) {
continue;
} else {
if (sendResult != null) {
return sendResult;
}
throw e;
throw e;
}
} catch (InterruptedException e) {
endTimestamp = System.currentTimeMillis();
......
......@@ -16,8 +16,11 @@
*/
package org.apache.rocketmq.client.producer;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService;
import org.apache.rocketmq.client.ClientConfig;
import org.apache.rocketmq.client.QueryResult;
......@@ -39,6 +42,7 @@ import org.apache.rocketmq.common.message.MessageDecoder;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageId;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.common.protocol.ResponseCode;
import org.apache.rocketmq.common.topic.TopicValidator;
import org.apache.rocketmq.logging.InternalLogger;
import org.apache.rocketmq.remoting.RPCHook;
......@@ -63,6 +67,15 @@ public class DefaultMQProducer extends ClientConfig implements MQProducer {
*/
protected final transient DefaultMQProducerImpl defaultMQProducerImpl;
private final InternalLogger log = ClientLogger.getLog();
private final Set<Integer> retryResponseCodes = new CopyOnWriteArraySet<Integer>(Arrays.asList(
ResponseCode.TOPIC_NOT_EXIST,
ResponseCode.SERVICE_NOT_AVAILABLE,
ResponseCode.SYSTEM_ERROR,
ResponseCode.NO_PERMISSION,
ResponseCode.NO_BUYER_ID,
ResponseCode.NOT_IN_CURRENT_UNIT
));
/**
* Producer group conceptually aggregates all producer instances of exactly same role, which is particularly
* important when transactional messages are involved. </p>
......@@ -158,22 +171,7 @@ public class DefaultMQProducer extends ClientConfig implements MQProducer {
*/
public DefaultMQProducer(final String producerGroup, RPCHook rpcHook, boolean enableMsgTrace,
final String customizedTraceTopic) {
this.producerGroup = producerGroup;
defaultMQProducerImpl = new DefaultMQProducerImpl(this, rpcHook);
//if client open the message trace feature
if (enableMsgTrace) {
try {
AsyncTraceDispatcher dispatcher = new AsyncTraceDispatcher(producerGroup, TraceDispatcher.Type.PRODUCE, customizedTraceTopic, rpcHook);
dispatcher.setHostProducer(this.defaultMQProducerImpl);
traceDispatcher = dispatcher;
this.defaultMQProducerImpl.registerSendMessageHook(
new SendMessageTraceHookImpl(traceDispatcher));
this.defaultMQProducerImpl.registerEndTransactionHook(
new EndTransactionTraceHookImpl(traceDispatcher));
} catch (Throwable e) {
log.error("system mqtrace hook init failed ,maybe can't send msg trace data");
}
}
this(null, producerGroup, rpcHook, enableMsgTrace, customizedTraceTopic);
}
/**
......@@ -251,9 +249,9 @@ public class DefaultMQProducer extends ClientConfig implements MQProducer {
if (enableMsgTrace) {
try {
AsyncTraceDispatcher dispatcher = new AsyncTraceDispatcher(producerGroup, TraceDispatcher.Type.PRODUCE, customizedTraceTopic, rpcHook);
dispatcher.setHostProducer(this.getDefaultMQProducerImpl());
dispatcher.setHostProducer(this.defaultMQProducerImpl);
traceDispatcher = dispatcher;
this.getDefaultMQProducerImpl().registerSendMessageHook(
this.defaultMQProducerImpl.registerSendMessageHook(
new SendMessageTraceHookImpl(traceDispatcher));
this.defaultMQProducerImpl.registerEndTransactionHook(
new EndTransactionTraceHookImpl(traceDispatcher));
......@@ -263,6 +261,14 @@ public class DefaultMQProducer extends ClientConfig implements MQProducer {
}
}
@Override
public void setUseTLS(boolean useTLS) {
super.setUseTLS(useTLS);
if (traceDispatcher != null && traceDispatcher instanceof AsyncTraceDispatcher) {
((AsyncTraceDispatcher) traceDispatcher).getTraceProducer().setUseTLS(useTLS);
}
}
/**
* Start this producer instance. </p>
*
......@@ -965,6 +971,15 @@ public class DefaultMQProducer extends ClientConfig implements MQProducer {
this.defaultMQProducerImpl.setAsyncSenderExecutor(asyncSenderExecutor);
}
/**
* Add response code for retrying.
*
* @param responseCode response code, {@link ResponseCode}
*/
public void addRetryResponseCode(int responseCode) {
this.retryResponseCodes.add(responseCode);
}
private MessageBatch batch(Collection<Message> msgs) throws MQClientException {
MessageBatch msgBatch;
try {
......@@ -1095,4 +1110,7 @@ public class DefaultMQProducer extends ClientConfig implements MQProducer {
return traceDispatcher;
}
public Set<Integer> getRetryResponseCodes() {
return retryResponseCodes;
}
}
......@@ -22,6 +22,8 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.rocketmq.client.common.ClientErrorCode;
import org.apache.rocketmq.client.exception.RequestTimeoutException;
import org.apache.rocketmq.client.log.ClientLogger;
......@@ -30,6 +32,7 @@ import org.apache.rocketmq.logging.InternalLogger;
public class RequestFutureTable {
private static InternalLogger log = ClientLogger.getLog();
private static ConcurrentHashMap<String, RequestResponseFuture> requestFutureTable = new ConcurrentHashMap<String, RequestResponseFuture>();
private static final AtomicInteger PRODUCER_NUM = new AtomicInteger(0);
public static ConcurrentHashMap<String, RequestResponseFuture> getRequestFutureTable() {
return requestFutureTable;
......@@ -59,4 +62,8 @@ public class RequestFutureTable {
}
}
}
public static AtomicInteger getProducerNum() {
return PRODUCER_NUM;
}
}
......@@ -16,7 +16,6 @@
*/
package org.apache.rocketmq.client.trace;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
......@@ -28,7 +27,9 @@ import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.AccessChannel;
import org.apache.rocketmq.client.common.ThreadLocalIndex;
......@@ -54,6 +55,7 @@ import static org.apache.rocketmq.client.trace.TraceConstants.TRACE_INSTANCE_NAM
public class AsyncTraceDispatcher implements TraceDispatcher {
private final static InternalLogger log = ClientLogger.getLog();
private final static AtomicInteger COUNTER = new AtomicInteger();
private final int queueSize;
private final int batchSize;
private final int maxMsgSize;
......@@ -62,7 +64,7 @@ public class AsyncTraceDispatcher implements TraceDispatcher {
// The last discard number of log
private AtomicLong discardCount;
private Thread worker;
private ArrayBlockingQueue<TraceContext> traceContextQueue;
private final ArrayBlockingQueue<TraceContext> traceContextQueue;
private ArrayBlockingQueue<Runnable> appenderQueue;
private volatile Thread shutDownHook;
private volatile boolean stopped = false;
......@@ -76,7 +78,7 @@ public class AsyncTraceDispatcher implements TraceDispatcher {
private String group;
private Type type;
public AsyncTraceDispatcher(String group, Type type,String traceTopicName, RPCHook rpcHook) {
public AsyncTraceDispatcher(String group, Type type, String traceTopicName, RPCHook rpcHook) {
// queueSize is greater than or equal to the n power of 2 of value
this.queueSize = 2048;
this.batchSize = 100;
......@@ -93,12 +95,12 @@ public class AsyncTraceDispatcher implements TraceDispatcher {
this.traceTopicName = TopicValidator.RMQ_SYS_TRACE_TOPIC;
}
this.traceExecutor = new ThreadPoolExecutor(//
10, //
20, //
1000 * 60, //
TimeUnit.MILLISECONDS, //
this.appenderQueue, //
new ThreadFactoryImpl("MQTraceSendThread_"));
10, //
20, //
1000 * 60, //
TimeUnit.MILLISECONDS, //
this.appenderQueue, //
new ThreadFactoryImpl("MQTraceSendThread_"));
traceProducer = getAndCreateTraceProducer(rpcHook);
}
......@@ -165,7 +167,7 @@ public class AsyncTraceDispatcher implements TraceDispatcher {
}
private String genGroupNameForTrace() {
return TraceConstants.GROUP_NAME_PREFIX + "-" + this.group + "-" + this.type ;
return TraceConstants.GROUP_NAME_PREFIX + "-" + this.group + "-" + this.type + "-" + COUNTER.incrementAndGet();
}
@Override
......@@ -178,10 +180,15 @@ public class AsyncTraceDispatcher implements TraceDispatcher {
}
@Override
public void flush() throws IOException {
public void flush() {
// The maximum waiting time for refresh,avoid being written all the time, resulting in failure to return.
long end = System.currentTimeMillis() + 500;
while (traceContextQueue.size() > 0 || appenderQueue.size() > 0 && System.currentTimeMillis() <= end) {
while (System.currentTimeMillis() <= end) {
synchronized (traceContextQueue) {
if (traceContextQueue.size() == 0 && appenderQueue.size() == 0) {
break;
}
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
......@@ -194,6 +201,7 @@ public class AsyncTraceDispatcher implements TraceDispatcher {
@Override
public void shutdown() {
this.stopped = true;
flush();
this.traceExecutor.shutdown();
if (isStarted.get()) {
traceProducer.shutdown();
......@@ -210,11 +218,7 @@ public class AsyncTraceDispatcher implements TraceDispatcher {
public void run() {
synchronized (this) {
if (!this.hasShutdown) {
try {
flush();
} catch (IOException e) {
log.error("system MQTrace hook shutdown failed ,maybe loss some trace data");
}
flush();
}
}
}
......@@ -240,25 +244,27 @@ public class AsyncTraceDispatcher implements TraceDispatcher {
public void run() {
while (!stopped) {
List<TraceContext> contexts = new ArrayList<TraceContext>(batchSize);
for (int i = 0; i < batchSize; i++) {
TraceContext context = null;
try {
//get trace data element from blocking Queue — traceContextQueue
context = traceContextQueue.poll(5, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
synchronized (traceContextQueue) {
for (int i = 0; i < batchSize; i++) {
TraceContext context = null;
try {
//get trace data element from blocking Queue - traceContextQueue
context = traceContextQueue.poll(5, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
}
if (context != null) {
contexts.add(context);
} else {
break;
}
}
if (context != null) {
contexts.add(context);
} else {
break;
if (contexts.size() > 0) {
AsyncAppenderRequest request = new AsyncAppenderRequest(contexts);
traceExecutor.submit(request);
} else if (AsyncTraceDispatcher.this.stopped) {
this.stopped = true;
}
}
if (contexts.size() > 0) {
AsyncAppenderRequest request = new AsyncAppenderRequest(contexts);
traceExecutor.submit(request);
} else if (AsyncTraceDispatcher.this.stopped) {
this.stopped = true;
}
}
}
......@@ -350,7 +356,7 @@ public class AsyncTraceDispatcher implements TraceDispatcher {
* Send message trace data
*
* @param keySet the keyset in this batch(including msgId in original message not offsetMsgId)
* @param data the message trace data in this batch
* @param data the message trace data in this batch
*/
private void sendTraceDataByMQ(Set<String> keySet, final String data, String dataTopic, String regionId) {
String traceTopic = traceTopicName;
......
......@@ -191,7 +191,6 @@ public class TraceDataEncoder {
.append(ctx.getContextCode()).append(TraceConstants.CONTENT_SPLITOR)
.append(ctx.getTimeStamp()).append(TraceConstants.CONTENT_SPLITOR)
.append(ctx.getGroupName()).append(TraceConstants.FIELD_SPLITOR);
}
}
break;
......
......@@ -17,9 +17,9 @@
package org.apache.rocketmq.client.trace;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.codec.Charsets;
import org.apache.rocketmq.common.message.MessageExt;
public class TraceView {
......@@ -40,7 +40,7 @@ public class TraceView {
public static List<TraceView> decodeFromTraceTransData(String key, MessageExt messageExt) {
List<TraceView> messageTraceViewList = new ArrayList<TraceView>();
String messageBody = new String(messageExt.getBody(), Charsets.UTF_8);
String messageBody = new String(messageExt.getBody(), StandardCharsets.UTF_8);
if (messageBody == null || messageBody.length() <= 0) {
return messageTraceViewList;
}
......
......@@ -43,6 +43,7 @@ import org.apache.rocketmq.common.PlainAccessConfig;
import org.apache.rocketmq.common.TopicConfig;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageConst;
import org.apache.rocketmq.common.protocol.RequestCode;
import org.apache.rocketmq.common.message.MessageDecoder;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageQueueAssignment;
......@@ -69,6 +70,7 @@ import org.apache.rocketmq.common.protocol.header.QueryConsumerOffsetResponseHea
import org.apache.rocketmq.common.protocol.header.SearchOffsetResponseHeader;
import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader;
import org.apache.rocketmq.common.protocol.header.SendMessageResponseHeader;
import org.apache.rocketmq.common.protocol.header.namesrv.AddWritePermOfBrokerResponseHeader;
import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader;
import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetResponseHeader;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
......@@ -90,6 +92,8 @@ import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import java.lang.reflect.Field;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Fail.failBecauseExceptionWasNotThrown;
import static org.mockito.ArgumentMatchers.any;
......@@ -924,4 +928,27 @@ public class MQClientAPIImplTest {
requestHeader.setMaxReconsumeTimes(10);
return requestHeader;
}
@Test
public void testAddWritePermOfBroker() throws Exception {
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
RemotingCommand request = invocationOnMock.getArgument(1);
if (request.getCode() != RequestCode.ADD_WRITE_PERM_OF_BROKER) {
return null;
}
RemotingCommand response = RemotingCommand.createResponseCommand(AddWritePermOfBrokerResponseHeader.class);
AddWritePermOfBrokerResponseHeader responseHeader = (AddWritePermOfBrokerResponseHeader) response.readCustomHeader();
response.setCode(ResponseCode.SUCCESS);
responseHeader.setAddTopicCount(7);
response.addExtField("addTopicCount", String.valueOf(responseHeader.getAddTopicCount()));
return response;
}
}).when(remotingClient).invokeSync(anyString(), any(RemotingCommand.class), anyLong());
int topicCnt = mqClientAPI.addWritePermOfBroker("127.0.0.1", "default-broker", 1000);
assertThat(topicCnt).isEqualTo(7);
}
}
\ No newline at end of file
......@@ -178,7 +178,7 @@ public class ConsumeMessageConcurrentlyServiceTest {
StatsItemSet itemSet = (StatsItemSet)statItmeSetField.get(mgr);
StatsItem item = itemSet.getAndCreateStatsItem(topic + "@" + pushConsumer.getDefaultMQPushConsumerImpl().groupName());
assertThat(item.getValue().get()).isGreaterThan(0L);
assertThat(item.getValue().sum()).isGreaterThan(0L);
MessageExt msg = messageAtomic.get();
assertThat(msg).isNotNull();
assertThat(msg.getTopic()).isEqualTo(topic);
......
......@@ -69,6 +69,7 @@ import org.apache.rocketmq.common.topic.TopicValidator;
import org.apache.rocketmq.remoting.RPCHook;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
......@@ -237,6 +238,14 @@ public class DefaultMQConsumerWithTraceTest {
assertThat(msg.getTopic()).isEqualTo(topic);
assertThat(msg.getBody()).isEqualTo(new byte[] {'a'});
}
@Test
public void testPushConsumerWithTraceTLS() {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumerGroup", true);
consumer.setUseTLS(true);
AsyncTraceDispatcher asyncTraceDispatcher = (AsyncTraceDispatcher) consumer.getTraceDispatcher();
Assert.assertTrue(asyncTraceDispatcher.getTraceProducer().isUseTLS());
}
private PullRequest createPullRequest() {
PullRequest pullRequest = new PullRequest();
......
......@@ -52,6 +52,7 @@ import org.apache.rocketmq.common.protocol.route.QueueData;
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
import org.apache.rocketmq.common.topic.TopicValidator;
import org.apache.rocketmq.remoting.RPCHook;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
......@@ -146,6 +147,15 @@ public class DefaultMQLitePullConsumerWithTraceTest {
}
}
@Test
public void testLitePullConsumerWithTraceTLS() throws Exception {
DefaultLitePullConsumer consumer = new DefaultLitePullConsumer("consumerGroup");
consumer.setUseTLS(true);
consumer.setEnableMsgTrace(true);
consumer.start();
AsyncTraceDispatcher asyncTraceDispatcher = (AsyncTraceDispatcher) consumer.getTraceDispatcher();
Assert.assertTrue(asyncTraceDispatcher.getTraceProducer().isUseTLS());
}
private DefaultLitePullConsumer createLitePullConsumerWithDefaultTraceTopic() throws Exception {
DefaultLitePullConsumer litePullConsumer = new DefaultLitePullConsumer(consumerGroup + System.currentTimeMillis());
......@@ -302,4 +312,4 @@ public class DefaultMQLitePullConsumerWithTraceTest {
doReturn(false).when(mQClientFactory).updateTopicRouteInfoFromNameServer(anyString());
}
}
\ No newline at end of file
}
......@@ -46,6 +46,7 @@ import org.apache.rocketmq.common.protocol.route.TopicRouteData;
import org.apache.rocketmq.common.topic.TopicValidator;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
......@@ -149,6 +150,15 @@ public class DefaultMQProducerWithTraceTest {
}
@Test
public void testProducerWithTraceTLS() {
DefaultMQProducer producer = new DefaultMQProducer(producerGroupTemp, true);
producer.setUseTLS(true);
AsyncTraceDispatcher asyncTraceDispatcher = (AsyncTraceDispatcher) producer.getTraceDispatcher();
Assert.assertTrue(asyncTraceDispatcher.getTraceProducer().isUseTLS());
}
@After
public void terminate() {
producer.shutdown();
......
......@@ -60,7 +60,6 @@ public class TraceDataEncoderTest {
Assert.assertEquals(contexts.get(0).getTraceType(), TraceType.Pub);
}
@Test
public void testEncoderFromContextBean() {
TraceContext context = new TraceContext();
......@@ -130,4 +129,109 @@ public class TraceDataEncoderTest {
Assert.assertEquals(before.getTransactionState(), after.getTransactionState());
Assert.assertEquals(before.isFromTransactionCheck(), after.isFromTransactionCheck());
}
@Test
public void testPubTraceDataFormatTest() {
TraceContext pubContext = new TraceContext();
pubContext.setTraceType(TraceType.Pub);
pubContext.setTimeStamp(time);
pubContext.setRegionId("Default-region");
pubContext.setGroupName("GroupName-test");
pubContext.setCostTime(34);
pubContext.setSuccess(true);
TraceBean bean = new TraceBean();
bean.setTopic("topic-test");
bean.setMsgId("AC1415116D1418B4AAC217FE1B4E0000");
bean.setTags("tags");
bean.setKeys("keys");
bean.setStoreHost("127.0.0.1:10911");
bean.setBodyLength(100);
bean.setMsgType(MessageType.Normal_Msg);
bean.setOffsetMsgId("AC1415116D1418B4AAC217FE1B4E0000");
pubContext.setTraceBeans(new ArrayList<TraceBean>(1));
pubContext.getTraceBeans().add(bean);
TraceTransferBean traceTransferBean = TraceDataEncoder.encoderFromContextBean(pubContext);
String transData = traceTransferBean.getTransData();
Assert.assertNotNull(transData);
String[] items = transData.split(String.valueOf(TraceConstants.CONTENT_SPLITOR));
Assert.assertEquals(14, items.length);
}
@Test
public void testSubBeforeTraceDataFormatTest() {
TraceContext subBeforeContext = new TraceContext();
subBeforeContext.setTraceType(TraceType.SubBefore);
subBeforeContext.setTimeStamp(time);
subBeforeContext.setRegionId("Default-region");
subBeforeContext.setGroupName("GroupName-test");
subBeforeContext.setRequestId("3455848576927");
TraceBean bean = new TraceBean();
bean.setMsgId("AC1415116D1418B4AAC217FE1B4E0000");
bean.setRetryTimes(0);
bean.setKeys("keys");
subBeforeContext.setTraceBeans(new ArrayList<TraceBean>(1));
subBeforeContext.getTraceBeans().add(bean);
TraceTransferBean traceTransferBean = TraceDataEncoder.encoderFromContextBean(subBeforeContext);
String transData = traceTransferBean.getTransData();
Assert.assertNotNull(transData);
String[] items = transData.split(String.valueOf(TraceConstants.CONTENT_SPLITOR));
Assert.assertEquals(8, items.length);
}
@Test
public void testSubAfterTraceDataFormatTest() {
TraceContext subAfterContext = new TraceContext();
subAfterContext.setTraceType(TraceType.SubAfter);
subAfterContext.setRequestId("3455848576927");
subAfterContext.setCostTime(20);
subAfterContext.setSuccess(true);
subAfterContext.setTimeStamp(1625883640000L);
subAfterContext.setGroupName("GroupName-test");
subAfterContext.setContextCode(98623046);
TraceBean bean = new TraceBean();
bean.setMsgId("AC1415116D1418B4AAC217FE1B4E0000");
bean.setKeys("keys");
subAfterContext.setTraceBeans(new ArrayList<TraceBean>(1));
subAfterContext.getTraceBeans().add(bean);
TraceTransferBean traceTransferBean = TraceDataEncoder.encoderFromContextBean(subAfterContext);
String transData = traceTransferBean.getTransData();
Assert.assertNotNull(transData);
String[] items = transData.split(String.valueOf(TraceConstants.CONTENT_SPLITOR));
Assert.assertEquals(9, items.length);
}
@Test
public void testEndTrxTraceDataFormatTest() {
TraceContext endTrxContext = new TraceContext();
endTrxContext.setTraceType(TraceType.EndTransaction);
endTrxContext.setGroupName("PID-test");
endTrxContext.setRegionId("DefaultRegion");
endTrxContext.setTimeStamp(time);
TraceBean endTrxTraceBean = new TraceBean();
endTrxTraceBean.setTopic("topic-test");
endTrxTraceBean.setKeys("Keys");
endTrxTraceBean.setTags("Tags");
endTrxTraceBean.setMsgId("AC1415116D1418B4AAC217FE1B4E0000");
endTrxTraceBean.setStoreHost("127.0.0.1:10911");
endTrxTraceBean.setMsgType(MessageType.Trans_msg_Commit);
endTrxTraceBean.setTransactionId("transactionId");
endTrxTraceBean.setTransactionState(LocalTransactionState.COMMIT_MESSAGE);
endTrxTraceBean.setFromTransactionCheck(false);
List<TraceBean> traceBeans = new ArrayList<TraceBean>();
traceBeans.add(endTrxTraceBean);
endTrxContext.setTraceBeans(traceBeans);
TraceTransferBean traceTransferBean = TraceDataEncoder.encoderFromContextBean(endTrxContext);
String transData = traceTransferBean.getTransData();
Assert.assertNotNull(transData);
String[] items = transData.split(String.valueOf(TraceConstants.CONTENT_SPLITOR));
Assert.assertEquals(13, items.length);
}
}
......@@ -17,12 +17,12 @@
package org.apache.rocketmq.client.trace;
import org.apache.commons.codec.Charsets;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageType;
import org.junit.Assert;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
import java.util.List;
public class TraceViewTest {
......@@ -46,7 +46,7 @@ public class TraceViewTest {
.append(true).append(TraceConstants.FIELD_SPLITOR)
.toString();
MessageExt message = new MessageExt();
message.setBody(messageBody.getBytes(Charsets.UTF_8));
message.setBody(messageBody.getBytes(StandardCharsets.UTF_8));
String key = "AC1415116D1418B4AAC217FE1B4E0000";
List<TraceView> traceViews = TraceView.decodeFromTraceTransData(key, message);
Assert.assertEquals(traceViews.size(), 1);
......
......@@ -58,10 +58,9 @@ public class BrokerConfig {
@ImportantField
private boolean traceTopicEnable = false;
/**
* thread numbers for send message thread pool, since spin lock will be used by default since 4.0.x, the default
* value is 1.
* thread numbers for send message thread pool.
*/
private int sendMessageThreadPoolNums = 1; //16 + Runtime.getRuntime().availableProcessors() * 4;
private int sendMessageThreadPoolNums = Math.min(Runtime.getRuntime().availableProcessors(), 4);
private int pullMessageThreadPoolNums = 16 + Runtime.getRuntime().availableProcessors() * 2;
private int ackMessageThreadPoolNums = 3;
private int processReplyMessageThreadPoolNums = 16 + Runtime.getRuntime().availableProcessors() * 2;
......@@ -76,7 +75,8 @@ public class BrokerConfig {
/**
* Thread numbers for EndTransactionProcessor
*/
private int endTransactionThreadPoolNums = 8 + Runtime.getRuntime().availableProcessors() * 2;
private int endTransactionThreadPoolNums = Math.max(8 + Runtime.getRuntime().availableProcessors() * 2,
sendMessageThreadPoolNums * 4);
private int flushConsumerOffsetInterval = 1000 * 5;
......
......@@ -61,6 +61,7 @@ public class MixAll {
public static final String DEFAULT_PRODUCER_GROUP = "DEFAULT_PRODUCER";
public static final String DEFAULT_CONSUMER_GROUP = "DEFAULT_CONSUMER";
public static final String TOOLS_CONSUMER_GROUP = "TOOLS_CONSUMER";
public static final String SCHEDULE_CONSUMER_GROUP = "SCHEDULE_CONSUMER";
public static final String FILTERSRV_CONSUMER_GROUP = "FILTERSRV_CONSUMER";
public static final String MONITOR_CONSUMER_GROUP = "__MONITOR_CONSUMER";
public static final String CLIENT_INNER_PRODUCER_GROUP = "CLIENT_INNER_PRODUCER";
......
......@@ -39,7 +39,6 @@ import java.util.Map;
import java.util.zip.CRC32;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.validator.routines.InetAddressValidator;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.logging.InternalLogger;
......@@ -218,10 +217,15 @@ public class UtilAll {
long totalSpace = file.getTotalSpace();
if (totalSpace > 0) {
long freeSpace = file.getFreeSpace();
long usedSpace = totalSpace - freeSpace;
return usedSpace / (double) totalSpace;
long usedSpace = totalSpace - file.getFreeSpace();
long usableSpace = file.getUsableSpace();
long entireSpace = usedSpace + usableSpace;
long roundNum = 0;
if (usedSpace * 100 % entireSpace != 0) {
roundNum = 1;
}
long result = usedSpace * 100 / entireSpace + roundNum;
return result / 100.0;
}
} catch (Exception e) {
log.error("Error when measuring disk space usage, got exception: :", e);
......@@ -461,7 +465,7 @@ public class UtilAll {
if (ip.length != 4) {
throw new RuntimeException("illegal ipv4 bytes");
}
InetAddressValidator validator = InetAddressValidator.getInstance();
return validator.isValidInet4Address(ipToIPv4Str(ip));
}
......@@ -561,27 +565,28 @@ public class UtilAll {
}
}
public static String list2String(List<String> list, String splitor) {
if (list == null || list.size() == 0) {
public static String join(List<String> list, String splitter) {
if (list == null) {
return null;
}
StringBuffer str = new StringBuffer();
StringBuilder str = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
str.append(list.get(i));
if (i == list.size() - 1) {
continue;
break;
}
str.append(splitor);
str.append(splitter);
}
return str.toString();
}
public static List<String> string2List(String str, String splitor) {
if (StringUtils.isEmpty(str)) {
public static List<String> split(String str, String splitter) {
if (str == null) {
return null;
}
String[] addrArray = str.split(splitor);
String[] addrArray = str.split(splitter);
return Arrays.asList(addrArray);
}
}
......@@ -43,11 +43,13 @@ public class Message implements Serializable {
this.flag = flag;
this.body = body;
if (tags != null && tags.length() > 0)
if (tags != null && tags.length() > 0) {
this.setTags(tags);
}
if (keys != null && keys.length() > 0)
if (keys != null && keys.length() > 0) {
this.setKeys(keys);
}
this.setWaitStoreMsgOK(waitStoreMsgOK);
}
......@@ -127,7 +129,7 @@ public class Message implements Serializable {
}
public void setKeys(Collection<String> keys) {
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
for (String k : keys) {
sb.append(k);
sb.append(MessageConst.KEY_SEPARATOR);
......@@ -151,8 +153,9 @@ public class Message implements Serializable {
public boolean isWaitStoreMsgOK() {
String result = this.getProperty(MessageConst.PROPERTY_WAIT_STORE_MSG_OK);
if (null == result)
if (null == result) {
return true;
}
return Boolean.parseBoolean(result);
}
......
......@@ -409,7 +409,23 @@ public class MessageDecoder {
}
public static String messageProperties2String(Map<String, String> properties) {
StringBuilder sb = new StringBuilder();
if (properties == null) {
return "";
}
int len = 0;
for (final Map.Entry<String, String> entry : properties.entrySet()) {
final String name = entry.getKey();
final String value = entry.getValue();
if (value == null) {
continue;
}
if (name != null) {
len += name.length();
}
len += value.length();
len += 2; // separator
}
StringBuilder sb = new StringBuilder(len);
if (properties != null) {
for (final Map.Entry<String, String> entry : properties.entrySet()) {
final String name = entry.getKey();
......@@ -423,6 +439,9 @@ public class MessageDecoder {
sb.append(value);
sb.append(PROPERTY_SEPARATOR);
}
if (sb.length() > 0) {
sb.deleteCharAt(sb.length() - 1);
}
}
return sb.toString();
}
......@@ -430,12 +449,22 @@ public class MessageDecoder {
public static Map<String, String> string2messageProperties(final String properties) {
Map<String, String> map = new HashMap<String, String>();
if (properties != null) {
String[] items = properties.split(String.valueOf(PROPERTY_SEPARATOR));
for (String i : items) {
String[] nv = i.split(String.valueOf(NAME_VALUE_SEPARATOR));
if (2 == nv.length) {
map.put(nv[0], nv[1]);
int len = properties.length();
int index = 0;
while (index < len) {
int newIndex = properties.indexOf(PROPERTY_SEPARATOR, index);
if (newIndex < 0) {
newIndex = len;
}
if (newIndex - index >= 3) {
int kvSepIndex = properties.indexOf(NAME_VALUE_SEPARATOR, index);
if (kvSepIndex > index && kvSepIndex < newIndex - 1) {
String k = properties.substring(index, kvSepIndex);
String v = properties.substring(kvSepIndex + 1, newIndex);
map.put(k, v);
}
}
index = newIndex + 1;
}
}
......
......@@ -120,7 +120,7 @@ public class NamespaceUtil {
return null;
}
return new StringBuffer()
return new StringBuilder()
.append(MixAll.RETRY_GROUP_TOPIC_PREFIX)
.append(wrapNamespace(namespace, consumerGroup))
.toString();
......
......@@ -193,6 +193,8 @@ public class RequestCode {
public static final int PUSH_REPLY_MESSAGE_TO_CLIENT = 326;
public static final int ADD_WRITE_PERM_OF_BROKER = 327;
public static final int GET_TOPIC_CONFIG = 351;
public static final int QUERY_ASSIGNMENT = 400;
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.common.protocol.header.namesrv;
import org.apache.rocketmq.remoting.CommandCustomHeader;
import org.apache.rocketmq.remoting.annotation.CFNotNull;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
public class AddWritePermOfBrokerRequestHeader implements CommandCustomHeader {
@CFNotNull
private String brokerName;
@Override
public void checkFields() throws RemotingCommandException {
}
public String getBrokerName() {
return brokerName;
}
public void setBrokerName(String brokerName) {
this.brokerName = brokerName;
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.common.protocol.header.namesrv;
import org.apache.rocketmq.remoting.CommandCustomHeader;
import org.apache.rocketmq.remoting.annotation.CFNotNull;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
public class AddWritePermOfBrokerResponseHeader implements CommandCustomHeader {
@CFNotNull
private Integer addTopicCount;
@Override
public void checkFields() throws RemotingCommandException {
}
public Integer getAddTopicCount() {
return addTopicCount;
}
public void setAddTopicCount(Integer addTopicCount) {
this.addTopicCount = addTopicCount;
}
}
......@@ -21,14 +21,16 @@ import java.util.LinkedList;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import org.apache.rocketmq.common.UtilAll;
import org.apache.rocketmq.logging.InternalLogger;
public class StatsItem {
private final AtomicLong value = new AtomicLong(0);
private final LongAdder value = new LongAdder();
private final AtomicLong times = new AtomicLong(0);
private final LongAdder times = new LongAdder();
private final LinkedList<CallSnapshot> csListMinute = new LinkedList<CallSnapshot>();
......@@ -157,8 +159,8 @@ public class StatsItem {
if (this.csListMinute.size() == 0) {
this.csListMinute.add(new CallSnapshot(System.currentTimeMillis() - 10 * 1000, 0, 0));
}
this.csListMinute.add(new CallSnapshot(System.currentTimeMillis(), this.times.get(), this.value
.get()));
this.csListMinute.add(new CallSnapshot(System.currentTimeMillis(), this.times.sum(), this.value
.sum()));
if (this.csListMinute.size() > 7) {
this.csListMinute.removeFirst();
}
......@@ -170,8 +172,8 @@ public class StatsItem {
if (this.csListHour.size() == 0) {
this.csListHour.add(new CallSnapshot(System.currentTimeMillis() - 10 * 60 * 1000, 0, 0));
}
this.csListHour.add(new CallSnapshot(System.currentTimeMillis(), this.times.get(), this.value
.get()));
this.csListHour.add(new CallSnapshot(System.currentTimeMillis(), this.times.sum(), this.value
.sum()));
if (this.csListHour.size() > 7) {
this.csListHour.removeFirst();
}
......@@ -183,8 +185,8 @@ public class StatsItem {
if (this.csListDay.size() == 0) {
this.csListDay.add(new CallSnapshot(System.currentTimeMillis() - 1 * 60 * 60 * 1000, 0, 0));
}
this.csListDay.add(new CallSnapshot(System.currentTimeMillis(), this.times.get(), this.value
.get()));
this.csListDay.add(new CallSnapshot(System.currentTimeMillis(), this.times.sum(), this.value
.sum()));
if (this.csListDay.size() > 25) {
this.csListDay.removeFirst();
}
......@@ -214,7 +216,7 @@ public class StatsItem {
ss.getAvgpt());
}
public AtomicLong getValue() {
public LongAdder getValue() {
return value;
}
......@@ -226,7 +228,7 @@ public class StatsItem {
return statsName;
}
public AtomicLong getTimes() {
public LongAdder getTimes() {
return times;
}
}
......
......@@ -154,14 +154,14 @@ public class StatsItemSet {
public void addValue(final String statsKey, final int incValue, final int incTimes) {
StatsItem statsItem = this.getAndCreateStatsItem(statsKey);
statsItem.getValue().addAndGet(incValue);
statsItem.getTimes().addAndGet(incTimes);
statsItem.getValue().add(incValue);
statsItem.getTimes().add(incTimes);
}
public void addRTValue(final String statsKey, final int incValue, final int incTimes) {
StatsItem statsItem = this.getAndCreateRTStatsItem(statsKey);
statsItem.getValue().addAndGet(incValue);
statsItem.getTimes().addAndGet(incTimes);
statsItem.getValue().add(incValue);
statsItem.getTimes().add(incTimes);
}
public void delValue(final String statsKey) {
......
......@@ -20,6 +20,7 @@ public class NameServerAddressUtils {
public static final String INSTANCE_PREFIX = "MQ_INST_";
public static final String INSTANCE_REGEX = INSTANCE_PREFIX + "\\w+_\\w+";
public static final String ENDPOINT_PREFIX = "(\\w+://|)";
public static final Pattern NAMESRV_ENDPOINT_PATTERN = Pattern.compile("^http://.*");
public static final Pattern INST_ENDPOINT_PATTERN = Pattern.compile("^" + ENDPOINT_PREFIX + INSTANCE_REGEX + "\\..*");
public static String getNameServerAddresses() {
......
......@@ -19,11 +19,15 @@ package org.apache.rocketmq.common;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.within;
import static org.junit.Assert.assertEquals;
public class UtilAllTest {
......@@ -109,6 +113,15 @@ public class UtilAllTest {
assertThat(UtilAll.ipToIPv6Str(nonInternal.getAddress()).toUpperCase()).isEqualTo("2408:4004:0180:8100:3FAA:1DDE:2B3F:898A");
}
@Test
public void testJoin() {
List<String> list = Arrays.asList("groupA=DENY", "groupB=PUB|SUB", "groupC=SUB");
String comma = ",";
assertEquals("groupA=DENY,groupB=PUB|SUB,groupC=SUB", UtilAll.join(list, comma));
assertEquals(null, UtilAll.join(null, comma));
assertEquals("", UtilAll.join(Collections.emptyList(), comma));
}
static class DemoConfig {
private int demoWidth = 0;
private int demoLength = 0;
......
......@@ -25,6 +25,8 @@ import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.Map;
import static org.apache.rocketmq.common.message.MessageDecoder.NAME_VALUE_SEPARATOR;
import static org.apache.rocketmq.common.message.MessageDecoder.PROPERTY_SEPARATOR;
import static org.apache.rocketmq.common.message.MessageDecoder.createMessageId;
import static org.assertj.core.api.Assertions.assertThat;
......@@ -265,4 +267,110 @@ public class MessageDecoderTest {
}
}
@Test
public void testString2messageProperties() {
StringBuilder sb = new StringBuilder();
sb.append("k1").append(NAME_VALUE_SEPARATOR).append("v1");
Map<String,String> m = MessageDecoder.string2messageProperties(sb.toString());
assertThat(m).size().isEqualTo(1);
assertThat(m.get("k1")).isEqualTo("v1");
m = MessageDecoder.string2messageProperties("");
assertThat(m).size().isEqualTo(0);
m = MessageDecoder.string2messageProperties(" ");
assertThat(m).size().isEqualTo(0);
m = MessageDecoder.string2messageProperties("aaa");
assertThat(m).size().isEqualTo(0);
sb.setLength(0);
sb.append("k1").append(NAME_VALUE_SEPARATOR);
m = MessageDecoder.string2messageProperties(sb.toString());
assertThat(m).size().isEqualTo(0);
sb.setLength(0);
sb.append(NAME_VALUE_SEPARATOR).append("v1");
m = MessageDecoder.string2messageProperties(sb.toString());
assertThat(m).size().isEqualTo(0);
sb.setLength(0);
sb.append("k1").append(NAME_VALUE_SEPARATOR).append("v1").append(PROPERTY_SEPARATOR);
m = MessageDecoder.string2messageProperties(sb.toString());
assertThat(m).size().isEqualTo(1);
assertThat(m.get("k1")).isEqualTo("v1");
sb.setLength(0);
sb.append("k1").append(NAME_VALUE_SEPARATOR).append("v1").append(PROPERTY_SEPARATOR)
.append("k2").append(NAME_VALUE_SEPARATOR).append("v2");
m = MessageDecoder.string2messageProperties(sb.toString());
assertThat(m).size().isEqualTo(2);
assertThat(m.get("k1")).isEqualTo("v1");
assertThat(m.get("k2")).isEqualTo("v2");
sb.setLength(0);
sb.append("k1").append(NAME_VALUE_SEPARATOR).append("v1").append(PROPERTY_SEPARATOR)
.append(NAME_VALUE_SEPARATOR).append("v2");
m = MessageDecoder.string2messageProperties(sb.toString());
assertThat(m).size().isEqualTo(1);
assertThat(m.get("k1")).isEqualTo("v1");
sb.setLength(0);
sb.append("k1").append(NAME_VALUE_SEPARATOR).append("v1").append(PROPERTY_SEPARATOR)
.append("k2").append(NAME_VALUE_SEPARATOR);
m = MessageDecoder.string2messageProperties(sb.toString());
assertThat(m).size().isEqualTo(1);
assertThat(m.get("k1")).isEqualTo("v1");
sb.setLength(0);
sb.append(NAME_VALUE_SEPARATOR).append("v1").append(PROPERTY_SEPARATOR)
.append("k2").append(NAME_VALUE_SEPARATOR).append("v2");
m = MessageDecoder.string2messageProperties(sb.toString());
assertThat(m).size().isEqualTo(1);
assertThat(m.get("k2")).isEqualTo("v2");
sb.setLength(0);
sb.append("k1").append(NAME_VALUE_SEPARATOR).append(PROPERTY_SEPARATOR)
.append("k2").append(NAME_VALUE_SEPARATOR).append("v2");
m = MessageDecoder.string2messageProperties(sb.toString());
assertThat(m).size().isEqualTo(1);
assertThat(m.get("k2")).isEqualTo("v2");
sb.setLength(0);
sb.append("1").append(NAME_VALUE_SEPARATOR).append("1").append(PROPERTY_SEPARATOR)
.append("2").append(NAME_VALUE_SEPARATOR).append("2");
m = MessageDecoder.string2messageProperties(sb.toString());
assertThat(m).size().isEqualTo(2);
assertThat(m.get("1")).isEqualTo("1");
assertThat(m.get("2")).isEqualTo("2");
sb.setLength(0);
sb.append("1").append(NAME_VALUE_SEPARATOR).append(PROPERTY_SEPARATOR)
.append("2").append(NAME_VALUE_SEPARATOR).append("2");
m = MessageDecoder.string2messageProperties(sb.toString());
assertThat(m).size().isEqualTo(1);
assertThat(m.get("2")).isEqualTo("2");
sb.setLength(0);
sb.append(NAME_VALUE_SEPARATOR).append("1").append(PROPERTY_SEPARATOR)
.append("2").append(NAME_VALUE_SEPARATOR).append("2");
m = MessageDecoder.string2messageProperties(sb.toString());
assertThat(m).size().isEqualTo(1);
assertThat(m.get("2")).isEqualTo("2");
sb.setLength(0);
sb.append("1").append(NAME_VALUE_SEPARATOR).append("1").append(PROPERTY_SEPARATOR)
.append("2").append(NAME_VALUE_SEPARATOR);
m = MessageDecoder.string2messageProperties(sb.toString());
assertThat(m).size().isEqualTo(1);
assertThat(m.get("1")).isEqualTo("1");
sb.setLength(0);
sb.append("1").append(NAME_VALUE_SEPARATOR).append("1").append(PROPERTY_SEPARATOR)
.append(NAME_VALUE_SEPARATOR).append("2");
m = MessageDecoder.string2messageProperties(sb.toString());
assertThat(m).size().isEqualTo(1);
assertThat(m.get("1")).isEqualTo("1");
}
}
\ No newline at end of file
......@@ -23,6 +23,8 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import org.apache.rocketmq.common.ThreadFactoryImpl;
import org.junit.After;
import org.junit.Test;
......@@ -95,7 +97,7 @@ public class StatsItemSetTest {
}
}
private AtomicLong test_unit() throws InterruptedException {
private LongAdder test_unit() throws InterruptedException {
final StatsItemSet statsItemSet = new StatsItemSet("topicTest", scheduler, null);
executor = new ThreadPoolExecutor(10, 20, 10, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(100), new ThreadFactoryImpl("testMultiThread"));
......
......@@ -82,7 +82,7 @@ public class IOTinyUtilsTest {
@Test
public void testReadLines() throws Exception {
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++) {
sb.append("testReadLines").append("\n");
}
......@@ -95,7 +95,7 @@ public class IOTinyUtilsTest {
@Test
public void testToBufferedReader() throws Exception {
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++) {
sb.append("testToBufferedReader").append("\n");
}
......
#!/bin/sh
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
sh ./runclass.sh org.apache.rocketmq.example.benchmark.BatchProducer $@ &
......@@ -28,7 +28,7 @@ set CLASSPATH=.;%BASE_DIR%conf;%CLASSPATH%
rem ===========================================================================================
rem JVM Configuration
rem ===========================================================================================
set "JAVA_OPT=%JAVA_OPT% -server -Xms2g -Xmx2g -Xmn1g"
set "JAVA_OPT=%JAVA_OPT% -server -Xms2g -Xmx2g"
set "JAVA_OPT=%JAVA_OPT% -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8"
set "JAVA_OPT=%JAVA_OPT% -verbose:gc -Xloggc:%USERPROFILE%\mq_gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy"
set "JAVA_OPT=%JAVA_OPT% -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m"
......
......@@ -64,7 +64,7 @@ choose_gc_log_directory()
choose_gc_log_directory
JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g -Xmn4g"
JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g"
JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0"
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${GC_LOG_DIR}/rmq_broker_gc_%p_%t.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy"
JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m"
......
......@@ -28,7 +28,7 @@ set CLASSPATH=.;%BASE_DIR%conf;%CLASSPATH%
set "JAVA_OPT=%JAVA_OPT% -server -Xms2g -Xmx2g -Xmn1g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
set "JAVA_OPT=%JAVA_OPT% -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8 -XX:-UseParNewGC"
set "JAVA_OPT=%JAVA_OPT% -verbose:gc -Xloggc:"%USERPROFILE%\rmq_srv_gc.log" -XX:+PrintGCDetails"
set "JAVA_OPT=%JAVA_OPT% -verbose:gc -Xloggc:"%USERPROFILE%\rmq_srv_gc.log" -XX:+PrintGCDetails -XX:+PrintGCDateStamps"
set "JAVA_OPT=%JAVA_OPT% -XX:-OmitStackTraceInFastThrow"
set "JAVA_OPT=%JAVA_OPT% -XX:-UseLargePages"
set "JAVA_OPT=%JAVA_OPT% -Djava.ext.dirs=%BASE_DIR%lib;%JAVA_HOME%\jre\lib\ext"
......
......@@ -68,18 +68,18 @@ choose_gc_options()
# '1' means releases befor Java 9
JAVA_MAJOR_VERSION=$("$JAVA" -version 2>&1 | sed -r -n 's/.* version "([0-9]*).*$/\1/p')
if [ -z "$JAVA_MAJOR_VERSION" ] || [ "$JAVA_MAJOR_VERSION" -lt "9" ] ; then
JAVA_OPT="${JAVA_OPT} -server -Xms4g -Xmx4g -Xmn2g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
JAVA_OPT="${JAVA_OPT} -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8 -XX:-UseParNewGC"
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${GC_LOG_DIR}/rmq_srv_gc_%p_%t.log -XX:+PrintGCDetails"
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${GC_LOG_DIR}/rmq_srv_gc_%p_%t.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps"
JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m"
else
JAVA_OPT="${JAVA_OPT} -server -Xms4g -Xmx4g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0"
JAVA_OPT="${JAVA_OPT} -Xlog:gc*:file=${GC_LOG_DIR}/rmq_srv_gc_%p_%t.log:time,tags:filecount=5,filesize=30M"
fi
}
choose_gc_log_directory
JAVA_OPT="${JAVA_OPT} -server -Xms4g -Xmx4g -Xmn2g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
choose_gc_options
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages"
......
......@@ -74,6 +74,10 @@
<dependencySets>
<dependencySet>
<outputDirectory>lib/</outputDirectory>
<excludes>
<exclude>io.jaegertracing:jaeger-core</exclude>
<exclude>io.jaegertracing:jaeger-client</exclude>
</excludes>
</dependencySet>
</dependencySets>
</binaries>
......
# 系统配置
本节重点介绍系统(JVM/OS)的配置
---
## **1 JVM 选项** ##
建议使用最新发布的 JDK 1.8 版本。设置相同的 Xms 和 Xmx 值以防止 JVM 调整堆大小,并获得更好的性能。一种通用的JVM配置如下:
-server -Xms8g -Xmx8g -Xmn4g
设置 Direct ByteBuffer 内存大小。当 Direct ByteBuffer 达到指定大小时,将触发 Full GC:
-XXMaxDirectMemorySize=15g
如果你不在乎 RocketMQ broker 的启动时间,建议启用预分配 Java 堆以确保在 JVM 初始化期间为每个页面分配内存。你可以通过以下方式启用它:
-XX+AlwaysPreTouch
禁用偏向锁定可以减少 JVM 停顿:
-XX-UseBiasedLocking
关于垃圾收集器,推荐使用 JDK 1.8 的 G1 收集器:
-XX+UseG1GC -XXG1HeapRegionSize=16m
-XXG1ReservePercent=25
-XXInitiatingHeapOccupancyPercent=30
这些 GC 选项看起来有点激进,但事实证明它在生产环境中具有良好的性能
不要把-XXMaxGCPauseMillis 的值设置太小,否则JVM会使用一个小的新生代来实现这个目标,从而导致频繁发生minor GC。因此,建议使用滚动 GC 日志文件:
-XX+UseGCLogFileRotation
-XXNumberOfGCLogFiles=5
-XXGCLogFileSize=30m
写 GC 文件会增加 broker 的延迟,因此可以考虑将 GC 日志文件重定向到内存文件系统:
-Xloggcdevshmmq_gc_%p.log123
## 2 Linux 内核参数 ##
在 bin 文件夹里,有一个 os.sh 脚本,里面列出了许多的内核参数,只需稍作更改即可用于生产用途。需特别关注以下参数,如想了解更多细节,请参考文档/proc/sys/vm/*
- **vm.extra_free_kbytes**, 控制VM在后台回收(kswapd)开始的阈值和直接回收(通过分配进程)开始的阈值之间保留额外的空闲内存。通过使用这个参数,RocketMQ 可以避免在内存分配过程中出现高延迟。(与内核版本版本有关)
- **vm.min_free_kbytes**, 该值不应设置低于1024KB,否则系统将遭到破坏,并且在高负载环境下容易出现死锁。
- **vm.max_map_count**, 规定进程可以拥有的最大内存映射区域数。 RocketMQ 使用 mmap 来加载 CommitLog 和 ConsumeQueue,因此建议将此参数设置为较大的值。
- **vm.swappiness**, 定义内核交换内存页的频率。该值若较大,则会导致频繁交换,较小则会减少交换量。为了避免交换延迟,建议将此值设为 10。
- **File descriptor limits**, RocketMQ 需要给文件(CommitLog 和 ConsumeQueue)和网络连接分配文件描述符。因此建议将该值设置为 655350。
- **Disk scheduler**, 推荐使用deadline IO 调度器,它可以为请求提供有保证的延迟。
\ No newline at end of file
# 部署架构和设置步骤
## 集群的设置
### 1 单master模式
这是最简单但也是最危险的模式,一旦broker服务器重启或宕机,整个服务将不可用。 建议在生产环境中不要使用这种部署方式,在本地测试和开发可以选择这种模式。 以下是构建的步骤。
**1)启动NameServer**
```shell
### 第一步启动namesrv
$ nohup sh mqnamesrv &
### 验证namesrv是否启动成功
$ tail -f ~/logs/rocketmqlogs/namesrv.log
The Name Server boot success...
```
我们可以在namesrv.log 中看到'The Name Server boot success..',表示NameServer 已成功启动。
**2)启动Broker**
```shell
### 第一步先启动broker
$ nohup sh bin/mqbroker -n localhost:9876 &
### 验证broker是否启动成功, 比如, broker的ip是192.168.1.2 然后名字是broker-a
$ tail -f ~/logs/rocketmqlogs/Broker.log
The broker[broker-a,192.169.1.2:10911] boot success...
```
我们可以在 Broker.log 中看到“The broker[brokerName,ip:port] boot success..”,这表明 broker 已成功启动。
### 2 多Master模式
该模式是指所有节点都是master主节点(比如2个或3个主节点),没有slave从节点的模式。 这种模式的优缺点如下:
- 优点:
1. 配置简单。
2. 一个master节点的宕机或者重启(维护)对应用程序没有影响。
3. 当磁盘配置为RAID10时,消息不会丢失,因为RAID10磁盘非常可靠,即使机器不可恢复(消息异步刷盘模式的情况下,会丢失少量消息;如果消息是同步刷盘模式,不会丢失任何消息)。
4. 在这种模式下,性能是最高的。
- 缺点:
1. 单台机器宕机时,本机未消费的消息,直到机器恢复后才会订阅,影响消息实时性。
多Master模式的启动步骤如下:
**1)启动 NameServer**
```shell
### 第一步先启动broker
$ nohup sh mqnamesrv &
### 验证namesrv是否启动成功
$ tail -f ~/logs/rocketmqlogs/namesrv.log
The Name Server boot success...
```
**2)启动 Broker 集群**
```shell
### 比如在A机器上启动第一个Master,假设配置的NameServer IP为:192.168.1.1
$ nohup sh mqbroker -n 192.168.1.1:9876 -c $ROCKETMQ_HOME/conf/2m-noslave/broker-a.properties &
### 然后在机器B上启动第二个Master,假设配置的NameServer IP是:192.168.1.1
$ nohup sh mqbroker -n 192.168.1.1:9876 -c $ROCKETMQ_HOME/conf/2m-noslave/broker-b.properties &
...
```
上面显示的boot命令用于单个NameServer的情况。对于多个NameServer的集群,broker boot命令中-n参数后面的地址列表用分号隔开,例如 192.168.1.1 : 9876; 192.161.2 : 9876
### 3 多Master多Slave模式-异步复制
每个主节点配置多个从节点,多对主从。HA采用异步复制,主节点和从节点之间有短消息延迟(毫秒)。这种模式的优缺点如下:
- 优点:
1. 即使磁盘损坏,也不会丢失极少的消息,不影响消息的实时性能。
2. 同时,当主节点宕机时,消费者仍然可以消费从节点的消息,这个过程对应用本身是透明的,不需要人为干预。
3. 性能几乎与多Master模式一样高。
- 缺点:
1. 主节点宕机、磁盘损坏时,会丢失少量消息。
多主多从模式的启动步骤如下:
**1)启动 NameServer**
```shell
### 第一步先启动broker
$ nohup sh mqnamesrv &
### 验证namesrv是否启动成功
$ tail -f ~/logs/rocketmqlogs/namesrv.log
The Name Server boot success...
```
**2)启动 Broker 集群**
```shell
### 例如在A机器上启动第一个Master,假设配置的NameServer IP为:192.168.1.1,端口为9876。
$ nohup sh mqbroker -n 192.168.1.1:9876 -c $ROCKETMQ_HOME/conf/2m-2s-async/broker-a.properties &
### 然后在机器B上启动第二个Master,假设配置的NameServer IP为:192.168.1.1,端口为9876。
$ nohup sh mqbroker -n 192.168.1.1:9876 -c $ROCKETMQ_HOME/conf/2m-2s-async/broker-b.properties &
### 然后在C机器上启动第一个Slave,假设配置的NameServer IP为:192.168.1.1,端口为9876。
$ nohup sh mqbroker -n 192.168.1.1:9876 -c $ROCKETMQ_HOME/conf/2m-2s-async/broker-a-s.properties &
### 最后在D机启动第二个Slave,假设配置的NameServer IP为:192.168.1.1,端口为9876。
$ nohup sh mqbroker -n 192.168.1.1:9876 -c $ROCKETMQ_HOME/conf/2m-2s-async/broker-b-s.properties &
```
上图显示了 2M-2S-Async 模式的启动命令,类似于其他 nM-nS-Async 模式。
### 4 多Master多Slave模式-同步双写
这种模式下,每个master节点配置多个slave节点,有多对Master-Slave。HA采用同步双写,即只有消息成功写入到主节点并复制到多个从节点,才会返回成功响应给应用程序。
这种模式的优缺点如下:
- 优点:
1. 数据和服务都没有单点故障。
2. 在master节点关闭的情况下,消息也没有延迟。
3. 服务可用性和数据可用性非常高;
- 缺点:
1. 这种模式下的性能略低于异步复制模式(大约低 10%)。
2. 发送单条消息的RT略高,目前版本,master节点宕机后,slave节点无法自动切换到master。
启动步骤如下:
**1)启动NameServer**
```shell
### 第一步启动broker
$ nohup sh mqnamesrv &
### 验证namesrv是否启动成功
$ tail -f ~/logs/rocketmqlogs/namesrv.log
The Name Server boot success...
```
**2)启动 Broker 集群**
```shell
### 例如在A机器上启动第一个Master,假设配置的NameServer IP为:192.168.1.1,端口为9876。
$ nohup sh mqbroker -n 192.168.1.1:9876 -c $ROCKETMQ_HOME/conf/2m-2s-sync/broker-a.properties &
### 然后在B机器上启动第二个Master,假设配置的NameServer IP为:192.168.1.1,端口为9876。
$ nohup sh mqbroker -n 192.168.1.1:9876 -c $ROCKETMQ_HOME/conf/2m-2s-sync/broker-b.properties &
### 然后在C机器上启动第一个Slave,假设配置的NameServer IP为:192.168.1.1,端口为9876。
$ nohup sh mqbroker -n 192.168.1.1:9876 -c $ROCKETMQ_HOME/conf/2m-2s-sync/broker-a-s.properties &
### 最后在D机启动第二个Slave,假设配置的NameServer IP为:192.168.1.1,端口为9876。
$ nohup sh mqbroker -n 192.168.1.1:9876 -c $ROCKETMQ_HOME/conf/2m-2s-sync/broker-b-s.properties &
```
上述Master和Slave是通过指定相同的config命名为“brokerName”来配对的,master节点的brokerId必须为0,slave节点的brokerId必须大于0。
\ No newline at end of file
# 批量消息发送
批量消息发送能够提高发送效率,提升系统吞吐量。同一批批量消息的topic、waitStoreMsgOK属性必须保持一致,批量消息不支持延迟消息。批量消息发送一次最多可以发送 4MiB 的消息,但是如果需要发送更大的消息,建议将较大的消息分成多个不超过 1MiB 的小消息。
### 1 发送批量消息
如果你一次只发送不超过 4MiB 的消息,使用批处理很容易:
```java
String topic = "BatchTest";
List<Message> messages = new ArrayList<>();
messages.add(new Message(topic, "TagA", "OrderID001", "Hello world 0".getBytes()));
messages.add(new Message(topic, "TagA", "OrderID002", "Hello world 1".getBytes()));
messages.add(new Message(topic, "TagA", "OrderID003", "Hello world 2".getBytes()));
try {
producer.send(messages);
} catch (Exception e) {
e.printStackTrace();
//handle the error
}
```
### 2 拆分
当您发送较大的消息时,复杂性会增加,如果您不确定它是否超过 4MiB的限制。 这时候,您最好将较大的消息分成多个不超过 1MiB 的小消息:
```java
public class ListSplitter implements Iterator<List<Message>> {
private final int SIZE_LIMIT = 1024 * 1024 * 4;
private final List<Message> messages;
private int currIndex;
public ListSplitter(List<Message> messages) {
this.messages = messages;
}
@Override public boolean hasNext() {
return currIndex < messages.size();
}
@Override public List<Message> next() {
int startIndex = getStartIndex();
int nextIndex = startIndex;
int totalSize = 0;
for (; nextIndex < messages.size(); nextIndex++) {
Message message = messages.get(nextIndex);
int tmpSize = calcMessageSize(message);
if (tmpSize + totalSize > SIZE_LIMIT) {
break;
} else {
totalSize += tmpSize;
}
}
List<Message> subList = messages.subList(startIndex, nextIndex);
currIndex = nextIndex;
return subList;
}
private int getStartIndex() {
Message currMessage = messages.get(currIndex);
int tmpSize = calcMessageSize(currMessage);
while(tmpSize > SIZE_LIMIT) {
currIndex += 1;
Message message = messages.get(curIndex);
tmpSize = calcMessageSize(message);
}
return currIndex;
}
private int calcMessageSize(Message message) {
int tmpSize = message.getTopic().length() + message.getBody().length();
Map<String, String> properties = message.getProperties();
for (Map.Entry<String, String> entry : properties.entrySet()) {
tmpSize += entry.getKey().length() + entry.getValue().length();
}
tmpSize = tmpSize + 20; // Increase the log overhead by 20 bytes
return tmpSize;
}
}
// then you could split the large list into small ones:
ListSplitter splitter = new ListSplitter(messages);
while (splitter.hasNext()) {
try {
List<Message> listItem = splitter.next();
producer.send(listItem);
} catch (Exception e) {
e.printStackTrace();
// handle the error
}
}
```
\ No newline at end of file
# Schedule example
### 1 启动消费者等待传入的订阅消息
```java
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import java.util.List;
public class ScheduledMessageConsumer {
public static void main(String[] args) throws Exception {
// Instantiate message consumer
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ExampleConsumer");
// Subscribe topics
consumer.subscribe("TestTopic", "*");
// Register message listener
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> messages, ConsumeConcurrentlyContext context) {
for (MessageExt message : messages) {
// Print approximate delay time period
System.out.println("Receive message[msgId=" + message.getMsgId() + "] "
+ (System.currentTimeMillis() - message.getStoreTimestamp()) + "ms later");
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
// Launch consumer
consumer.start();
}
}
```
### 2 发送延迟消息
```java
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.common.message.Message;
public class ScheduledMessageProducer {
public static void main(String[] args) throws Exception {
// Instantiate a producer to send scheduled messages
DefaultMQProducer producer = new DefaultMQProducer("ExampleProducerGroup");
// Launch producer
producer.start();
int totalMessagesToSend = 100;
for (int i = 0; i < totalMessagesToSend; i++) {
Message message = new Message("TestTopic", ("Hello scheduled message " + i).getBytes());
// This message will be delivered to consumer 10 seconds later.
message.setDelayTimeLevel(3);
// Send the message
producer.send(message);
}
// Shutdown producer after use.
producer.shutdown();
}
}
```
### 3 确认
您应该会看到消息在其存储时间后大约 10 秒被消耗。
### 4 延迟消息的使用场景
例如在电子商务中,如果提交订单,可以发送延迟消息,1小时后可以查看订单状态。 如果订单仍未付款,则可以取消订单并释放库存。
### 5 使用延迟消息的限制
```java
// org/apache/rocketmq/store/config/MessageStoreConfig.java
private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
```
当前 RocketMQ 不支持任意时间的延迟。 生产者发送延迟消息前需要设置几个固定的延迟级别,分别对应1s到2h的1到18个延迟级,消息消费失败会进入延迟消息队列,消息发送时间与设置的延迟级别和重试次数有关。
See `SendMessageProcessor.java`
# Basic Sample
------
基本示例中提供了以下两个功能
* RocketMQ可用于以三种方式发送消息:可靠的同步、可靠的异步和单向传输。前两种消息类型是可靠的,因为无论它们是否成功发送都有响应。
* RocketMQ可以用来消费消息。
### 1 添加依赖
maven:
``` java
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.3.0</version>
</dependency>
```
gradle:
``` java
compile 'org.apache.rocketmq:rocketmq-client:4.3.0'
```
### 2 发送消息
##### 2.1 使用Producer发送同步消息
可靠的同步传输被广泛应用于各种场景,如重要的通知消息、短消息通知等。
``` java
public class SyncProducer {
public static void main(String[] args) throws Exception {
// Instantiate with a producer group name
DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
// Specify name server addresses
producer.setNamesrvAddr("localhost:9876");
// Launch the producer instance
producer.start();
for (int i = 0; i < 100; i++) {
// Create a message instance with specifying topic, tag and message body
Message msg = new Message("TopicTest" /* Topic */,
"TagA" /* Tag */,
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
);
// Send message to one of brokers
SendResult sendResult = producer.send(msg);
// Check whether the message has been delivered by the callback of sendResult
System.out.printf("%s%n", sendResult);
}
// Shut down once the producer instance is not longer in use
producer.shutdown();
}
}
```
##### 2.2 发送异步消息
异步传输通常用于响应时间敏感的业务场景。这意味着发送方无法等待代理的响应太长时间。
``` java
public class AsyncProducer {
public static void main(String[] args) throws Exception {
// Instantiate with a producer group name
DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
// Specify name server addresses
producer.setNamesrvAddr("localhost:9876");
// Launch the producer instance
producer.start();
producer.setRetryTimesWhenSendAsyncFailed(0);
for (int i = 0; i < 100; i++) {
final int index = i;
// Create a message instance with specifying topic, tag and message body
Message msg = new Message("TopicTest",
"TagA",
"OrderID188",
"Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
// SendCallback: receive the callback of the asynchronous return result.
producer.send(msg, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.printf("%-10d OK %s %n", index,
sendResult.getMsgId());
}
@Override
public void onException(Throwable e) {
System.out.printf("%-10d Exception %s %n", index, e);
e.printStackTrace();
}
});
}
// Shut down once the producer instance is not longer in use
producer.shutdown();
}
}
```
##### 2.3 以单向模式发送消息
单向传输用于需要中等可靠性的情况,如日志收集。
``` java
public class OnewayProducer {
public static void main(String[] args) throws Exception{
// Instantiate with a producer group name
DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
// Specify name server addresses
producer.setNamesrvAddr("localhost:9876");
// Launch the producer instance
producer.start();
for (int i = 0; i < 100; i++) {
// Create a message instance with specifying topic, tag and message body
Message msg = new Message("TopicTest" /* Topic */,
"TagA" /* Tag */,
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
);
// Send in one-way mode, no return result
producer.sendOneway(msg);
}
// Shut down once the producer instance is not longer in use
producer.shutdown();
}
}
```
### 3 消费消息
``` java
public class Consumer {
public static void main(String[] args) throws InterruptedException, MQClientException {
// Instantiate with specified consumer group name
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");
// Specify name server addresses
consumer.setNamesrvAddr("localhost:9876");
// Subscribe one or more topics and tags for finding those messages need to be consumed
consumer.subscribe("TopicTest", "*");
// Register callback to execute on arrival of messages fetched from brokers
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
// Mark the message that have been consumed successfully
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
// Launch the consumer instance
consumer.start();
System.out.printf("Consumer Started.%n");
}
}
```
\ No newline at end of file
# 经常被问到的问题
以下是关于RocketMQ项目的常见问题
## 1 基本
1. **为什么我们要使用RocketMQ而不是选择其他的产品?**
请参考[为什么要选择RocketMQ](http://rocketmq.apache.org/docs/motivation/)
2. **我是否需要安装其他的软件才能使用RocketMQ,例如zookeeper?**
不需要,RocketMQ可以独立的运行。
## 2 使用
1. **新创建的Consumer ID从哪里开始消费消息?**
1)如果发送的消息在三天之内,那么消费者会从服务器中保存的第一条消息开始消费。
2)如果发送的消息已经超过三天,则消费者会从服务器中的最新消息开始消费,也就是从队列的尾部开始消费。
3)如果消费者重新启动,那么它会从最后一个消费位置开始消费消息。
2. **当消费失败的时候如何重新消费消息?**
1)在集群模式下,消费的业务逻辑代码会返回Action.ReconsumerLater,NULL,或者抛出异常,如果一条消息消费失败,最多会重试16次,之后该消息会被丢弃。
2)在广播消费模式下,广播消费仍然保证消息至少被消费一次,但不提供重发的选项。
3. **当消费失败的时候如何找到失败的消息?**
1)使用按时间的主题查询,可以查询到一段时间内的消息。
2)使用主题和消息ID来准确查询消息。
3)使用主题和消息的Key来准确查询所有消息Key相同的消息。
4. **消息只会被传递一次吗?**
RocketMQ 确保所有消息至少传递一次。 在大多数情况下,消息不会重复。
5. **如何增加一个新的Broker?**
1)启动一个新的Broker并将其注册到name server中的Broker列表里。
2)默认只自动创建内部系统topic和consumer group。 如果您希望在新节点上拥有您的业务主题和消费者组,请从现有的Broker中复制它们。 我们提供了管理工具和命令行来处理此问题。
## 3 配置相关
以下回答均为默认值,可通过配置修改。
1. **消息在服务器上可以保存多长时间?**
存储的消息将最多保存 3 天,超过 3 天未使用的消息将被删除。
2. **消息体的大小限制是多少?**
通常是256KB
3. **怎么设置消费者线程数?**
当你启动消费者的时候,可以设置 ConsumeThreadNums属性的值,举例如下:
```java
consumer.setConsumeThreadMin(20);
consumer.setConsumeThreadMax(20);
```
## 4 错误
1. **当你启动一个生产者或消费者的过程失败了并且错误信息是生产者组或消费者重复**
原因:使用同一个Producer/Consumer Group在同一个JVM中启动多个Producer/Consumer实例可能会导致客户端无法启动。
解决方案:确保一个 Producer/Consumer Group 对应的 JVM 只启动一个 Producer/Consumer 实例。
2. **消费者无法在广播模式下开始加载 json 文件**
原因:fastjson 版本太低,无法让广播消费者加载本地 offsets.json,导致消费者启动失败。 损坏的 fastjson 文件也会导致同样的问题。
解决方案:Fastjson 版本必须升级到 RocketMQ 客户端依赖版本,以确保可以加载本地 offsets.json。 默认情况下,offsets.json 文件在 /home/{user}/.rocketmq_offsets 中。 或者检查fastjson的完整性。
3. **Broker崩溃以后有什么影响?**
1)Master节点崩溃
消息不能再发送到该Broker集群,但是如果您有另一个可用的Broker集群,那么在主题存在的条件下仍然可以发送消息。消息仍然可以从Slave节点消费。
2)一些Slave节点崩溃
只要有另一个工作的slave,就不会影响发送消息。 对消费消息也不会产生影响,除非消费者组设置为优先从该Slave消费。 默认情况下,消费者组从 master 消费。
3)所有Slave节点崩溃
向master发送消息不会有任何影响,但是,如果master是SYNC_MASTER,producer会得到一个SLAVE_NOT_AVAILABLE,表示消息没有发送给任何slave。 对消费消息也没有影响,除非消费者组设置为优先从slave消费。 默认情况下,消费者组从master消费。
4. **Producer提示“No Topic Route Info”,如何诊断?**
当您尝试将消息发送到一个路由信息对生产者不可用的主题时,就会发生这种情况。
1)确保生产者可以连接到名称服务器并且能够从中获取路由元信息。
2)确保名称服务器确实包含主题的路由元信息。 您可以使用管理工具或 Web 控制台通过 topicRoute 从名称服务器查询路由元信息。
3)确保您的Broker将心跳发送到您的生产者正在连接的同一name server列表。
4)确保主题的权限为6(rw-),或至少为2(-w-)。
如果找不到此主题,请通过管理工具命令updateTopic或Web控制台在Broker上创建它。
\ No newline at end of file
......@@ -54,7 +54,7 @@
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.3.0</version>
<version>4.9.1</version>
</dependency>
```
`gradle`
......@@ -120,13 +120,15 @@ public class AsyncProducer {
producer.send(msg, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
countDownLatch.countDown();
System.out.printf("%-10d OK %s %n", index,
sendResult.getMsgId());
}
@Override
public void onException(Throwable e) {
System.out.printf("%-10d Exception %s %n", index, e);
e.printStackTrace();
countDownLatch.countDown();
System.out.printf("%-10d Exception %s %n", index, e);
e.printStackTrace();
}
});
}
......
......@@ -186,8 +186,8 @@ msgId一定是全局唯一标识符,但是实际使用中,可能会存在相
| brokerName | null | broker 的名称 |
| brokerClusterName | DefaultCluster | 本 broker 所属的 Cluser 名称 |
| brokerId | 0 | broker id, 0 表示 master, 其他的正整数表示 slave |
| storePathRootDir | $HOME/store/ | 存储根路径 |
| storePathCommitLog | $HOME/store/commitlog/ | 存储 commit log 的路径 |
| storePathConsumerQueue | $HOME/store/consumequeue/ | 存储 consume queue 的路径 |
| mappedFileSizeCommitLog | 1024 * 1024 * 1024(1G) | commit log 的映射文件大小 |​
| deleteWhen | 04 | 在每天的什么时间删除已经超过文件保留时间的 commit log |​
| fileReservedTime | 72 | 以小时计算的文件保留时间 |​
......
......@@ -10,7 +10,7 @@
#### 1.1 消息存储整体架构
消息存储架构图中主要有下面三个跟消息存储相关的文件构成。
(1) CommitLog:消息主体以及元数据的存储主体,存储Producer端写入的消息主体内容,消息内容不是定长的。单个文件大小默认1G文件名长度为20位,左边补零,剩余为起始偏移量,比如00000000000000000000代表了第一个文件,起始偏移量为0,文件大小为1G=1073741824;当第一个文件写满了,第二个文件为00000000001073741824,起始偏移量为1073741824,以此类推。消息主要是顺序写入日志文件,当文件满了,写入下一个文件;
(1) CommitLog:消息主体以及元数据的存储主体,存储Producer端写入的消息主体内容,消息内容不是定长的。单个文件大小默认1G, 文件名长度为20位,左边补零,剩余为起始偏移量,比如00000000000000000000代表了第一个文件,起始偏移量为0,文件大小为1G=1073741824;当第一个文件写满了,第二个文件为00000000001073741824,起始偏移量为1073741824,以此类推。消息主要是顺序写入日志文件,当文件满了,写入下一个文件;
(2) ConsumeQueue:消息消费队列,引入的目的主要是提高消息消费的性能,由于RocketMQ是基于主题topic的订阅模式,消息消费是针对主题进行的,如果要遍历commitlog文件中根据topic检索消息是非常低效的。Consumer即可根据ConsumeQueue来查找待消费的消息。其中,ConsumeQueue(逻辑消费队列)作为消费消息的索引,保存了指定Topic下的队列消息在CommitLog中的起始物理偏移量offset,消息大小size和消息Tag的HashCode值。consumequeue文件可以看成是基于topic的commitlog索引文件,故consumequeue文件夹的组织方式如下:topic/queue/file三层组织结构,具体存储路径为:$HOME/store/consumequeue/{topic}/{queueId}/{fileName}。同样consumequeue文件采取定长设计,每一个条目共20个字节,分别为8字节的commitlog物理偏移量、4字节的消息长度、8字节tag hashcode,单个文件由30W个条目组成,可以像数组一样随机访问每一个条目,每个ConsumeQueue文件大小约5.72M;
......@@ -95,7 +95,7 @@ M1 | NettyServerCodecThread_%d | Worker线程池
M2 | RemotingExecutorThread_%d | 业务processor处理线程池
### 3 消息过滤
RocketMQ分布式消息队列的消息过滤方式有别于其它MQ中间件,是在Consumer端订阅消息时再做消息过滤的。RocketMQ这么做是在于其Producer端写入消息和Consumer端订阅消息采用分离存储的机制来实现的,Consumer端订阅消息是需要通过ConsumeQueue这个消息消费的逻辑队列拿到一个索引,然后再从CommitLog里面读取真正的消息实体内容,所以说到底也是还绕不开其存储结构。其ConsumeQueue的存储结构如下,可以看到其中有8个字节存储的Message Tag的哈希值,基于Tag的消息过滤正基于这个字段值的。
RocketMQ分布式消息队列的消息过滤方式有别于其它MQ中间件,是在Consumer端订阅消息时再做消息过滤的。RocketMQ这么做是在于其Producer端写入消息和Consumer端订阅消息采用分离存储的机制来实现的,Consumer端订阅消息是需要通过ConsumeQueue这个消息消费的逻辑队列拿到一个索引,然后再从CommitLog里面读取真正的消息实体内容,所以说到底也是还绕不开其存储结构。其ConsumeQueue的存储结构如下,可以看到其中有8个字节存储的Message Tag的哈希值,基于Tag的消息过滤正基于这个字段值的。
![](image/rocketmq_design_7.png)
......
......@@ -100,6 +100,19 @@ RocketMQ的消息轨迹特性支持两种存储轨迹数据的方式:
......
```
### 4.4 使用mqadmin命令发送和查看轨迹
- 发送消息
```shell
./mqadmin sendMessage -m true --topic some-topic-name -n 127.0.0.1:9876 -p "your meesgae content"
```
- 查询轨迹
```shell
./mqadmin QueryMsgTraceById -n 127.0.0.1:9876 -i "some-message-id"
```
- 查询轨迹结果
```
RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).
RocketMQLog:WARN Please initialize the logger system properly.
#Type #ProducerGroup #ClientHost #SendTime #CostTimes #Status
Pub 1623305799667 xxx.xxx.xxx.xxx 2021-06-10 14:16:40 131ms success
```
......@@ -25,7 +25,7 @@ The Name Server boot success...
### 启动Broker
$ nohup sh bin/mqbroker -n localhost:9876 &
### 验证Name Server 是否启动成功,例如Broker的IP为:192.168.1.2,且名称为broker-a
### 验证Broker是否启动成功,例如Broker的IP为:192.168.1.2,且名称为broker-a
$ tail -f ~/logs/rocketmqlogs/broker.log
The broker[broker-a, 192.169.1.2:10911] boot success...
```
......@@ -566,6 +566,14 @@ $ nohup sh mqbroker -n 192.168.1.1:9876 -c $ROCKETMQ_HOME/conf/2m-2s-sync/broker
<td class=xl67 width=87 style='width:65pt'>-b</td>
<td class=xl68 width=87 style='width:65pt'>BrokerName</td>
</tr>
<tr height=57 style='height:43.0pt'>
<td rowspan=3 height=137 class=xl69 width=191 style='border-bottom:1.0pt;
height:103.0pt;border-top:none;width:143pt'>addWritePerm</td>
<td rowspan=3 class=xl72 width=87 style='border-bottom:1.0pt
border-top:none;width:65pt'>从NameServer上添加 Broker写权限</td>
<td class=xl67 width=87 style='width:65pt'>-b</td>
<td class=xl68 width=87 style='width:65pt'>BrokerName</td>
</tr>
<tr height=57 style='height:43.0pt'>
<td height=57 class=xl67 width=87 style='height:43.0pt;width:65pt'>-n</td>
<td class=xl68 width=87 style='width:65pt'>NameServer 服务地址,格式 ip:port</td>
......
......@@ -426,6 +426,14 @@ Before introducing the mqadmin management tool, the following points need to be
<td class=xl67 width=87 style='width:65pt'>-b</td>
<td class=xl68 width=87 style='width:65pt'>Declare the BrokerName</td>
</tr>
<tr height=57 style='height:43.0pt'>
<td rowspan=3 height=137 class=xl69 width=191 style='border-bottom:1.0pt;
height:103.0pt;border-top:none;width:143pt'>addWritePerm</td>
<td rowspan=3 class=xl72 width=87 style='border-bottom:1.0pt
border-top:none;width:65pt'>Add write permissions for broker from nameServer</td>
<td class=xl67 width=87 style='width:65pt'>-b</td>
<td class=xl68 width=87 style='width:65pt'>Declare the BrokerName</td>
</tr>
<tr height=57 style='height:43.0pt'>
<td height=57 class=xl67 width=87 style='height:43.0pt;width:65pt'>-n</td>
<td class=xl68 width=87 style='width:65pt'>Service address used to specify nameServer and formatted as ip:port</td>
......
......@@ -89,7 +89,7 @@ public class TransactionListenerImpl implements TransactionListener {
## 3 Usage Constraint
1. Messages of the transactional have no schedule and batch support.
2. In order to avoid a single message being checked too many times and lead to half queue message accumulation, we limited the number of checks for a single message to 15 times by default, but users can change this limit by change the ```transactionCheckMax``` parameter in the configuration of the broker, if one message has been checked over ```transactionCheckMax``` times, broker will discard this message and print an error log at the same time by default. Users can change this behavior by override the ```AbstractTransactionalMessageCheckListener``` class.
3. A transactional message will be checked after a certain period of time that determined by parameter g```transactionTimeout``` in the configuration of the broker. And users also can change this limit by set user property ```CHECK_IMMUNITY_TIME_IN_SECONDS``` when sending transactional message, this parameter takes precedence over the ```transactionTimeout``` parameter.
3. A transactional message will be checked after a certain period of time that determined by parameter ```transactionTimeout``` in the configuration of the broker. And users also can change this limit by set user property ```CHECK_IMMUNITY_TIME_IN_SECONDS``` when sending transactional message, this parameter takes precedence over the ```transactionTimeout``` parameter.
4. A transactional message maybe checked or consumed more than once.
5. Committed message reput to the user’s target topic may fail. Currently, it depends on the log record. High availability is ensured by the high availability mechanism of RocketMQ itself. If you want to ensure that the transactional message isn’t lost and the transaction integrity is guaranteed, it is recommended to use synchronous double write. mechanism.
6. Producer IDs of transactional messages cannot be shared with producer IDs of other types of messages. Unlike other types of message, transactional messages allow backward queries. MQ Server query clients by their Producer IDs.
......
......@@ -20,8 +20,8 @@
| brokerName | null | broker name |
| brokerClusterName | DefaultCluster | this broker belongs to which cluster |
| brokerId | 0 | broker id, 0 means master, positive integers mean slave |
| storePathRootDir | $HOME/store/ | file path for root store |
| storePathCommitLog | $HOME/store/commitlog/ | file path for commit log |
| storePathConsumerQueue | $HOME/store/consumequeue/ | file path for consume queue |
| mappedFileSizeCommitLog | 1024 * 1024 * 1024(1G) | mapped file size for commit log |​
| deleteWhen | 04 | When to delete the commitlog which is out of the reserve time |​
| fileReserverdTime | 72 | The number of hours to keep a commitlog before deleting it |​
......
## DefaultMQProducer
---
### Class introduction
`public class DefaultMQProducer
extends ClientConfig
implements MQProducer`
>`DefaultMQProducer` is the entry point for an application to post messages, out of the box,ca quickly create a producer with a no-argument construction. it is mainly responsible for message sending, support synchronous、asynchronous、one-way send. All of these send methods support batch send. The parameters of the sender can be adjusted through the getter/setter methods , provided by this class. `DefaultMQProducer` has multi send method and each method is slightly different. Make sure you know the usage before you use it . Blow is a producer example . [see more examples](https://github.com/apache/rocketmq/blob/master/example/src/main/java/org/apache/rocketmq/example/)。
``` java
public class Producer {
public static void main(String[] args) throws MQClientException {
// create a produce with producer_group_name
DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
// start the producer
producer.start();
for (int i = 0; i < 128; i++)
try {
// construct the msg
Message msg = new Message("TopicTest",
"TagA",
"OrderID188",
"Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
// send sync
SendResult sendResult = producer.send(msg);
// print the result
System.out.printf("%s%n", sendResult);
} catch (Exception e) {
e.printStackTrace();
}
producer.shutdown();
}
}
```
**Note** : This class is thread safe. It can be safely shared between multiple threads after configuration and startup is complete.
### Variable
|Type|Name| description |
|------|-------|-------|
|DefaultMQProducerImpl|defaultMQProducerImpl|The producer's internal default implementation|
|String|producerGroup|The producer's group|
|String|createTopicKey| Topics that do not exist on the server are automatically created when the message is sent |
|int|defaultTopicQueueNums|The default number of queues to create a topic|
|int|sendMsgTimeout|The timeout for the message to be sent|
|int|compressMsgBodyOverHowmuch|the threshold of the compress of message body|
|int|retryTimesWhenSendFailed|Maximum number of internal attempts to send a message in synchronous mode|
|int|retryTimesWhenSendAsyncFailed|Maximum number of internal attempts to send a message in asynchronous mode|
|boolean|retryAnotherBrokerWhenNotStoreOK|Whether to retry another broker if an internal send fails|
|int|maxMessageSize| Maximum length of message |
|TraceDispatcher|traceDispatcher| Message trackers. Use rcpHook to track messages |
### construction method
|方法名称|方法描述|
|-------|------------|
|DefaultMQProducer()| creates a producer with default parameter values |
|DefaultMQProducer(final String producerGroup)| creates a producer with producer group name. |
|DefaultMQProducer(final String producerGroup, boolean enableMsgTrace)|creates a producer with producer group name and set whether to enable message tracking|
|DefaultMQProducer(final String producerGroup, boolean enableMsgTrace, final String customizedTraceTopic)|creates a producer with producer group name and set whether to enable message tracking、the trace topic.|
|DefaultMQProducer(RPCHook rpcHook)|creates a producer with a rpc hook.|
|DefaultMQProducer(final String producerGroup, RPCHook rpcHook)|creates a producer with a rpc hook and producer group.|
|DefaultMQProducer(final String producerGroup, RPCHook rpcHook, boolean enableMsgTrace,final String customizedTraceTopic)|all of above.|
......@@ -101,5 +101,21 @@ Adjusting instantiation of DefaultMQProducer and DefaultMQPushConsumer as follow
```
### 4.4 Send and query message trace by mqadmin command
- send message
```shell
./mqadmin sendMessage -m true --topic some-topic-name -n 127.0.0.1:9876 -p "your meesgae content"
```
- query trace
```shell
./mqadmin QueryMsgTraceById -n 127.0.0.1:9876 -i "some-message-id"
```
- query trace result
```
RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).
RocketMQLog:WARN Please initialize the logger system properly.
#Type #ProducerGroup #ClientHost #SendTime #CostTimes #Status
Pub 1623305799667 xxx.xxx.xxx.xxx 2021-06-10 14:16:40 131ms success
```
......@@ -25,7 +25,7 @@ The Name Server boot success...
### start Broker
$ nohup sh bin/mqbroker -n localhost:9876 &
### check whether Name Server is successfully started, eg: Broker's IP is 192.168.1.2, Broker's name is broker-a
### check whether Broker is successfully started, eg: Broker's IP is 192.168.1.2, Broker's name is broker-a
$ tail -f ~/logs/rocketmqlogs/Broker.log
The broker[broker-a, 192.169.1.2:10911] boot success...
```
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.example.benchmark;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.rocketmq.acl.common.AclClientRPCHook;
import org.apache.rocketmq.acl.common.SessionCredentials;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.log.ClientLogger;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.logging.InternalLogger;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.RPCHook;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.apache.rocketmq.srvutil.ServerUtil;
public class BatchProducer {
private static byte[] msgBody;
public static void main(String[] args) throws MQClientException {
Options options = ServerUtil.buildCommandlineOptions(new Options());
CommandLine commandLine = ServerUtil.parseCmdLine("benchmarkBatchProducer", args, buildCommandlineOptions(options), new PosixParser());
if (null == commandLine) {
System.exit(-1);
}
final String namesrv = getOptionValue(commandLine, 'n', "127.0.0.1:9876");
final String topic = getOptionValue(commandLine, 't', "BenchmarkTest");
final int threadCount = getOptionValue(commandLine, 'w', 64);
final int messageSize = getOptionValue(commandLine, 's', 128);
final int batchSize = getOptionValue(commandLine, 'b', 16);
final boolean keyEnable = getOptionValue(commandLine, 'k', false);
final int propertySize = getOptionValue(commandLine, 'p', 0);
final int tagCount = getOptionValue(commandLine, 'l', 0);
final boolean msgTraceEnable = getOptionValue(commandLine, 'm', false);
final boolean aclEnable = getOptionValue(commandLine, 'a', false);
final String ak = getOptionValue(commandLine, 'c', "rocketmq2");
final String sk = getOptionValue(commandLine, 'e', "12346789");
System.out.printf("topic: %s threadCount: %d messageSize: %d batchSize: %d keyEnable: %s propertySize: %d tagCount: %d traceEnable: %s aclEnable: %s%n",
topic, threadCount, messageSize, batchSize, keyEnable, propertySize, tagCount, msgTraceEnable, aclEnable);
StringBuilder sb = new StringBuilder(messageSize);
for (int i = 0; i < messageSize; i++) {
sb.append(RandomStringUtils.randomAlphanumeric(1));
}
msgBody = sb.toString().getBytes(StandardCharsets.UTF_8);
final StatsBenchmarkBatchProducer statsBenchmark = new StatsBenchmarkBatchProducer();
statsBenchmark.start();
final DefaultMQProducer producer = initInstance(namesrv, msgTraceEnable, aclEnable, ak, sk);
producer.start();
final InternalLogger log = ClientLogger.getLog();
final ExecutorService sendThreadPool = Executors.newFixedThreadPool(threadCount);
for (int i = 0; i < threadCount; i++) {
sendThreadPool.execute(new Runnable() {
@Override
public void run() {
while (true) {
List<Message> msgs = buildBathMessage(batchSize, topic);
if (CollectionUtils.isEmpty(msgs)) {
return;
}
try {
long beginTimestamp = System.currentTimeMillis();
long sendSucCount = statsBenchmark.getSendMessageSuccessCount().longValue();
setKeys(keyEnable, msgs, String.valueOf(beginTimestamp / 1000));
setTags(tagCount, msgs, sendSucCount);
setProperties(propertySize, msgs);
SendResult sendResult = producer.send(msgs);
if (sendResult.getSendStatus() == SendStatus.SEND_OK) {
statsBenchmark.getSendRequestSuccessCount().increment();
statsBenchmark.getSendMessageSuccessCount().add(msgs.size());
} else {
statsBenchmark.getSendRequestFailedCount().increment();
statsBenchmark.getSendMessageFailedCount().add(msgs.size());
}
long currentRT = System.currentTimeMillis() - beginTimestamp;
statsBenchmark.getSendMessageSuccessTimeTotal().add(currentRT);
long prevMaxRT = statsBenchmark.getSendMessageMaxRT().longValue();
while (currentRT > prevMaxRT) {
boolean updated = statsBenchmark.getSendMessageMaxRT().compareAndSet(prevMaxRT, currentRT);
if (updated) {
break;
}
prevMaxRT = statsBenchmark.getSendMessageMaxRT().get();
}
} catch (RemotingException e) {
statsBenchmark.getSendRequestFailedCount().increment();
statsBenchmark.getSendMessageFailedCount().add(msgs.size());
log.error("[BENCHMARK_PRODUCER] Send Exception", e);
try {
Thread.sleep(3000);
} catch (InterruptedException ignored) {
}
} catch (InterruptedException e) {
statsBenchmark.getSendRequestFailedCount().increment();
statsBenchmark.getSendMessageFailedCount().add(msgs.size());
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
}
statsBenchmark.getSendRequestFailedCount().increment();
statsBenchmark.getSendMessageFailedCount().add(msgs.size());
log.error("[BENCHMARK_PRODUCER] Send Exception", e);
} catch (MQClientException e) {
statsBenchmark.getSendRequestFailedCount().increment();
statsBenchmark.getSendMessageFailedCount().add(msgs.size());
log.error("[BENCHMARK_PRODUCER] Send Exception", e);
} catch (MQBrokerException e) {
statsBenchmark.getSendRequestFailedCount().increment();
statsBenchmark.getSendMessageFailedCount().add(msgs.size());
log.error("[BENCHMARK_PRODUCER] Send Exception", e);
try {
Thread.sleep(3000);
} catch (InterruptedException ignored) {
}
}
}
}
});
}
}
public static Options buildCommandlineOptions(final Options options) {
Option opt = new Option("w", "threadCount", true, "Thread count, Default: 64");
opt.setRequired(false);
options.addOption(opt);
opt = new Option("s", "messageSize", true, "Message Size, Default: 128");
opt.setRequired(false);
options.addOption(opt);
opt = new Option("b", "batchSize", true, "Batch Size, Default: 16");
opt.setRequired(false);
options.addOption(opt);
opt = new Option("k", "keyEnable", true, "Message Key Enable, Default: false");
opt.setRequired(false);
options.addOption(opt);
opt = new Option("t", "topic", true, "Topic name, Default: BenchmarkTest");
opt.setRequired(false);
options.addOption(opt);
opt = new Option("l", "tagCount", true, "Tag count, Default: 0");
opt.setRequired(false);
options.addOption(opt);
opt = new Option("m", "msgTraceEnable", true, "Message Trace Enable, Default: false");
opt.setRequired(false);
options.addOption(opt);
opt = new Option("a", "aclEnable", true, "Acl Enable, Default: false");
opt.setRequired(false);
options.addOption(opt);
opt = new Option("c", "accessKey", true, "Acl Access Key, Default: rocketmq2");
opt.setRequired(false);
options.addOption(opt);
opt = new Option("e", "secretKey", true, "Acl Secret Key, Default: 123456789");
opt.setRequired(false);
options.addOption(opt);
opt = new Option("p", "propertySize", true, "Property Size, Default: 0");
opt.setRequired(false);
options.addOption(opt);
opt = new Option("n", "namesrv", true, "name server, Default: 127.0.0.1:9876");
opt.setRequired(false);
options.addOption(opt);
return options;
}
private static String getOptionValue(CommandLine commandLine, char key, String defaultValue) {
if (commandLine.hasOption(key)) {
return commandLine.getOptionValue(key).trim();
}
return defaultValue;
}
private static int getOptionValue(CommandLine commandLine, char key, int defaultValue) {
if (commandLine.hasOption(key)) {
return Integer.parseInt(commandLine.getOptionValue(key).trim());
}
return defaultValue;
}
private static boolean getOptionValue(CommandLine commandLine, char key, boolean defaultValue) {
if (commandLine.hasOption(key)) {
return Boolean.parseBoolean(commandLine.getOptionValue(key).trim());
}
return defaultValue;
}
private static List<Message> buildBathMessage(final int batchSize, final String topic) {
List<Message> batchMessage = new ArrayList<>(batchSize);
for (int i = 0; i < batchSize; i++) {
Message msg = new Message(topic, msgBody);
batchMessage.add(msg);
}
return batchMessage;
}
private static void setKeys(boolean keyEnable, List<Message> msgs, String keys) {
if (!keyEnable) {
return;
}
for (Message msg : msgs) {
msg.setKeys(keys);
}
}
private static void setTags(int tagCount, List<Message> msgs, long startTagId) {
if (tagCount <= 0) {
return;
}
long tagId = startTagId % tagCount;
for (Message msg : msgs) {
msg.setTags(String.format("tag%d", tagId++));
}
}
private static void setProperties(int propertySize, List<Message> msgs) {
if (propertySize <= 0) {
return;
}
for (Message msg : msgs) {
if (msg.getProperties() != null) {
msg.getProperties().clear();
}
int startValue = (new Random(System.currentTimeMillis())).nextInt(100);
int size = 0;
for (int i = 0; ; i++) {
String prop1 = "prop" + i, prop1V = "hello" + startValue;
msg.putUserProperty(prop1, prop1V);
size += prop1.length() + prop1V.length();
if (size > propertySize) {
break;
}
startValue++;
}
}
}
private static DefaultMQProducer initInstance(String namesrv, boolean traceEnable, boolean aclEnable, String ak,
String sk) {
RPCHook rpcHook = aclEnable ? new AclClientRPCHook(new SessionCredentials(ak, sk)) : null;
final DefaultMQProducer producer = new DefaultMQProducer("benchmark_batch_producer", rpcHook, traceEnable, null);
producer.setInstanceName(Long.toString(System.currentTimeMillis()));
producer.setNamesrvAddr(namesrv);
producer.setCompressMsgBodyOverHowmuch(Integer.MAX_VALUE);
return producer;
}
}
class StatsBenchmarkBatchProducer {
private final LongAdder sendRequestSuccessCount = new LongAdder();
private final LongAdder sendRequestFailedCount = new LongAdder();
private final LongAdder sendMessageSuccessTimeTotal = new LongAdder();
private final AtomicLong sendMessageMaxRT = new AtomicLong(0L);
private final LongAdder sendMessageSuccessCount = new LongAdder();
private final LongAdder sendMessageFailedCount = new LongAdder();
private final Timer timer = new Timer("BenchmarkTimerThread", true);
private final LinkedList<Long[]> snapshotList = new LinkedList<>();
public Long[] createSnapshot() {
Long[] snap = new Long[] {
System.currentTimeMillis(),
this.sendRequestSuccessCount.longValue(),
this.sendRequestFailedCount.longValue(),
this.sendMessageSuccessCount.longValue(),
this.sendMessageFailedCount.longValue(),
this.sendMessageSuccessTimeTotal.longValue(),
};
return snap;
}
public LongAdder getSendRequestSuccessCount() {
return sendRequestSuccessCount;
}
public LongAdder getSendRequestFailedCount() {
return sendRequestFailedCount;
}
public LongAdder getSendMessageSuccessTimeTotal() {
return sendMessageSuccessTimeTotal;
}
public AtomicLong getSendMessageMaxRT() {
return sendMessageMaxRT;
}
public LongAdder getSendMessageSuccessCount() {
return sendMessageSuccessCount;
}
public LongAdder getSendMessageFailedCount() {
return sendMessageFailedCount;
}
public void start() {
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
snapshotList.addLast(createSnapshot());
if (snapshotList.size() > 10) {
snapshotList.removeFirst();
}
}
}, 1000, 1000);
timer.scheduleAtFixedRate(new TimerTask() {
private void printStats() {
if (snapshotList.size() >= 10) {
Long[] begin = snapshotList.getFirst();
Long[] end = snapshotList.getLast();
final long sendTps = (long) (((end[1] - begin[1]) / (double) (end[0] - begin[0])) * 1000L);
final long sendMps = (long) (((end[3] - begin[3]) / (double) (end[0] - begin[0])) * 1000L);
final double averageRT = (end[5] - begin[5]) / (double) (end[1] - begin[1]);
final double averageMsgRT = (end[5] - begin[5]) / (double) (end[3] - begin[3]);
System.out.printf("Current Time: %s Send TPS: %d Send MPS: %d Max RT(ms): %d Average RT(ms): %7.3f Average Message RT(ms): %7.3f Send Failed: %d Send Message Failed: %d%n",
System.currentTimeMillis(), sendTps, sendMps, getSendMessageMaxRT().longValue(), averageRT, averageMsgRT, end[2], end[4]);
}
}
@Override
public void run() {
try {
this.printStats();
} catch (Exception e) {
e.printStackTrace();
}
}
}, 10000, 10000);
}
public void shutdown() {
timer.cancel();
}
}
\ No newline at end of file
......@@ -17,18 +17,12 @@
package org.apache.rocketmq.example.benchmark;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.MessageSelector;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
......@@ -42,6 +36,16 @@ import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.remoting.RPCHook;
import org.apache.rocketmq.srvutil.ServerUtil;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
public class Consumer {
public static void main(String[] args) throws MQClientException, IOException {
......@@ -71,11 +75,12 @@ public class Consumer {
final StatsBenchmarkConsumer statsBenchmarkConsumer = new StatsBenchmarkConsumer();
final Timer timer = new Timer("BenchmarkTimerThread", true);
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("BenchmarkTimerThread-%d").daemon(true).build());
final LinkedList<Long[]> snapshotList = new LinkedList<Long[]>();
timer.scheduleAtFixedRate(new TimerTask() {
executorService.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
snapshotList.addLast(statsBenchmarkConsumer.createSnapshot());
......@@ -83,9 +88,9 @@ public class Consumer {
snapshotList.removeFirst();
}
}
}, 1000, 1000);
}, 1000, 1000, TimeUnit.MILLISECONDS);
timer.scheduleAtFixedRate(new TimerTask() {
executorService.scheduleAtFixedRate(new TimerTask() {
private void printStats() {
if (snapshotList.size() >= 10) {
Long[] begin = snapshotList.getFirst();
......@@ -116,7 +121,7 @@ public class Consumer {
e.printStackTrace();
}
}
}, 10000, 10000);
}, 10000, 10000, TimeUnit.MILLISECONDS);
RPCHook rpcHook = aclEnable ? AclClient.getAclRPCHook() : null;
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(group, rpcHook, new AllocateMessageQueueAveragely(), msgTraceEnable, null);
......@@ -151,20 +156,20 @@ public class Consumer {
MessageExt msg = msgs.get(0);
long now = System.currentTimeMillis();
statsBenchmarkConsumer.getReceiveMessageTotalCount().incrementAndGet();
statsBenchmarkConsumer.getReceiveMessageTotalCount().increment();
long born2ConsumerRT = now - msg.getBornTimestamp();
statsBenchmarkConsumer.getBorn2ConsumerTotalRT().addAndGet(born2ConsumerRT);
statsBenchmarkConsumer.getBorn2ConsumerTotalRT().add(born2ConsumerRT);
long store2ConsumerRT = now - msg.getStoreTimestamp();
statsBenchmarkConsumer.getStore2ConsumerTotalRT().addAndGet(store2ConsumerRT);
statsBenchmarkConsumer.getStore2ConsumerTotalRT().add(store2ConsumerRT);
compareAndSetMax(statsBenchmarkConsumer.getBorn2ConsumerMaxRT(), born2ConsumerRT);
compareAndSetMax(statsBenchmarkConsumer.getStore2ConsumerMaxRT(), store2ConsumerRT);
if (ThreadLocalRandom.current().nextDouble() < failRate) {
statsBenchmarkConsumer.getFailCount().incrementAndGet();
statsBenchmarkConsumer.getFailCount().increment();
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
} else {
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
......@@ -189,8 +194,7 @@ public class Consumer {
opt = new Option("g", "group", true, "Consumer group name, Default: benchmark_consumer");
opt.setRequired(false);
options.addOption(opt);
opt = new Option("p", "group suffix enable", true, "Consumer group suffix enable, Default: false");
opt = new Option("p", "group prefix enable", true, "Is group prefix enable, Default: false");
opt.setRequired(false);
options.addOption(opt);
......@@ -230,39 +234,39 @@ public class Consumer {
}
class StatsBenchmarkConsumer {
private final AtomicLong receiveMessageTotalCount = new AtomicLong(0L);
private final LongAdder receiveMessageTotalCount = new LongAdder();
private final AtomicLong born2ConsumerTotalRT = new AtomicLong(0L);
private final LongAdder born2ConsumerTotalRT = new LongAdder();
private final AtomicLong store2ConsumerTotalRT = new AtomicLong(0L);
private final LongAdder store2ConsumerTotalRT = new LongAdder();
private final AtomicLong born2ConsumerMaxRT = new AtomicLong(0L);
private final AtomicLong store2ConsumerMaxRT = new AtomicLong(0L);
private final AtomicLong failCount = new AtomicLong(0L);
private final LongAdder failCount = new LongAdder();
public Long[] createSnapshot() {
Long[] snap = new Long[] {
System.currentTimeMillis(),
this.receiveMessageTotalCount.get(),
this.born2ConsumerTotalRT.get(),
this.store2ConsumerTotalRT.get(),
this.failCount.get()
this.receiveMessageTotalCount.longValue(),
this.born2ConsumerTotalRT.longValue(),
this.store2ConsumerTotalRT.longValue(),
this.failCount.longValue()
};
return snap;
}
public AtomicLong getReceiveMessageTotalCount() {
public LongAdder getReceiveMessageTotalCount() {
return receiveMessageTotalCount;
}
public AtomicLong getBorn2ConsumerTotalRT() {
public LongAdder getBorn2ConsumerTotalRT() {
return born2ConsumerTotalRT;
}
public AtomicLong getStore2ConsumerTotalRT() {
public LongAdder getStore2ConsumerTotalRT() {
return store2ConsumerTotalRT;
}
......@@ -274,7 +278,7 @@ class StatsBenchmarkConsumer {
return store2ConsumerMaxRT;
}
public AtomicLong getFailCount() {
public LongAdder getFailCount() {
return failCount;
}
}
......@@ -16,35 +16,40 @@
*/
package org.apache.rocketmq.example.benchmark;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.LongAdder;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.log.ClientLogger;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.logging.InternalLogger;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.logging.InternalLogger;
import org.apache.rocketmq.remoting.RPCHook;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.apache.rocketmq.srvutil.ServerUtil;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Random;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicLong;
public class Producer {
public static void main(String[] args) throws MQClientException, UnsupportedEncodingException {
private static byte[] msgBody;
public static void main(String[] args) throws MQClientException {
Options options = ServerUtil.buildCommandlineOptions(new Options());
CommandLine commandLine = ServerUtil.parseCmdLine("benchmarkProducer", args, buildCommandlineOptions(options), new PosixParser());
......@@ -61,9 +66,17 @@ public class Producer {
final boolean msgTraceEnable = commandLine.hasOption('m') && Boolean.parseBoolean(commandLine.getOptionValue('m'));
final boolean aclEnable = commandLine.hasOption('a') && Boolean.parseBoolean(commandLine.getOptionValue('a'));
final long messageNum = commandLine.hasOption('q') ? Long.parseLong(commandLine.getOptionValue('q')) : 0;
final boolean delayEnable = commandLine.hasOption('d') && Boolean.parseBoolean(commandLine.getOptionValue('d'));
final int delayLevel = commandLine.hasOption('e') ? Integer.parseInt(commandLine.getOptionValue('e')) : 1;
System.out.printf("topic: %s threadCount: %d messageSize: %d keyEnable: %s propertySize: %d tagCount: %d traceEnable: %s aclEnable: %s messageQuantity: %d%n",
topic, threadCount, messageSize, keyEnable, propertySize, tagCount, msgTraceEnable, aclEnable, messageNum);
System.out.printf("topic: %s threadCount: %d messageSize: %d keyEnable: %s propertySize: %d tagCount: %d traceEnable: %s aclEnable: %s messageQuantity: %d%n delayEnable: %s%n delayLevel: %s%n",
topic, threadCount, messageSize, keyEnable, propertySize, tagCount, msgTraceEnable, aclEnable, messageNum, delayEnable, delayLevel);
StringBuilder sb = new StringBuilder(messageSize);
for (int i = 0; i < messageSize; i++) {
sb.append(RandomStringUtils.randomAlphanumeric(1));
}
msgBody = sb.toString().getBytes(StandardCharsets.UTF_8);
final InternalLogger log = ClientLogger.getLog();
......@@ -71,7 +84,8 @@ public class Producer {
final StatsBenchmarkProducer statsBenchmark = new StatsBenchmarkProducer();
final Timer timer = new Timer("BenchmarkTimerThread", true);
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("BenchmarkTimerThread-%d").daemon(true).build());
final LinkedList<Long[]> snapshotList = new LinkedList<Long[]>();
......@@ -85,7 +99,7 @@ public class Producer {
}
}
timer.scheduleAtFixedRate(new TimerTask() {
executorService.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
snapshotList.addLast(statsBenchmark.createSnapshot());
......@@ -93,9 +107,9 @@ public class Producer {
snapshotList.removeFirst();
}
}
}, 1000, 1000);
}, 1000, 1000, TimeUnit.MILLISECONDS);
timer.scheduleAtFixedRate(new TimerTask() {
executorService.scheduleAtFixedRate(new TimerTask() {
private void printStats() {
if (snapshotList.size() >= 10) {
doPrintStats(snapshotList, statsBenchmark, false);
......@@ -110,7 +124,7 @@ public class Producer {
e.printStackTrace();
}
}
}, 10000, 10000);
}, 10000, 10000, TimeUnit.MILLISECONDS);
RPCHook rpcHook = aclEnable ? AclClient.getAclRPCHook() : null;
final DefaultMQProducer producer = new DefaultMQProducer("benchmark_producer", rpcHook, msgTraceEnable, null);
......@@ -136,20 +150,16 @@ public class Producer {
int num = 0;
while (true) {
try {
final Message msg;
try {
msg = buildMessage(messageSize, topic);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return;
}
final Message msg = buildMessage(topic);
final long beginTimestamp = System.currentTimeMillis();
if (keyEnable) {
msg.setKeys(String.valueOf(beginTimestamp / 1000));
}
if (delayEnable) {
msg.setDelayTimeLevel(delayLevel);
}
if (tagCount > 0) {
long sendSucCount = statsBenchmark.getReceiveResponseSuccessCount().get();
msg.setTags(String.format("tag%d", sendSucCount % tagCount));
msg.setTags(String.format("tag%d", System.currentTimeMillis() % tagCount));
}
if (propertySize > 0) {
if (msg.getProperties() != null) {
......@@ -172,20 +182,20 @@ public class Producer {
}
}
producer.send(msg);
statsBenchmark.getSendRequestSuccessCount().incrementAndGet();
statsBenchmark.getReceiveResponseSuccessCount().incrementAndGet();
statsBenchmark.getSendRequestSuccessCount().increment();
statsBenchmark.getReceiveResponseSuccessCount().increment();
final long currentRT = System.currentTimeMillis() - beginTimestamp;
statsBenchmark.getSendMessageSuccessTimeTotal().addAndGet(currentRT);
long prevMaxRT = statsBenchmark.getSendMessageMaxRT().get();
statsBenchmark.getSendMessageSuccessTimeTotal().add(currentRT);
long prevMaxRT = statsBenchmark.getSendMessageMaxRT().longValue();
while (currentRT > prevMaxRT) {
boolean updated = statsBenchmark.getSendMessageMaxRT().compareAndSet(prevMaxRT, currentRT);
if (updated)
break;
prevMaxRT = statsBenchmark.getSendMessageMaxRT().get();
prevMaxRT = statsBenchmark.getSendMessageMaxRT().longValue();
}
} catch (RemotingException e) {
statsBenchmark.getSendRequestFailedCount().incrementAndGet();
statsBenchmark.getSendRequestFailedCount().increment();
log.error("[BENCHMARK_PRODUCER] Send Exception", e);
try {
......@@ -193,16 +203,16 @@ public class Producer {
} catch (InterruptedException ignored) {
}
} catch (InterruptedException e) {
statsBenchmark.getSendRequestFailedCount().incrementAndGet();
statsBenchmark.getSendRequestFailedCount().increment();
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
}
} catch (MQClientException e) {
statsBenchmark.getSendRequestFailedCount().incrementAndGet();
statsBenchmark.getSendRequestFailedCount().increment();
log.error("[BENCHMARK_PRODUCER] Send Exception", e);
} catch (MQBrokerException e) {
statsBenchmark.getReceiveResponseFailedCount().incrementAndGet();
statsBenchmark.getReceiveResponseFailedCount().increment();
log.error("[BENCHMARK_PRODUCER] Send Exception", e);
try {
Thread.sleep(3000);
......@@ -219,13 +229,18 @@ public class Producer {
try {
sendThreadPool.shutdown();
sendThreadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
timer.cancel();
executorService.shutdown();
try {
executorService.awaitTermination(5000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
}
if (snapshotList.size() > 1) {
doPrintStats(snapshotList, statsBenchmark, true);
} else {
System.out.printf("[Complete] Send Total: %d Send Failed: %d Response Failed: %d%n",
statsBenchmark.getSendRequestSuccessCount().get() + statsBenchmark.getSendRequestFailedCount().get(),
statsBenchmark.getSendRequestFailedCount().get(), statsBenchmark.getReceiveResponseFailedCount().get());
statsBenchmark.getSendRequestSuccessCount().longValue() + statsBenchmark.getSendRequestFailedCount().longValue(),
statsBenchmark.getSendRequestFailedCount().longValue(), statsBenchmark.getReceiveResponseFailedCount().longValue());
}
producer.shutdown();
} catch (InterruptedException e) {
......@@ -266,21 +281,19 @@ public class Producer {
opt.setRequired(false);
options.addOption(opt);
return options;
}
private static Message buildMessage(final int messageSize, final String topic) throws UnsupportedEncodingException {
Message msg = new Message();
msg.setTopic(topic);
opt = new Option("d", "delayEnable", true, "Delay message Enable, Default: false");
opt.setRequired(false);
options.addOption(opt);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < messageSize; i += 10) {
sb.append("hello baby");
}
opt = new Option("e", "delayLevel", true, "Delay message level, Default: 1");
opt.setRequired(false);
options.addOption(opt);
msg.setBody(sb.toString().getBytes(RemotingHelper.DEFAULT_CHARSET));
return options;
}
return msg;
private static Message buildMessage(final String topic) {
return new Message(topic, msgBody);
}
private static void doPrintStats(final LinkedList<Long[]> snapshotList, final StatsBenchmarkProducer statsBenchmark, boolean done) {
......@@ -292,58 +305,58 @@ public class Producer {
if (done) {
System.out.printf("[Complete] Send Total: %d Send TPS: %d Max RT(ms): %d Average RT(ms): %7.3f Send Failed: %d Response Failed: %d%n",
statsBenchmark.getSendRequestSuccessCount().get() + statsBenchmark.getSendRequestFailedCount().get(),
sendTps, statsBenchmark.getSendMessageMaxRT().get(), averageRT, end[2], end[4]);
statsBenchmark.getSendRequestSuccessCount().longValue() + statsBenchmark.getSendRequestFailedCount().longValue(),
sendTps, statsBenchmark.getSendMessageMaxRT().longValue(), averageRT, end[2], end[4]);
} else {
System.out.printf("Current Time: %s Send TPS: %d Max RT(ms): %d Average RT(ms): %7.3f Send Failed: %d Response Failed: %d%n",
System.currentTimeMillis(), sendTps, statsBenchmark.getSendMessageMaxRT().get(), averageRT, end[2], end[4]);
System.currentTimeMillis(), sendTps, statsBenchmark.getSendMessageMaxRT().longValue(), averageRT, end[2], end[4]);
}
}
}
class StatsBenchmarkProducer {
private final AtomicLong sendRequestSuccessCount = new AtomicLong(0L);
private final LongAdder sendRequestSuccessCount = new LongAdder();
private final AtomicLong sendRequestFailedCount = new AtomicLong(0L);
private final LongAdder sendRequestFailedCount = new LongAdder();
private final AtomicLong receiveResponseSuccessCount = new AtomicLong(0L);
private final LongAdder receiveResponseSuccessCount = new LongAdder();
private final AtomicLong receiveResponseFailedCount = new AtomicLong(0L);
private final LongAdder receiveResponseFailedCount = new LongAdder();
private final AtomicLong sendMessageSuccessTimeTotal = new AtomicLong(0L);
private final LongAdder sendMessageSuccessTimeTotal = new LongAdder();
private final AtomicLong sendMessageMaxRT = new AtomicLong(0L);
public Long[] createSnapshot() {
Long[] snap = new Long[] {
System.currentTimeMillis(),
this.sendRequestSuccessCount.get(),
this.sendRequestFailedCount.get(),
this.receiveResponseSuccessCount.get(),
this.receiveResponseFailedCount.get(),
this.sendMessageSuccessTimeTotal.get(),
this.sendRequestSuccessCount.longValue(),
this.sendRequestFailedCount.longValue(),
this.receiveResponseSuccessCount.longValue(),
this.receiveResponseFailedCount.longValue(),
this.sendMessageSuccessTimeTotal.longValue(),
};
return snap;
}
public AtomicLong getSendRequestSuccessCount() {
public LongAdder getSendRequestSuccessCount() {
return sendRequestSuccessCount;
}
public AtomicLong getSendRequestFailedCount() {
public LongAdder getSendRequestFailedCount() {
return sendRequestFailedCount;
}
public AtomicLong getReceiveResponseSuccessCount() {
public LongAdder getReceiveResponseSuccessCount() {
return receiveResponseSuccessCount;
}
public AtomicLong getReceiveResponseFailedCount() {
public LongAdder getReceiveResponseFailedCount() {
return receiveResponseFailedCount;
}
public AtomicLong getSendMessageSuccessTimeTotal() {
public LongAdder getSendMessageSuccessTimeTotal() {
return sendMessageSuccessTimeTotal;
}
......
......@@ -17,26 +17,11 @@
package org.apache.rocketmq.example.benchmark;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendResult;
......@@ -48,9 +33,28 @@ import org.apache.rocketmq.common.message.MessageConst;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.srvutil.ServerUtil;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.LongAdder;
public class TransactionProducer {
private static final long START_TIME = System.currentTimeMillis();
private static final AtomicLong MSG_COUNT = new AtomicLong(0);
private static final LongAdder MSG_COUNT = new LongAdder();
//broker max check times should less than this value
static final int MAX_CHECK_RESULT_IN_MSG = 20;
......@@ -69,16 +73,18 @@ public class TransactionProducer {
config.batchId = commandLine.hasOption("b") ? Long.parseLong(commandLine.getOptionValue("b")) : System.currentTimeMillis();
config.sendInterval = commandLine.hasOption("i") ? Integer.parseInt(commandLine.getOptionValue("i")) : 0;
config.aclEnable = commandLine.hasOption('a') && Boolean.parseBoolean(commandLine.getOptionValue('a'));
config.msgTraceEnable = commandLine.hasOption('m') && Boolean.parseBoolean(commandLine.getOptionValue('m'));
final ExecutorService sendThreadPool = Executors.newFixedThreadPool(config.threadCount);
final StatsBenchmarkTProducer statsBenchmark = new StatsBenchmarkTProducer();
final Timer timer = new Timer("BenchmarkTimerThread", true);
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("BenchmarkTimerThread-%d").daemon(true).build());
final LinkedList<Snapshot> snapshotList = new LinkedList<>();
timer.scheduleAtFixedRate(new TimerTask() {
executorService.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
snapshotList.addLast(statsBenchmark.createSnapshot());
......@@ -86,9 +92,9 @@ public class TransactionProducer {
snapshotList.removeFirst();
}
}
}, 1000, 1000);
}, 1000, 1000, TimeUnit.MILLISECONDS);
timer.scheduleAtFixedRate(new TimerTask() {
executorService.scheduleAtFixedRate(new TimerTask() {
private void printStats() {
if (snapshotList.size() >= 10) {
Snapshot begin = snapshotList.getFirst();
......@@ -120,11 +126,15 @@ public class TransactionProducer {
e.printStackTrace();
}
}
}, 10000, 10000);
}, 10000, 10000, TimeUnit.MILLISECONDS);
final TransactionListener transactionCheckListener = new TransactionListenerImpl(statsBenchmark, config);
final TransactionMQProducer producer =
new TransactionMQProducer("benchmark_transaction_producer", config.aclEnable ? AclClient.getAclRPCHook() : null);
final TransactionMQProducer producer = new TransactionMQProducer(
null,
"benchmark_transaction_producer",
config.aclEnable ? AclClient.getAclRPCHook() : null,
config.msgTraceEnable,
null);
producer.setInstanceName(Long.toString(System.currentTimeMillis()));
producer.setTransactionListener(transactionCheckListener);
producer.setDefaultTopicQueueNums(1000);
......@@ -149,7 +159,7 @@ public class TransactionProducer {
success = false;
} finally {
final long currentRT = System.currentTimeMillis() - beginTimestamp;
statsBenchmark.getSendMessageTimeTotal().addAndGet(currentRT);
statsBenchmark.getSendMessageTimeTotal().add(currentRT);
long prevMaxRT = statsBenchmark.getSendMessageMaxRT().get();
while (currentRT > prevMaxRT) {
boolean updated = statsBenchmark.getSendMessageMaxRT()
......@@ -160,9 +170,9 @@ public class TransactionProducer {
prevMaxRT = statsBenchmark.getSendMessageMaxRT().get();
}
if (success) {
statsBenchmark.getSendRequestSuccessCount().incrementAndGet();
statsBenchmark.getSendRequestSuccessCount().increment();
} else {
statsBenchmark.getSendRequestFailedCount().incrementAndGet();
statsBenchmark.getSendRequestFailedCount().increment();
}
if (config.sendInterval > 0) {
try {
......@@ -185,7 +195,9 @@ public class TransactionProducer {
ByteBuffer buf = ByteBuffer.wrap(bs);
buf.putLong(config.batchId);
long sendMachineId = START_TIME << 32;
long msgId = sendMachineId | MSG_COUNT.getAndIncrement();
long count = MSG_COUNT.longValue();
long msgId = sendMachineId | count;
MSG_COUNT.increment();
buf.putLong(msgId);
// save send tx result in message
......@@ -256,6 +268,10 @@ public class TransactionProducer {
opt.setRequired(false);
options.addOption(opt);
opt = new Option("m", "msgTraceEnable", true, "Message Trace Enable, Default: false");
opt.setRequired(false);
options.addOption(opt);
return options;
}
}
......@@ -303,7 +319,7 @@ class TransactionListenerImpl implements TransactionListener {
// message not generated in this test
return LocalTransactionState.ROLLBACK_MESSAGE;
}
statBenchmark.getCheckCount().incrementAndGet();
statBenchmark.getCheckCount().increment();
int times = 0;
try {
......@@ -326,7 +342,7 @@ class TransactionListenerImpl implements TransactionListener {
dup = newCheckLog.equals(oldCheckLog);
}
if (dup) {
statBenchmark.getDuplicatedCheckCount().incrementAndGet();
statBenchmark.getDuplicatedCheckCount().increment();
}
if (msgMeta.sendResult != LocalTransactionState.UNKNOW) {
System.out.printf("%s unexpected check: msgId=%s,txId=%s,checkTimes=%s,sendResult=%s\n",
......@@ -334,7 +350,7 @@ class TransactionListenerImpl implements TransactionListener {
msg.getMsgId(), msg.getTransactionId(),
msg.getUserProperty(MessageConst.PROPERTY_TRANSACTION_CHECK_TIMES),
msgMeta.sendResult.toString());
statBenchmark.getUnexpectedCheckCount().incrementAndGet();
statBenchmark.getUnexpectedCheckCount().increment();
return msgMeta.sendResult;
}
......@@ -345,7 +361,7 @@ class TransactionListenerImpl implements TransactionListener {
new SimpleDateFormat("HH:mm:ss,SSS").format(new Date()),
msg.getMsgId(), msg.getTransactionId(),
msg.getUserProperty(MessageConst.PROPERTY_TRANSACTION_CHECK_TIMES), s);
statBenchmark.getUnexpectedCheckCount().incrementAndGet();
statBenchmark.getUnexpectedCheckCount().increment();
return s;
}
}
......@@ -372,42 +388,42 @@ class Snapshot {
}
class StatsBenchmarkTProducer {
private final AtomicLong sendRequestSuccessCount = new AtomicLong(0L);
private final LongAdder sendRequestSuccessCount = new LongAdder();
private final AtomicLong sendRequestFailedCount = new AtomicLong(0L);
private final LongAdder sendRequestFailedCount = new LongAdder();
private final AtomicLong sendMessageTimeTotal = new AtomicLong(0L);
private final LongAdder sendMessageTimeTotal = new LongAdder();
private final AtomicLong sendMessageMaxRT = new AtomicLong(0L);
private final AtomicLong checkCount = new AtomicLong(0L);
private final LongAdder checkCount = new LongAdder();
private final AtomicLong unexpectedCheckCount = new AtomicLong(0L);
private final LongAdder unexpectedCheckCount = new LongAdder();
private final AtomicLong duplicatedCheckCount = new AtomicLong(0);
private final LongAdder duplicatedCheckCount = new LongAdder();
public Snapshot createSnapshot() {
Snapshot s = new Snapshot();
s.endTime = System.currentTimeMillis();
s.sendRequestSuccessCount = sendRequestSuccessCount.get();
s.sendRequestFailedCount = sendRequestFailedCount.get();
s.sendMessageTimeTotal = sendMessageTimeTotal.get();
s.sendRequestSuccessCount = sendRequestSuccessCount.longValue();
s.sendRequestFailedCount = sendRequestFailedCount.longValue();
s.sendMessageTimeTotal = sendMessageTimeTotal.longValue();
s.sendMessageMaxRT = sendMessageMaxRT.get();
s.checkCount = checkCount.get();
s.unexpectedCheckCount = unexpectedCheckCount.get();
s.duplicatedCheck = duplicatedCheckCount.get();
s.checkCount = checkCount.longValue();
s.unexpectedCheckCount = unexpectedCheckCount.longValue();
s.duplicatedCheck = duplicatedCheckCount.longValue();
return s;
}
public AtomicLong getSendRequestSuccessCount() {
public LongAdder getSendRequestSuccessCount() {
return sendRequestSuccessCount;
}
public AtomicLong getSendRequestFailedCount() {
public LongAdder getSendRequestFailedCount() {
return sendRequestFailedCount;
}
public AtomicLong getSendMessageTimeTotal() {
public LongAdder getSendMessageTimeTotal() {
return sendMessageTimeTotal;
}
......@@ -415,15 +431,15 @@ class StatsBenchmarkTProducer {
return sendMessageMaxRT;
}
public AtomicLong getCheckCount() {
public LongAdder getCheckCount() {
return checkCount;
}
public AtomicLong getUnexpectedCheckCount() {
public LongAdder getUnexpectedCheckCount() {
return unexpectedCheckCount;
}
public AtomicLong getDuplicatedCheckCount() {
public LongAdder getDuplicatedCheckCount() {
return duplicatedCheckCount;
}
}
......@@ -439,6 +455,7 @@ class TxSendConfig {
long batchId;
int sendInterval;
boolean aclEnable;
boolean msgTraceEnable;
}
class LRUMap<K, V> extends LinkedHashMap<K, V> {
......
......@@ -65,6 +65,39 @@ public class Producer {
* Call send message to deliver message to one of brokers.
*/
SendResult sendResult = producer.send(msg);
/*
* There are different ways to send message, if you don't care about the send result,you can use this way
* {@code
* producer.sendOneway(msg);
* }
*/
/*
* if you want to get the send result in a synchronize way, you can use this send method
* {@code
* SendResult sendResult = producer.send(msg);
* System.out.printf("%s%n", sendResult);
* }
*/
/*
* if you want to get the send result in a asynchronize way, you can use this send method
* {@code
*
* producer.send(msg, new SendCallback() {
* @Override
* public void onSuccess(SendResult sendResult) {
* // do something
* }
*
* @Override
* public void onException(Throwable e) {
* // do something
* }
*});
*
*}
*/
System.out.printf("%s%n", sendResult);
} catch (Exception e) {
......
......@@ -16,63 +16,131 @@
*/
package org.apache.rocketmq.example.simple;
import java.util.HashMap;
import java.util.Map;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
import org.apache.rocketmq.client.consumer.PullResult;
import org.apache.rocketmq.client.consumer.store.ReadOffsetType;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.remoting.exception.RemotingException;
@SuppressWarnings("deprecation")
public class PullConsumer {
private static final Map<MessageQueue, Long> OFFSE_TABLE = new HashMap<MessageQueue, Long>();
public static void main(String[] args) throws MQClientException {
DefaultMQPullConsumer consumer = new DefaultMQPullConsumer("please_rename_unique_group_name_5");
consumer.setNamesrvAddr("127.0.0.1:9876");
Set<String> topics = new HashSet<>();
//You would better to register topics,It will use in rebalance when starting
topics.add("TopicTest");
consumer.setRegisterTopics(topics);
consumer.start();
Set<MessageQueue> mqs = consumer.fetchSubscribeMessageQueues("broker-a");
for (MessageQueue mq : mqs) {
System.out.printf("Consume from the queue: %s%n", mq);
SINGLE_MQ:
while (true) {
try {
PullResult pullResult =
consumer.pullBlockIfNotFound(mq, null, getMessageQueueOffset(mq), 32);
System.out.printf("%s%n", pullResult);
putMessageQueueOffset(mq, pullResult.getNextBeginOffset());
switch (pullResult.getPullStatus()) {
case FOUND:
break;
case NO_MATCHED_MSG:
break;
case NO_NEW_MSG:
break SINGLE_MQ;
case OFFSET_ILLEGAL:
break;
default:
break;
}
} catch (Exception e) {
e.printStackTrace();
}
ExecutorService executors = Executors.newFixedThreadPool(topics.size(), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "PullConsumerThread");
}
});
for(String topic : consumer.getRegisterTopics()){
executors.execute(new Runnable() {
public void doSomething(List<MessageExt> msgs){
//do you business
System.out.println(msgs);
}
@Override
public void run() {
while(true){
try {
Set<MessageQueue> messageQueues = consumer.fetchMessageQueuesInBalance(topic);
if(messageQueues == null || messageQueues.isEmpty()){
Thread.sleep(1000);
continue;
}
PullResult pullResult = null;
for(MessageQueue messageQueue : messageQueues){
try {
long offset = this.consumeFromOffset(messageQueue);
pullResult = consumer.pull(messageQueue, "*", offset, 32);
switch (pullResult.getPullStatus()) {
case FOUND:
List<MessageExt> msgs = pullResult.getMsgFoundList();
if(msgs != null && !msgs.isEmpty()){
this.doSomething(msgs);
//update offset to broker
consumer.updateConsumeOffset(messageQueue, pullResult.getNextBeginOffset());
//print pull tps
this.incPullTPS(topic, pullResult.getMsgFoundList().size());
}
break;
case OFFSET_ILLEGAL:
consumer.updateConsumeOffset(messageQueue, pullResult.getNextBeginOffset());
break;
case NO_NEW_MSG:
Thread.sleep(1);
consumer.updateConsumeOffset(messageQueue, pullResult.getNextBeginOffset());
break;
case NO_MATCHED_MSG:
consumer.updateConsumeOffset(messageQueue, pullResult.getNextBeginOffset());
break;
default:
}
} catch (RemotingException e) {
e.printStackTrace();
} catch (MQBrokerException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
}
} catch (MQClientException e) {
//reblance error
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
}
}
public long consumeFromOffset(MessageQueue messageQueue) throws MQClientException{
//-1 when started
long offset = consumer.getOffsetStore().readOffset(messageQueue, ReadOffsetType.READ_FROM_MEMORY);
if(offset < 0){
//query from broker
offset = consumer.getOffsetStore().readOffset(messageQueue, ReadOffsetType.READ_FROM_STORE);
}
if (offset < 0){
//first time start from last offset
offset = consumer.maxOffset(messageQueue);
}
//make sure
if (offset < 0){
offset = 0;
}
return offset;
}
public void incPullTPS(String topic, int pullSize) {
consumer.getDefaultMQPullConsumerImpl().getRebalanceImpl().getmQClientFactory()
.getConsumerStatsManager().incPullTPS(consumer.getConsumerGroup(), topic, pullSize);
}
});
}
consumer.shutdown();
// executors.shutdown();
// consumer.shutdown();
}
private static long getMessageQueueOffset(MessageQueue mq) {
Long offset = OFFSE_TABLE.get(mq);
if (offset != null)
return offset;
return 0;
}
private static void putMessageQueueOffset(MessageQueue mq, long offset) {
OFFSE_TABLE.put(mq, offset);
}
}
......@@ -84,7 +84,7 @@ public class ParserTest {
@Test
public void testParse_floatOverFlow() {
try {
StringBuffer sb = new StringBuffer(210000);
StringBuilder sb = new StringBuilder(210000);
sb.append("1");
for (int i = 0; i < 2048; i ++) {
sb.append("111111111111111111111111111111111111111111111111111");
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册