Skip to content

Commit 3aa8ee5

Browse files
maixiaohaizhangxu16
and
zhangxu16
authored
[ISSUE #669] Support RocketMQ as storage of mqtt broker (#687)
* Config refactor, add some rocketmq config * Add rmq publish producer * Fix NPE start with memory mode, remove useless dependency * Non-standard mqtt request return directly * Add rmq subscribe consumer and related pull task, complete mqtt SUBSCRIBE and UNSUBSCRIBE protcol * Fix subTopic not remove when disconnect * Fix connection management, fix consume delay to make pull task to queue level * Fix ut not pass when root topic removed from subsription * Fix integration test not pass when not use rmq subscribe consumer Co-authored-by: zhangxu16 <[email protected]>
1 parent ce5c543 commit 3aa8ee5

24 files changed

+940
-96
lines changed

rocketmq-iot-bridge/pom.xml

+16-6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ limitations under the License.
2626
<name>rocketmq-iot-bridge ${project.version}</name>
2727

2828
<dependencies>
29+
<dependency>
30+
<groupId>org.apache.rocketmq</groupId>
31+
<artifactId>rocketmq-tools</artifactId>
32+
<version>${rocketmq.version}</version>
33+
</dependency>
2934
<dependency>
3035
<groupId>io.netty</groupId>
3136
<artifactId>netty-all</artifactId>
@@ -53,12 +58,6 @@ limitations under the License.
5358
<version>1.9.5</version>
5459
<scope>test</scope>
5560
</dependency>
56-
<dependency>
57-
<groupId>org.apache.commons</groupId>
58-
<artifactId>commons-lang3</artifactId>
59-
<version>3.0</version>
60-
<scope>test</scope>
61-
</dependency>
6261
<dependency>
6362
<groupId>org.slf4j</groupId>
6463
<artifactId>slf4j-api</artifactId>
@@ -74,7 +73,10 @@ limitations under the License.
7473
<properties>
7574
<maven.compiler.source>1.8</maven.compiler.source>
7675
<maven.compiler.target>1.8</maven.compiler.target>
76+
77+
<rocketmq.version>4.8.0</rocketmq.version>
7778
</properties>
79+
7880
<build>
7981
<plugins>
8082
<plugin>
@@ -209,6 +211,14 @@ limitations under the License.
209211
</execution>
210212
</executions>
211213
</plugin>
214+
<plugin>
215+
<groupId>org.apache.maven.plugins</groupId>
216+
<artifactId>maven-compiler-plugin</artifactId>
217+
<configuration>
218+
<source>${maven.compiler.source}</source>
219+
<target>${maven.compiler.target}</target>
220+
</configuration>
221+
</plugin>
212222
</plugins>
213223
</build>
214224
</project>

rocketmq-iot-bridge/src/main/java/org/apache/rocketmq/iot/MQTTBridge.java

+49-15
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import io.netty.channel.socket.nio.NioServerSocketChannel;
2828
import io.netty.handler.codec.mqtt.MqttDecoder;
2929
import io.netty.handler.codec.mqtt.MqttEncoder;
30-
import org.apache.rocketmq.iot.common.configuration.MQTTBridgeConfiguration;
30+
import org.apache.rocketmq.iot.common.config.MqttBridgeConfig;
3131
import org.apache.rocketmq.iot.common.data.Message;
3232
import org.apache.rocketmq.iot.connection.client.ClientManager;
3333
import org.apache.rocketmq.iot.protocol.mqtt.handler.MessageDispatcher;
@@ -38,36 +38,61 @@
3838
import org.apache.rocketmq.iot.protocol.mqtt.handler.downstream.impl.MqttDisconnectMessageHandler;
3939
import org.apache.rocketmq.iot.protocol.mqtt.handler.downstream.impl.MqttMessageForwarder;
4040
import org.apache.rocketmq.iot.protocol.mqtt.handler.downstream.impl.MqttPingreqMessageHandler;
41+
import org.apache.rocketmq.iot.protocol.mqtt.handler.downstream.impl.MqttPublishMessageHandler;
4142
import org.apache.rocketmq.iot.protocol.mqtt.handler.downstream.impl.MqttSubscribeMessageHandler;
4243
import org.apache.rocketmq.iot.protocol.mqtt.handler.downstream.impl.MqttUnsubscribeMessagHandler;
44+
import org.apache.rocketmq.iot.storage.message.MessageStore;
45+
import org.apache.rocketmq.iot.storage.rocketmq.PublishProducer;
46+
import org.apache.rocketmq.iot.storage.rocketmq.RocketMQPublishProducer;
47+
import org.apache.rocketmq.iot.storage.rocketmq.RocketMQSubscribeConsumer;
48+
import org.apache.rocketmq.iot.storage.rocketmq.SubscribeConsumer;
4349
import org.apache.rocketmq.iot.storage.subscription.SubscriptionStore;
4450
import org.apache.rocketmq.iot.storage.subscription.impl.InMemorySubscriptionStore;
4551
import org.slf4j.Logger;
4652
import org.slf4j.LoggerFactory;
4753

4854
public class MQTTBridge {
55+
private Logger logger = LoggerFactory.getLogger(MQTTBridge.class);
56+
57+
private MqttBridgeConfig bridgeConfig;
4958

5059
private ServerBootstrap serverBootstrap;
5160
private NioEventLoopGroup bossGroup;
5261
private NioEventLoopGroup workerGroup;
62+
5363
private MessageDispatcher messageDispatcher;
5464
private SubscriptionStore subscriptionStore;
5565
private ClientManager clientManager;
5666
private MqttConnectionHandler connectionHandler;
57-
private Logger logger = LoggerFactory.getLogger(MQTTBridge.class);
67+
private MessageStore messageStore;
68+
private PublishProducer publishProducer;
69+
private SubscribeConsumer subscribeConsumer;
5870

5971
public MQTTBridge() {
6072
init();
6173
}
6274

6375
private void init() {
64-
bossGroup = new NioEventLoopGroup(MQTTBridgeConfiguration.threadNumOfBossGroup());
65-
workerGroup = new NioEventLoopGroup(MQTTBridgeConfiguration.threadNumOfWorkerGroup());
76+
this.bridgeConfig = new MqttBridgeConfig();
77+
78+
subscriptionStore = new InMemorySubscriptionStore();
79+
if (bridgeConfig.isEnableRocketMQStore()) {
80+
this.publishProducer = new RocketMQPublishProducer(bridgeConfig);
81+
this.subscribeConsumer = new RocketMQSubscribeConsumer(bridgeConfig, subscriptionStore);
82+
}
83+
84+
clientManager = new ClientManagerImpl();
85+
messageDispatcher = new MessageDispatcher(clientManager);
86+
connectionHandler = new MqttConnectionHandler(clientManager, subscriptionStore, subscribeConsumer);
87+
registerMessageHandlers();
88+
89+
bossGroup = new NioEventLoopGroup(bridgeConfig.getBossGroupThreadNum());
90+
workerGroup = new NioEventLoopGroup(bridgeConfig.getWorkerGroupThreadNum());
6691
serverBootstrap = new ServerBootstrap();
6792
serverBootstrap.group(bossGroup, workerGroup)
68-
.localAddress(MQTTBridgeConfiguration.port())
93+
.localAddress(bridgeConfig.getBrokerPort())
6994
.channel(NioServerSocketChannel.class)
70-
.option(ChannelOption.SO_BACKLOG, MQTTBridgeConfiguration.socketBacklog())
95+
.option(ChannelOption.SO_BACKLOG, bridgeConfig.getSocketBacklogSize())
7196
.childHandler(new ChannelInitializer<SocketChannel>() {
7297
@Override protected void initChannel(SocketChannel ch) throws Exception {
7398
ChannelPipeline pipeline = ch.pipeline();
@@ -78,29 +103,35 @@ private void init() {
78103
pipeline.addLast("connection-manager", connectionHandler);
79104
}
80105
});
81-
subscriptionStore = new InMemorySubscriptionStore();
82-
clientManager = new ClientManagerImpl();
83-
messageDispatcher = new MessageDispatcher(clientManager);
84-
connectionHandler = new MqttConnectionHandler(clientManager, subscriptionStore);
85-
registerMessageHandlers();
106+
86107
}
87108

88109
private void registerMessageHandlers() {
89110
messageDispatcher.registerHandler(Message.Type.MQTT_CONNECT, new MqttConnectMessageHandler(clientManager));
90111
messageDispatcher.registerHandler(Message.Type.MQTT_DISCONNECT, new MqttDisconnectMessageHandler(clientManager));
91-
messageDispatcher.registerHandler(Message.Type.MQTT_PUBLISH, new MqttMessageForwarder(subscriptionStore));
112+
if (bridgeConfig.isEnableRocketMQStore()) {
113+
messageDispatcher.registerHandler(Message.Type.MQTT_PUBLISH, new MqttPublishMessageHandler(messageStore, publishProducer));
114+
// TODO: mqtt cluster inner forwarder, need management of offset and client
115+
} else {
116+
messageDispatcher.registerHandler(Message.Type.MQTT_PUBLISH, new MqttMessageForwarder(subscriptionStore));
117+
}
92118
// TODO qos 1/2 PUBLISH
93119
// TODO qos 1: PUBACK
94120
// TODO qos 2: PUBREC
95121
// TODO qos 2: PUBREL
96122
// TODO qos 2: PUBCOMP
97123
messageDispatcher.registerHandler(Message.Type.MQTT_PINGREQ, new MqttPingreqMessageHandler());
98-
messageDispatcher.registerHandler(Message.Type.MQTT_SUBSCRIBE, new MqttSubscribeMessageHandler(subscriptionStore));
99-
messageDispatcher.registerHandler(Message.Type.MQTT_UNSUBSCRIBE, new MqttUnsubscribeMessagHandler(subscriptionStore));
124+
messageDispatcher.registerHandler(Message.Type.MQTT_SUBSCRIBE, new MqttSubscribeMessageHandler(subscriptionStore, subscribeConsumer));
125+
messageDispatcher.registerHandler(Message.Type.MQTT_UNSUBSCRIBE, new MqttUnsubscribeMessagHandler(subscriptionStore, subscribeConsumer));
100126
}
101127

102128
public void start() {
129+
logger.info("start the MQTTServer with config " + bridgeConfig);
103130
try {
131+
if (bridgeConfig.isEnableRocketMQStore()) {
132+
publishProducer.start();
133+
subscribeConsumer.start();
134+
}
104135
ChannelFuture channelFuture = serverBootstrap.bind().sync();
105136
channelFuture.channel().closeFuture().sync();
106137
} catch (Exception e) {
@@ -109,12 +140,15 @@ public void start() {
109140
logger.info("shutdown the MQTTServer");
110141
shutdown();
111142
}
112-
113143
}
114144

115145
public void shutdown() {
116146
bossGroup.shutdownGracefully();
117147
workerGroup.shutdownGracefully();
148+
if (bridgeConfig.isEnableRocketMQStore()) {
149+
publishProducer.shutdown();
150+
subscribeConsumer.shutdown();
151+
}
118152
}
119153

120154
public static void main(String [] args) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.rocketmq.iot.common.config;
19+
20+
import java.util.Properties;
21+
22+
import static org.apache.rocketmq.iot.common.configuration.MQTTBridgeConfiguration.*;
23+
24+
public class MqttBridgeConfig {
25+
private Properties properties;
26+
27+
private String brokerHost;
28+
private int brokerPort;
29+
private int bossGroupThreadNum;
30+
private int workerGroupThreadNum;
31+
private int socketBacklogSize;
32+
33+
private boolean enableRocketMQStore;
34+
private String rmqNamesrvAddr;
35+
private String rmqProductGroup;
36+
private String rmqConsumerGroup;
37+
private int rmqConsumerPullNums;
38+
private String rmqAccessKey;
39+
private String rmqSecretKey;
40+
41+
public MqttBridgeConfig() {
42+
initConfig();
43+
}
44+
45+
public MqttBridgeConfig(Properties properties) {
46+
this.properties = properties;
47+
}
48+
49+
public void initConfig() {
50+
this.brokerHost = System.getProperty(MQTT_BROKER_HOST, MQTT_BROKER_HOST_DEFAULT);
51+
this.brokerPort = Integer.parseInt(System.getProperty(MQTT_BROKER_PORT, MQTT_BROKER_PORT_DEFAULT));
52+
53+
this.bossGroupThreadNum = Integer.parseInt(System.getProperty(MQTT_SERVER_BOSS_GROUP_THREAD_NUM,
54+
MQTT_SERVER_BOSS_GROUP_THREAD_NUM_DEFAULT));
55+
this.workerGroupThreadNum = Integer.parseInt(System.getProperty(MQTT_SERVER_WORKER_GROUP_THREAD_NUM,
56+
MQTT_SERVER_WORKER_GROUP_THREAD_NUM_DEFAULT));
57+
this.socketBacklogSize = Integer.parseInt(System.getProperty(MQTT_SERVER_SOCKET_BACKLOG_SIZE,
58+
MQTT_SERVER_SOCKET_BACKLOG_SIZE_DEFAULT));
59+
60+
this.enableRocketMQStore = Boolean.parseBoolean(System.getProperty(MQTT_ROCKETMQ_STORE_ENABLED, MQTT_ROCKETMQ_STORE_ENABLED_DEFAULT));
61+
if (enableRocketMQStore) {
62+
this.rmqNamesrvAddr = System.getProperty(MQTT_ROCKETMQ_NAMESRVADDR, MQTT_ROCKETMQ_NAMESRVADDR_DEFAULT);
63+
this.rmqProductGroup = System.getProperty(MQTT_ROCKETMQ_PRODUCER_GROUP, MQTT_ROCKETMQ_PRODUCER_GROUP_DEFAULT);
64+
this.rmqConsumerGroup = System.getProperty(MQTT_ROCKETMQ_CONSUMER_GROUP, MQTT_ROCKETMQ_CONSUMER_GROUP_DEFAULT);
65+
this.rmqConsumerPullNums = Integer.parseInt(System.getProperty(MQTT_ROKECTMQ_CONSUMER_PULL_NUMS,
66+
MQTT_ROKECTMQ_CONSUMER_PULL_NUMS_DEFAULT));
67+
68+
this.rmqAccessKey = System.getProperty(MQTT_ROCKETMQ_ACCESSKEY, MQTT_ROCKETMQ_ACCESSKEY_DEFAULT);
69+
this.rmqSecretKey = System.getProperty(MQTT_ROCKETMQ_SECRETKEY, MQTT_ROCKETMQ_SECRETKEY_DEFAULT);
70+
}
71+
72+
}
73+
74+
public String getBrokerHost() {
75+
return brokerHost;
76+
}
77+
78+
public int getBrokerPort() {
79+
return brokerPort;
80+
}
81+
82+
public int getBossGroupThreadNum() {
83+
return bossGroupThreadNum;
84+
}
85+
86+
public int getWorkerGroupThreadNum() {
87+
return workerGroupThreadNum;
88+
}
89+
90+
public int getSocketBacklogSize() {
91+
return socketBacklogSize;
92+
}
93+
94+
public boolean isEnableRocketMQStore() {
95+
return enableRocketMQStore;
96+
}
97+
98+
public String getRmqAccessKey() {
99+
return rmqAccessKey;
100+
}
101+
102+
public String getRmqSecretKey() {
103+
return rmqSecretKey;
104+
}
105+
106+
public String getRmqNamesrvAddr() {
107+
return rmqNamesrvAddr;
108+
}
109+
110+
public String getRmqProductGroup() {
111+
return rmqProductGroup;
112+
}
113+
114+
public String getRmqConsumerGroup() {
115+
return rmqConsumerGroup;
116+
}
117+
118+
public int getRmqConsumerPullNums() {
119+
return rmqConsumerPullNums;
120+
}
121+
122+
@Override public String toString() {
123+
return "MqttBridgeConfig{" +
124+
"brokerHost='" + brokerHost + '\'' +
125+
", brokerPort=" + brokerPort +
126+
", bossGroupThreadNum=" + bossGroupThreadNum +
127+
", workerGroupThreadNum=" + workerGroupThreadNum +
128+
", socketBacklogSize=" + socketBacklogSize +
129+
", enableRocketMQStore=" + enableRocketMQStore +
130+
", rmqNamesrvAddr='" + rmqNamesrvAddr + '\'' +
131+
", rmqProductGroup='" + rmqProductGroup + '\'' +
132+
", rmqConsumerGroup='" + rmqConsumerGroup + '\'' +
133+
", rmqConsumerPullNums='" + rmqConsumerPullNums + '\'' +
134+
", rmqAccessKey='" + rmqAccessKey + '\'' +
135+
", rmqSecretKey='" + rmqSecretKey + '\'' +
136+
'}';
137+
}
138+
}

0 commit comments

Comments
 (0)