You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rocketmq.apache.org by du...@apache.org on 2019/01/02 16:45:24 UTC

[rocketmq] branch snode created (now cd4403c)

This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a change to branch snode
in repository https://gitbox.apache.org/repos/asf/rocketmq.git.


      at cd4403c  Modify license header

This branch includes the following new commits:

     new fa2f611  Refactor remoting module
     new 71696dc  Change ServiceProvide path
     new c668abb  Modify Serviceloader implementation
     new e42970b  Polish async invoke implementation, prevent the block occurred during create channel
     new 9f5383e  Add Snode server
     new 36cec93  Add async response interface and implementation
     new 20da514  Add subscription, consumer offset, sendback etc. management module
     new e836fc3  Add push and push session interface
     new f84239e  Remove netty dependency in RemotingClient and Remoting Server
     new 6014a03  Remove netty dependency of RemotingClient and RemotingServer interface
     new fe63f3a  Rename rocket-snode directory name
     new db97b40  Polish snode related RemotingChannel implementation
     new 6a49f0c  Add snode interceptor
     new cd4403c  Modify license header

The 14 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[rocketmq] 05/14: Add Snode server

Posted by du...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a commit to branch snode
in repository https://gitbox.apache.org/repos/asf/rocketmq.git

commit 9f5383e58a6886b253395d5b6f2852e1b13552d2
Author: duhenglucky <du...@gmail.com>
AuthorDate: Fri Dec 21 02:43:48 2018 +0800

    Add Snode server
---
 .../apache/rocketmq/broker/BrokerController.java   |  11 +-
 .../org/apache/rocketmq/broker/BrokerStartup.java  |   7 +-
 .../broker/client/ClientHousekeepingService.java   |   1 -
 .../broker/longpolling/PullRequestHoldService.java |  18 +-
 .../broker/processor/ClientManageProcessor.java    |   2 +
 .../processor/SnodePullMessageProcessor.java       | 449 +++++++++++++++++++++
 .../rocketmq/client/impl/MQClientAPIImpl.java      |  17 +-
 .../client/impl/factory/MQClientInstance.java      |   4 +-
 .../impl/producer/DefaultMQProducerImpl.java       |  37 +-
 .../rocketmq/common/constant/LoggerName.java       |   1 +
 .../common/namesrv/RegisterSnodeResult.java        |  20 +
 .../rocketmq/common/protocol/RequestCode.java      |   5 +
 .../rocketmq/common/protocol/body/ClusterInfo.java |  22 +
 .../protocol/header/PullMessageRequestHeader.java  |  10 +
 .../protocol/header/SendMessageRequestHeader.java  |  10 +
 .../header/SendMessageRequestHeaderV2.java         |  12 +
 .../header/namesrv/RegisterSnodeRequestHeader.java |  61 +++
 .../namesrv/RegisterSnodeResponseHeader.java       |  20 +
 .../common/protocol/heartbeat/HeartbeatData.java   |  20 +-
 .../common/protocol/heartbeat/SnodeData.java       |  34 ++
 .../rocketmq/common/protocol/route/SnodeData.java  |  57 +++
 .../common/utils/PositiveAtomicCounter.java        |  40 ++
 distribution/conf/logback_snode.xml                |  92 +++++
 .../rocketmq/example/quickstart/Producer.java      |   4 +-
 .../apache/rocketmq/example/simple/Producer.java   |   1 -
 .../namesrv/processor/DefaultRequestProcessor.java |  18 +-
 .../namesrv/routeinfo/RouteInfoManager.java        |  31 ++
 pom.xml                                            |   1 +
 rocketmq-snode/pom.xml                             |  93 +++++
 .../org/apache/rocketmq/snode/SnodeController.java | 205 ++++++++++
 .../org/apache/rocketmq/snode/SnodeStartup.java    | 144 +++++++
 .../rocketmq/snode/client/ClientChannelInfo.java   | 100 +++++
 .../snode}/client/ClientHousekeepingService.java   |  36 +-
 .../rocketmq/snode/client/ConsumerGroupEvent.java  |  33 ++
 .../rocketmq/snode/client/ConsumerGroupInfo.java   | 248 ++++++++++++
 .../snode/client/ConsumerIdsChangeListener.java    |  22 +
 .../rocketmq/snode/client/ConsumerManager.java     | 189 +++++++++
 .../client/DefaultConsumerIdsChangeListener.java   |  64 +++
 .../rocketmq/snode/client/ProducerManager.java     | 224 ++++++++++
 .../snode/client/SubscriptionGroupManager.java     | 200 +++++++++
 .../apache/rocketmq/snode/config/SnodeConfig.java  | 223 ++++++++++
 .../snode/processor/ConsumerManageProcessor.java   |  96 +++++
 .../snode/processor/HearbeatProcessor.java         |  92 +++++
 .../snode/processor/PullMessageProcessor.java      |  40 ++
 .../snode/processor/SendMessageProcessor.java      |  44 ++
 .../rocketmq/snode/service/ScheduledService.java   |  21 +
 .../snode/service/SendTransferService.java         |  26 ++
 .../rocketmq/snode/service/SnodeOuterService.java  |  52 +++
 .../snode/service/impl/ScheduledServiceImpl.java   | 113 ++++++
 .../service/impl/SendTransferServiceImpl.java      |  45 +++
 .../snode/service/impl/SnodeOuterServiceImpl.java  | 270 +++++++++++++
 .../rocketmq/snode/topic/TopicConfigManager.java   |  19 +
 52 files changed, 3542 insertions(+), 62 deletions(-)

diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
index 1cbd39c..9639f65 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
@@ -58,6 +58,7 @@ import org.apache.rocketmq.broker.processor.EndTransactionProcessor;
 import org.apache.rocketmq.broker.processor.PullMessageProcessor;
 import org.apache.rocketmq.broker.processor.QueryMessageProcessor;
 import org.apache.rocketmq.broker.processor.SendMessageProcessor;
+import org.apache.rocketmq.broker.processor.SnodePullMessageProcessor;
 import org.apache.rocketmq.broker.slave.SlaveSynchronize;
 import org.apache.rocketmq.broker.subscription.SubscriptionGroupManager;
 import org.apache.rocketmq.broker.topic.TopicConfigManager;
@@ -115,6 +116,7 @@ public class BrokerController {
     private final ProducerManager producerManager;
     private final ClientHousekeepingService clientHousekeepingService;
     private final PullMessageProcessor pullMessageProcessor;
+    private final SnodePullMessageProcessor snodePullMessageProcessor;
     private final PullRequestHoldService pullRequestHoldService;
     private final MessageArrivingListener messageArrivingListener;
     private final Broker2Client broker2Client;
@@ -184,7 +186,7 @@ public class BrokerController {
         this.filterServerManager = new FilterServerManager(this);
 
         this.slaveSynchronize = new SlaveSynchronize(this);
-
+        this.snodePullMessageProcessor = new SnodePullMessageProcessor(this);
         this.sendThreadPoolQueue = new LinkedBlockingQueue<Runnable>(this.brokerConfig.getSendThreadPoolQueueCapacity());
         this.pullThreadPoolQueue = new LinkedBlockingQueue<Runnable>(this.brokerConfig.getPullThreadPoolQueueCapacity());
         this.queryThreadPoolQueue = new LinkedBlockingQueue<Runnable>(this.brokerConfig.getQueryThreadPoolQueueCapacity());
@@ -513,7 +515,8 @@ public class BrokerController {
          */
         this.remotingServer.registerProcessor(RequestCode.PULL_MESSAGE, this.pullMessageProcessor, this.pullMessageExecutor);
         this.pullMessageProcessor.registerConsumeMessageHook(consumeMessageHookList);
-
+        this.remotingServer.registerProcessor(RequestCode.SNODE_PULL_MESSAGE, this.snodePullMessageProcessor,pullMessageExecutor);
+        this.snodePullMessageProcessor.registerConsumeMessageHook(consumeMessageHookList);
         /**
          * QueryMessageProcessor
          */
@@ -671,6 +674,10 @@ public class BrokerController {
         return pullMessageProcessor;
     }
 
+    public SnodePullMessageProcessor getSnodePullMessageProcessor() {
+        return snodePullMessageProcessor;
+    }
+
     public PullRequestHoldService getPullRequestHoldService() {
         return pullRequestHoldService;
     }
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java
index 4b986c0..c623d52 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java
@@ -60,9 +60,7 @@ public class BrokerStartup {
 
     public static BrokerController start(BrokerController controller) {
         try {
-
             controller.start();
-
             String tip = "The broker[" + controller.getBrokerConfig().getBrokerName() + ", "
                 + controller.getBrokerAddr() + "] boot success. serializeType=" + RemotingCommand.getSerializeTypeConfigInThisServer();
 
@@ -100,8 +98,9 @@ public class BrokerStartup {
 
         try {
             //PackageConflictDetect.detectFastjson();
+
             Options options = ServerUtil.buildCommandlineOptions(new Options());
-            commandLine = ServerUtil.parseCmdLine("mqbroker", args, buildCommandlineOptions(options),
+            commandLine = ServerUtil.parseCmdLine("broker", args, buildCommandlineOptions(options),
                 new PosixParser());
             if (null == commandLine) {
                 System.exit(-1);
@@ -260,6 +259,8 @@ public class BrokerStartup {
     }
 
     private static Options buildCommandlineOptions(final Options options) {
+
+
         Option opt = new Option("c", "configFile", true, "Broker config properties file");
         opt.setRequired(false);
         options.addOption(opt);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ClientHousekeepingService.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ClientHousekeepingService.java
index d536db5..7e023dd 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/ClientHousekeepingService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ClientHousekeepingService.java
@@ -55,7 +55,6 @@ public class ClientHousekeepingService implements ChannelEventListener {
     private void scanExceptionChannel() {
         this.brokerController.getProducerManager().scanNotActiveChannel();
         this.brokerController.getConsumerManager().scanNotActiveChannel();
-        this.brokerController.getFilterServerManager().scanNotActiveChannel();
     }
 
     public void shutdown() {
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
index 417ec0d..af6addc 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
@@ -138,8 +138,13 @@ public class PullRequestHoldService extends ServiceThread {
 
                         if (match) {
                             try {
-                                this.brokerController.getPullMessageProcessor().executeRequestWhenWakeup(request.getClientChannel(),
-                                    request.getRequestCommand());
+                                if (request.getMessageFilter() == null && request.getSubscriptionData() == null) {
+                                    this.brokerController.getSnodePullMessageProcessor().executeRequestWhenWakeup(request.getClientChannel(),
+                                        request.getRequestCommand());
+                                } else {
+                                    this.brokerController.getPullMessageProcessor().executeRequestWhenWakeup(request.getClientChannel(),
+                                        request.getRequestCommand());
+                                }
                             } catch (Throwable e) {
                                 log.error("execute request when wakeup failed.", e);
                             }
@@ -149,8 +154,13 @@ public class PullRequestHoldService extends ServiceThread {
 
                     if (System.currentTimeMillis() >= (request.getSuspendTimestamp() + request.getTimeoutMillis())) {
                         try {
-                            this.brokerController.getPullMessageProcessor().executeRequestWhenWakeup(request.getClientChannel(),
-                                request.getRequestCommand());
+                            if (request.getMessageFilter() == null && request.getSubscriptionData() == null) {
+                                this.brokerController.getSnodePullMessageProcessor().executeRequestWhenWakeup(request.getClientChannel(),
+                                    request.getRequestCommand());
+                            } else {
+                                this.brokerController.getPullMessageProcessor().executeRequestWhenWakeup(request.getClientChannel(),
+                                    request.getRequestCommand());
+                            }
                         } catch (Throwable e) {
                             log.error("execute request when wakeup failed.", e);
                         }
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java
index b5e6085..f0d155f 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java
@@ -74,6 +74,7 @@ public class ClientManageProcessor implements NettyRequestProcessor {
     public RemotingCommand heartBeat(ChannelHandlerContext ctx, RemotingCommand request) {
         RemotingCommand response = RemotingCommand.createResponseCommand(null);
         HeartbeatData heartbeatData = HeartbeatData.decode(request.getBody(), HeartbeatData.class);
+        log.info("heart beat request:{}", heartbeatData);
         ClientChannelInfo clientChannelInfo = new ClientChannelInfo(
             ctx.channel(),
             heartbeatData.getClientID(),
@@ -121,6 +122,7 @@ public class ClientManageProcessor implements NettyRequestProcessor {
             this.brokerController.getProducerManager().registerProducer(data.getGroupName(),
                 clientChannelInfo);
         }
+
         response.setCode(ResponseCode.SUCCESS);
         response.setRemark(null);
         return response;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/SnodePullMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/SnodePullMessageProcessor.java
new file mode 100644
index 0000000..8beb6fa
--- /dev/null
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/SnodePullMessageProcessor.java
@@ -0,0 +1,449 @@
+/*
+ * 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 io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.FileRegion;
+import java.nio.ByteBuffer;
+import java.util.List;
+import org.apache.rocketmq.broker.BrokerController;
+import org.apache.rocketmq.broker.client.ConsumerGroupInfo;
+import org.apache.rocketmq.broker.filter.ConsumerFilterData;
+import org.apache.rocketmq.broker.filter.ConsumerFilterManager;
+import org.apache.rocketmq.broker.filter.ExpressionForRetryMessageFilter;
+import org.apache.rocketmq.broker.filter.ExpressionMessageFilter;
+import org.apache.rocketmq.broker.longpolling.PullRequest;
+import org.apache.rocketmq.broker.mqtrace.ConsumeMessageContext;
+import org.apache.rocketmq.broker.mqtrace.ConsumeMessageHook;
+import org.apache.rocketmq.broker.pagecache.ManyMessageTransfer;
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.TopicConfig;
+import org.apache.rocketmq.common.TopicFilterType;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.constant.PermName;
+import org.apache.rocketmq.common.filter.ExpressionType;
+import org.apache.rocketmq.common.filter.FilterAPI;
+import org.apache.rocketmq.common.help.FAQUrl;
+import org.apache.rocketmq.common.message.MessageDecoder;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.common.protocol.ResponseCode;
+import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader;
+import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader;
+import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.common.protocol.topic.OffsetMovedEvent;
+import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.common.sysflag.PullSysFlag;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.common.RemotingUtil;
+import org.apache.rocketmq.remoting.exception.RemotingCommandException;
+import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.netty.RequestTask;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.store.GetMessageResult;
+import org.apache.rocketmq.store.MessageExtBrokerInner;
+import org.apache.rocketmq.store.MessageFilter;
+import org.apache.rocketmq.store.PutMessageResult;
+import org.apache.rocketmq.store.config.BrokerRole;
+import org.apache.rocketmq.store.stats.BrokerStatsManager;
+
+public class SnodePullMessageProcessor implements NettyRequestProcessor {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
+    private final BrokerController brokerController;
+    private List<ConsumeMessageHook> consumeMessageHookList;
+
+    public SnodePullMessageProcessor(final BrokerController brokerController) {
+        this.brokerController = brokerController;
+    }
+
+    @Override
+    public RemotingCommand processRequest(final ChannelHandlerContext ctx,
+        RemotingCommand request) throws RemotingCommandException {
+        return this.processRequest(ctx.channel(), request, true);
+    }
+
+    @Override
+    public boolean rejectRequest() {
+        return false;
+    }
+
+    private RemotingCommand processRequest(final Channel channel, RemotingCommand request, boolean brokerAllowSuspend)
+        throws RemotingCommandException {
+        RemotingCommand response = RemotingCommand.createResponseCommand(PullMessageResponseHeader.class);
+        final PullMessageResponseHeader responseHeader = (PullMessageResponseHeader) response.readCustomHeader();
+        final PullMessageRequestHeader requestHeader =
+            (PullMessageRequestHeader) request.decodeCommandCustomHeader(PullMessageRequestHeader.class);
+
+        response.setOpaque(request.getOpaque());
+
+        log.info("receive PullMessage request command, {}", request);
+        final boolean hasSuspendFlag = PullSysFlag.hasSuspendFlag(requestHeader.getSysFlag());
+        final boolean hasCommitOffsetFlag = PullSysFlag.hasCommitOffsetFlag(requestHeader.getSysFlag());
+        final boolean hasSubscriptionFlag = PullSysFlag.hasSubscriptionFlag(requestHeader.getSysFlag());
+
+        final long suspendTimeoutMillisLong = hasSuspendFlag ? requestHeader.getSuspendTimeoutMillis() : 0;
+        if (!PermName.isReadable(this.brokerController.getBrokerConfig().getBrokerPermission())) {
+            response.setCode(ResponseCode.NO_PERMISSION);
+            response.setRemark(String.format("the broker[%s] pulling message is forbidden", this.brokerController.getBrokerConfig().getBrokerIP1()));
+            return response;
+        }
+
+        final GetMessageResult getMessageResult =
+            this.brokerController.getMessageStore().getMessage(requestHeader.getConsumerGroup(), requestHeader.getTopic(),
+                requestHeader.getQueueId(), requestHeader.getQueueOffset(), requestHeader.getMaxMsgNums(), null);
+
+        log.info("Get message response:{}",getMessageResult);
+        if (getMessageResult != null) {
+            response.setRemark(getMessageResult.getStatus().name());
+            responseHeader.setNextBeginOffset(getMessageResult.getNextBeginOffset());
+            responseHeader.setMinOffset(getMessageResult.getMinOffset());
+            responseHeader.setMaxOffset(getMessageResult.getMaxOffset());
+
+            if (getMessageResult.isSuggestPullingFromSlave()) {
+                responseHeader.setSuggestWhichBrokerId(0L);
+            } else {
+                responseHeader.setSuggestWhichBrokerId(MixAll.MASTER_ID);
+            }
+
+            switch (this.brokerController.getMessageStoreConfig().getBrokerRole()) {
+                case ASYNC_MASTER:
+                case SYNC_MASTER:
+                    break;
+                case SLAVE:
+                    if (!this.brokerController.getBrokerConfig().isSlaveReadEnable()) {
+                        response.setCode(ResponseCode.PULL_RETRY_IMMEDIATELY);
+                        responseHeader.setSuggestWhichBrokerId(MixAll.MASTER_ID);
+                    }
+                    break;
+            }
+
+//            if (this.brokerController.getBrokerConfig().isSlaveReadEnable()) {
+//                // consume too slow ,redirect to another machine
+//                if (getMessageResult.isSuggestPullingFromSlave()) {
+//                    responseHeader.setSuggestWhichBrokerId(subscriptionGroupConfig.getWhichBrokerWhenConsumeSlowly());
+//                }
+//                // consume ok
+//                else {
+//                    responseHeader.setSuggestWhichBrokerId(subscriptionGroupConfig.getBrokerId());
+//                }
+//            } else {
+//                responseHeader.setSuggestWhichBrokerId(MixAll.MASTER_ID);
+//            }
+
+            switch (getMessageResult.getStatus()) {
+                case FOUND:
+                    response.setCode(ResponseCode.SUCCESS);
+                    break;
+                case MESSAGE_WAS_REMOVING:
+                    response.setCode(ResponseCode.PULL_RETRY_IMMEDIATELY);
+                    break;
+                case NO_MATCHED_LOGIC_QUEUE:
+                case NO_MESSAGE_IN_QUEUE:
+                    if (0 != requestHeader.getQueueOffset()) {
+                        response.setCode(ResponseCode.PULL_OFFSET_MOVED);
+
+                        // XXX: warn and notify me
+                        log.info("the broker store no queue data, fix the request offset {} to {}, Topic: {} QueueId: {} Consumer Group: {}",
+                            requestHeader.getQueueOffset(),
+                            getMessageResult.getNextBeginOffset(),
+                            requestHeader.getTopic(),
+                            requestHeader.getQueueId(),
+                            requestHeader.getConsumerGroup()
+                        );
+                    } else {
+                        response.setCode(ResponseCode.PULL_NOT_FOUND);
+                    }
+                    break;
+                case NO_MATCHED_MESSAGE:
+                    response.setCode(ResponseCode.PULL_RETRY_IMMEDIATELY);
+                    break;
+                case OFFSET_FOUND_NULL:
+                    response.setCode(ResponseCode.PULL_NOT_FOUND);
+                    break;
+                case OFFSET_OVERFLOW_BADLY:
+                    response.setCode(ResponseCode.PULL_OFFSET_MOVED);
+                    // XXX: warn and notify me
+                    log.info("the request offset: {} over flow badly, broker max offset: {}, consumer: {}",
+                        requestHeader.getQueueOffset(), getMessageResult.getMaxOffset(), channel.remoteAddress());
+                    break;
+                case OFFSET_OVERFLOW_ONE:
+                    response.setCode(ResponseCode.PULL_NOT_FOUND);
+                    break;
+                case OFFSET_TOO_SMALL:
+                    response.setCode(ResponseCode.PULL_OFFSET_MOVED);
+                    log.info("the request offset too small. group={}, topic={}, requestOffset={}, brokerMinOffset={}, clientIp={}",
+                        requestHeader.getConsumerGroup(), requestHeader.getTopic(), requestHeader.getQueueOffset(),
+                        getMessageResult.getMinOffset(), channel.remoteAddress());
+                    break;
+                default:
+                    assert false;
+                    break;
+            }
+
+            if (this.hasConsumeMessageHook()) {
+                ConsumeMessageContext context = new ConsumeMessageContext();
+                context.setConsumerGroup(requestHeader.getConsumerGroup());
+                context.setTopic(requestHeader.getTopic());
+                context.setQueueId(requestHeader.getQueueId());
+
+                String owner = request.getExtFields().get(BrokerStatsManager.COMMERCIAL_OWNER);
+
+                switch (response.getCode()) {
+                    case ResponseCode.SUCCESS:
+                        int commercialBaseCount = brokerController.getBrokerConfig().getCommercialBaseCount();
+                        int incValue = getMessageResult.getMsgCount4Commercial() * commercialBaseCount;
+
+                        context.setCommercialRcvStats(BrokerStatsManager.StatsType.RCV_SUCCESS);
+                        context.setCommercialRcvTimes(incValue);
+                        context.setCommercialRcvSize(getMessageResult.getBufferTotalSize());
+                        context.setCommercialOwner(owner);
+
+                        break;
+                    case ResponseCode.PULL_NOT_FOUND:
+                        if (!brokerAllowSuspend) {
+
+                            context.setCommercialRcvStats(BrokerStatsManager.StatsType.RCV_EPOLLS);
+                            context.setCommercialRcvTimes(1);
+                            context.setCommercialOwner(owner);
+
+                        }
+                        break;
+                    case ResponseCode.PULL_RETRY_IMMEDIATELY:
+                    case ResponseCode.PULL_OFFSET_MOVED:
+                        context.setCommercialRcvStats(BrokerStatsManager.StatsType.RCV_EPOLLS);
+                        context.setCommercialRcvTimes(1);
+                        context.setCommercialOwner(owner);
+                        break;
+                    default:
+                        assert false;
+                        break;
+                }
+
+                this.executeConsumeMessageHookBefore(context);
+            }
+
+            switch (response.getCode()) {
+                case ResponseCode.SUCCESS:
+
+                    this.brokerController.getBrokerStatsManager().incGroupGetNums(requestHeader.getConsumerGroup(), requestHeader.getTopic(),
+                        getMessageResult.getMessageCount());
+
+                    this.brokerController.getBrokerStatsManager().incGroupGetSize(requestHeader.getConsumerGroup(), requestHeader.getTopic(),
+                        getMessageResult.getBufferTotalSize());
+
+                    this.brokerController.getBrokerStatsManager().incBrokerGetNums(getMessageResult.getMessageCount());
+                    if (this.brokerController.getBrokerConfig().isTransferMsgByHeap()) {
+                        final long beginTimeMills = this.brokerController.getMessageStore().now();
+                        final byte[] r = this.readGetMessageResult(getMessageResult, requestHeader.getConsumerGroup(), requestHeader.getTopic(), requestHeader.getQueueId());
+                        this.brokerController.getBrokerStatsManager().incGroupGetLatency(requestHeader.getConsumerGroup(),
+                            requestHeader.getTopic(), requestHeader.getQueueId(),
+                            (int) (this.brokerController.getMessageStore().now() - beginTimeMills));
+                        response.setBody(r);
+                    } else {
+                        try {
+                            FileRegion fileRegion =
+                                new ManyMessageTransfer(response.encodeHeader(getMessageResult.getBufferTotalSize()), getMessageResult);
+                            channel.writeAndFlush(fileRegion).addListener(new ChannelFutureListener() {
+                                @Override
+                                public void operationComplete(ChannelFuture future) throws Exception {
+                                    getMessageResult.release();
+                                    if (!future.isSuccess()) {
+                                        log.error("transfer many message by pagecache failed, {}", channel.remoteAddress(), future.cause());
+                                    }
+                                }
+                            });
+                        } catch (Throwable e) {
+                            log.error("transfer many message by pagecache exception", e);
+                            getMessageResult.release();
+                        }
+
+                        response = null;
+                    }
+                    break;
+                case ResponseCode.PULL_NOT_FOUND:
+
+                    if (brokerAllowSuspend && hasSuspendFlag) {
+                        long pollingTimeMills = suspendTimeoutMillisLong;
+                        if (!this.brokerController.getBrokerConfig().isLongPollingEnable()) {
+                            pollingTimeMills = this.brokerController.getBrokerConfig().getShortPollingTimeMills();
+                        }
+
+                        String topic = requestHeader.getTopic();
+                        long offset = requestHeader.getQueueOffset();
+                        int queueId = requestHeader.getQueueId();
+                        PullRequest pullRequest = new PullRequest(request, channel, pollingTimeMills,
+                            this.brokerController.getMessageStore().now(), offset, null, null);
+                        this.brokerController.getPullRequestHoldService().suspendPullRequest(topic, queueId, pullRequest);
+                        response = null;
+                        break;
+                    }
+
+                case ResponseCode.PULL_RETRY_IMMEDIATELY:
+                    break;
+                case ResponseCode.PULL_OFFSET_MOVED:
+                    if (this.brokerController.getMessageStoreConfig().getBrokerRole() != BrokerRole.SLAVE
+                        || this.brokerController.getMessageStoreConfig().isOffsetCheckInSlave()) {
+                        MessageQueue mq = new MessageQueue();
+                        mq.setTopic(requestHeader.getTopic());
+                        mq.setQueueId(requestHeader.getQueueId());
+                        mq.setBrokerName(this.brokerController.getBrokerConfig().getBrokerName());
+
+                        OffsetMovedEvent event = new OffsetMovedEvent();
+                        event.setConsumerGroup(requestHeader.getConsumerGroup());
+                        event.setMessageQueue(mq);
+                        event.setOffsetRequest(requestHeader.getQueueOffset());
+                        event.setOffsetNew(getMessageResult.getNextBeginOffset());
+                        this.generateOffsetMovedEvent(event);
+                        log.warn(
+                            "PULL_OFFSET_MOVED:correction offset. topic={}, groupId={}, requestOffset={}, newOffset={}, suggestBrokerId={}",
+                            requestHeader.getTopic(), requestHeader.getConsumerGroup(), event.getOffsetRequest(), event.getOffsetNew(),
+                            responseHeader.getSuggestWhichBrokerId());
+                    } else {
+//                        responseHeader.setSuggestWhichBrokerId(subscriptionGroupConfig.getBrokerId());
+                        response.setCode(ResponseCode.PULL_RETRY_IMMEDIATELY);
+                        log.warn("PULL_OFFSET_MOVED:none correction. topic={}, groupId={}, requestOffset={}, suggestBrokerId={}",
+                            requestHeader.getTopic(), requestHeader.getConsumerGroup(), requestHeader.getQueueOffset(),
+                            responseHeader.getSuggestWhichBrokerId());
+                    }
+
+                    break;
+                default:
+                    assert false;
+            }
+        } else {
+            response.setCode(ResponseCode.SYSTEM_ERROR);
+            response.setRemark("store getMessage return null");
+        }
+
+        boolean storeOffsetEnable = brokerAllowSuspend;
+        storeOffsetEnable = storeOffsetEnable && hasCommitOffsetFlag;
+        storeOffsetEnable = storeOffsetEnable
+            && this.brokerController.getMessageStoreConfig().getBrokerRole() != BrokerRole.SLAVE;
+        if (storeOffsetEnable) {
+            this.brokerController.getConsumerOffsetManager().commitOffset(RemotingHelper.parseChannelRemoteAddr(channel),
+                requestHeader.getConsumerGroup(), requestHeader.getTopic(), requestHeader.getQueueId(), requestHeader.getCommitOffset());
+        }
+        return response;
+    }
+
+    public boolean hasConsumeMessageHook() {
+        return consumeMessageHookList != null && !this.consumeMessageHookList.isEmpty();
+    }
+
+    public void executeConsumeMessageHookBefore(final ConsumeMessageContext context) {
+        if (hasConsumeMessageHook()) {
+            for (ConsumeMessageHook hook : this.consumeMessageHookList) {
+                try {
+                    hook.consumeMessageBefore(context);
+                } catch (Throwable e) {
+                }
+            }
+        }
+    }
+
+    private byte[] readGetMessageResult(final GetMessageResult getMessageResult, final String group, final String topic,
+        final int queueId) {
+        final ByteBuffer byteBuffer = ByteBuffer.allocate(getMessageResult.getBufferTotalSize());
+
+        long storeTimestamp = 0;
+        try {
+            List<ByteBuffer> messageBufferList = getMessageResult.getMessageBufferList();
+            for (ByteBuffer bb : messageBufferList) {
+
+                byteBuffer.put(bb);
+                storeTimestamp = bb.getLong(MessageDecoder.MESSAGE_STORE_TIMESTAMP_POSTION);
+            }
+        } finally {
+            getMessageResult.release();
+        }
+
+        this.brokerController.getBrokerStatsManager().recordDiskFallBehindTime(group, topic, queueId, this.brokerController.getMessageStore().now() - storeTimestamp);
+        return byteBuffer.array();
+    }
+
+    private void generateOffsetMovedEvent(final OffsetMovedEvent event) {
+        try {
+            MessageExtBrokerInner msgInner = new MessageExtBrokerInner();
+            msgInner.setTopic(MixAll.OFFSET_MOVED_EVENT);
+            msgInner.setTags(event.getConsumerGroup());
+            msgInner.setDelayTimeLevel(0);
+            msgInner.setKeys(event.getConsumerGroup());
+            msgInner.setBody(event.encode());
+            msgInner.setFlag(0);
+            msgInner.setPropertiesString(MessageDecoder.messageProperties2String(msgInner.getProperties()));
+            msgInner.setTagsCode(MessageExtBrokerInner.tagsString2tagsCode(TopicFilterType.SINGLE_TAG, msgInner.getTags()));
+
+            msgInner.setQueueId(0);
+            msgInner.setSysFlag(0);
+            msgInner.setBornTimestamp(System.currentTimeMillis());
+            msgInner.setBornHost(RemotingUtil.string2SocketAddress(this.brokerController.getBrokerAddr()));
+            msgInner.setStoreHost(msgInner.getBornHost());
+
+            msgInner.setReconsumeTimes(0);
+
+            PutMessageResult putMessageResult = this.brokerController.getMessageStore().putMessage(msgInner);
+        } catch (Exception e) {
+            log.warn(String.format("generateOffsetMovedEvent Exception, %s", event.toString()), e);
+        }
+    }
+
+    public void executeRequestWhenWakeup(final Channel channel,
+        final RemotingCommand request) throws RemotingCommandException {
+        Runnable run = new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    final RemotingCommand response = SnodePullMessageProcessor.this.processRequest(channel, request, false);
+
+                    if (response != null) {
+                        response.setOpaque(request.getOpaque());
+                        response.markResponseType();
+                        try {
+                            channel.writeAndFlush(response).addListener(new ChannelFutureListener() {
+                                @Override
+                                public void operationComplete(ChannelFuture future) throws Exception {
+                                    if (!future.isSuccess()) {
+                                        log.error("processRequestWrapper response to {} failed",
+                                            future.channel().remoteAddress(), future.cause());
+                                        log.error(request.toString());
+                                        log.error(response.toString());
+                                    }
+                                }
+                            });
+                        } catch (Throwable e) {
+                            log.error("processRequestWrapper process request over, but response failed", e);
+                            log.error(request.toString());
+                            log.error(response.toString());
+                        }
+                    }
+                } catch (RemotingCommandException e1) {
+                    log.error("excuteRequestWhenWakeup run", e1);
+                }
+            }
+        };
+        this.brokerController.getPullMessageExecutor().submit(new RequestTask(run, channel, request));
+    }
+
+    public void registerConsumeMessageHook(List<ConsumeMessageHook> sendMessageHookList) {
+        this.consumeMessageHookList = sendMessageHookList;
+    }
+}
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
index 0fa1ae7..6302cd0 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
@@ -353,7 +353,8 @@ public class MQClientAPIImpl {
         final long timeoutMillis,
         final RemotingCommand request
     ) throws RemotingException, MQBrokerException, InterruptedException {
-        RemotingCommand response = this.remotingClient.invokeSync(addr, request, timeoutMillis);
+        String addrS = "localhost:11911";//TODO FIXME
+        RemotingCommand response = this.remotingClient.invokeSync(addrS, request, timeoutMillis);
         assert response != null;
         return this.processSendResponse(brokerName, msg, response);
     }
@@ -557,14 +558,15 @@ public class MQClientAPIImpl {
     }
 
     public PullResult pullMessage(
-        final String addr,
+         String addr,
         final PullMessageRequestHeader requestHeader,
         final long timeoutMillis,
         final CommunicationMode communicationMode,
         final PullCallback pullCallback
     ) throws RemotingException, MQBrokerException, InterruptedException {
-        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, requestHeader);
-
+        requestHeader.setEnodeAddr(addr);
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SNODE_PULL_MESSAGE, requestHeader);
+         addr = "localhost:11911"; //TODO FIXME
         switch (communicationMode) {
             case ONEWAY:
                 assert false;
@@ -647,7 +649,7 @@ public class MQClientAPIImpl {
 
         PullMessageResponseHeader responseHeader =
             (PullMessageResponseHeader) response.decodeCommandCustomHeader(PullMessageResponseHeader.class);
-
+        log.info("response header: {}", responseHeader.getSuggestWhichBrokerId());
         return new PullResultExt(pullStatus, responseHeader.getNextBeginOffset(), responseHeader.getMinOffset(),
             responseHeader.getMaxOffset(), null, responseHeader.getSuggestWhichBrokerId(), response.getBody());
     }
@@ -728,11 +730,12 @@ public class MQClientAPIImpl {
         final String consumerGroup,
         final long timeoutMillis) throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException,
         MQBrokerException, InterruptedException {
+
         GetConsumerListByGroupRequestHeader requestHeader = new GetConsumerListByGroupRequestHeader();
         requestHeader.setConsumerGroup(consumerGroup);
         RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_CONSUMER_LIST_BY_GROUP, requestHeader);
-
-        RemotingCommand response = this.remotingClient.invokeSync(MixAll.brokerVIPChannel(this.clientConfig.isVipChannelEnabled(), addr),
+        String addrS = "localhost:11911";//TODO FIXME
+        RemotingCommand response = this.remotingClient.invokeSync(addrS,
             request, timeoutMillis);
         assert response != null;
         switch (response.getCode()) {
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
index 9ffaed0..984e2cc 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
@@ -537,7 +537,8 @@ public class MQClientInstance {
                             }
 
                             try {
-                                int version = this.mQClientAPIImpl.sendHearbeat(addr, heartbeatData, 3000);
+                                String addrS = "localhost:11911"; //TODO FIXME
+                                int version = this.mQClientAPIImpl.sendHearbeat(addrS, heartbeatData, 3000);
                                 if (!this.brokerVersionTable.containsKey(brokerName)) {
                                     this.brokerVersionTable.put(brokerName, new HashMap<String, Integer>(4));
                                 }
@@ -547,6 +548,7 @@ public class MQClientInstance {
                                     log.info(heartbeatData.toString());
                                 }
                             } catch (Exception e) {
+                                log.error("send heart beat error:{}",e);
                                 if (this.isBrokerInNameServer(addr)) {
                                     log.info("send heart beat to broker[{} {} {}] failed", brokerName, id, addr);
                                 } else {
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java
index 7ace9d5..9ada834 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java
@@ -247,6 +247,7 @@ public class DefaultMQProducerImpl implements MQProducerInner {
 
     /**
      * This method will be removed in the version 5.0.0 and <code>getCheckListener</code> is recommended.
+     *
      * @return
      */
     @Override
@@ -440,13 +441,14 @@ public class DefaultMQProducerImpl implements MQProducerInner {
      * DEFAULT ASYNC -------------------------------------------------------
      */
     public void send(Message msg,
-                     SendCallback sendCallback) throws MQClientException, RemotingException, InterruptedException {
+        SendCallback sendCallback) throws MQClientException, RemotingException, InterruptedException {
         send(msg, sendCallback, this.defaultMQProducer.getSendMsgTimeout());
     }
 
     /**
-     * It will be removed at 4.4.0 cause for exception handling and the wrong Semantics of timeout.
-     * A new one will be provided in next version
+     * It will be removed at 4.4.0 cause for exception handling and the wrong Semantics of timeout. A new one will be
+     * provided in next version
+     *
      * @param msg
      * @param sendCallback
      * @param timeout the <code>sendCallback</code> will be invoked at most time
@@ -481,7 +483,6 @@ public class DefaultMQProducerImpl implements MQProducerInner {
 
     }
 
-
     public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final String lastBrokerName) {
         return this.mqFaultStrategy.selectOneMessageQueue(tpInfo, lastBrokerName);
     }
@@ -653,18 +654,17 @@ public class DefaultMQProducerImpl implements MQProducerInner {
     }
 
     private SendResult sendKernelImpl(final Message msg,
-                                      final MessageQueue mq,
-                                      final CommunicationMode communicationMode,
-                                      final SendCallback sendCallback,
-                                      final TopicPublishInfo topicPublishInfo,
-                                      final long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
+        final MessageQueue mq,
+        final CommunicationMode communicationMode,
+        final SendCallback sendCallback,
+        final TopicPublishInfo topicPublishInfo,
+        final long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
         long beginStartTime = System.currentTimeMillis();
         String brokerAddr = this.mQClientFactory.findBrokerAddressInPublish(mq.getBrokerName());
         if (null == brokerAddr) {
             tryToFindTopicPublishInfo(mq.getTopic());
             brokerAddr = this.mQClientFactory.findBrokerAddressInPublish(mq.getBrokerName());
         }
-
         SendMessageContext context = null;
         if (brokerAddr != null) {
             brokerAddr = MixAll.brokerVIPChannel(this.defaultMQProducer.isSendMessageWithVIPChannel(), brokerAddr);
@@ -733,6 +733,7 @@ public class DefaultMQProducerImpl implements MQProducerInner {
                 requestHeader.setReconsumeTimes(0);
                 requestHeader.setUnitMode(this.isUnitMode());
                 requestHeader.setBatch(msg instanceof MessageBatch);
+                requestHeader.setEnodeAddr(brokerAddr);
                 if (requestHeader.getTopic().startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) {
                     String reconsumeTimes = MessageAccessor.getReconsumeTime(msg);
                     if (reconsumeTimes != null) {
@@ -943,8 +944,9 @@ public class DefaultMQProducerImpl implements MQProducerInner {
     }
 
     /**
-     * It will be removed at 4.4.0 cause for exception handling and the wrong Semantics of timeout.
-     * A new one will be provided in next version
+     * It will be removed at 4.4.0 cause for exception handling and the wrong Semantics of timeout. A new one will be
+     * provided in next version
+     *
      * @param msg
      * @param mq
      * @param sendCallback
@@ -1064,8 +1066,9 @@ public class DefaultMQProducerImpl implements MQProducerInner {
     }
 
     /**
-     * It will be removed at 4.4.0 cause for exception handling and the wrong Semantics of timeout.
-     * A new one will be provided in next version
+     * It will be removed at 4.4.0 cause for exception handling and the wrong Semantics of timeout. A new one will be
+     * provided in next version
+     *
      * @param msg
      * @param selector
      * @param arg
@@ -1076,7 +1079,8 @@ public class DefaultMQProducerImpl implements MQProducerInner {
      * @throws InterruptedException
      */
     @Deprecated
-    public void send(final Message msg, final MessageQueueSelector selector, final Object arg, final SendCallback sendCallback, final long timeout)
+    public void send(final Message msg, final MessageQueueSelector selector, final Object arg,
+        final SendCallback sendCallback, final long timeout)
         throws MQClientException, RemotingException, InterruptedException {
         final long beginStartTime = System.currentTimeMillis();
         ExecutorService executor = this.getCallbackExecutor();
@@ -1120,7 +1124,7 @@ public class DefaultMQProducerImpl implements MQProducerInner {
     }
 
     public TransactionSendResult sendMessageInTransaction(final Message msg,
-                                                          final LocalTransactionExecuter localTransactionExecuter, final Object arg)
+        final LocalTransactionExecuter localTransactionExecuter, final Object arg)
         throws MQClientException {
         TransactionListener transactionListener = getCheckListener();
         if (null == localTransactionExecuter && null == transactionListener) {
@@ -1243,6 +1247,7 @@ public class DefaultMQProducerImpl implements MQProducerInner {
     public void setCallbackExecutor(final ExecutorService callbackExecutor) {
         this.mQClientFactory.getMQClientAPIImpl().getRemotingClient().setCallbackExecutor(callbackExecutor);
     }
+
     public ExecutorService getCallbackExecutor() {
         return this.mQClientFactory.getMQClientAPIImpl().getRemotingClient().getCallbackExecutor();
 
diff --git a/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java b/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java
index fe0ae9f..48295a3 100644
--- a/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java
+++ b/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java
@@ -37,4 +37,5 @@ public class LoggerName {
     public static final String PROTECTION_LOGGER_NAME = "RocketmqProtection";
     public static final String WATER_MARK_LOGGER_NAME = "RocketmqWaterMark";
     public static final String FILTER_LOGGER_NAME = "RocketmqFilter";
+    public static final String SNODE_LOGGER_NAME = "RocketmqSnode";
 }
diff --git a/common/src/main/java/org/apache/rocketmq/common/namesrv/RegisterSnodeResult.java b/common/src/main/java/org/apache/rocketmq/common/namesrv/RegisterSnodeResult.java
new file mode 100644
index 0000000..6527a55
--- /dev/null
+++ b/common/src/main/java/org/apache/rocketmq/common/namesrv/RegisterSnodeResult.java
@@ -0,0 +1,20 @@
+package org.apache.rocketmq.common.namesrv;/*
+ * 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.
+ */
+
+public class RegisterSnodeResult {
+
+}
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/RequestCode.java b/common/src/main/java/org/apache/rocketmq/common/protocol/RequestCode.java
index 8cf2d46..b36bdb2 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/RequestCode.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/RequestCode.java
@@ -167,4 +167,9 @@ public class RequestCode {
     public static final int QUERY_CONSUME_QUEUE = 321;
 
     public static final int QUERY_DATA_VERSION = 322;
+
+    public static final int REGISTER_SNODE = 350;
+
+    public static final int SNODE_PULL_MESSAGE = 351;
+
 }
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ClusterInfo.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ClusterInfo.java
index 566bf93..9c4d913 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ClusterInfo.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ClusterInfo.java
@@ -20,7 +20,9 @@ package org.apache.rocketmq.common.protocol.body;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import org.apache.rocketmq.common.MixAll;
 import org.apache.rocketmq.common.protocol.route.BrokerData;
 import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
@@ -59,6 +61,26 @@ public class ClusterInfo extends RemotingSerializable {
         return addrs.toArray(new String[] {});
     }
 
+    public String[] retrieveAllMasterAddrByCluster(String cluster) {
+        List<String> addrs = new ArrayList<String>();
+        if (clusterAddrTable.containsKey(cluster)) {
+            Set<String> brokerNames = clusterAddrTable.get(cluster);
+            for (String brokerName : brokerNames) {
+                BrokerData brokerData = brokerAddrTable.get(brokerName);
+                if (null != brokerData) {
+                    HashMap<Long, String> brokerAddrs = brokerData.getBrokerAddrs();
+                    for (Map.Entry<Long, String> entry : brokerAddrs.entrySet()) {
+                        if (MixAll.MASTER_ID == entry.getKey()) {
+                            addrs.add(entry.getValue());
+                        }
+                    }
+
+                }
+            }
+        }
+        return addrs.toArray(new String[] {});
+    }
+
     public String[] retrieveAllClusterNames() {
         return clusterAddrTable.keySet().toArray(new String[] {});
     }
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java
index 106e89e..8332307 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java
@@ -48,6 +48,16 @@ public class PullMessageRequestHeader implements CommandCustomHeader {
     private Long subVersion;
     private String expressionType;
 
+    private String enodeAddr;
+
+    public String getEnodeAddr() {
+        return enodeAddr;
+    }
+
+    public void setEnodeAddr(String enodeAddr) {
+        this.enodeAddr = enodeAddr;
+    }
+
     @Override
     public void checkFields() throws RemotingCommandException {
     }
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java
index 2df31e6..81e0cff 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java
@@ -52,6 +52,8 @@ public class SendMessageRequestHeader implements CommandCustomHeader {
     private boolean batch = false;
     private Integer maxReconsumeTimes;
 
+    private String enodeAddr;
+
     @Override
     public void checkFields() throws RemotingCommandException {
     }
@@ -159,4 +161,12 @@ public class SendMessageRequestHeader implements CommandCustomHeader {
     public void setBatch(boolean batch) {
         this.batch = batch;
     }
+
+    public String getEnodeAddr() {
+        return enodeAddr;
+    }
+
+    public void setEnodeAddr(String enodeAddr) {
+        this.enodeAddr = enodeAddr;
+    }
 }
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeaderV2.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeaderV2.java
index 4e0098b..9602805 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeaderV2.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeaderV2.java
@@ -54,6 +54,8 @@ public class SendMessageRequestHeaderV2 implements CommandCustomHeader {
     @CFNullable
     private boolean m; //batch
 
+    private String n; //enode addr
+
     public static SendMessageRequestHeader createSendMessageRequestHeaderV1(final SendMessageRequestHeaderV2 v2) {
         SendMessageRequestHeader v1 = new SendMessageRequestHeader();
         v1.setProducerGroup(v2.a);
@@ -69,6 +71,7 @@ public class SendMessageRequestHeaderV2 implements CommandCustomHeader {
         v1.setUnitMode(v2.k);
         v1.setMaxReconsumeTimes(v2.l);
         v1.setBatch(v2.m);
+        v1.setEnodeAddr(v2.n);
         return v1;
     }
 
@@ -87,6 +90,7 @@ public class SendMessageRequestHeaderV2 implements CommandCustomHeader {
         v2.k = v1.isUnitMode();
         v2.l = v1.getMaxReconsumeTimes();
         v2.m = v1.isBatch();
+        v2.n = v1.getEnodeAddr();
         return v2;
     }
 
@@ -197,4 +201,12 @@ public class SendMessageRequestHeaderV2 implements CommandCustomHeader {
     public void setM(boolean m) {
         this.m = m;
     }
+
+    public String getN() {
+        return n;
+    }
+
+    public void setN(String n) {
+        this.n = n;
+    }
 }
\ No newline at end of file
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/namesrv/RegisterSnodeRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/namesrv/RegisterSnodeRequestHeader.java
new file mode 100644
index 0000000..7752cd7
--- /dev/null
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/namesrv/RegisterSnodeRequestHeader.java
@@ -0,0 +1,61 @@
+package org.apache.rocketmq.common.protocol.header.namesrv;/*
+ * 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.
+ */
+
+import org.apache.rocketmq.remoting.CommandCustomHeader;
+import org.apache.rocketmq.remoting.annotation.CFNotNull;
+import org.apache.rocketmq.remoting.exception.RemotingCommandException;
+
+public class RegisterSnodeRequestHeader implements CommandCustomHeader {
+
+    @CFNotNull
+    private String snodeName;
+
+    @CFNotNull
+    private String snodeAddr;
+
+    @CFNotNull
+    private String clusterName;
+
+    @Override
+    public void checkFields() throws RemotingCommandException {
+
+    }
+
+    public String getClusterName() {
+        return clusterName;
+    }
+
+    public void setClusterName(String clusterName) {
+        this.clusterName = clusterName;
+    }
+
+    public String getSnodeName() {
+        return snodeName;
+    }
+
+    public void setSnodeName(String snodeName) {
+        this.snodeName = snodeName;
+    }
+
+    public String getSnodeAddr() {
+        return snodeAddr;
+    }
+
+    public void setSnodeAddr(String snodeAddr) {
+        this.snodeAddr = snodeAddr;
+    }
+}
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/namesrv/RegisterSnodeResponseHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/namesrv/RegisterSnodeResponseHeader.java
new file mode 100644
index 0000000..4d4f15f
--- /dev/null
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/namesrv/RegisterSnodeResponseHeader.java
@@ -0,0 +1,20 @@
+package org.apache.rocketmq.common.protocol.header.namesrv;/*
+ * 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.
+ */
+
+public class RegisterSnodeResponseHeader {
+
+}
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/HeartbeatData.java b/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/HeartbeatData.java
index 03151f5..eb32749 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/HeartbeatData.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/HeartbeatData.java
@@ -28,6 +28,15 @@ public class HeartbeatData extends RemotingSerializable {
     private String clientID;
     private Set<ProducerData> producerDataSet = new HashSet<ProducerData>();
     private Set<ConsumerData> consumerDataSet = new HashSet<ConsumerData>();
+    private SnodeData snodeData;
+
+    public SnodeData getSnodeData() {
+        return snodeData;
+    }
+
+    public void setSnodeData(SnodeData snodeData) {
+        this.snodeData = snodeData;
+    }
 
     public String getClientID() {
         return clientID;
@@ -53,9 +62,12 @@ public class HeartbeatData extends RemotingSerializable {
         this.consumerDataSet = consumerDataSet;
     }
 
-    @Override
-    public String toString() {
-        return "HeartbeatData [clientID=" + clientID + ", producerDataSet=" + producerDataSet
-            + ", consumerDataSet=" + consumerDataSet + "]";
+    @Override public String toString() {
+        return "HeartbeatData{" +
+            "clientID='" + clientID + '\'' +
+            ", producerDataSet=" + producerDataSet +
+            ", consumerDataSet=" + consumerDataSet +
+            ", snodeData='" + snodeData + '\'' +
+            '}';
     }
 }
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/SnodeData.java b/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/SnodeData.java
new file mode 100644
index 0000000..e4cb9b1
--- /dev/null
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/SnodeData.java
@@ -0,0 +1,34 @@
+package org.apache.rocketmq.common.protocol.heartbeat;/*
+ * 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.
+ */
+
+public class SnodeData {
+    private String snodeName;
+
+    public String getSnodeName() {
+        return snodeName;
+    }
+
+    public void setSnodeName(String snodeName) {
+        this.snodeName = snodeName;
+    }
+
+    @Override public String toString() {
+        return "SnodeData{" +
+            "snodeName='" + snodeName + '\'' +
+            '}';
+    }
+}
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/route/SnodeData.java b/common/src/main/java/org/apache/rocketmq/common/protocol/route/SnodeData.java
new file mode 100644
index 0000000..db76ad2
--- /dev/null
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/route/SnodeData.java
@@ -0,0 +1,57 @@
+package org.apache.rocketmq.common.protocol.route;/*
+ * 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.
+ */
+
+public class SnodeData {
+    private String snodeName;
+
+    private String addr;
+
+    private String clusterName;
+
+    public String getClusterName() {
+        return clusterName;
+    }
+
+    public void setClusterName(String clusterName) {
+        this.clusterName = clusterName;
+    }
+
+    public String getSnodeName() {
+        return snodeName;
+    }
+
+    public void setSnodeName(String snodeName) {
+        this.snodeName = snodeName;
+    }
+
+    public String getAddr() {
+        return addr;
+    }
+
+    public void setAddr(String addr) {
+        this.addr = addr;
+    }
+
+    @Override
+    public String toString() {
+        return "SnodeData{" +
+            "snodeName='" + snodeName + '\'' +
+            ", addr='" + addr + '\'' +
+            ", clusterName='" + clusterName + '\'' +
+            '}';
+    }
+}
diff --git a/common/src/main/java/org/apache/rocketmq/common/utils/PositiveAtomicCounter.java b/common/src/main/java/org/apache/rocketmq/common/utils/PositiveAtomicCounter.java
new file mode 100644
index 0000000..105b88c
--- /dev/null
+++ b/common/src/main/java/org/apache/rocketmq/common/utils/PositiveAtomicCounter.java
@@ -0,0 +1,40 @@
+/*
+ * 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.utils;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class PositiveAtomicCounter {
+    private static final int MASK = 0x7FFFFFFF;
+    private final AtomicInteger atom;
+
+
+    public PositiveAtomicCounter() {
+        atom = new AtomicInteger(0);
+    }
+
+
+    public final int incrementAndGet() {
+        final int rt = atom.incrementAndGet();
+        return rt & MASK;
+    }
+
+
+    public int intValue() {
+        return atom.intValue();
+    }
+}
diff --git a/distribution/conf/logback_snode.xml b/distribution/conf/logback_snode.xml
new file mode 100644
index 0000000..554f589
--- /dev/null
+++ b/distribution/conf/logback_snode.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+
+<configuration>
+    <appender name="DefaultAppender"
+              class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${user.home}/logs/rocketmqlogs/snode_default.log</file>
+        <append>true</append>
+        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+            <fileNamePattern>${user.home}/logs/rocketmqlogs/otherdays/snode_default.%i.log.gz</fileNamePattern>
+            <minIndex>1</minIndex>
+            <maxIndex>5</maxIndex>
+        </rollingPolicy>
+        <triggeringPolicy
+            class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+            <maxFileSize>100MB</maxFileSize>
+        </triggeringPolicy>
+        <encoder>
+            <pattern>%d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n</pattern>
+            <charset class="java.nio.charset.Charset">UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <appender name="RocketmqSnodeAppender_inner"
+              class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${user.home}/logs/rocketmqlogs/snode.log</file>
+        <append>true</append>
+        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+            <fileNamePattern>${user.home}/logs/rocketmqlogs/otherdays/snode.%i.log.gz</fileNamePattern>
+            <minIndex>1</minIndex>
+            <maxIndex>5</maxIndex>
+        </rollingPolicy>
+        <triggeringPolicy
+            class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+            <maxFileSize>100MB</maxFileSize>
+        </triggeringPolicy>
+        <encoder>
+            <pattern>%d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n</pattern>
+            <charset class="java.nio.charset.Charset">UTF-8</charset>
+        </encoder>
+    </appender>
+    <appender name="RocketmqSnodeAppender" class="ch.qos.logback.classic.AsyncAppender">
+        <appender-ref ref="RocketmqSnodeAppender_inner"/>
+        <discardingThreshold>0</discardingThreshold>
+    </appender>
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <append>true</append>
+        <encoder>
+            <pattern>%d{yyy-MM-dd HH\:mm\:ss,SSS} %p %t - %m%n</pattern>
+            <charset class="java.nio.charset.Charset">UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <logger name="RocketmqSnode" additivity="false">
+        <level value="INFO"/>
+        <appender-ref ref="RocketmqSnodeAppender"/>
+        <appender-ref ref="STDOUT"/>
+    </logger>
+
+    <logger name="RocketmqCommon" additivity="false">
+        <level value="INFO"/>
+        <appender-ref ref="RocketmqSnodeAppender"/>
+    </logger>
+
+    <logger name="RocketmqRemoting" additivity="false">
+        <level value="INFO"/>
+        <appender-ref ref="RocketmqSnodeAppender"/>
+        <appender-ref ref="STDOUT"/>
+    </logger>
+
+    <root>
+        <level value="debug"/>
+        <appender-ref ref="STDOUT"/>
+        <appender-ref ref="DefaultAppender"/>
+    </root>
+</configuration>
diff --git a/example/src/main/java/org/apache/rocketmq/example/quickstart/Producer.java b/example/src/main/java/org/apache/rocketmq/example/quickstart/Producer.java
index 53a1d4d..b2609c8 100644
--- a/example/src/main/java/org/apache/rocketmq/example/quickstart/Producer.java
+++ b/example/src/main/java/org/apache/rocketmq/example/quickstart/Producer.java
@@ -20,6 +20,7 @@ import org.apache.rocketmq.client.exception.MQClientException;
 import org.apache.rocketmq.client.producer.DefaultMQProducer;
 import org.apache.rocketmq.client.producer.SendResult;
 import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.common.utils.ThreadUtils;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 
 /**
@@ -50,7 +51,7 @@ public class Producer {
          */
         producer.start();
 
-        for (int i = 0; i < 1000; i++) {
+        for (int i = 0; i < 10; i++) {
             try {
 
                 /*
@@ -76,6 +77,7 @@ public class Producer {
         /*
          * Shut down once the producer instance is not longer in use.
          */
+        Thread.sleep(100000000000L);
         producer.shutdown();
     }
 }
diff --git a/example/src/main/java/org/apache/rocketmq/example/simple/Producer.java b/example/src/main/java/org/apache/rocketmq/example/simple/Producer.java
index 7b504dd..84b7872 100644
--- a/example/src/main/java/org/apache/rocketmq/example/simple/Producer.java
+++ b/example/src/main/java/org/apache/rocketmq/example/simple/Producer.java
@@ -43,7 +43,6 @@ public class Producer {
             } catch (Exception e) {
                 e.printStackTrace();
             }
-
         producer.shutdown();
     }
 }
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
index dc32445..3b12d49 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
@@ -27,6 +27,7 @@ import org.apache.rocketmq.common.MixAll;
 import org.apache.rocketmq.common.UtilAll;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.common.help.FAQUrl;
+import org.apache.rocketmq.common.protocol.header.namesrv.RegisterSnodeRequestHeader;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.common.namesrv.NamesrvUtil;
@@ -77,7 +78,6 @@ public class DefaultRequestProcessor implements NettyRequestProcessor {
                 request);
         }
 
-
         switch (request.getCode()) {
             case RequestCode.PUT_KV_CONFIG:
                 return this.putKVConfig(ctx, request);
@@ -122,12 +122,26 @@ public class DefaultRequestProcessor implements NettyRequestProcessor {
                 return this.updateConfig(ctx, request);
             case RequestCode.GET_NAMESRV_CONFIG:
                 return this.getConfig(ctx, request);
+            case RequestCode.REGISTER_SNODE:
+                return this.registerSnode(ctx, request);
             default:
                 break;
         }
         return null;
     }
 
+    public RemotingCommand registerSnode(ChannelHandlerContext ctx,
+        RemotingCommand request) throws RemotingCommandException {
+        final RemotingCommand response = RemotingCommand.createResponseCommand(null);
+        final RegisterSnodeRequestHeader requestHeader =
+            (RegisterSnodeRequestHeader) request.decodeCommandCustomHeader(RegisterSnodeRequestHeader.class);
+        this.namesrvController.getRouteInfoManager().registerSnode(
+            requestHeader.getClusterName(),
+            requestHeader.getSnodeName(),
+            requestHeader.getSnodeAddr());
+        return response;
+    }
+
     @Override
     public boolean rejectRequest() {
         return false;
@@ -280,7 +294,7 @@ public class DefaultRequestProcessor implements NettyRequestProcessor {
         final RegisterBrokerResponseHeader responseHeader = (RegisterBrokerResponseHeader) response.readCustomHeader();
         final RegisterBrokerRequestHeader requestHeader =
             (RegisterBrokerRequestHeader) request.decodeCommandCustomHeader(RegisterBrokerRequestHeader.class);
-        log.info("requestHeader:  " + requestHeader );
+        log.info("requestHeader:  " + requestHeader);
         if (!checksum(ctx, request, requestHeader)) {
             response.setCode(ResponseCode.SYSTEM_ERROR);
             response.setRemark("crc32 not match");
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java
index 00962ef..beef528 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java
@@ -33,6 +33,7 @@ import org.apache.rocketmq.common.MixAll;
 import org.apache.rocketmq.common.TopicConfig;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.common.constant.PermName;
+import org.apache.rocketmq.common.protocol.route.SnodeData;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.common.namesrv.RegisterBrokerResult;
@@ -54,6 +55,8 @@ public class RouteInfoManager {
     private final HashMap<String/* clusterName */, Set<String/* brokerName */>> clusterAddrTable;
     private final HashMap<String/* brokerAddr */, BrokerLiveInfo> brokerLiveTable;
     private final HashMap<String/* brokerAddr */, List<String>/* Filter Server */> filterServerTable;
+    private final HashMap<String/* snodeName*/, SnodeData> snodeTable;
+    private final HashMap<String/* clusterName*/, Set<String/*snodeName*/>> snodeCluster;
 
     public RouteInfoManager() {
         this.topicQueueTable = new HashMap<String, List<QueueData>>(1024);
@@ -61,6 +64,8 @@ public class RouteInfoManager {
         this.clusterAddrTable = new HashMap<String, Set<String>>(32);
         this.brokerLiveTable = new HashMap<String, BrokerLiveInfo>(256);
         this.filterServerTable = new HashMap<String, List<String>>(256);
+        this.snodeTable = new HashMap<>(256);
+        this.snodeCluster = new HashMap<>(256);
     }
 
     public byte[] getAllClusterInfo() {
@@ -99,6 +104,32 @@ public class RouteInfoManager {
         return topicList.encode();
     }
 
+    public void registerSnode(
+        final String clusterName,
+        final String snodeName,
+        final String snodeAddr) {
+        try {
+            this.lock.writeLock().lockInterruptibly();
+            Set<String> snodeSet = this.snodeCluster.get(clusterName);
+            if (snodeSet == null) {
+                snodeSet = new HashSet<>();
+                snodeSet.add(snodeName);
+                this.snodeCluster.put(clusterName, snodeSet);
+            } else {
+                snodeSet.add(snodeName);
+            }
+            SnodeData snodeData = new SnodeData();
+            snodeData.setAddr(snodeAddr);
+            snodeData.setSnodeName(snodeName);
+            snodeData.setClusterName(clusterName);
+            snodeTable.put(snodeName, snodeData);
+        } catch (Exception ex) {
+            log.error("Register snode error", ex);
+        } finally {
+            this.lock.writeLock().unlock();
+        }
+    }
+
     public RegisterBrokerResult registerBroker(
         final String clusterName,
         final String brokerAddr,
diff --git a/pom.xml b/pom.xml
index 0a8a41e..47a7b68 100644
--- a/pom.xml
+++ b/pom.xml
@@ -125,6 +125,7 @@
         <module>distribution</module>
         <module>openmessaging</module>
         <module>logging</module>
+        <module>rocketmq-snode</module>
     </modules>
 
     <build>
diff --git a/rocketmq-snode/pom.xml b/rocketmq-snode/pom.xml
new file mode 100644
index 0000000..d3df574
--- /dev/null
+++ b/rocketmq-snode/pom.xml
@@ -0,0 +1,93 @@
+<!--
+  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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.apache.rocketmq</groupId>
+        <artifactId>rocketmq-all</artifactId>
+        <version>4.4.0-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+    <artifactId>rocketmq-snode</artifactId>
+    <name>rocketmq-snode ${project.version}</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>rocketmq-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>rocketmq-store</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>rocketmq-remoting</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>rocketmq-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>rocketmq-srvutil</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>rocketmq-filter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.javassist</groupId>
+            <artifactId>javassist</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <!--<dependency>-->
+            <!--<groupId>org.apache.rocketmq</groupId>-->
+            <!--<artifactId>rocketmq-broker</artifactId>-->
+        <!--</dependency>-->
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.19.1</version>
+                <configuration>
+                    <forkCount>1</forkCount>
+                    <reuseForks>false</reuseForks>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
new file mode 100644
index 0000000..cb19bc9
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
@@ -0,0 +1,205 @@
+package org.apache.rocketmq.snode;/*
+ * 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.
+ */
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import org.apache.rocketmq.common.ThreadFactoryImpl;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.protocol.RequestCode;
+import org.apache.rocketmq.common.utils.ThreadUtils;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingServer;
+import org.apache.rocketmq.remoting.RemotingServerFactory;
+import org.apache.rocketmq.remoting.netty.NettyClientConfig;
+import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.snode.client.ClientHousekeepingService;
+import org.apache.rocketmq.snode.client.ConsumerIdsChangeListener;
+import org.apache.rocketmq.snode.client.ConsumerManager;
+import org.apache.rocketmq.snode.client.DefaultConsumerIdsChangeListener;
+import org.apache.rocketmq.snode.client.ProducerManager;
+import org.apache.rocketmq.snode.client.SubscriptionGroupManager;
+import org.apache.rocketmq.snode.config.SnodeConfig;
+import org.apache.rocketmq.snode.processor.ConsumerManageProcessor;
+import org.apache.rocketmq.snode.processor.HearbeatProcessor;
+import org.apache.rocketmq.snode.processor.PullMessageProcessor;
+import org.apache.rocketmq.snode.processor.SendMessageProcessor;
+import org.apache.rocketmq.snode.service.ScheduledService;
+import org.apache.rocketmq.snode.service.SnodeOuterService;
+import org.apache.rocketmq.snode.service.impl.ScheduledServiceImpl;
+import org.apache.rocketmq.snode.service.impl.SnodeOuterServiceImpl;
+
+public class SnodeController {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
+
+    private final SnodeConfig snodeConfig;
+    private final NettyServerConfig nettyServerConfig;
+    private final NettyClientConfig nettyClientConfig;
+    private RemotingServer snodeServer;
+    private ExecutorService sendMessageExcutor;
+    private ExecutorService heartbeatExecutor;
+    private ExecutorService pullMessageExcutor;
+    private SnodeOuterService snodeOuterService;
+    private ExecutorService consumerManagerExcutor;
+    private ScheduledService scheduledService;
+    private ProducerManager producerManager;
+    private ConsumerManager consumerManager;
+    private ClientHousekeepingService clientHousekeepingService;
+    private SubscriptionGroupManager subscriptionGroupManager;
+
+    private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl(
+        "SnodeControllerScheduledThread"));
+
+    public SnodeController(NettyServerConfig nettyServerConfig,
+        NettyClientConfig nettyClientConfig,
+        SnodeConfig snodeConfig) {
+        this.nettyClientConfig = nettyClientConfig;
+        this.nettyServerConfig = nettyServerConfig;
+        this.snodeConfig = snodeConfig;
+        this.snodeOuterService = SnodeOuterServiceImpl.getInstance(this);
+        this.scheduledService = new ScheduledServiceImpl(this.snodeOuterService, this.snodeConfig);
+        this.sendMessageExcutor = ThreadUtils.newThreadPoolExecutor(
+            snodeConfig.getSnodeSendMessageMinPoolSize(),
+            snodeConfig.getSnodeSendMessageMaxPoolSize(),
+            3000,
+            TimeUnit.MILLISECONDS,
+            new ArrayBlockingQueue<Runnable>(snodeConfig.getSnodeSendThreadPoolQueueCapacity()),
+            "SnodeSendMessageThread",
+            false);
+
+        this.pullMessageExcutor = ThreadUtils.newThreadPoolExecutor(
+            snodeConfig.getSnodeSendMessageMinPoolSize(),
+            snodeConfig.getSnodeSendMessageMaxPoolSize(),
+            3000,
+            TimeUnit.MILLISECONDS,
+            new ArrayBlockingQueue<Runnable>(snodeConfig.getSnodeSendThreadPoolQueueCapacity()),
+            "SnodePullMessageThread",
+            false);
+
+        this.heartbeatExecutor = ThreadUtils.newThreadPoolExecutor(
+            snodeConfig.getSnodeHeartBeatCorePoolSize(),
+            snodeConfig.getSnodeHeartBeatMaxPoolSize(),
+            1000 * 60,
+            TimeUnit.MILLISECONDS,
+            new ArrayBlockingQueue<Runnable>(snodeConfig.getSnodeHeartBeatThreadPoolQueueCapacity()),
+            "SnodeHeartbeatThread",
+            true);
+
+        this.consumerManagerExcutor = ThreadUtils.newThreadPoolExecutor(
+            snodeConfig.getSnodeSendMessageMinPoolSize(),
+            snodeConfig.getSnodeSendMessageMaxPoolSize(),
+            3000,
+            TimeUnit.MILLISECONDS,
+            new ArrayBlockingQueue<Runnable>(snodeConfig.getSnodeSendThreadPoolQueueCapacity()),
+            "SnodePullMessageThread",
+            false);
+
+        if (this.snodeConfig.getNamesrvAddr() != null) {
+            this.snodeOuterService.updateNameServerAddressList(this.snodeConfig.getNamesrvAddr());
+            log.info("Set user specified name server address: {}", this.snodeConfig.getNamesrvAddr());
+        }
+
+        this.producerManager = new ProducerManager();
+
+        ConsumerIdsChangeListener consumerIdsChangeListener = new DefaultConsumerIdsChangeListener(this);
+        this.consumerManager = new ConsumerManager(consumerIdsChangeListener);
+        this.subscriptionGroupManager = new SubscriptionGroupManager(this);
+        this.clientHousekeepingService = new ClientHousekeepingService(this.producerManager, this.consumerManager);
+    }
+
+    public SnodeConfig getSnodeConfig() {
+        return snodeConfig;
+    }
+
+    public boolean initialize() {
+        this.snodeServer = RemotingServerFactory.createInstance().init(this.nettyServerConfig, null);
+        this.registerProcessor();
+        return true;
+    }
+
+    public void registerProcessor() {
+        snodeServer.registerProcessor(RequestCode.SEND_MESSAGE_V2, new SendMessageProcessor(this.snodeOuterService), sendMessageExcutor);
+        snodeServer.registerProcessor(RequestCode.HEART_BEAT, new HearbeatProcessor(this), heartbeatExecutor);
+        snodeServer.registerProcessor(RequestCode.SNODE_PULL_MESSAGE, new PullMessageProcessor(this.snodeOuterService), pullMessageExcutor);
+        snodeServer.registerProcessor(RequestCode.GET_CONSUMER_LIST_BY_GROUP, new ConsumerManageProcessor(this), consumerManagerExcutor);
+    }
+
+    public void start() {
+        initialize();
+        this.snodeServer.start();
+        this.snodeOuterService.start();
+        this.scheduledService.startScheduleTask();
+        this.clientHousekeepingService.start(this.snodeConfig.getHouseKeepingInterval());
+    }
+
+    public void shutdown() {
+        this.sendMessageExcutor.shutdown();
+        this.pullMessageExcutor.shutdown();
+        this.heartbeatExecutor.shutdown();
+        this.scheduledExecutorService.shutdown();
+        this.snodeOuterService.shutdown();
+        this.scheduledService.shutdown();
+        this.clientHousekeepingService.shutdown();
+    }
+
+    public ProducerManager getProducerManager() {
+        return producerManager;
+    }
+
+    public void setProducerManager(ProducerManager producerManager) {
+        this.producerManager = producerManager;
+    }
+
+    public RemotingServer getSnodeServer() {
+        return snodeServer;
+    }
+
+    public void setSnodeServer(RemotingServer snodeServer) {
+        this.snodeServer = snodeServer;
+    }
+
+    public ConsumerManager getConsumerManager() {
+        return consumerManager;
+    }
+
+    public void setConsumerManager(ConsumerManager consumerManager) {
+        this.consumerManager = consumerManager;
+    }
+
+    public SubscriptionGroupManager getSubscriptionGroupManager() {
+        return subscriptionGroupManager;
+    }
+
+    public void setSubscriptionGroupManager(SubscriptionGroupManager subscriptionGroupManager) {
+        this.subscriptionGroupManager = subscriptionGroupManager;
+    }
+
+    public NettyClientConfig getNettyClientConfig() {
+        return nettyClientConfig;
+    }
+
+    public SnodeOuterService getSnodeOuterService() {
+        return snodeOuterService;
+    }
+
+    public void setSnodeOuterService(SnodeOuterService snodeOuterService) {
+        this.snodeOuterService = snodeOuterService;
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java
new file mode 100644
index 0000000..ddbeef8
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java
@@ -0,0 +1,144 @@
+package org.apache.rocketmq.snode;/*
+ * 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.
+ */
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.core.joran.spi.JoranException;
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+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.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.common.TlsMode;
+import org.apache.rocketmq.remoting.netty.NettyClientConfig;
+import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.netty.TlsSystemConfig;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.snode.config.SnodeConfig;
+import org.apache.rocketmq.srvutil.ServerUtil;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_ENABLE;
+
+public class SnodeStartup {
+    private static InternalLogger log;
+    public static Properties properties = null;
+    public static CommandLine commandLine = null;
+    public static String configFile = null;
+
+    public static void main(String[] args) throws IOException, JoranException {
+        startup(createSnodeController(args));
+    }
+
+    public static SnodeController startup(SnodeController controller) {
+        try {
+            controller.start();
+
+            String tip = "The snode[" + controller.getSnodeConfig().getSnodeName() + ", "
+                + controller.getSnodeConfig().getSnodeAddr() + "] boot success. serializeType=" + RemotingCommand.getSerializeTypeConfigInThisServer();
+
+            if (null != controller.getSnodeConfig().getNamesrvAddr()) {
+                tip += " and name server is " + controller.getSnodeConfig().getNamesrvAddr();
+            }
+            log.info(tip);
+            System.out.printf("%s%n", tip);
+            return controller;
+        } catch (Throwable e) {
+            e.printStackTrace();
+            System.exit(-1);
+        }
+        return null;
+    }
+
+    public static SnodeController createSnodeController(String[] args) throws IOException, JoranException {
+        Options options = ServerUtil.buildCommandlineOptions(new Options());
+        commandLine = ServerUtil.parseCmdLine("snode", args, buildCommandlineOptions(options),
+            new PosixParser());
+        if (null == commandLine) {
+            System.exit(-1);
+        }
+
+        final SnodeConfig snodeConfig = new SnodeConfig();
+        final NettyServerConfig nettyServerConfig = new NettyServerConfig();
+        final NettyClientConfig nettyClientConfig = new NettyClientConfig();
+
+        nettyServerConfig.setListenPort(snodeConfig.getListenPort());
+
+        nettyClientConfig.setUseTLS(Boolean.parseBoolean(System.getProperty(TLS_ENABLE,
+            String.valueOf(TlsSystemConfig.tlsMode == TlsMode.ENFORCING))));
+
+        if (commandLine.hasOption('c')) {
+            String file = commandLine.getOptionValue('c');
+            if (file != null) {
+                configFile = file;
+                InputStream in = new BufferedInputStream(new FileInputStream(file));
+                properties = new Properties();
+                properties.load(in);
+                MixAll.properties2Object(properties, snodeConfig);
+                MixAll.properties2Object(properties, nettyServerConfig);
+                MixAll.properties2Object(properties, nettyClientConfig);
+                in.close();
+            }
+        }
+
+        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+        JoranConfigurator configurator = new JoranConfigurator();
+        configurator.setContext(lc);
+        lc.reset();
+        configurator.doConfigure(snodeConfig.getRocketmqHome() + "/conf/logback_snode.xml");
+        log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
+
+        MixAll.printObjectProperties(log, snodeConfig);
+        MixAll.printObjectProperties(log, nettyClientConfig);
+        MixAll.printObjectProperties(log, nettyServerConfig);
+        final SnodeController snodeController = new SnodeController(
+            nettyServerConfig,
+            nettyClientConfig,
+            snodeConfig);
+
+        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+            private volatile boolean hasShutdown = false;
+
+            @Override
+            public void run() {
+                synchronized (this) {
+                    if (!this.hasShutdown) {
+                        this.hasShutdown = true;
+                        snodeController.shutdown();
+                    }
+                }
+            }
+        }));
+        return snodeController;
+    }
+
+    private static Options buildCommandlineOptions(final Options options) {
+        Option opt = new Option("c", "configFile", true, "Broker config properties file");
+        opt.setRequired(false);
+        options.addOption(opt);
+        return options;
+    }
+}
+
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientChannelInfo.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientChannelInfo.java
new file mode 100644
index 0000000..16d8cde
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientChannelInfo.java
@@ -0,0 +1,100 @@
+/*
+ * 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.snode.client;
+
+import io.netty.channel.Channel;
+import org.apache.rocketmq.remoting.serialize.LanguageCode;
+
+public class ClientChannelInfo {
+    private final Channel channel;
+    private final String clientId;
+    private final LanguageCode language;
+    private final int version;
+    private volatile long lastUpdateTimestamp = System.currentTimeMillis();
+
+    public ClientChannelInfo(Channel channel) {
+        this(channel, null, null, 0);
+    }
+
+    public ClientChannelInfo(Channel channel, String clientId, LanguageCode language, int version) {
+        this.channel = channel;
+        this.clientId = clientId;
+        this.language = language;
+        this.version = version;
+    }
+
+    public Channel getChannel() {
+        return channel;
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public LanguageCode getLanguage() {
+        return language;
+    }
+
+    public int getVersion() {
+        return version;
+    }
+
+    public long getLastUpdateTimestamp() {
+        return lastUpdateTimestamp;
+    }
+
+    public void setLastUpdateTimestamp(long lastUpdateTimestamp) {
+        this.lastUpdateTimestamp = lastUpdateTimestamp;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((channel == null) ? 0 : channel.hashCode());
+        result = prime * result + ((clientId == null) ? 0 : clientId.hashCode());
+        result = prime * result + ((language == null) ? 0 : language.hashCode());
+        result = prime * result + (int) (lastUpdateTimestamp ^ (lastUpdateTimestamp >>> 32));
+        result = prime * result + version;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        ClientChannelInfo other = (ClientChannelInfo) obj;
+        if (channel == null) {
+            if (other.channel != null)
+                return false;
+        } else if (this.channel != other.channel) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "ClientChannelInfo [channel=" + channel + ", clientId=" + clientId + ", language=" + language
+            + ", version=" + version + ", lastUpdateTimestamp=" + lastUpdateTimestamp + "]";
+    }
+}
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ClientHousekeepingService.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java
similarity index 63%
copy from broker/src/main/java/org/apache/rocketmq/broker/client/ClientHousekeepingService.java
copy to rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java
index d536db5..e71ea0a 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/ClientHousekeepingService.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java
@@ -14,13 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.rocketmq.broker.client;
+package org.apache.rocketmq.snode.client;
 
 import io.netty.channel.Channel;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
-import org.apache.rocketmq.broker.BrokerController;
 import org.apache.rocketmq.common.ThreadFactoryImpl;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.InternalLogger;
@@ -29,17 +28,18 @@ import org.apache.rocketmq.remoting.ChannelEventListener;
 
 public class ClientHousekeepingService implements ChannelEventListener {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
-    private final BrokerController brokerController;
+    private final ProducerManager producerManager;
+    private final ConsumerManager consumerManager;
 
     private ScheduledExecutorService scheduledExecutorService = Executors
         .newSingleThreadScheduledExecutor(new ThreadFactoryImpl("ClientHousekeepingScheduledThread"));
 
-    public ClientHousekeepingService(final BrokerController brokerController) {
-        this.brokerController = brokerController;
+    public ClientHousekeepingService(final ProducerManager producerManager, final ConsumerManager consumerManager) {
+        this.producerManager = producerManager;
+        this.consumerManager = consumerManager;
     }
 
-    public void start() {
-
+    public void start(long interval) {
         this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
             @Override
             public void run() {
@@ -49,13 +49,12 @@ public class ClientHousekeepingService implements ChannelEventListener {
                     log.error("Error occurred when scan not active client channels.", e);
                 }
             }
-        }, 1000 * 10, 1000 * 10, TimeUnit.MILLISECONDS);
+        }, 1000 * 10, interval, TimeUnit.MILLISECONDS);
     }
 
     private void scanExceptionChannel() {
-        this.brokerController.getProducerManager().scanNotActiveChannel();
-        this.brokerController.getConsumerManager().scanNotActiveChannel();
-        this.brokerController.getFilterServerManager().scanNotActiveChannel();
+        this.producerManager.scanNotActiveChannel();
+        //this.consumerManager.scanNotActiveChannel();
     }
 
     public void shutdown() {
@@ -69,22 +68,19 @@ public class ClientHousekeepingService implements ChannelEventListener {
 
     @Override
     public void onChannelClose(String remoteAddr, Channel channel) {
-        this.brokerController.getProducerManager().doChannelCloseEvent(remoteAddr, channel);
-        this.brokerController.getConsumerManager().doChannelCloseEvent(remoteAddr, channel);
-        this.brokerController.getFilterServerManager().doChannelCloseEvent(remoteAddr, channel);
+        this.producerManager.doChannelCloseEvent(remoteAddr, channel);
+        this.producerManager.doChannelCloseEvent(remoteAddr, channel);
     }
 
     @Override
     public void onChannelException(String remoteAddr, Channel channel) {
-        this.brokerController.getProducerManager().doChannelCloseEvent(remoteAddr, channel);
-        this.brokerController.getConsumerManager().doChannelCloseEvent(remoteAddr, channel);
-        this.brokerController.getFilterServerManager().doChannelCloseEvent(remoteAddr, channel);
+        this.producerManager.doChannelCloseEvent(remoteAddr, channel);
+        this.consumerManager.doChannelCloseEvent(remoteAddr, channel);
     }
 
     @Override
     public void onChannelIdle(String remoteAddr, Channel channel) {
-        this.brokerController.getProducerManager().doChannelCloseEvent(remoteAddr, channel);
-        this.brokerController.getConsumerManager().doChannelCloseEvent(remoteAddr, channel);
-        this.brokerController.getFilterServerManager().doChannelCloseEvent(remoteAddr, channel);
+        this.producerManager.doChannelCloseEvent(remoteAddr, channel);
+        this.consumerManager.doChannelCloseEvent(remoteAddr, channel);
     }
 }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupEvent.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupEvent.java
new file mode 100644
index 0000000..0ebcf17
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupEvent.java
@@ -0,0 +1,33 @@
+/*
+ * 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.snode.client;
+
+public enum ConsumerGroupEvent {
+
+    /**
+     * Some consumers in the group are changed.
+     */
+    CHANGE,
+    /**
+     * The group of consumer is unregistered.
+     */
+    UNREGISTER,
+    /**
+     * The group of consumer is registered.
+     */
+    REGISTER
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java
new file mode 100644
index 0000000..9b366a5
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java
@@ -0,0 +1,248 @@
+/*
+ * 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.snode.client;
+
+import io.netty.channel.Channel;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
+import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
+import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+
+public class ConsumerGroupInfo {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
+    private final String groupName;
+    private final ConcurrentMap<String/* Topic */, SubscriptionData> subscriptionTable =
+        new ConcurrentHashMap<String, SubscriptionData>();
+    private final ConcurrentMap<Channel, ClientChannelInfo> channelInfoTable =
+        new ConcurrentHashMap<Channel, ClientChannelInfo>(16);
+    private volatile ConsumeType consumeType;
+    private volatile MessageModel messageModel;
+    private volatile ConsumeFromWhere consumeFromWhere;
+    private volatile long lastUpdateTimestamp = System.currentTimeMillis();
+
+    public ConsumerGroupInfo(String groupName, ConsumeType consumeType, MessageModel messageModel,
+        ConsumeFromWhere consumeFromWhere) {
+        this.groupName = groupName;
+        this.consumeType = consumeType;
+        this.messageModel = messageModel;
+        this.consumeFromWhere = consumeFromWhere;
+    }
+
+    public ClientChannelInfo findChannel(final String clientId) {
+        Iterator<Entry<Channel, ClientChannelInfo>> it = this.channelInfoTable.entrySet().iterator();
+        while (it.hasNext()) {
+            Entry<Channel, ClientChannelInfo> next = it.next();
+            if (next.getValue().getClientId().equals(clientId)) {
+                return next.getValue();
+            }
+        }
+
+        return null;
+    }
+
+    public ConcurrentMap<String, SubscriptionData> getSubscriptionTable() {
+        return subscriptionTable;
+    }
+
+    public ConcurrentMap<Channel, ClientChannelInfo> getChannelInfoTable() {
+        return channelInfoTable;
+    }
+
+    public List<Channel> getAllChannel() {
+        List<Channel> result = new ArrayList<>();
+
+        result.addAll(this.channelInfoTable.keySet());
+
+        return result;
+    }
+
+    public List<String> getAllClientId() {
+        List<String> result = new ArrayList<>();
+
+        Iterator<Entry<Channel, ClientChannelInfo>> it = this.channelInfoTable.entrySet().iterator();
+
+        while (it.hasNext()) {
+            Entry<Channel, ClientChannelInfo> entry = it.next();
+            ClientChannelInfo clientChannelInfo = entry.getValue();
+            result.add(clientChannelInfo.getClientId());
+        }
+
+        return result;
+    }
+
+    public void unregisterChannel(final ClientChannelInfo clientChannelInfo) {
+        ClientChannelInfo old = this.channelInfoTable.remove(clientChannelInfo.getChannel());
+        if (old != null) {
+            log.info("unregister a consumer[{}] from consumerGroupInfo {}", this.groupName, old.toString());
+        }
+    }
+
+    public boolean doChannelCloseEvent(final String remoteAddr, final Channel channel) {
+        final ClientChannelInfo info = this.channelInfoTable.remove(channel);
+        if (info != null) {
+            log.warn(
+                "NETTY EVENT: remove not active channel[{}] from ConsumerGroupInfo groupChannelTable, consumer group: {}",
+                info.toString(), groupName);
+            return true;
+        }
+
+        return false;
+    }
+
+    public boolean updateChannel(final ClientChannelInfo infoNew, ConsumeType consumeType,
+        MessageModel messageModel, ConsumeFromWhere consumeFromWhere) {
+        boolean updated = false;
+        this.consumeType = consumeType;
+        this.messageModel = messageModel;
+        this.consumeFromWhere = consumeFromWhere;
+
+        ClientChannelInfo infoOld = this.channelInfoTable.get(infoNew.getChannel());
+        if (null == infoOld) {
+            ClientChannelInfo prev = this.channelInfoTable.put(infoNew.getChannel(), infoNew);
+            if (null == prev) {
+                log.info("new consumer connected, group: {} {} {} channel: {}", this.groupName, consumeType,
+                    messageModel, infoNew.toString());
+                updated = true;
+            }
+
+            infoOld = infoNew;
+        } else {
+            if (!infoOld.getClientId().equals(infoNew.getClientId())) {
+                log.error("[BUG] consumer channel exist in broker, but clientId not equal. GROUP: {} OLD: {} NEW: {} ",
+                    this.groupName,
+                    infoOld.toString(),
+                    infoNew.toString());
+                this.channelInfoTable.put(infoNew.getChannel(), infoNew);
+            }
+        }
+
+        this.lastUpdateTimestamp = System.currentTimeMillis();
+        infoOld.setLastUpdateTimestamp(this.lastUpdateTimestamp);
+
+        return updated;
+    }
+
+    public boolean updateSubscription(final Set<SubscriptionData> subList) {
+        boolean updated = false;
+
+        for (SubscriptionData sub : subList) {
+            SubscriptionData old = this.subscriptionTable.get(sub.getTopic());
+            if (old == null) {
+                SubscriptionData prev = this.subscriptionTable.putIfAbsent(sub.getTopic(), sub);
+                if (null == prev) {
+                    updated = true;
+                    log.info("subscription changed, add new topic, group: {} {}",
+                        this.groupName,
+                        sub.toString());
+                }
+            } else if (sub.getSubVersion() > old.getSubVersion()) {
+                if (this.consumeType == ConsumeType.CONSUME_PASSIVELY) {
+                    log.info("subscription changed, group: {} OLD: {} NEW: {}",
+                        this.groupName,
+                        old.toString(),
+                        sub.toString()
+                    );
+                }
+
+                this.subscriptionTable.put(sub.getTopic(), sub);
+            }
+        }
+
+        Iterator<Entry<String, SubscriptionData>> it = this.subscriptionTable.entrySet().iterator();
+        while (it.hasNext()) {
+            Entry<String, SubscriptionData> next = it.next();
+            String oldTopic = next.getKey();
+
+            boolean exist = false;
+            for (SubscriptionData sub : subList) {
+                if (sub.getTopic().equals(oldTopic)) {
+                    exist = true;
+                    break;
+                }
+            }
+
+            if (!exist) {
+                log.warn("subscription changed, group: {} remove topic {} {}",
+                    this.groupName,
+                    oldTopic,
+                    next.getValue().toString()
+                );
+
+                it.remove();
+                updated = true;
+            }
+        }
+
+        this.lastUpdateTimestamp = System.currentTimeMillis();
+
+        return updated;
+    }
+
+    public Set<String> getSubscribeTopics() {
+        return subscriptionTable.keySet();
+    }
+
+    public SubscriptionData findSubscriptionData(final String topic) {
+        return this.subscriptionTable.get(topic);
+    }
+
+    public ConsumeType getConsumeType() {
+        return consumeType;
+    }
+
+    public void setConsumeType(ConsumeType consumeType) {
+        this.consumeType = consumeType;
+    }
+
+    public MessageModel getMessageModel() {
+        return messageModel;
+    }
+
+    public void setMessageModel(MessageModel messageModel) {
+        this.messageModel = messageModel;
+    }
+
+    public String getGroupName() {
+        return groupName;
+    }
+
+    public long getLastUpdateTimestamp() {
+        return lastUpdateTimestamp;
+    }
+
+    public void setLastUpdateTimestamp(long lastUpdateTimestamp) {
+        this.lastUpdateTimestamp = lastUpdateTimestamp;
+    }
+
+    public ConsumeFromWhere getConsumeFromWhere() {
+        return consumeFromWhere;
+    }
+
+    public void setConsumeFromWhere(ConsumeFromWhere consumeFromWhere) {
+        this.consumeFromWhere = consumeFromWhere;
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerIdsChangeListener.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerIdsChangeListener.java
new file mode 100644
index 0000000..ba950f1
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerIdsChangeListener.java
@@ -0,0 +1,22 @@
+/*
+ * 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.snode.client;
+
+public interface ConsumerIdsChangeListener {
+
+    void handle(ConsumerGroupEvent event, String group, Object... args);
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java
new file mode 100644
index 0000000..8d3b665
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java
@@ -0,0 +1,189 @@
+/*
+ * 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.snode.client;
+
+import io.netty.channel.Channel;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
+import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
+import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.common.RemotingUtil;
+
+public class ConsumerManager {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
+    private static final long CHANNEL_EXPIRED_TIMEOUT = 1000 * 120;
+    private final ConcurrentMap<String/* Group */, ConsumerGroupInfo> consumerTable =
+        new ConcurrentHashMap<String, ConsumerGroupInfo>(1024);
+    private final ConsumerIdsChangeListener consumerIdsChangeListener;
+
+    public ConsumerManager(final ConsumerIdsChangeListener consumerIdsChangeListener) {
+        this.consumerIdsChangeListener = consumerIdsChangeListener;
+    }
+
+    public ClientChannelInfo findChannel(final String group, final String clientId) {
+        ConsumerGroupInfo consumerGroupInfo = this.consumerTable.get(group);
+        if (consumerGroupInfo != null) {
+            return consumerGroupInfo.findChannel(clientId);
+        }
+        return null;
+    }
+
+    public SubscriptionData findSubscriptionData(final String group, final String topic) {
+        ConsumerGroupInfo consumerGroupInfo = this.getConsumerGroupInfo(group);
+        if (consumerGroupInfo != null) {
+            return consumerGroupInfo.findSubscriptionData(topic);
+        }
+
+        return null;
+    }
+
+    public ConsumerGroupInfo getConsumerGroupInfo(final String group) {
+        return this.consumerTable.get(group);
+    }
+
+    public int findSubscriptionDataCount(final String group) {
+        ConsumerGroupInfo consumerGroupInfo = this.getConsumerGroupInfo(group);
+        if (consumerGroupInfo != null) {
+            return consumerGroupInfo.getSubscriptionTable().size();
+        }
+
+        return 0;
+    }
+
+    public void doChannelCloseEvent(final String remoteAddr, final Channel channel) {
+        Iterator<Entry<String, ConsumerGroupInfo>> it = this.consumerTable.entrySet().iterator();
+        while (it.hasNext()) {
+            Entry<String, ConsumerGroupInfo> next = it.next();
+            ConsumerGroupInfo info = next.getValue();
+            boolean removed = info.doChannelCloseEvent(remoteAddr, channel);
+            if (removed) {
+                if (info.getChannelInfoTable().isEmpty()) {
+                    ConsumerGroupInfo remove = this.consumerTable.remove(next.getKey());
+                    if (remove != null) {
+                        log.info("unregister consumer ok, no any connection, and remove consumer group, {}",
+                            next.getKey());
+                        this.consumerIdsChangeListener.handle(ConsumerGroupEvent.UNREGISTER, next.getKey());
+                    }
+                }
+
+                this.consumerIdsChangeListener.handle(ConsumerGroupEvent.CHANGE, next.getKey(), info.getAllChannel());
+            }
+        }
+    }
+
+    public boolean registerConsumer(final String group, final ClientChannelInfo clientChannelInfo,
+        ConsumeType consumeType, MessageModel messageModel, ConsumeFromWhere consumeFromWhere,
+        final Set<SubscriptionData> subList, boolean isNotifyConsumerIdsChangedEnable) {
+
+        ConsumerGroupInfo consumerGroupInfo = this.consumerTable.get(group);
+        if (null == consumerGroupInfo) {
+            ConsumerGroupInfo tmp = new ConsumerGroupInfo(group, consumeType, messageModel, consumeFromWhere);
+            ConsumerGroupInfo prev = this.consumerTable.putIfAbsent(group, tmp);
+            consumerGroupInfo = prev != null ? prev : tmp;
+        }
+
+        boolean r1 =
+            consumerGroupInfo.updateChannel(clientChannelInfo, consumeType, messageModel,
+                consumeFromWhere);
+        boolean r2 = consumerGroupInfo.updateSubscription(subList);
+
+        if (r1 || r2) {
+            if (isNotifyConsumerIdsChangedEnable) {
+                this.consumerIdsChangeListener.handle(ConsumerGroupEvent.CHANGE, group, consumerGroupInfo.getAllChannel());
+            }
+        }
+
+        this.consumerIdsChangeListener.handle(ConsumerGroupEvent.REGISTER, group, subList);
+
+        return r1 || r2;
+    }
+
+    public void unregisterConsumer(final String group, final ClientChannelInfo clientChannelInfo,
+        boolean isNotifyConsumerIdsChangedEnable) {
+        ConsumerGroupInfo consumerGroupInfo = this.consumerTable.get(group);
+        if (null != consumerGroupInfo) {
+            consumerGroupInfo.unregisterChannel(clientChannelInfo);
+            if (consumerGroupInfo.getChannelInfoTable().isEmpty()) {
+                ConsumerGroupInfo remove = this.consumerTable.remove(group);
+                if (remove != null) {
+                    log.info("unregister consumer ok, no any connection, and remove consumer group, {}", group);
+
+                    this.consumerIdsChangeListener.handle(ConsumerGroupEvent.UNREGISTER, group);
+                }
+            }
+            if (isNotifyConsumerIdsChangedEnable) {
+                this.consumerIdsChangeListener.handle(ConsumerGroupEvent.CHANGE, group, consumerGroupInfo.getAllChannel());
+            }
+        }
+    }
+
+    public void scanNotActiveChannel() {
+        Iterator<Entry<String, ConsumerGroupInfo>> it = this.consumerTable.entrySet().iterator();
+        while (it.hasNext()) {
+            Entry<String, ConsumerGroupInfo> next = it.next();
+            String group = next.getKey();
+            ConsumerGroupInfo consumerGroupInfo = next.getValue();
+            ConcurrentMap<Channel, ClientChannelInfo> channelInfoTable =
+                consumerGroupInfo.getChannelInfoTable();
+
+            Iterator<Entry<Channel, ClientChannelInfo>> itChannel = channelInfoTable.entrySet().iterator();
+            while (itChannel.hasNext()) {
+                Entry<Channel, ClientChannelInfo> nextChannel = itChannel.next();
+                ClientChannelInfo clientChannelInfo = nextChannel.getValue();
+                long diff = System.currentTimeMillis() - clientChannelInfo.getLastUpdateTimestamp();
+                if (diff > CHANNEL_EXPIRED_TIMEOUT) {
+                    log.warn(
+                        "SCAN: remove expired channel from ConsumerManager consumerTable. channel={}, consumerGroup={}",
+                        RemotingHelper.parseChannelRemoteAddr(clientChannelInfo.getChannel()), group);
+                    RemotingUtil.closeChannel(clientChannelInfo.getChannel());
+                    itChannel.remove();
+                }
+            }
+
+            if (channelInfoTable.isEmpty()) {
+                log.warn(
+                    "SCAN: remove expired channel from ConsumerManager consumerTable, all clear, consumerGroup={}",
+                    group);
+                it.remove();
+            }
+        }
+    }
+
+    public HashSet<String> queryTopicConsumeByWho(final String topic) {
+        HashSet<String> groups = new HashSet<>();
+        Iterator<Entry<String, ConsumerGroupInfo>> it = this.consumerTable.entrySet().iterator();
+        while (it.hasNext()) {
+            Entry<String, ConsumerGroupInfo> entry = it.next();
+            ConcurrentMap<String, SubscriptionData> subscriptionTable =
+                entry.getValue().getSubscriptionTable();
+            if (subscriptionTable.containsKey(topic)) {
+                groups.add(entry.getKey());
+            }
+        }
+        return groups;
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java
new file mode 100644
index 0000000..cb7c164
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java
@@ -0,0 +1,64 @@
+/*
+ * 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.snode.client;
+
+import io.netty.channel.Channel;
+import java.util.Collection;
+import java.util.List;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.snode.SnodeController;
+
+//TODO Filter implementation
+public class DefaultConsumerIdsChangeListener implements ConsumerIdsChangeListener {
+    private final SnodeController snodeController;
+
+    public DefaultConsumerIdsChangeListener(SnodeController snodeController) {
+        this.snodeController = snodeController;
+    }
+
+    @Override
+    public void handle(ConsumerGroupEvent event, String group, Object... args) {
+        if (event == null) {
+            return;
+        }
+        switch (event) {
+            case CHANGE:
+                if (args == null || args.length < 1) {
+                    return;
+                }
+                List<Channel> channels = (List<Channel>) args[0];
+                if (channels != null && snodeController.getSnodeConfig().isNotifyConsumerIdsChangedEnable()) {
+                    for (Channel chl : channels) {
+                        this.snodeController.getSnodeOuterService().notifyConsumerIdsChanged(chl, group);
+                    }
+                }
+                break;
+            case UNREGISTER:
+//                this.snodeController.getConsumerFilterManager().unRegister(group);
+                break;
+            case REGISTER:
+                if (args == null || args.length < 1) {
+                    return;
+                }
+//                Collection<SubscriptionData> subscriptionDataList = (Collection<SubscriptionData>) args[0];
+//                this.snodeController.getConsumerFilterManager().register(group, subscriptionDataList);
+                break;
+            default:
+                throw new RuntimeException("Unknown event " + event);
+        }
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java
new file mode 100644
index 0000000..b80c027
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java
@@ -0,0 +1,224 @@
+/*
+ * 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.snode.client;
+
+import io.netty.channel.Channel;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.utils.PositiveAtomicCounter;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.common.RemotingUtil;
+
+public class ProducerManager {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
+    private static final long LOCK_TIMEOUT_MILLIS = 3000;
+    private static final long CHANNEL_EXPIRED_TIMEOUT = 1000 * 120;
+    private static final int GET_AVALIABLE_CHANNEL_RETRY_COUNT = 3;
+    private final Lock groupChannelLock = new ReentrantLock();
+    private final HashMap<String /* group name */, HashMap<Channel, ClientChannelInfo>> groupChannelTable =
+        new HashMap<String, HashMap<Channel, ClientChannelInfo>>();
+    private PositiveAtomicCounter positiveAtomicCounter = new PositiveAtomicCounter();
+    public ProducerManager() {
+
+    }
+
+    public HashMap<String, HashMap<Channel, ClientChannelInfo>> getGroupChannelTable() {
+        HashMap<String /* group name */, HashMap<Channel, ClientChannelInfo>> newGroupChannelTable =
+            new HashMap<String, HashMap<Channel, ClientChannelInfo>>();
+        try {
+            if (this.groupChannelLock.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
+                try {
+                    newGroupChannelTable.putAll(groupChannelTable);
+                } finally {
+                    groupChannelLock.unlock();
+                }
+            }
+        } catch (InterruptedException e) {
+            log.error("", e);
+        }
+        return newGroupChannelTable;
+    }
+
+    public void scanNotActiveChannel() {
+        try {
+            if (this.groupChannelLock.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
+                try {
+                    for (final Entry<String, HashMap<Channel, ClientChannelInfo>> entry : this.groupChannelTable
+                        .entrySet()) {
+                        final String group = entry.getKey();
+                        final HashMap<Channel, ClientChannelInfo> chlMap = entry.getValue();
+
+                        Iterator<Entry<Channel, ClientChannelInfo>> it = chlMap.entrySet().iterator();
+                        while (it.hasNext()) {
+                            Entry<Channel, ClientChannelInfo> item = it.next();
+                            // final Integer id = item.getKey();
+                            final ClientChannelInfo info = item.getValue();
+
+                            long diff = System.currentTimeMillis() - info.getLastUpdateTimestamp();
+                            if (diff > CHANNEL_EXPIRED_TIMEOUT) {
+                                it.remove();
+                                log.warn(
+                                    "SCAN: remove expired channel[{}] from ProducerManager groupChannelTable, producer group name: {}",
+                                    RemotingHelper.parseChannelRemoteAddr(info.getChannel()), group);
+                                RemotingUtil.closeChannel(info.getChannel());
+                            }
+                        }
+                    }
+                } finally {
+                    this.groupChannelLock.unlock();
+                }
+            } else {
+                log.warn("ProducerManager scanNotActiveChannel lock timeout");
+            }
+        } catch (InterruptedException e) {
+            log.error("", e);
+        }
+    }
+
+    public void doChannelCloseEvent(final String remoteAddr, final Channel channel) {
+        if (channel != null) {
+            try {
+                if (this.groupChannelLock.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
+                    try {
+                        for (final Entry<String, HashMap<Channel, ClientChannelInfo>> entry : this.groupChannelTable
+                            .entrySet()) {
+                            final String group = entry.getKey();
+                            final HashMap<Channel, ClientChannelInfo> clientChannelInfoTable =
+                                entry.getValue();
+                            final ClientChannelInfo clientChannelInfo =
+                                clientChannelInfoTable.remove(channel);
+                            if (clientChannelInfo != null) {
+                                log.info(
+                                    "NETTY EVENT: remove channel[{}][{}] from ProducerManager groupChannelTable, producer group: {}",
+                                    clientChannelInfo.toString(), remoteAddr, group);
+                            }
+
+                        }
+                    } finally {
+                        this.groupChannelLock.unlock();
+                    }
+                } else {
+                    log.warn("ProducerManager doChannelCloseEvent lock timeout");
+                }
+            } catch (InterruptedException e) {
+                log.error("", e);
+            }
+        }
+    }
+
+    public void registerProducer(final String group, final ClientChannelInfo clientChannelInfo) {
+        try {
+            ClientChannelInfo clientChannelInfoFound = null;
+
+            if (this.groupChannelLock.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
+                try {
+                    HashMap<Channel, ClientChannelInfo> channelTable = this.groupChannelTable.get(group);
+                    if (null == channelTable) {
+                        channelTable = new HashMap<>();
+                        this.groupChannelTable.put(group, channelTable);
+                    }
+
+                    clientChannelInfoFound = channelTable.get(clientChannelInfo.getChannel());
+                    if (null == clientChannelInfoFound) {
+                        channelTable.put(clientChannelInfo.getChannel(), clientChannelInfo);
+                        log.info("new producer connected, group: {} channel: {}", group,
+                            clientChannelInfo.toString());
+                    }
+                } finally {
+                    this.groupChannelLock.unlock();
+                }
+
+                if (clientChannelInfoFound != null) {
+                    clientChannelInfoFound.setLastUpdateTimestamp(System.currentTimeMillis());
+                }
+            } else {
+                log.warn("ProducerManager registerProducer lock timeout");
+            }
+        } catch (InterruptedException e) {
+            log.error("", e);
+        }
+    }
+
+    public void unregisterProducer(final String group, final ClientChannelInfo clientChannelInfo) {
+        try {
+            if (this.groupChannelLock.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
+                try {
+                    HashMap<Channel, ClientChannelInfo> channelTable = this.groupChannelTable.get(group);
+                    if (null != channelTable && !channelTable.isEmpty()) {
+                        ClientChannelInfo old = channelTable.remove(clientChannelInfo.getChannel());
+                        if (old != null) {
+                            log.info("unregister a producer[{}] from groupChannelTable {}", group,
+                                clientChannelInfo.toString());
+                        }
+
+                        if (channelTable.isEmpty()) {
+                            this.groupChannelTable.remove(group);
+                            log.info("unregister a producer group[{}] from groupChannelTable", group);
+                        }
+                    }
+                } finally {
+                    this.groupChannelLock.unlock();
+                }
+            } else {
+                log.warn("ProducerManager unregisterProducer lock timeout");
+            }
+        } catch (InterruptedException e) {
+            log.error("", e);
+        }
+    }
+
+    public Channel getAvaliableChannel(String groupId) {
+        HashMap<Channel, ClientChannelInfo> channelClientChannelInfoHashMap = groupChannelTable.get(groupId);
+        List<Channel> channelList = new ArrayList<Channel>();
+        if (channelClientChannelInfoHashMap != null) {
+            for (Channel channel : channelClientChannelInfoHashMap.keySet()) {
+                channelList.add(channel);
+            }
+            int size = channelList.size();
+            if (0 == size) {
+                log.warn("Channel list is empty. groupId={}", groupId);
+                return null;
+            }
+
+            int index = positiveAtomicCounter.incrementAndGet() % size;
+            Channel channel = channelList.get(index);
+            int count = 0;
+            boolean isOk = channel.isActive() && channel.isWritable();
+            while (count++ < GET_AVALIABLE_CHANNEL_RETRY_COUNT) {
+                if (isOk) {
+                    return channel;
+                }
+                index = (++index) % size;
+                channel = channelList.get(index);
+                isOk = channel.isActive() && channel.isWritable();
+            }
+        } else {
+            log.warn("Check transaction failed, channel table is empty. groupId={}", groupId);
+            return null;
+        }
+        return null;
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/SubscriptionGroupManager.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/SubscriptionGroupManager.java
new file mode 100644
index 0000000..3c6799e
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/SubscriptionGroupManager.java
@@ -0,0 +1,200 @@
+/*
+ * 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.snode.client;
+
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.apache.rocketmq.common.ConfigManager;
+import org.apache.rocketmq.common.DataVersion;
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
+import org.apache.rocketmq.snode.SnodeController;
+
+public class SubscriptionGroupManager extends ConfigManager {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
+
+    private final ConcurrentMap<String, SubscriptionGroupConfig> subscriptionGroupTable =
+        new ConcurrentHashMap<String, SubscriptionGroupConfig>(1024);
+    private final DataVersion dataVersion = new DataVersion();
+    private transient SnodeController snodeController;
+
+    public enum SUBSCRIPTION_EVENT {
+        CREATE,
+        UPDATE,
+        DELETE
+    }
+
+    public SubscriptionGroupManager() {
+        this.init();
+    }
+
+    public SubscriptionGroupManager(SnodeController snodeController) {
+        this.snodeController = snodeController;
+        this.init();
+    }
+
+    private void init() {
+        {
+            SubscriptionGroupConfig subscriptionGroupConfig = new SubscriptionGroupConfig();
+            subscriptionGroupConfig.setGroupName(MixAll.TOOLS_CONSUMER_GROUP);
+            this.subscriptionGroupTable.put(MixAll.TOOLS_CONSUMER_GROUP, subscriptionGroupConfig);
+        }
+
+        {
+            SubscriptionGroupConfig subscriptionGroupConfig = new SubscriptionGroupConfig();
+            subscriptionGroupConfig.setGroupName(MixAll.FILTERSRV_CONSUMER_GROUP);
+            this.subscriptionGroupTable.put(MixAll.FILTERSRV_CONSUMER_GROUP, subscriptionGroupConfig);
+        }
+
+        {
+            SubscriptionGroupConfig subscriptionGroupConfig = new SubscriptionGroupConfig();
+            subscriptionGroupConfig.setGroupName(MixAll.SELF_TEST_CONSUMER_GROUP);
+            this.subscriptionGroupTable.put(MixAll.SELF_TEST_CONSUMER_GROUP, subscriptionGroupConfig);
+        }
+
+        {
+            SubscriptionGroupConfig subscriptionGroupConfig = new SubscriptionGroupConfig();
+            subscriptionGroupConfig.setGroupName(MixAll.ONS_HTTP_PROXY_GROUP);
+            subscriptionGroupConfig.setConsumeBroadcastEnable(true);
+            this.subscriptionGroupTable.put(MixAll.ONS_HTTP_PROXY_GROUP, subscriptionGroupConfig);
+        }
+
+        {
+            SubscriptionGroupConfig subscriptionGroupConfig = new SubscriptionGroupConfig();
+            subscriptionGroupConfig.setGroupName(MixAll.CID_ONSAPI_PULL_GROUP);
+            subscriptionGroupConfig.setConsumeBroadcastEnable(true);
+            this.subscriptionGroupTable.put(MixAll.CID_ONSAPI_PULL_GROUP, subscriptionGroupConfig);
+        }
+
+        {
+            SubscriptionGroupConfig subscriptionGroupConfig = new SubscriptionGroupConfig();
+            subscriptionGroupConfig.setGroupName(MixAll.CID_ONSAPI_PERMISSION_GROUP);
+            subscriptionGroupConfig.setConsumeBroadcastEnable(true);
+            this.subscriptionGroupTable.put(MixAll.CID_ONSAPI_PERMISSION_GROUP, subscriptionGroupConfig);
+        }
+
+        {
+            SubscriptionGroupConfig subscriptionGroupConfig = new SubscriptionGroupConfig();
+            subscriptionGroupConfig.setGroupName(MixAll.CID_ONSAPI_OWNER_GROUP);
+            subscriptionGroupConfig.setConsumeBroadcastEnable(true);
+            this.subscriptionGroupTable.put(MixAll.CID_ONSAPI_OWNER_GROUP, subscriptionGroupConfig);
+        }
+    }
+
+    public void updateSubscriptionGroupConfig(final SubscriptionGroupConfig config) {
+        SubscriptionGroupConfig old = this.subscriptionGroupTable.put(config.getGroupName(), config);
+        if (old != null) {
+            log.info("update subscription group config, old: {} new: {}", old, config);
+        } else {
+            log.info("create new subscription group, {}", config);
+        }
+
+        this.dataVersion.nextVersion();
+
+        this.persistToEnode(SUBSCRIPTION_EVENT.UPDATE, config);
+    }
+
+    public void disableConsume(final String groupName) {
+        SubscriptionGroupConfig old = this.subscriptionGroupTable.get(groupName);
+        if (old != null) {
+            old.setConsumeEnable(false);
+            this.dataVersion.nextVersion();
+        }
+    }
+
+    public SubscriptionGroupConfig findSubscriptionGroupConfig(final String group) {
+        SubscriptionGroupConfig subscriptionGroupConfig = this.subscriptionGroupTable.get(group);
+        if (null == subscriptionGroupConfig) {
+            if (snodeController.getSnodeConfig().isAutoCreateSubscriptionGroup() || MixAll.isSysConsumerGroup(group)) {
+                subscriptionGroupConfig = new SubscriptionGroupConfig();
+                subscriptionGroupConfig.setGroupName(group);
+                SubscriptionGroupConfig preConfig = this.subscriptionGroupTable.putIfAbsent(group, subscriptionGroupConfig);
+                if (null == preConfig) {
+                    log.info("auto create a subscription group, {}", subscriptionGroupConfig.toString());
+                }
+                this.dataVersion.nextVersion();
+                this.persistToEnode(SUBSCRIPTION_EVENT.CREATE, subscriptionGroupConfig);
+            }
+        }
+
+        return subscriptionGroupConfig;
+    }
+
+    @Override
+    public String encode() {
+        return this.encode(false);
+    }
+
+    @Override
+    public String configFilePath() {
+        //TODO  get subscription persist request code
+        return null;
+    }
+
+    @Override
+    public void decode(String jsonString) {
+        if (jsonString != null) {
+            SubscriptionGroupManager obj = RemotingSerializable.fromJson(jsonString, SubscriptionGroupManager.class);
+            if (obj != null) {
+                this.subscriptionGroupTable.putAll(obj.subscriptionGroupTable);
+                this.dataVersion.assignNewOne(obj.dataVersion);
+                this.printLoadDataWhenFirstBoot(obj);
+            }
+        }
+    }
+
+    public String encode(final boolean prettyFormat) {
+        return RemotingSerializable.toJson(this, prettyFormat);
+    }
+
+    private void printLoadDataWhenFirstBoot(final SubscriptionGroupManager sgm) {
+        Iterator<Entry<String, SubscriptionGroupConfig>> it = sgm.getSubscriptionGroupTable().entrySet().iterator();
+        while (it.hasNext()) {
+            Entry<String, SubscriptionGroupConfig> next = it.next();
+            log.info("load exist subscription group, {}", next.getValue().toString());
+        }
+    }
+
+    public ConcurrentMap<String, SubscriptionGroupConfig> getSubscriptionGroupTable() {
+        return subscriptionGroupTable;
+    }
+
+    public DataVersion getDataVersion() {
+        return dataVersion;
+    }
+
+    public void deleteSubscriptionGroupConfig(final String groupName) {
+        SubscriptionGroupConfig old = this.subscriptionGroupTable.remove(groupName);
+        if (old != null) {
+            log.info("delete subscription group OK, subscription group:{}", old);
+            this.dataVersion.nextVersion();
+            this.persistToEnode(SUBSCRIPTION_EVENT.DELETE, old);
+        } else {
+            log.warn("delete subscription group failed, subscription groupName: {} not exist", groupName);
+        }
+    }
+
+    void persistToEnode(SUBSCRIPTION_EVENT event, SubscriptionGroupConfig config) {
+
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java
new file mode 100644
index 0000000..725cf6a
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java
@@ -0,0 +1,223 @@
+package org.apache.rocketmq.snode.config;/*
+ * 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.
+ */
+
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.annotation.ImportantField;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+
+public class SnodeConfig {
+
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.COMMON_LOGGER_NAME);
+
+    private String rocketmqHome = System.getProperty(MixAll.ROCKETMQ_HOME_PROPERTY, System.getenv(MixAll.ROCKETMQ_HOME_ENV));
+
+    @ImportantField
+    private String namesrvAddr = System.getProperty(MixAll.NAMESRV_ADDR_PROPERTY, System.getenv(MixAll.NAMESRV_ADDR_ENV));
+
+    private String snodeName = "defaultNode";
+
+    private String snodeAddr = "127.0.0.1:11911";
+
+    private String clusterName = "defaultCluster";
+
+    private int snodeSendThreadPoolQueueCapacity = 10000;
+
+    private int snodeSendMessageMinPoolSize = 10;
+
+    private int snodeSendMessageMaxPoolSize = 20;
+
+    private int snodeHeartBeatCorePoolSize = 1;
+
+    private int snodeHeartBeatMaxPoolSize = 2;
+
+    private int snodeHeartBeatThreadPoolQueueCapacity = 1000;
+
+    private long snodeHeartBeatInterval = 30 * 1000;
+
+    private boolean fetechNameserver = false;
+
+    private long houseKeepingInterval = 10 * 1000;
+
+    private boolean notifyConsumerIdsChangedEnable = true;
+
+    private boolean autoCreateSubscriptionGroup = true;
+
+    private int listenPort = 11911;
+
+    public void setSnodeHeartBeatInterval(long snodeHeartBeatInterval) {
+        this.snodeHeartBeatInterval = snodeHeartBeatInterval;
+    }
+
+    public long getHouseKeepingInterval() {
+        return houseKeepingInterval;
+    }
+
+    public void setHouseKeepingInterval(long houseKeepingInterval) {
+        this.houseKeepingInterval = houseKeepingInterval;
+    }
+
+    public boolean isFetechNameserver() {
+        return fetechNameserver;
+    }
+
+    public void setFetechNameserver(boolean fetechNameserver) {
+        this.fetechNameserver = fetechNameserver;
+    }
+
+    public long getSnodeHeartBeatInterval() {
+        return snodeHeartBeatInterval;
+    }
+
+    public String getClusterName() {
+        return clusterName;
+    }
+
+    public void setClusterName(String clusterName) {
+        this.clusterName = clusterName;
+    }
+
+    /**
+     * This configurable item defines interval of topics registration of broker to name server. Allowing values are
+     * between 10, 000 and 60, 000 milliseconds.
+     */
+    private int registerNameServerPeriod = 1000 * 30;
+
+    public int getRegisterNameServerPeriod() {
+        return registerNameServerPeriod;
+    }
+
+    public void setRegisterNameServerPeriod(int registerNameServerPeriod) {
+        this.registerNameServerPeriod = registerNameServerPeriod;
+    }
+
+    @ImportantField
+    private boolean fetchNamesrvAddrByAddressServer = false;
+
+    public boolean isFetchNamesrvAddrByAddressServer() {
+        return fetchNamesrvAddrByAddressServer;
+    }
+
+    public void setFetchNamesrvAddrByAddressServer(boolean fetchNamesrvAddrByAddressServer) {
+        this.fetchNamesrvAddrByAddressServer = fetchNamesrvAddrByAddressServer;
+    }
+
+    public int getSnodeHeartBeatThreadPoolQueueCapacity() {
+        return snodeHeartBeatThreadPoolQueueCapacity;
+    }
+
+    public void setSnodeHeartBeatThreadPoolQueueCapacity(int snodeHeartBeatThreadPoolQueueCapacity) {
+        this.snodeHeartBeatThreadPoolQueueCapacity = snodeHeartBeatThreadPoolQueueCapacity;
+    }
+
+    public int getSnodeHeartBeatCorePoolSize() {
+        return snodeHeartBeatCorePoolSize;
+    }
+
+    public void setSnodeHeartBeatCorePoolSize(int snodeHeartBeatCorePoolSize) {
+        this.snodeHeartBeatCorePoolSize = snodeHeartBeatCorePoolSize;
+    }
+
+    public int getSnodeHeartBeatMaxPoolSize() {
+        return snodeHeartBeatMaxPoolSize;
+    }
+
+    public void setSnodeHeartBeatMaxPoolSize(int snodeHeartBeatMaxPoolSize) {
+        this.snodeHeartBeatMaxPoolSize = snodeHeartBeatMaxPoolSize;
+    }
+
+    public int getListenPort() {
+        return listenPort;
+    }
+
+    public String getRocketmqHome() {
+        return rocketmqHome;
+    }
+
+    public void setRocketmqHome(String rocketmqHome) {
+        this.rocketmqHome = rocketmqHome;
+    }
+
+    public void setListenPort(int listenPort) {
+        this.listenPort = listenPort;
+    }
+
+    public int getSnodeSendThreadPoolQueueCapacity() {
+        return snodeSendThreadPoolQueueCapacity;
+    }
+
+    public void setSnodeSendThreadPoolQueueCapacity(int snodeSendThreadPoolQueueCapacity) {
+        this.snodeSendThreadPoolQueueCapacity = snodeSendThreadPoolQueueCapacity;
+    }
+
+    public int getSnodeSendMessageMinPoolSize() {
+        return snodeSendMessageMinPoolSize;
+    }
+
+    public void setSnodeSendMessageMinPoolSize(int snodeSendMessageMinPoolSize) {
+        this.snodeSendMessageMinPoolSize = snodeSendMessageMinPoolSize;
+    }
+
+    public int getSnodeSendMessageMaxPoolSize() {
+        return snodeSendMessageMaxPoolSize;
+    }
+
+    public void setSnodeSendMessageMaxPoolSize(int snodeSendMessageMaxPoolSize) {
+        this.snodeSendMessageMaxPoolSize = snodeSendMessageMaxPoolSize;
+    }
+
+    public String getSnodeAddr() {
+        return snodeAddr;
+    }
+
+    public void setSnodeAddr(String snodeAddr) {
+        this.snodeAddr = snodeAddr;
+    }
+
+    public String getSnodeName() {
+        return snodeName;
+    }
+
+    public void setSnodeName(String snodeName) {
+        this.snodeName = snodeName;
+    }
+
+    public String getNamesrvAddr() {
+        return namesrvAddr;
+    }
+
+    public void setNamesrvAddr(String namesrvAddr) {
+        this.namesrvAddr = namesrvAddr;
+    }
+
+    public boolean isNotifyConsumerIdsChangedEnable() {
+        return notifyConsumerIdsChangedEnable;
+    }
+
+    public void setNotifyConsumerIdsChangedEnable(boolean notifyConsumerIdsChangedEnable) {
+        this.notifyConsumerIdsChangedEnable = notifyConsumerIdsChangedEnable;
+    }
+
+    public boolean isAutoCreateSubscriptionGroup() {
+        return autoCreateSubscriptionGroup;
+    }
+
+    public void setAutoCreateSubscriptionGroup(boolean autoCreateSubscriptionGroup) {
+        this.autoCreateSubscriptionGroup = autoCreateSubscriptionGroup;
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
new file mode 100644
index 0000000..8509546
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
@@ -0,0 +1,96 @@
+/*
+ * 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.snode.processor;
+
+import io.netty.channel.ChannelHandlerContext;
+import java.util.List;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.protocol.RequestCode;
+import org.apache.rocketmq.common.protocol.ResponseCode;
+import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader;
+import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupResponseBody;
+import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupResponseHeader;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.exception.RemotingCommandException;
+import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.snode.SnodeController;
+import org.apache.rocketmq.snode.client.ConsumerGroupInfo;
+
+public class ConsumerManageProcessor implements NettyRequestProcessor {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
+
+    private final SnodeController snodeController;
+
+    public ConsumerManageProcessor(final SnodeController snodeController) {
+        this.snodeController = snodeController;
+    }
+
+    @Override
+    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request)
+        throws RemotingCommandException {
+        switch (request.getCode()) {
+            case RequestCode.GET_CONSUMER_LIST_BY_GROUP:
+                return this.getConsumerListByGroup(ctx, request);
+            default:
+                break;
+        }
+        return null;
+    }
+
+    @Override
+    public boolean rejectRequest() {
+        return false;
+    }
+
+    public RemotingCommand getConsumerListByGroup(ChannelHandlerContext ctx, RemotingCommand request)
+        throws RemotingCommandException {
+        final RemotingCommand response =
+            RemotingCommand.createResponseCommand(GetConsumerListByGroupResponseHeader.class);
+        final GetConsumerListByGroupRequestHeader requestHeader =
+            (GetConsumerListByGroupRequestHeader) request
+                .decodeCommandCustomHeader(GetConsumerListByGroupRequestHeader.class);
+
+        ConsumerGroupInfo consumerGroupInfo =
+            this.snodeController.getConsumerManager().getConsumerGroupInfo(
+                requestHeader.getConsumerGroup());
+        if (consumerGroupInfo != null) {
+            List<String> clientIds = consumerGroupInfo.getAllClientId();
+            if (!clientIds.isEmpty()) {
+                GetConsumerListByGroupResponseBody body = new GetConsumerListByGroupResponseBody();
+                body.setConsumerIdList(clientIds);
+                response.setBody(body.encode());
+                response.setCode(ResponseCode.SUCCESS);
+                response.setRemark(null);
+                return response;
+            } else {
+                log.warn("getAllClientId failed, {} {}", requestHeader.getConsumerGroup(),
+                    RemotingHelper.parseChannelRemoteAddr(ctx.channel()));
+            }
+        } else {
+            log.warn("getConsumerGroupInfo failed, {} {}", requestHeader.getConsumerGroup(),
+                RemotingHelper.parseChannelRemoteAddr(ctx.channel()));
+        }
+
+        response.setCode(ResponseCode.SYSTEM_ERROR);
+        response.setRemark("no consumer for this group, " + requestHeader.getConsumerGroup());
+        return response;
+    }
+
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
new file mode 100644
index 0000000..f06af79
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
@@ -0,0 +1,92 @@
+package org.apache.rocketmq.snode.processor;/*
+ * 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.
+ */
+
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.constant.PermName;
+import org.apache.rocketmq.common.protocol.heartbeat.ConsumerData;
+import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData;
+import org.apache.rocketmq.common.protocol.heartbeat.ProducerData;
+import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.common.sysflag.TopicSysFlag;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.snode.SnodeController;
+import org.apache.rocketmq.snode.client.ClientChannelInfo;
+
+public class HearbeatProcessor implements NettyRequestProcessor {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
+    private final SnodeController snodeController;
+
+    public HearbeatProcessor(SnodeController snodeController) {
+        this.snodeController = snodeController;
+    }
+
+    @Override
+    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) {
+        HeartbeatData heartbeatData = HeartbeatData.decode(request.getBody(), HeartbeatData.class);
+        ClientChannelInfo clientChannelInfo = new ClientChannelInfo(
+            ctx.channel(),
+            heartbeatData.getClientID(),
+            request.getLanguage(),
+            request.getVersion()
+        );
+
+        if (heartbeatData.getProducerDataSet() != null) {
+            for (ProducerData producerData : heartbeatData.getProducerDataSet()) {
+                this.snodeController.getProducerManager().registerProducer(producerData.getGroupName(),
+                    clientChannelInfo);
+            }
+        }
+
+        if (heartbeatData.getConsumerDataSet() != null) {
+            for (ConsumerData data : heartbeatData.getConsumerDataSet()) {
+                SubscriptionGroupConfig subscriptionGroupConfig =
+                    this.snodeController.getSubscriptionGroupManager().findSubscriptionGroupConfig(
+                        data.getGroupName());
+                boolean isNotifyConsumerIdsChangedEnable = subscriptionGroupConfig.isNotifyConsumerIdsChangedEnable();
+                boolean changed = this.snodeController.getConsumerManager().registerConsumer(
+                    data.getGroupName(),
+                    clientChannelInfo,
+                    data.getConsumeType(),
+                    data.getMessageModel(),
+                    data.getConsumeFromWhere(),
+                    data.getSubscriptionDataSet(),
+                    isNotifyConsumerIdsChangedEnable
+                );
+
+                if (changed) {
+                    log.info("registerConsumer info changed {} {}",
+                        data.toString(),
+                        RemotingHelper.parseChannelRemoteAddr(ctx.channel())
+                    );
+                }
+            }
+        }
+        RemotingCommand response = RemotingCommand.createResponseCommand(null);
+        return response;
+    }
+
+    @Override
+    public boolean rejectRequest() {
+        return false;
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
new file mode 100644
index 0000000..a165fd4
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
@@ -0,0 +1,40 @@
+package org.apache.rocketmq.snode.processor;/*
+ * 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.
+ */
+
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.snode.service.SnodeOuterService;
+
+public class PullMessageProcessor implements NettyRequestProcessor {
+
+    private final SnodeOuterService snodeOuterService;
+
+    public PullMessageProcessor(SnodeOuterService snodeOuterService){
+        this.snodeOuterService = snodeOuterService;
+    }
+
+    @Override
+    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) {
+        return snodeOuterService.pullMessage(request);
+    }
+
+    @Override
+    public boolean rejectRequest() {
+        return false;
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
new file mode 100644
index 0000000..e419475
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
@@ -0,0 +1,44 @@
+package org.apache.rocketmq.snode.processor;/*
+ * 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.
+ */
+
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.snode.service.SnodeOuterService;
+
+public class SendMessageProcessor implements NettyRequestProcessor {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
+
+    private final SnodeOuterService snodeOuterService;
+
+    public SendMessageProcessor(final SnodeOuterService snodeOuterService) {
+        this.snodeOuterService = snodeOuterService;
+    }
+
+    @Override
+    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) {
+        return snodeOuterService.sendMessage(request);
+    }
+
+    @Override
+    public boolean rejectRequest() {
+        return false;
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/ScheduledService.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/ScheduledService.java
new file mode 100644
index 0000000..dc86688
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/ScheduledService.java
@@ -0,0 +1,21 @@
+package org.apache.rocketmq.snode.service;/*
+ * 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.
+ */
+
+public interface ScheduledService {
+    void startScheduleTask();
+    void shutdown();
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SendTransferService.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SendTransferService.java
new file mode 100644
index 0000000..6dad57c
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SendTransferService.java
@@ -0,0 +1,26 @@
+package org.apache.rocketmq.snode.service;/*
+ * 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.
+ */
+
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+
+public interface SendTransferService {
+    RemotingCommand sendMessage(RemotingCommand request);
+
+    boolean start();
+
+    void shutdown();
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SnodeOuterService.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SnodeOuterService.java
new file mode 100644
index 0000000..8764228
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SnodeOuterService.java
@@ -0,0 +1,52 @@
+package org.apache.rocketmq.snode.service;/*
+ * 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.
+ */
+
+import io.netty.channel.Channel;
+import org.apache.rocketmq.client.exception.MQBrokerException;
+import org.apache.rocketmq.common.TopicConfig;
+import org.apache.rocketmq.remoting.exception.RemotingConnectException;
+import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
+import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.snode.config.SnodeConfig;
+
+public interface SnodeOuterService {
+    void sendHearbeat(RemotingCommand remotingCommand);
+
+    RemotingCommand sendMessage(RemotingCommand remotingCommand);
+
+    RemotingCommand pullMessage(RemotingCommand remotingCommand);
+
+    void saveSubscriptionData(RemotingCommand remotingCommand);
+
+    void start();
+
+    void shutdown();
+
+    void registerSnode(SnodeConfig snodeConfig);
+
+    void updateNameServerAddressList(final String addrs);
+
+    String fetchNameServerAddr();
+
+    void updateEnodeAddr(String clusterName) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException, MQBrokerException;
+
+    void notifyConsumerIdsChanged(final Channel channel, final String consumerGroup);
+
+    RemotingCommand creatTopic(TopicConfig topicConfig);
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java
new file mode 100644
index 0000000..23d8867
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java
@@ -0,0 +1,113 @@
+package org.apache.rocketmq.snode.service.impl;/*
+ * 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.
+ */
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.protocol.RequestCode;
+import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData;
+import org.apache.rocketmq.common.protocol.heartbeat.SnodeData;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.snode.config.SnodeConfig;
+import org.apache.rocketmq.snode.service.ScheduledService;
+import org.apache.rocketmq.snode.service.SnodeOuterService;
+
+public class ScheduledServiceImpl implements ScheduledService {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
+
+    private SnodeOuterService snodeOuterService;
+    private SnodeConfig snodeConfig;
+
+    private final RemotingCommand enodeHeartbeat;
+
+    public ScheduledServiceImpl(SnodeOuterService snodeOuterService, SnodeConfig snodeConfig) {
+        this.snodeOuterService = snodeOuterService;
+        this.snodeConfig = snodeConfig;
+        enodeHeartbeat = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null);
+        HeartbeatData heartbeatData = new HeartbeatData();
+        heartbeatData.setClientID(snodeConfig.getSnodeName());
+        SnodeData snodeData = new SnodeData();
+        snodeData.setSnodeName(snodeConfig.getSnodeName());
+        heartbeatData.setSnodeData(snodeData);
+        enodeHeartbeat.setBody(heartbeatData.encode());
+    }
+
+    private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
+        @Override
+        public Thread newThread(Runnable r) {
+            return new Thread(r, "SNodeScheduledThread");
+        }
+    });
+
+    @Override
+    public void startScheduleTask() {
+
+        this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    snodeOuterService.sendHearbeat(enodeHeartbeat);
+                } catch (Exception e) {
+                    log.error("ScheduledTask updateTopicRouteInfoFromNameServer exception", e);
+                }
+            }
+        }, 1000 * 10, this.snodeConfig.getSnodeHeartBeatInterval(), TimeUnit.MILLISECONDS);
+
+        if (snodeConfig.isFetchNamesrvAddrByAddressServer()) {
+            this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        snodeOuterService.fetchNameServerAddr();
+                    } catch (Throwable e) {
+                        log.error("ScheduledTask fetchNameServerAddr exception", e);
+                    }
+                }
+            }, 1000 * 10, 1000 * 60 * 2, TimeUnit.MILLISECONDS);
+        }
+
+        this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
+            @Override
+            public void run() {
+                snodeOuterService.registerSnode(snodeConfig);
+            }
+        }, 1000 * 10, Math.max(10000, Math.min(snodeConfig.getRegisterNameServerPeriod(), 60000)), TimeUnit.MILLISECONDS);
+
+        this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    snodeOuterService.updateEnodeAddr(snodeConfig.getClusterName());
+                } catch (Exception ex) {
+                    log.warn("Update broker addr error:{}", ex);
+                }
+            }
+        }, 1000 * 10, Math.max(10000, Math.min(snodeConfig.getRegisterNameServerPeriod(), 60000)), TimeUnit.MILLISECONDS);
+
+    }
+
+    @Override
+    public void shutdown() {
+        if (this.scheduledExecutorService != null) {
+            this.scheduledExecutorService.shutdown();
+        }
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SendTransferServiceImpl.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SendTransferServiceImpl.java
new file mode 100644
index 0000000..df589da
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SendTransferServiceImpl.java
@@ -0,0 +1,45 @@
+package org.apache.rocketmq.snode.service.impl;/*
+ * 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.
+ */
+
+import org.apache.rocketmq.common.ServiceState;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.snode.service.SendTransferService;
+import org.apache.rocketmq.snode.service.SnodeOuterService;
+
+public class SendTransferServiceImpl implements SendTransferService {
+    private ServiceState serviceState = ServiceState.CREATE_JUST;
+    private SnodeOuterService snodeOuterService;
+
+    public SendTransferServiceImpl(SnodeOuterService snodeOuterService) {
+        snodeOuterService = snodeOuterService;
+    }
+
+    @Override
+    public RemotingCommand sendMessage(RemotingCommand request) {
+        return snodeOuterService.sendMessage(request);
+    }
+
+    @Override
+    public boolean start() {
+        return false;
+    }
+
+    @Override
+    public void shutdown() {
+
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SnodeOuterServiceImpl.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SnodeOuterServiceImpl.java
new file mode 100644
index 0000000..14e577e
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SnodeOuterServiceImpl.java
@@ -0,0 +1,270 @@
+package org.apache.rocketmq.snode.service.impl;/*
+ * 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.
+ */
+
+import io.netty.channel.Channel;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.apache.rocketmq.client.exception.MQBrokerException;
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.TopicConfig;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.namesrv.TopAddressing;
+import org.apache.rocketmq.common.protocol.RequestCode;
+import org.apache.rocketmq.common.protocol.ResponseCode;
+import org.apache.rocketmq.common.protocol.body.ClusterInfo;
+import org.apache.rocketmq.common.protocol.header.CreateTopicRequestHeader;
+import org.apache.rocketmq.common.protocol.header.NotifyConsumerIdsChangedRequestHeader;
+import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader;
+import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader;
+import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeaderV2;
+import org.apache.rocketmq.common.protocol.header.namesrv.RegisterSnodeRequestHeader;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingClient;
+import org.apache.rocketmq.remoting.RemotingClientFactory;
+import org.apache.rocketmq.remoting.exception.RemotingConnectException;
+import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
+import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.snode.SnodeController;
+import org.apache.rocketmq.snode.config.SnodeConfig;
+import org.apache.rocketmq.snode.service.SnodeOuterService;
+
+public class SnodeOuterServiceImpl implements SnodeOuterService {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
+    private final TopAddressing topAddressing = new TopAddressing(MixAll.getWSAddr());
+    private String nameSrvAddr = null;
+    private RemotingClient client;
+    private SnodeController snodeController;
+    private static SnodeOuterServiceImpl snodeOuterService;
+    private final ConcurrentMap<String/* Broker Name */, HashMap<Long/* brokerId */, String/* address */>> enodeTable =
+        new ConcurrentHashMap<>();
+    private final long defaultTimeoutMills = 3000L;
+
+    private SnodeOuterServiceImpl() {
+
+    }
+
+    public static SnodeOuterServiceImpl getInstance(SnodeController snodeController) {
+        if (snodeOuterService == null) {
+            synchronized (SnodeOuterServiceImpl.class) {
+                if (snodeOuterService == null) {
+                    snodeOuterService = new SnodeOuterServiceImpl(snodeController);
+                    return snodeOuterService;
+                }
+            }
+        }
+        return snodeOuterService;
+    }
+
+    private SnodeOuterServiceImpl(SnodeController snodeController) {
+        this.snodeController = snodeController;
+        this.client = RemotingClientFactory.createInstance().init(snodeController.getNettyClientConfig(), null);
+    }
+
+    @Override
+    public void start() {
+        this.client.start();
+    }
+
+    @Override
+    public void shutdown() {
+        this.client.shutdown();
+    }
+
+    @Override
+    public void sendHearbeat(RemotingCommand remotingCommand) {
+        for (Map.Entry<String, HashMap<Long, String>> entry : enodeTable.entrySet()) {
+            String enodeAddr = entry.getValue().get(MixAll.MASTER_ID);
+            if (enodeAddr != null) {
+                try {
+                    RemotingCommand response = this.client.invokeSync(enodeAddr, remotingCommand, defaultTimeoutMills);
+                } catch (Exception ex) {
+                    log.warn("Send heart beat faild:{} ,ex:{}", enodeAddr, ex);
+                }
+            }
+        }
+    }
+
+    @Override
+    public RemotingCommand sendMessage(RemotingCommand request) {
+        try {
+            SendMessageRequestHeaderV2 sendMessageRequestHeaderV2 = (SendMessageRequestHeaderV2) request.decodeCommandCustomHeader(SendMessageRequestHeaderV2.class);
+            RemotingCommand response =
+                this.client.invokeSync(sendMessageRequestHeaderV2.getN(), request, defaultTimeoutMills);
+            return response;
+        } catch (Exception ex) {
+            log.error("Send message async error:", ex);
+        }
+        return null;
+    }
+
+    @Override
+    public RemotingCommand pullMessage(RemotingCommand request) {
+        try {
+            final PullMessageRequestHeader requestHeader =
+                (PullMessageRequestHeader) request.decodeCommandCustomHeader(PullMessageRequestHeader.class);
+            RemotingCommand remotingCommand =  this.client.invokeSync(requestHeader.getEnodeAddr(), request, 20 * defaultTimeoutMills);
+            log.info("Pull message response:{}", remotingCommand);
+            log.info("Pull message response:{}", remotingCommand.getBody().length);
+            return remotingCommand;
+        } catch (Exception ex) {
+            log.error("pull message async error:", ex);
+        }
+        return null;
+    }
+
+    @Override
+    public void saveSubscriptionData(RemotingCommand remotingCommand) {
+
+    }
+
+    @Override
+    public String fetchNameServerAddr() {
+        try {
+            String addrs = this.topAddressing.fetchNSAddr();
+            if (addrs != null) {
+                if (!addrs.equals(this.nameSrvAddr)) {
+                    log.info("name server address changed, old: {} new: {}", this.nameSrvAddr, addrs);
+                    this.updateNameServerAddressList(addrs);
+                    this.nameSrvAddr = addrs;
+                    return nameSrvAddr;
+                }
+            }
+        } catch (Exception e) {
+            log.error("fetchNameServerAddr Exception", e);
+        }
+        return nameSrvAddr;
+    }
+
+    private ClusterInfo getBrokerClusterInfo(
+        final long timeoutMillis) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException, MQBrokerException {
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_BROKER_CLUSTER_INFO, null);
+        RemotingCommand response = this.client.invokeSync(null, request, timeoutMillis);
+        assert response != null;
+        switch (response.getCode()) {
+            case ResponseCode.SUCCESS: {
+                return ClusterInfo.decode(response.getBody(), ClusterInfo.class);
+            }
+            default:
+                break;
+        }
+        throw new MQBrokerException(response.getCode(), response.getRemark());
+    }
+
+    @Override
+    public void updateEnodeAddr(String clusterName) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException, MQBrokerException {
+        synchronized (this) {
+            ClusterInfo clusterInfo = getBrokerClusterInfo(defaultTimeoutMills);
+            if (clusterInfo != null) {
+                HashMap<String, Set<String>> brokerAddrs = clusterInfo.getClusterAddrTable();
+                for (Map.Entry<String, Set<String>> entry : brokerAddrs.entrySet()) {
+                    Set<String> brokerNames = entry.getValue();
+                    if (brokerNames != null) {
+                        for (String brokerName : brokerNames) {
+                            enodeTable.put(brokerName, clusterInfo.getBrokerAddrTable().get(brokerName).getBrokerAddrs());
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public void updateNameServerAddressList(final String addrs) {
+        List<String> list = new ArrayList<String>();
+        String[] addrArray = addrs.split(";");
+        for (String addr : addrArray) {
+            list.add(addr);
+        }
+        this.client.updateNameServerAddressList(list);
+    }
+
+    public void registerSnode(SnodeConfig snodeConfig) {
+        List<String> nameServerAddressList = this.client.getNameServerAddressList();
+        RemotingCommand remotingCommand = new RemotingCommand();
+        RegisterSnodeRequestHeader requestHeader = new RegisterSnodeRequestHeader();
+        requestHeader.setSnodeAddr(snodeConfig.getSnodeAddr());
+        requestHeader.setSnodeName(snodeConfig.getSnodeName());
+        requestHeader.setClusterName(snodeConfig.getClusterName());
+        remotingCommand.setCustomHeader(requestHeader);
+        remotingCommand.setCode(RequestCode.REGISTER_SNODE);
+        if (nameServerAddressList != null && nameServerAddressList.size() > 0) {
+            for (String nameServer : nameServerAddressList) {
+                try {
+                    this.client.invokeSync(nameSrvAddr, remotingCommand, 3000L);
+                } catch (Exception ex) {
+                    log.warn("Register Snode to Nameserver addr: {} error, ex:{} ", nameServer, ex);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void notifyConsumerIdsChanged(
+        final Channel channel,
+        final String consumerGroup) {
+        if (null == consumerGroup) {
+            log.error("notifyConsumerIdsChanged consumerGroup is null");
+            return;
+        }
+
+        NotifyConsumerIdsChangedRequestHeader requestHeader = new NotifyConsumerIdsChangedRequestHeader();
+        requestHeader.setConsumerGroup(consumerGroup);
+        RemotingCommand request =
+            RemotingCommand.createRequestCommand(RequestCode.NOTIFY_CONSUMER_IDS_CHANGED, requestHeader);
+
+        try {
+            this.snodeController.getSnodeServer().invokeOneway(channel, request, 10);
+        } catch (Exception e) {
+            log.error("notifyConsumerIdsChanged exception, " + consumerGroup, e.getMessage());
+        }
+    }
+
+    @Override
+    public RemotingCommand creatTopic(TopicConfig topicConfig) {
+//        CreateTopicRequestHeader requestHeader = new CreateTopicRequestHeader();
+//        requestHeader.setTopic(topicConfig.getTopicName());
+//        requestHeader.setDefaultTopic(defaultTopic);
+//        requestHeader.setReadQueueNums(topicConfig.getReadQueueNums());
+//        requestHeader.setWriteQueueNums(topicConfig.getWriteQueueNums());
+//        requestHeader.setPerm(topicConfig.getPerm());
+//        requestHeader.setTopicFilterType(topicConfig.getTopicFilterType().name());
+//        requestHeader.setTopicSysFlag(topicConfig.getTopicSysFlag());
+//        requestHeader.setOrder(topicConfig.isOrder());
+//
+//        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UPDATE_AND_CREATE_TOPIC, requestHeader);
+//
+//        RemotingCommand response = this.client.invokeSync(,
+//            request, defaultTimeoutMills);
+//        assert response != null;
+//        switch (response.getCode()) {
+//            case ResponseCode.SUCCESS: {
+//                return;
+//            }
+//            default:
+//                break;
+//        }
+        return null;
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/topic/TopicConfigManager.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/topic/TopicConfigManager.java
new file mode 100644
index 0000000..b8b6eb7
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/topic/TopicConfigManager.java
@@ -0,0 +1,19 @@
+package org.apache.rocketmq.snode.topic;/*
+ * 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.
+ */
+
+public class TopicConfigManager {
+}


[rocketmq] 02/14: Change ServiceProvide path

Posted by du...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a commit to branch snode
in repository https://gitbox.apache.org/repos/asf/rocketmq.git

commit 71696dc1bf26c7d712c46276309041e3223a493f
Author: 翊名 <du...@alibaba-inc.com>
AuthorDate: Wed Dec 12 14:28:38 2018 +0800

    Change ServiceProvide path
---
 .../apache/rocketmq/broker/BrokerController.java   |   2 +-
 .../rocketmq/broker/util/ServiceProvider.java      | 193 ---------------------
 .../rocketmq/remoting/util/ServiceProvider.java    |   8 +-
 3 files changed, 7 insertions(+), 196 deletions(-)

diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
index 3e9762a..024ce67 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
@@ -67,7 +67,6 @@ import org.apache.rocketmq.broker.transaction.TransactionalMessageService;
 import org.apache.rocketmq.broker.transaction.queue.DefaultTransactionalMessageCheckListener;
 import org.apache.rocketmq.broker.transaction.queue.TransactionalMessageBridge;
 import org.apache.rocketmq.broker.transaction.queue.TransactionalMessageServiceImpl;
-import org.apache.rocketmq.broker.util.ServiceProvider;
 import org.apache.rocketmq.common.BrokerConfig;
 import org.apache.rocketmq.common.Configuration;
 import org.apache.rocketmq.common.DataVersion;
@@ -92,6 +91,7 @@ import org.apache.rocketmq.remoting.netty.NettyServerConfig;
 import org.apache.rocketmq.remoting.netty.RequestTask;
 import org.apache.rocketmq.remoting.netty.TlsSystemConfig;
 import org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingServer;
+import org.apache.rocketmq.remoting.util.ServiceProvider;
 import org.apache.rocketmq.srvutil.FileWatchService;
 import org.apache.rocketmq.store.DefaultMessageStore;
 import org.apache.rocketmq.store.MessageArrivingListener;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/util/ServiceProvider.java b/broker/src/main/java/org/apache/rocketmq/broker/util/ServiceProvider.java
deleted file mode 100644
index 8b9b63e..0000000
--- a/broker/src/main/java/org/apache/rocketmq/broker/util/ServiceProvider.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/**
- * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.util;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.List;
-
-public class ServiceProvider {
-
-    private final static Logger LOG = LoggerFactory
-        .getLogger(ServiceProvider.class);
-    /**
-     * A reference to the classloader that loaded this class. It's more efficient to compute it once and cache it here.
-     */
-    private static ClassLoader thisClassLoader;
-
-    /**
-     * JDK1.3+ <a href= "http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service%20Provider" > 'Service Provider' specification</a>.
-     */
-    public static final String TRANSACTION_SERVICE_ID = "META-INF/service/org.apache.rocketmq.broker.transaction.TransactionalMessageService";
-
-    public static final String TRANSACTION_LISTENER_ID = "META-INF/service/org.apache.rocketmq.broker.transaction.AbstractTransactionalMessageCheckListener";
-
-    static {
-        thisClassLoader = getClassLoader(ServiceProvider.class);
-    }
-
-    /**
-     * Returns a string that uniquely identifies the specified object, including its class.
-     * <p>
-     * The returned string is of form "classname@hashcode", ie is the same as the return value of the Object.toString() method, but works even when the specified object's class has overidden the toString method.
-     *
-     * @param o may be null.
-     * @return a string of form classname@hashcode, or "null" if param o is null.
-     */
-    protected static String objectId(Object o) {
-        if (o == null) {
-            return "null";
-        } else {
-            return o.getClass().getName() + "@" + System.identityHashCode(o);
-        }
-    }
-
-    protected static ClassLoader getClassLoader(Class<?> clazz) {
-        try {
-            return clazz.getClassLoader();
-        } catch (SecurityException e) {
-            LOG.error("Unable to get classloader for class {} due to security restrictions !",
-                clazz, e.getMessage());
-            throw e;
-        }
-    }
-
-    protected static ClassLoader getContextClassLoader() {
-        ClassLoader classLoader = null;
-        try {
-            classLoader = Thread.currentThread().getContextClassLoader();
-        } catch (SecurityException ex) {
-            /**
-             * The getContextClassLoader() method throws SecurityException when the context
-             * class loader isn't an ancestor of the calling class's class
-             * loader, or if security permissions are restricted.
-             */
-        }
-        return classLoader;
-    }
-
-    protected static InputStream getResourceAsStream(ClassLoader loader, String name) {
-        if (loader != null) {
-            return loader.getResourceAsStream(name);
-        } else {
-            return ClassLoader.getSystemResourceAsStream(name);
-        }
-    }
-
-    public static <T> List<T> load(String name, Class<?> clazz) {
-        LOG.info("Looking for a resource file of name [{}] ...", name);
-        List<T> services = new ArrayList<T>();
-        try {
-            ArrayList<String> names = new ArrayList<String>();
-            final InputStream is = getResourceAsStream(getContextClassLoader(), name);
-            if (is != null) {
-                BufferedReader reader;
-                try {
-                    reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
-                } catch (java.io.UnsupportedEncodingException e) {
-                    reader = new BufferedReader(new InputStreamReader(is));
-                }
-                String serviceName = reader.readLine();
-                while (serviceName != null && !"".equals(serviceName)) {
-                    LOG.info(
-                        "Creating an instance as specified by file {} which was present in the path of the context classloader.",
-                        name);
-                    if (!names.contains(serviceName)) {
-                        names.add(serviceName);
-                    }
-
-                    services.add((T)initService(getContextClassLoader(), serviceName, clazz));
-
-                    serviceName = reader.readLine();
-                }
-                reader.close();
-            } else {
-                // is == null
-                LOG.warn("No resource file with name [{}] found.", name);
-            }
-        } catch (Exception e) {
-            LOG.error("Error occured when looking for resource file " + name, e);
-        }
-        return services;
-    }
-
-    public static <T> T loadClass(String name, Class<?> clazz) {
-        final InputStream is = getResourceAsStream(getContextClassLoader(), name);
-        if (is != null) {
-            BufferedReader reader;
-            try {
-                try {
-                    reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
-                } catch (java.io.UnsupportedEncodingException e) {
-                    reader = new BufferedReader(new InputStreamReader(is));
-                }
-                String serviceName = reader.readLine();
-                reader.close();
-                if (serviceName != null && !"".equals(serviceName)) {
-                    return initService(getContextClassLoader(), serviceName, clazz);
-                } else {
-                    LOG.warn("ServiceName is empty!");
-                    return null;
-                }
-            } catch (Exception e) {
-                LOG.warn("Error occurred when looking for resource file " + name, e);
-            }
-        }
-        return null;
-    }
-
-    protected static <T> T initService(ClassLoader classLoader, String serviceName, Class<?> clazz) {
-        Class<?> serviceClazz = null;
-        try {
-            if (classLoader != null) {
-                try {
-                    // Warning: must typecast here & allow exception to be generated/caught & recast properly
-                    serviceClazz = classLoader.loadClass(serviceName);
-                    if (clazz.isAssignableFrom(serviceClazz)) {
-                        LOG.info("Loaded class {} from classloader {}", serviceClazz.getName(),
-                            objectId(classLoader));
-                    } else {
-                        // This indicates a problem with the ClassLoader tree. An incompatible ClassLoader was used to load the implementation.
-                        LOG.error(
-                            "Class {} loaded from classloader {} does not extend {} as loaded by this classloader.",
-                            new Object[] {serviceClazz.getName(),
-                                objectId(serviceClazz.getClassLoader()), clazz.getName()});
-                    }
-                    return (T)serviceClazz.newInstance();
-                } catch (ClassNotFoundException ex) {
-                    if (classLoader == thisClassLoader) {
-                        // Nothing more to try, onwards.
-                        LOG.warn("Unable to locate any class {} via classloader", serviceName,
-                            objectId(classLoader));
-                        throw ex;
-                    }
-                    // Ignore exception, continue
-                } catch (NoClassDefFoundError e) {
-                    if (classLoader == thisClassLoader) {
-                        // Nothing more to try, onwards.
-                        LOG.warn(
-                            "Class {} cannot be loaded via classloader {}.it depends on some other class that cannot be found.",
-                            serviceClazz, objectId(classLoader));
-                        throw e;
-                    }
-                    // Ignore exception, continue
-                }
-            }
-        } catch (Exception e) {
-            LOG.error("Unable to init service.", e);
-        }
-        return (T)serviceClazz;
-    }
-}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/util/ServiceProvider.java b/remoting/src/main/java/org/apache/rocketmq/remoting/util/ServiceProvider.java
index d3a2312..24fa721 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/util/ServiceProvider.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/util/ServiceProvider.java
@@ -31,8 +31,12 @@ public class ServiceProvider {
     private static ClassLoader thisClassLoader;
 
     /**
-     * JDK1.3+ <a href= "http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service%20Provider" > 'Service Provider' specification</a>.
+     * JDK1.3+ <a href= "http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service%20Provider" > 'Service Provider'
+     * specification</a>.
      */
+    public static final String TRANSACTION_SERVICE_ID = "META-INF/service/org.apache.rocketmq.broker.transaction.TransactionalMessageService";
+
+    public static final String TRANSACTION_LISTENER_ID = "META-INF/service/org.apache.rocketmq.broker.transaction.AbstractTransactionalMessageCheckListener";
 
     static {
         thisClassLoader = getClassLoader(ServiceProvider.class);
@@ -129,7 +133,7 @@ public class ServiceProvider {
         return services;
     }
 
-    public static <T> T loadClass(String name, String path, Class<?> clazz) {
+    public static <T> T loadClass(String name, Class<?> clazz) {
         final InputStream is = getResourceAsStream(getContextClassLoader(), name);
         if (is != null) {
             BufferedReader reader;


[rocketmq] 12/14: Polish snode related RemotingChannel implementation

Posted by du...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a commit to branch snode
in repository https://gitbox.apache.org/repos/asf/rocketmq.git

commit db97b4063888e85a9d2f39246dc9f71ebde75ad0
Author: duhenglucky <du...@gmail.com>
AuthorDate: Wed Jan 2 14:51:10 2019 +0800

    Polish snode related RemotingChannel implementation
---
 .../rocketmq/remoting/RemotingClientFactory.java   | 16 ++++++++
 .../apache/rocketmq/remoting/RemotingServer.java   |  4 +-
 .../rocketmq/remoting/RemotingServerFactory.java   | 16 ++++++++
 .../netty/NettyChannelHandlerContextImpl.java      | 43 ++++++++++++++--------
 .../rocketmq/remoting/netty/NettyChannelImpl.java  | 20 +++++++++-
 .../remoting/serialize/MsgPackSerializable.java    | 21 +++++++++--
 .../remoting/serialize/SerializerFactory.java      | 16 ++++++++
 .../transport/NettyRemotingServerAbstract.java     | 16 ++++++++
 .../remoting/transport/http2/Http2ClientImpl.java  | 16 ++++++++
 .../remoting/transport/http2/Http2ServerImpl.java  | 20 ++++++++--
 .../transport/rocketmq/NettyRemotingServer.java    | 23 ------------
 .../org/apache/rocketmq/snode/SnodeStartup.java    |  6 ++-
 .../snode/processor/ConsumerManageProcessor.java   | 39 +++++++++-----------
 .../snode/processor/HearbeatProcessor.java         | 22 ++++-------
 .../snode/processor/PullMessageProcessor.java      | 12 +-----
 .../snode/processor/SendMessageProcessor.java      |  3 +-
 .../rocketmq/snode/service/EnodeService.java       |  4 +-
 .../snode/service/impl/EnodeServiceImpl.java       |  6 +--
 .../snode/service/impl/NnodeServiceImpl.java       |  2 -
 19 files changed, 197 insertions(+), 108 deletions(-)

diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClientFactory.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClientFactory.java
index 825d96b..4df2a70 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClientFactory.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClientFactory.java
@@ -1,3 +1,19 @@
+/*
+ * 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.remoting;
 
 import java.util.Map;
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java
index c773e5a..a37b538 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java
@@ -48,7 +48,5 @@ public interface RemotingServer extends RemotingService {
         throws InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException,
         RemotingSendRequestException;
 
-    RemotingServer init(ServerConfig nettyServerConfig, ChannelEventListener channelEventListener);
-
-    void sendResponse(final RemotingChannel remotingChannel, RemotingCommand remotingCommand);
+    RemotingServer init(ServerConfig serverConfig, ChannelEventListener channelEventListener);
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java
index a2cdf2b..6dbf22a 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java
@@ -1,3 +1,19 @@
+/*
+ * 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.remoting;
 
 import java.util.Map;
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelHandlerContextImpl.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelHandlerContextImpl.java
index 673c12a..a00ef05 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelHandlerContextImpl.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelHandlerContextImpl.java
@@ -1,19 +1,16 @@
-package org.apache.rocketmq.remoting.netty;/*
- * 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
+/**
+ * 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
+ * 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.
+ * 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.remoting.netty;
 
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelFutureListener;
@@ -69,8 +66,24 @@ public class NettyChannelHandlerContextImpl implements RemotingChannel {
     }
 
     @Override
-    public void reply(final RemotingCommand command) {
-        channelHandlerContext.writeAndFlush(command);
+    public void reply(final RemotingCommand response) {
+        if (response != null) {
+            response.markResponseType();
+            try {
+                this.channelHandlerContext.writeAndFlush(response).addListener(new ChannelFutureListener() {
+                    @Override
+                    public void operationComplete(ChannelFuture future) throws Exception {
+                        if (!future.isSuccess()) {
+                            log.error("processRequestWrapper response to {} failed",
+                                future.channel().remoteAddress(), future.cause());
+                        }
+                    }
+                });
+            } catch (Throwable e) {
+                log.error("processRequestWrapper process request over, but response failed", e);
+                log.error(response.toString());
+            }
+        }
     }
 
     public ChannelHandlerContext getChannelHandlerContext() {
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelImpl.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelImpl.java
index 86436c1..fe33a52 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelImpl.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelImpl.java
@@ -71,8 +71,24 @@ public class NettyChannelImpl implements RemotingChannel {
     }
 
     @Override
-    public void reply(final RemotingCommand command) {
-        channel.writeAndFlush(command);
+    public void reply(final RemotingCommand response) {
+        if (response != null) {
+            response.markResponseType();
+            try {
+                channel.writeAndFlush(response).addListener(new ChannelFutureListener() {
+                    @Override
+                    public void operationComplete(ChannelFuture future) {
+                        if (!future.isSuccess()) {
+                            log.error("ProcessRequestWrapper response to {} failed",
+                                future.channel().remoteAddress(), future.cause());
+                        }
+                    }
+                });
+            } catch (Throwable e) {
+                log.error("ProcessRequestWrapper process request over, but response failed", e);
+                log.error(response.toString());
+            }
+        }
     }
 
     public io.netty.channel.Channel getChannel() {
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/MsgPackSerializable.java b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/MsgPackSerializable.java
index 6c7ba78..4bf1896 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/MsgPackSerializable.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/MsgPackSerializable.java
@@ -1,3 +1,19 @@
+/*
+ * 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.remoting.serialize;
 
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
@@ -6,10 +22,7 @@ import org.msgpack.MessagePack;
 public class MsgPackSerializable implements Serializer {
     private final MessagePack messagePack = new MessagePack();
 
-//    public MsgPackSerializable(){
-//        messagePack.register(LanguageCode.class);
-//        messagePack.register(SerializeType.class);
-//    }
+
     @Override
     public SerializeType type() {
         return SerializeType.MSGPACK;
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/SerializerFactory.java b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/SerializerFactory.java
index e015478..1330b39 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/SerializerFactory.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/SerializerFactory.java
@@ -1,3 +1,19 @@
+/*
+ * 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.remoting.serialize;
 
 import java.util.Map;
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingServerAbstract.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingServerAbstract.java
index cec0086..5ef9783 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingServerAbstract.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingServerAbstract.java
@@ -1,3 +1,19 @@
+/*
+ * 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.remoting.transport;
 
 import io.netty.channel.Channel;
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java
index e37f354..71bee1e 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java
@@ -1,3 +1,19 @@
+/*
+ * 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.remoting.transport.http2;
 
 import io.netty.bootstrap.Bootstrap;
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java
index 8e5e4c7..649055b 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java
@@ -1,3 +1,19 @@
+/*
+ * 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.remoting.transport.http2;
 
 import io.netty.bootstrap.ServerBootstrap;
@@ -244,8 +260,4 @@ public class Http2ServerImpl extends NettyRemotingServerAbstract implements Remo
         return this.channelEventListener;
     }
 
-    @Override
-    public void sendResponse(RemotingChannel channel, RemotingCommand remotingCommand) {
-
-    }
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java
index 2bd397c..89b9820 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java
@@ -350,27 +350,4 @@ public class NettyRemotingServer extends NettyRemotingServerAbstract implements
     public void push(String addr, String sessionId, RemotingCommand remotingCommand) {
 
     }
-
-    @Override
-    public void sendResponse(RemotingChannel remotingChannel, RemotingCommand response) {
-        NettyChannelHandlerContextImpl channelHandlerContext = (NettyChannelHandlerContextImpl) remotingChannel;
-        ChannelHandlerContext ctx = channelHandlerContext.getChannelHandlerContext();
-        if (response != null) {
-            response.markResponseType();
-            try {
-                ctx.writeAndFlush(response).addListener(new ChannelFutureListener() {
-                    @Override
-                    public void operationComplete(ChannelFuture future) throws Exception {
-                        if (!future.isSuccess()) {
-                            log.error("processRequestWrapper response to {} failed",
-                                future.channel().remoteAddress(), future.cause());
-                        }
-                    }
-                });
-            } catch (Throwable e) {
-                log.error("processRequestWrapper process request over, but response failed", e);
-                log.error(response.toString());
-            }
-        }
-    }
 }
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java b/snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java
index 8ccb34e..f745ede 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java
@@ -102,6 +102,10 @@ public class SnodeStartup {
                 in.close();
             }
         }
+        if (null == snodeConfig.getRocketmqHome()) {
+            System.out.printf("Please set the %s variable in your environment to match the location of the RocketMQ installation", MixAll.ROCKETMQ_HOME_ENV);
+            System.exit(-2);
+        }
 
         LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
         JoranConfigurator configurator = new JoranConfigurator();
@@ -135,7 +139,7 @@ public class SnodeStartup {
     }
 
     private static Options buildCommandlineOptions(final Options options) {
-        Option opt = new Option("c", "configFile", true, "Broker config properties file");
+        Option opt = new Option("c", "configFile", true, "SNode config properties file");
         opt.setRequired(false);
         options.addOption(opt);
         return options;
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java b/snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
index bc58a5c..edb4b58 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
@@ -16,7 +16,6 @@
  */
 package org.apache.rocketmq.snode.processor;
 
-import io.netty.channel.ChannelHandlerContext;
 import java.util.List;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.common.protocol.RequestCode;
@@ -34,13 +33,12 @@ import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetResponseHe
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.RemotingChannel;
+import org.apache.rocketmq.remoting.RequestProcessor;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
-import org.apache.rocketmq.remoting.RequestProcessor;
-import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.snode.SnodeController;
 import org.apache.rocketmq.snode.client.ConsumerGroupInfo;
@@ -57,23 +55,20 @@ public class ConsumerManageProcessor implements RequestProcessor {
     @Override
     public RemotingCommand processRequest(RemotingChannel remotingChannel,
         RemotingCommand request) throws InterruptedException, RemotingTimeoutException,
-        RemotingSendRequestException, RemotingConnectException, RemotingCommandException  {
-        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl)remotingChannel;
-        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
-
+        RemotingSendRequestException, RemotingConnectException, RemotingCommandException {
         switch (request.getCode()) {
             case RequestCode.GET_CONSUMER_LIST_BY_GROUP:
-                return this.getConsumerListByGroup(ctx, request);
+                return this.getConsumerListByGroup(remotingChannel, request);
             case RequestCode.UPDATE_CONSUMER_OFFSET:
-                return this.updateConsumerOffset(ctx, request);
+                return this.updateConsumerOffset(remotingChannel, request);
             case RequestCode.QUERY_CONSUMER_OFFSET:
-                return this.queryConsumerOffset(ctx, request);
+                return this.queryConsumerOffset(remotingChannel, request);
             case RequestCode.SEARCH_OFFSET_BY_TIMESTAMP:
-                return searchOffsetByTimestamp(ctx, request);
+                return searchOffsetByTimestamp(remotingChannel, request);
             case RequestCode.GET_MAX_OFFSET:
-                return getMaxOffset(ctx, request);
+                return getMaxOffset(remotingChannel, request);
             case RequestCode.GET_MIN_OFFSET:
-                return getMinOffset(ctx, request);
+                return getMinOffset(remotingChannel, request);
             default:
                 break;
         }
@@ -85,7 +80,7 @@ public class ConsumerManageProcessor implements RequestProcessor {
         return false;
     }
 
-    public RemotingCommand searchOffsetByTimestamp(ChannelHandlerContext ctx,
+    public RemotingCommand searchOffsetByTimestamp(RemotingChannel remotingChannel,
         RemotingCommand request) throws RemotingCommandException {
         final SearchOffsetRequestHeader requestHeader =
             (SearchOffsetRequestHeader) request
@@ -98,7 +93,7 @@ public class ConsumerManageProcessor implements RequestProcessor {
         return null;
     }
 
-    public RemotingCommand getMinOffset(ChannelHandlerContext ctx,
+    public RemotingCommand getMinOffset(RemotingChannel remotingChannel,
         RemotingCommand request) throws RemotingCommandException {
         final GetMinOffsetRequestHeader requestHeader =
             (GetMinOffsetRequestHeader) request
@@ -111,7 +106,7 @@ public class ConsumerManageProcessor implements RequestProcessor {
         return null;
     }
 
-    public RemotingCommand getMaxOffset(ChannelHandlerContext ctx,
+    public RemotingCommand getMaxOffset(RemotingChannel remotingChannel,
         RemotingCommand request) throws RemotingCommandException {
         final GetMaxOffsetRequestHeader requestHeader =
             (GetMaxOffsetRequestHeader) request
@@ -124,7 +119,7 @@ public class ConsumerManageProcessor implements RequestProcessor {
         return null;
     }
 
-    public RemotingCommand getConsumerListByGroup(ChannelHandlerContext ctx, RemotingCommand request)
+    public RemotingCommand getConsumerListByGroup(RemotingChannel remotingChannel, RemotingCommand request)
         throws RemotingCommandException {
         final RemotingCommand response =
             RemotingCommand.createResponseCommand(GetConsumerListByGroupResponseHeader.class);
@@ -146,11 +141,11 @@ public class ConsumerManageProcessor implements RequestProcessor {
                 return response;
             } else {
                 log.warn("GetAllClientId failed, {} {}", requestHeader.getConsumerGroup(),
-                    RemotingHelper.parseChannelRemoteAddr(ctx.channel()));
+                    RemotingHelper.parseChannelRemoteAddr(remotingChannel.remoteAddress()));
             }
         } else {
             log.warn("GetConsumerGroupInfo failed, {} {}", requestHeader.getConsumerGroup(),
-                RemotingHelper.parseChannelRemoteAddr(ctx.channel()));
+                RemotingHelper.parseChannelRemoteAddr(remotingChannel.remoteAddress()));
         }
 
         response.setCode(ResponseCode.SYSTEM_ERROR);
@@ -158,21 +153,21 @@ public class ConsumerManageProcessor implements RequestProcessor {
         return response;
     }
 
-    private RemotingCommand updateConsumerOffset(ChannelHandlerContext ctx, RemotingCommand request)
+    private RemotingCommand updateConsumerOffset(RemotingChannel remotingChannel, RemotingCommand request)
         throws RemotingCommandException {
         final RemotingCommand response =
             RemotingCommand.createResponseCommand(UpdateConsumerOffsetResponseHeader.class);
         final UpdateConsumerOffsetRequestHeader requestHeader =
             (UpdateConsumerOffsetRequestHeader) request
                 .decodeCommandCustomHeader(UpdateConsumerOffsetRequestHeader.class);
-        this.snodeController.getConsumerOffsetManager().commitOffset(requestHeader.getEnodeName(), RemotingHelper.parseChannelRemoteAddr(ctx.channel()), requestHeader.getConsumerGroup(),
+        this.snodeController.getConsumerOffsetManager().commitOffset(requestHeader.getEnodeName(), RemotingHelper.parseChannelRemoteAddr(remotingChannel.remoteAddress()), requestHeader.getConsumerGroup(),
             requestHeader.getTopic(), requestHeader.getQueueId(), requestHeader.getCommitOffset());
         response.setCode(ResponseCode.SUCCESS);
         response.setRemark(null);
         return response;
     }
 
-    private RemotingCommand queryConsumerOffset(ChannelHandlerContext ctx, RemotingCommand request)
+    private RemotingCommand queryConsumerOffset(RemotingChannel remotingChannel, RemotingCommand request)
         throws InterruptedException, RemotingTimeoutException,
         RemotingSendRequestException, RemotingConnectException, RemotingCommandException {
         final RemotingCommand response =
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java b/snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
index c69ba5d..829ad0e 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
@@ -16,7 +16,6 @@
  */
 package org.apache.rocketmq.snode.processor;
 
-import io.netty.channel.ChannelHandlerContext;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.common.protocol.RequestCode;
 import org.apache.rocketmq.common.protocol.ResponseCode;
@@ -29,11 +28,8 @@ import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.RemotingChannel;
-import org.apache.rocketmq.remoting.common.RemotingHelper;
-import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
-import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
-import org.apache.rocketmq.remoting.netty.NettyChannelImpl;
 import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.snode.SnodeController;
 import org.apache.rocketmq.snode.client.ClientChannelInfo;
@@ -49,23 +45,21 @@ public class HearbeatProcessor implements RequestProcessor {
     @Override
     public RemotingCommand processRequest(RemotingChannel remotingChannel,
         RemotingCommand request) throws Exception {
-        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl)remotingChannel;
-        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
         switch (request.getCode()) {
             case RequestCode.HEART_BEAT:
-                return heartbeat(ctx, request);
+                return heartbeat(remotingChannel, request);
             case RequestCode.UNREGISTER_CLIENT:
-                return unregister(ctx, request);
+                return unregister(remotingChannel, request);
             default:
                 break;
         }
         return null;
     }
 
-    private RemotingCommand heartbeat(ChannelHandlerContext ctx, RemotingCommand request) {
+    private RemotingCommand heartbeat(RemotingChannel remotingChannel, RemotingCommand request) {
         HeartbeatData heartbeatData = HeartbeatData.decode(request.getBody(), HeartbeatData.class);
         ClientChannelInfo clientChannelInfo = new ClientChannelInfo(
-            new NettyChannelImpl(ctx.channel()),
+            remotingChannel,
             heartbeatData.getClientID(),
             request.getLanguage(),
             request.getVersion()
@@ -100,7 +94,7 @@ public class HearbeatProcessor implements RequestProcessor {
                 if (changed) {
                     log.info("registerConsumer info changed {} {}",
                         data.toString(),
-                        RemotingHelper.parseChannelRemoteAddr(ctx.channel())
+                        RemotingHelper.parseChannelRemoteAddr(remotingChannel.remoteAddress())
                     );
                 }
             }
@@ -111,14 +105,14 @@ public class HearbeatProcessor implements RequestProcessor {
         return response;
     }
 
-    private RemotingCommand unregister(ChannelHandlerContext ctx, RemotingCommand request) throws Exception {
+    private RemotingCommand unregister(RemotingChannel remotingChannel, RemotingCommand request) throws Exception {
         final RemotingCommand response =
             RemotingCommand.createResponseCommand(UnregisterClientResponseHeader.class);
         final UnregisterClientRequestHeader requestHeader =
             (UnregisterClientRequestHeader) request.decodeCommandCustomHeader(UnregisterClientRequestHeader.class);
 
         ClientChannelInfo clientChannelInfo = new ClientChannelInfo(
-            new NettyChannelImpl(ctx.channel()),
+            remotingChannel,
             requestHeader.getClientID(),
             request.getLanguage(),
             request.getVersion());
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java b/snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
index 951d175..645d7fc 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
@@ -15,7 +15,6 @@ package org.apache.rocketmq.snode.processor;/*
  * limitations under the License.
  */
 
-import io.netty.channel.ChannelHandlerContext;
 import java.util.concurrent.CompletableFuture;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.common.help.FAQUrl;
@@ -30,10 +29,6 @@ import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.RequestProcessor;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.exception.RemotingConnectException;
-import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
-import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
-import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.snode.SnodeController;
 import org.apache.rocketmq.snode.client.ConsumerGroupInfo;
@@ -50,9 +45,6 @@ public class PullMessageProcessor implements RequestProcessor {
     @Override
     public RemotingCommand processRequest(RemotingChannel remotingChannel,
         RemotingCommand request) throws RemotingCommandException {
-        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl) remotingChannel;
-        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
-
         RemotingCommand response = RemotingCommand.createResponseCommand(PullMessageResponseHeader.class);
 
         final PullMessageRequestHeader requestHeader =
@@ -97,10 +89,10 @@ public class PullMessageProcessor implements RequestProcessor {
             return response;
         }
 
-        CompletableFuture<RemotingCommand> responseFuture = snodeController.getEnodeService().pullMessage(ctx, request);
+        CompletableFuture<RemotingCommand> responseFuture = snodeController.getEnodeService().pullMessage(request);
         responseFuture.whenComplete((data, ex) -> {
             if (ex == null) {
-                this.snodeController.getSnodeServer().sendResponse(remotingChannel, data);
+                remotingChannel.reply(data);
             } else {
                 log.error("Pull message error: {}", ex);
             }
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java b/snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
index 6641b2a..bd18339 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
@@ -15,7 +15,6 @@ package org.apache.rocketmq.snode.processor;/*
  * limitations under the License.
  */
 
-import io.netty.channel.ChannelHandlerContext;
 import java.util.concurrent.CompletableFuture;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.InternalLogger;
@@ -39,7 +38,7 @@ public class SendMessageProcessor implements RequestProcessor {
         CompletableFuture<RemotingCommand> responseFuture = snodeController.getEnodeService().sendMessage(request);
         responseFuture.whenComplete((data, ex) -> {
             if (ex == null) {
-                snodeController.getSnodeServer().sendResponse(remotingChannel, data);
+                remotingChannel.reply(data);
             } else {
                 log.error("Send Message error: {}", ex);
             }
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java b/snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java
index add1cde..4c3f894 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java
@@ -15,7 +15,6 @@ package org.apache.rocketmq.snode.service;/*
  * limitations under the License.
  */
 
-import io.netty.channel.ChannelHandlerContext;
 import java.util.concurrent.CompletableFuture;
 import org.apache.rocketmq.client.exception.MQBrokerException;
 import org.apache.rocketmq.common.TopicConfig;
@@ -32,8 +31,7 @@ public interface EnodeService {
 
     CompletableFuture<RemotingCommand> sendMessage(final RemotingCommand request);
 
-    CompletableFuture<RemotingCommand> pullMessage(final ChannelHandlerContext context,
-        final RemotingCommand remotingCommand);
+    CompletableFuture<RemotingCommand> pullMessage(final RemotingCommand request);
 
     void notifyConsumerIdsChanged(final RemotingChannel channel, final String consumerGroup);
 
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
index cd4a519..20a4d2f 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
@@ -47,6 +47,7 @@ import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
 import org.apache.rocketmq.remoting.netty.ResponseFuture;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
@@ -81,8 +82,7 @@ public class EnodeServiceImpl implements EnodeService {
     }
 
     @Override
-    public CompletableFuture<RemotingCommand> pullMessage(final ChannelHandlerContext context,
-        RemotingCommand request) {
+    public CompletableFuture<RemotingCommand> pullMessage(RemotingCommand request) {
 
         CompletableFuture<RemotingCommand> future = new CompletableFuture<>();
         try {
@@ -106,7 +106,7 @@ public class EnodeServiceImpl implements EnodeService {
                 }
             });
         } catch (Exception ex) {
-            log.error("pull message async error:", ex);
+            log.error("Pull message async error:", ex);
             future.completeExceptionally(ex);
         }
         return future;
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java
index fe28571..b272c31 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java
@@ -19,7 +19,6 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import org.apache.rocketmq.client.ClientConfig;
 import org.apache.rocketmq.client.exception.MQClientException;
 import org.apache.rocketmq.common.MixAll;
 import org.apache.rocketmq.common.constant.LoggerName;
@@ -39,7 +38,6 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.snode.SnodeController;
 import org.apache.rocketmq.snode.config.SnodeConfig;
 import org.apache.rocketmq.snode.constant.SnodeConstant;
-import org.apache.rocketmq.snode.exception.SnodeException;
 import org.apache.rocketmq.snode.service.NnodeService;
 
 public class NnodeServiceImpl implements NnodeService {


[rocketmq] 09/14: Remove netty dependency in RemotingClient and Remoting Server

Posted by du...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a commit to branch snode
in repository https://gitbox.apache.org/repos/asf/rocketmq.git

commit f84239ef03d057a6f309187c21c3097d3ccb504e
Author: duhenglucky <du...@gmail.com>
AuthorDate: Wed Jan 2 01:52:05 2019 +0800

    Remove netty dependency in RemotingClient and Remoting Server
---
 .../apache/rocketmq/broker/BrokerController.java   | 20 ++---
 .../org/apache/rocketmq/broker/BrokerStartup.java  |  8 +-
 .../rocketmq/broker/client/ClientChannelInfo.java  |  9 ++-
 .../broker/client/ClientHousekeepingService.java   | 22 +++--
 .../rocketmq/broker/client/ConsumerGroupInfo.java  | 19 ++---
 .../rocketmq/broker/client/ConsumerManager.java    | 12 +--
 .../client/DefaultConsumerIdsChangeListener.java   |  5 +-
 .../rocketmq/broker/client/ProducerManager.java    | 42 +++++-----
 .../rocketmq/broker/client/net/Broker2Client.java  | 19 ++---
 .../apache/rocketmq/broker/out/BrokerOuterAPI.java |  6 +-
 .../processor/AbstractSendMessageProcessor.java    |  4 +-
 .../broker/processor/AdminBrokerProcessor.java     | 21 ++---
 .../broker/processor/ClientManageProcessor.java    | 18 +++--
 .../broker/processor/ConsumerManageProcessor.java  | 13 ++-
 .../broker/processor/EndTransactionProcessor.java  | 15 ++--
 .../broker/processor/ForwardRequestProcessor.java  | 10 ++-
 .../broker/processor/PullMessageProcessor.java     | 11 ++-
 .../broker/processor/QueryMessageProcessor.java    | 12 ++-
 .../broker/processor/SendMessageProcessor.java     | 11 ++-
 .../processor/SnodePullMessageProcessor.java       | 11 ++-
 .../AbstractTransactionalMessageCheckListener.java |  3 +-
 .../rocketmq/broker/BrokerControllerTest.java      |  8 +-
 .../apache/rocketmq/broker/BrokerOuterAPITest.java |  8 +-
 .../broker/client/ProducerManagerTest.java         | 11 +--
 .../processor/ClientManageProcessorTest.java       | 25 +++---
 .../processor/EndTransactionProcessorTest.java     | 22 +++--
 .../broker/processor/PullMessageProcessorTest.java | 39 ++++++---
 .../broker/processor/SendMessageProcessorTest.java | 21 +++--
 ...faultTransactionalMessageCheckListenerTest.java |  8 +-
 .../queue/TransactionalMessageBridgeTest.java      |  8 +-
 .../queue/TransactionalMessageServiceImplTest.java |  8 +-
 .../NettyClientConfig.java => ClientConfig.java}   |  0
 .../apache/rocketmq/remoting/RemotingChannel.java  | 78 ++++++++++++++++++
 ...RequestProcessor.java => RequestProcessor.java} |  0
 .../NettyServerConfig.java => ServerConfig.java}   |  0
 ...or.java => NettyChannelHandlerContextImpl.java} | 15 +---
 .../rocketmq/remoting/netty/NettyChannelImpl.java  | 94 ++++++++++++++++++++++
 37 files changed, 445 insertions(+), 191 deletions(-)

diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
index eff8fd4..61a5008 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
@@ -86,9 +86,9 @@ import org.apache.rocketmq.remoting.RPCHook;
 import org.apache.rocketmq.remoting.RemotingServer;
 import org.apache.rocketmq.remoting.RemotingServerFactory;
 import org.apache.rocketmq.remoting.common.TlsMode;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.ClientConfig;
+import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.remoting.netty.RequestTask;
 import org.apache.rocketmq.remoting.netty.TlsSystemConfig;
 import org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingServer;
@@ -107,8 +107,8 @@ public class BrokerController {
     private static final InternalLogger LOG_PROTECTION = InternalLoggerFactory.getLogger(LoggerName.PROTECTION_LOGGER_NAME);
     private static final InternalLogger LOG_WATER_MARK = InternalLoggerFactory.getLogger(LoggerName.WATER_MARK_LOGGER_NAME);
     private final BrokerConfig brokerConfig;
-    private final NettyServerConfig nettyServerConfig;
-    private final NettyClientConfig nettyClientConfig;
+    private final ServerConfig nettyServerConfig;
+    private final ClientConfig nettyClientConfig;
     private final MessageStoreConfig messageStoreConfig;
     private final ConsumerOffsetManager consumerOffsetManager;
     private final ConsumerManager consumerManager;
@@ -162,8 +162,8 @@ public class BrokerController {
 
     public BrokerController(
         final BrokerConfig brokerConfig,
-        final NettyServerConfig nettyServerConfig,
-        final NettyClientConfig nettyClientConfig,
+        final ServerConfig nettyServerConfig,
+        final ClientConfig nettyClientConfig,
         final MessageStoreConfig messageStoreConfig
     ) {
         this.brokerConfig = brokerConfig;
@@ -210,7 +210,7 @@ public class BrokerController {
         return brokerConfig;
     }
 
-    public NettyServerConfig getNettyServerConfig() {
+    public ServerConfig getNettyServerConfig() {
         return nettyServerConfig;
     }
 
@@ -251,7 +251,7 @@ public class BrokerController {
             this.remotingServer = RemotingServerFactory.createInstance();
             this.remotingServer.init(this.nettyServerConfig, this.clientHousekeepingService);
 //            this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.clientHousekeepingService);
-            NettyServerConfig fastConfig = (NettyServerConfig) this.nettyServerConfig.clone();
+            ServerConfig fastConfig = (ServerConfig) this.nettyServerConfig.clone();
             fastConfig.setListenPort(nettyServerConfig.getListenPort() - 2);
 //            this.fastRemotingServer = new NettyRemotingServer(fastConfig, this.clientHousekeepingService);
             this.fastRemotingServer = RemotingServerFactory.createInstance();
@@ -520,7 +520,7 @@ public class BrokerController {
         /**
          * QueryMessageProcessor
          */
-        NettyRequestProcessor queryProcessor = new QueryMessageProcessor(this);
+        RequestProcessor queryProcessor = new QueryMessageProcessor(this);
         this.remotingServer.registerProcessor(RequestCode.QUERY_MESSAGE, queryProcessor, this.queryMessageExecutor);
         this.remotingServer.registerProcessor(RequestCode.VIEW_MESSAGE_BY_ID, queryProcessor, this.queryMessageExecutor);
 
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java
index c623d52..17d2f0e 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java
@@ -30,8 +30,8 @@ import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.common.RemotingUtil;
 import org.apache.rocketmq.remoting.common.TlsMode;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.ClientConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.remoting.netty.NettySystemConfig;
 import org.apache.rocketmq.remoting.netty.TlsSystemConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
@@ -107,8 +107,8 @@ public class BrokerStartup {
             }
 
             final BrokerConfig brokerConfig = new BrokerConfig();
-            final NettyServerConfig nettyServerConfig = new NettyServerConfig();
-            final NettyClientConfig nettyClientConfig = new NettyClientConfig();
+            final ServerConfig nettyServerConfig = new ServerConfig();
+            final ClientConfig nettyClientConfig = new ClientConfig();
 
             nettyClientConfig.setUseTLS(Boolean.parseBoolean(System.getProperty(TLS_ENABLE,
                 String.valueOf(TlsSystemConfig.tlsMode == TlsMode.ENFORCING))));
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ClientChannelInfo.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ClientChannelInfo.java
index 7c5e25b..192a6f8 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/ClientChannelInfo.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ClientChannelInfo.java
@@ -17,27 +17,28 @@
 package org.apache.rocketmq.broker.client;
 
 import io.netty.channel.Channel;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.serialize.LanguageCode;
 
 public class ClientChannelInfo {
-    private final Channel channel;
+    private final RemotingChannel channel;
     private final String clientId;
     private final LanguageCode language;
     private final int version;
     private volatile long lastUpdateTimestamp = System.currentTimeMillis();
 
-    public ClientChannelInfo(Channel channel) {
+    public ClientChannelInfo(RemotingChannel channel) {
         this(channel, null, null, 0);
     }
 
-    public ClientChannelInfo(Channel channel, String clientId, LanguageCode language, int version) {
+    public ClientChannelInfo(RemotingChannel channel, String clientId, LanguageCode language, int version) {
         this.channel = channel;
         this.clientId = clientId;
         this.language = language;
         this.version = version;
     }
 
-    public Channel getChannel() {
+    public RemotingChannel getChannel() {
         return channel;
     }
 
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ClientHousekeepingService.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ClientHousekeepingService.java
index 7e023dd..5a39e4f 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/ClientHousekeepingService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ClientHousekeepingService.java
@@ -26,6 +26,9 @@ import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.ChannelEventListener;
+import org.apache.rocketmq.remoting.RemotingChannel;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.netty.NettyChannelImpl;
 
 public class ClientHousekeepingService implements ChannelEventListener {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
@@ -62,26 +65,35 @@ public class ClientHousekeepingService implements ChannelEventListener {
     }
 
     @Override
-    public void onChannelConnect(String remoteAddr, Channel channel) {
-
+    public void onChannelConnect(String remoteAddr, RemotingChannel channel) {
+        log.info("Remoting channel connected: {}", RemotingHelper.parseChannelRemoteAddr(channel.remoteAddress()));
     }
 
     @Override
-    public void onChannelClose(String remoteAddr, Channel channel) {
+    public void onChannelClose(String remoteAddr, RemotingChannel remotingChannel) {
+        log.info("Remoting channel closed: {}", RemotingHelper.parseChannelRemoteAddr(remotingChannel.remoteAddress()));
+        NettyChannelImpl nettyChannel = (NettyChannelImpl) remotingChannel;
+        Channel channel = nettyChannel.getChannel();
         this.brokerController.getProducerManager().doChannelCloseEvent(remoteAddr, channel);
         this.brokerController.getConsumerManager().doChannelCloseEvent(remoteAddr, channel);
         this.brokerController.getFilterServerManager().doChannelCloseEvent(remoteAddr, channel);
     }
 
     @Override
-    public void onChannelException(String remoteAddr, Channel channel) {
+    public void onChannelException(String remoteAddr, RemotingChannel remotingChannel) {
+        log.info("Remoting channel exception: {}", RemotingHelper.parseChannelRemoteAddr(remotingChannel.remoteAddress()));
+        NettyChannelImpl nettyChannel = (NettyChannelImpl) remotingChannel;
+        Channel channel = nettyChannel.getChannel();
         this.brokerController.getProducerManager().doChannelCloseEvent(remoteAddr, channel);
         this.brokerController.getConsumerManager().doChannelCloseEvent(remoteAddr, channel);
         this.brokerController.getFilterServerManager().doChannelCloseEvent(remoteAddr, channel);
     }
 
     @Override
-    public void onChannelIdle(String remoteAddr, Channel channel) {
+    public void onChannelIdle(String remoteAddr, RemotingChannel remotingChannel) {
+        log.info("Remoting channel idle: {}", RemotingHelper.parseChannelRemoteAddr(remotingChannel.remoteAddress()));
+        NettyChannelImpl nettyChannel = (NettyChannelImpl) remotingChannel;
+        Channel channel = nettyChannel.getChannel();
         this.brokerController.getProducerManager().doChannelCloseEvent(remoteAddr, channel);
         this.brokerController.getConsumerManager().doChannelCloseEvent(remoteAddr, channel);
         this.brokerController.getFilterServerManager().doChannelCloseEvent(remoteAddr, channel);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupInfo.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupInfo.java
index c90d494..407b0b6 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupInfo.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupInfo.java
@@ -31,14 +31,15 @@ import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
 import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
 import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.remoting.RemotingChannel;
 
 public class ConsumerGroupInfo {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
     private final String groupName;
     private final ConcurrentMap<String/* Topic */, SubscriptionData> subscriptionTable =
         new ConcurrentHashMap<String, SubscriptionData>();
-    private final ConcurrentMap<Channel, ClientChannelInfo> channelInfoTable =
-        new ConcurrentHashMap<Channel, ClientChannelInfo>(16);
+    private final ConcurrentMap<RemotingChannel, ClientChannelInfo> channelInfoTable =
+        new ConcurrentHashMap<>(16);
     private volatile ConsumeType consumeType;
     private volatile MessageModel messageModel;
     private volatile ConsumeFromWhere consumeFromWhere;
@@ -53,9 +54,9 @@ public class ConsumerGroupInfo {
     }
 
     public ClientChannelInfo findChannel(final String clientId) {
-        Iterator<Entry<Channel, ClientChannelInfo>> it = this.channelInfoTable.entrySet().iterator();
+        Iterator<Entry<RemotingChannel, ClientChannelInfo>> it = this.channelInfoTable.entrySet().iterator();
         while (it.hasNext()) {
-            Entry<Channel, ClientChannelInfo> next = it.next();
+            Entry<RemotingChannel, ClientChannelInfo> next = it.next();
             if (next.getValue().getClientId().equals(clientId)) {
                 return next.getValue();
             }
@@ -68,12 +69,12 @@ public class ConsumerGroupInfo {
         return subscriptionTable;
     }
 
-    public ConcurrentMap<Channel, ClientChannelInfo> getChannelInfoTable() {
+    public ConcurrentMap<RemotingChannel, ClientChannelInfo> getChannelInfoTable() {
         return channelInfoTable;
     }
 
-    public List<Channel> getAllChannel() {
-        List<Channel> result = new ArrayList<>();
+    public List<RemotingChannel> getAllChannel() {
+        List<RemotingChannel> result = new ArrayList<>();
 
         result.addAll(this.channelInfoTable.keySet());
 
@@ -83,10 +84,10 @@ public class ConsumerGroupInfo {
     public List<String> getAllClientId() {
         List<String> result = new ArrayList<>();
 
-        Iterator<Entry<Channel, ClientChannelInfo>> it = this.channelInfoTable.entrySet().iterator();
+        Iterator<Entry<RemotingChannel, ClientChannelInfo>> it = this.channelInfoTable.entrySet().iterator();
 
         while (it.hasNext()) {
-            Entry<Channel, ClientChannelInfo> entry = it.next();
+            Entry<RemotingChannel, ClientChannelInfo> entry = it.next();
             ClientChannelInfo clientChannelInfo = entry.getValue();
             result.add(clientChannelInfo.getClientId());
         }
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java
index cb60655..f621c1d 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java
@@ -30,6 +30,7 @@ import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
 import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
 import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.common.RemotingUtil;
 
@@ -147,19 +148,20 @@ public class ConsumerManager {
             Entry<String, ConsumerGroupInfo> next = it.next();
             String group = next.getKey();
             ConsumerGroupInfo consumerGroupInfo = next.getValue();
-            ConcurrentMap<Channel, ClientChannelInfo> channelInfoTable =
+            ConcurrentMap<RemotingChannel, ClientChannelInfo> channelInfoTable =
                 consumerGroupInfo.getChannelInfoTable();
 
-            Iterator<Entry<Channel, ClientChannelInfo>> itChannel = channelInfoTable.entrySet().iterator();
+            Iterator<Entry<RemotingChannel, ClientChannelInfo>> itChannel = channelInfoTable.entrySet().iterator();
             while (itChannel.hasNext()) {
-                Entry<Channel, ClientChannelInfo> nextChannel = itChannel.next();
+                Entry<RemotingChannel, ClientChannelInfo> nextChannel = itChannel.next();
                 ClientChannelInfo clientChannelInfo = nextChannel.getValue();
                 long diff = System.currentTimeMillis() - clientChannelInfo.getLastUpdateTimestamp();
                 if (diff > CHANNEL_EXPIRED_TIMEOUT) {
                     log.warn(
                         "SCAN: remove expired channel from ConsumerManager consumerTable. channel={}, consumerGroup={}",
-                        RemotingHelper.parseChannelRemoteAddr(clientChannelInfo.getChannel()), group);
-                    RemotingUtil.closeChannel(clientChannelInfo.getChannel());
+                        RemotingHelper.parseChannelRemoteAddr(clientChannelInfo.getChannel().remoteAddress()), group);
+
+                    clientChannelInfo.getChannel().close();
                     itChannel.remove();
                 }
             }
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/DefaultConsumerIdsChangeListener.java b/broker/src/main/java/org/apache/rocketmq/broker/client/DefaultConsumerIdsChangeListener.java
index d716a33..e2174dc 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/DefaultConsumerIdsChangeListener.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/DefaultConsumerIdsChangeListener.java
@@ -23,6 +23,7 @@ import java.util.List;
 
 import org.apache.rocketmq.broker.BrokerController;
 import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.remoting.RemotingChannel;
 
 public class DefaultConsumerIdsChangeListener implements ConsumerIdsChangeListener {
     private final BrokerController brokerController;
@@ -41,9 +42,9 @@ public class DefaultConsumerIdsChangeListener implements ConsumerIdsChangeListen
                 if (args == null || args.length < 1) {
                     return;
                 }
-                List<Channel> channels = (List<Channel>) args[0];
+                List<RemotingChannel> channels = (List<RemotingChannel>) args[0];
                 if (channels != null && brokerController.getBrokerConfig().isNotifyConsumerIdsChangedEnable()) {
-                    for (Channel chl : channels) {
+                    for (RemotingChannel chl : channels) {
                         this.brokerController.getBroker2Client().notifyConsumerIdsChanged(chl, group);
                     }
                 }
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerManager.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerManager.java
index 61ceae5..1c9a557 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ProducerManager.java
@@ -32,6 +32,7 @@ import org.apache.rocketmq.broker.util.PositiveAtomicCounter;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.common.RemotingUtil;
 
@@ -41,15 +42,16 @@ public class ProducerManager {
     private static final long CHANNEL_EXPIRED_TIMEOUT = 1000 * 120;
     private static final int GET_AVALIABLE_CHANNEL_RETRY_COUNT = 3;
     private final Lock groupChannelLock = new ReentrantLock();
-    private final HashMap<String /* group name */, HashMap<Channel, ClientChannelInfo>> groupChannelTable =
-        new HashMap<String, HashMap<Channel, ClientChannelInfo>>();
+    private final HashMap<String /* group name */, HashMap<RemotingChannel, ClientChannelInfo>> groupChannelTable =
+        new HashMap<>();
     private PositiveAtomicCounter positiveAtomicCounter = new PositiveAtomicCounter();
+
     public ProducerManager() {
     }
 
-    public HashMap<String, HashMap<Channel, ClientChannelInfo>> getGroupChannelTable() {
-        HashMap<String /* group name */, HashMap<Channel, ClientChannelInfo>> newGroupChannelTable =
-            new HashMap<String, HashMap<Channel, ClientChannelInfo>>();
+    public HashMap<String, HashMap<RemotingChannel, ClientChannelInfo>> getGroupChannelTable() {
+        HashMap<String /* group name */, HashMap<RemotingChannel, ClientChannelInfo>> newGroupChannelTable =
+            new HashMap<>();
         try {
             if (this.groupChannelLock.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
                 try {
@@ -68,14 +70,14 @@ public class ProducerManager {
         try {
             if (this.groupChannelLock.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
                 try {
-                    for (final Map.Entry<String, HashMap<Channel, ClientChannelInfo>> entry : this.groupChannelTable
+                    for (final Map.Entry<String, HashMap<RemotingChannel, ClientChannelInfo>> entry : this.groupChannelTable
                         .entrySet()) {
                         final String group = entry.getKey();
-                        final HashMap<Channel, ClientChannelInfo> chlMap = entry.getValue();
+                        final HashMap<RemotingChannel, ClientChannelInfo> chlMap = entry.getValue();
 
-                        Iterator<Entry<Channel, ClientChannelInfo>> it = chlMap.entrySet().iterator();
+                        Iterator<Entry<RemotingChannel, ClientChannelInfo>> it = chlMap.entrySet().iterator();
                         while (it.hasNext()) {
-                            Entry<Channel, ClientChannelInfo> item = it.next();
+                            Entry<RemotingChannel, ClientChannelInfo> item = it.next();
                             // final Integer id = item.getKey();
                             final ClientChannelInfo info = item.getValue();
 
@@ -84,8 +86,8 @@ public class ProducerManager {
                                 it.remove();
                                 log.warn(
                                     "SCAN: remove expired channel[{}] from ProducerManager groupChannelTable, producer group name: {}",
-                                    RemotingHelper.parseChannelRemoteAddr(info.getChannel()), group);
-                                RemotingUtil.closeChannel(info.getChannel());
+                                    RemotingHelper.parseChannelRemoteAddr(info.getChannel().remoteAddress()), group);
+                                info.getChannel().close();
                             }
                         }
                     }
@@ -105,10 +107,10 @@ public class ProducerManager {
             try {
                 if (this.groupChannelLock.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
                     try {
-                        for (final Map.Entry<String, HashMap<Channel, ClientChannelInfo>> entry : this.groupChannelTable
+                        for (final Map.Entry<String, HashMap<RemotingChannel, ClientChannelInfo>> entry : this.groupChannelTable
                             .entrySet()) {
                             final String group = entry.getKey();
-                            final HashMap<Channel, ClientChannelInfo> clientChannelInfoTable =
+                            final HashMap<RemotingChannel, ClientChannelInfo> clientChannelInfoTable =
                                 entry.getValue();
                             final ClientChannelInfo clientChannelInfo =
                                 clientChannelInfoTable.remove(channel);
@@ -137,7 +139,7 @@ public class ProducerManager {
 
             if (this.groupChannelLock.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
                 try {
-                    HashMap<Channel, ClientChannelInfo> channelTable = this.groupChannelTable.get(group);
+                    HashMap<RemotingChannel, ClientChannelInfo> channelTable = this.groupChannelTable.get(group);
                     if (null == channelTable) {
                         channelTable = new HashMap<>();
                         this.groupChannelTable.put(group, channelTable);
@@ -168,7 +170,7 @@ public class ProducerManager {
         try {
             if (this.groupChannelLock.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
                 try {
-                    HashMap<Channel, ClientChannelInfo> channelTable = this.groupChannelTable.get(group);
+                    HashMap<RemotingChannel, ClientChannelInfo> channelTable = this.groupChannelTable.get(group);
                     if (null != channelTable && !channelTable.isEmpty()) {
                         ClientChannelInfo old = channelTable.remove(clientChannelInfo.getChannel());
                         if (old != null) {
@@ -192,11 +194,11 @@ public class ProducerManager {
         }
     }
 
-    public Channel getAvaliableChannel(String groupId) {
-        HashMap<Channel, ClientChannelInfo> channelClientChannelInfoHashMap = groupChannelTable.get(groupId);
-        List<Channel> channelList = new ArrayList<Channel>();
+    public RemotingChannel getAvaliableChannel(String groupId) {
+        HashMap<RemotingChannel, ClientChannelInfo> channelClientChannelInfoHashMap = groupChannelTable.get(groupId);
+        List<RemotingChannel> channelList = new ArrayList<>();
         if (channelClientChannelInfoHashMap != null) {
-            for (Channel channel : channelClientChannelInfoHashMap.keySet()) {
+            for (RemotingChannel channel : channelClientChannelInfoHashMap.keySet()) {
                 channelList.add(channel);
             }
             int size = channelList.size();
@@ -206,7 +208,7 @@ public class ProducerManager {
             }
 
             int index = positiveAtomicCounter.incrementAndGet() % size;
-            Channel channel = channelList.get(index);
+            RemotingChannel channel = channelList.get(index);
             int count = 0;
             boolean isOk = channel.isActive() && channel.isWritable();
             while (count++ < GET_AVALIABLE_CHANNEL_RETRY_COUNT) {
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/net/Broker2Client.java b/broker/src/main/java/org/apache/rocketmq/broker/client/net/Broker2Client.java
index 4c409f2..4eee9db 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/net/Broker2Client.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/net/Broker2Client.java
@@ -39,6 +39,7 @@ import org.apache.rocketmq.common.protocol.header.NotifyConsumerIdsChangedReques
 import org.apache.rocketmq.common.protocol.header.ResetOffsetRequestHeader;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
@@ -61,7 +62,7 @@ public class Broker2Client {
 
     public void checkProducerTransactionState(
         final String group,
-        final Channel channel,
+        final RemotingChannel channel,
         final CheckTransactionStateRequestHeader requestHeader,
         final MessageExt messageExt) throws Exception {
         RemotingCommand request =
@@ -74,14 +75,14 @@ public class Broker2Client {
         }
     }
 
-    public RemotingCommand callClient(final Channel channel,
+    public RemotingCommand callClient(final RemotingChannel channel,
                                       final RemotingCommand request
     ) throws RemotingSendRequestException, RemotingTimeoutException, InterruptedException {
         return this.brokerController.getRemotingServer().invokeSync(channel, request, 10000);
     }
 
     public void notifyConsumerIdsChanged(
-        final Channel channel,
+        final RemotingChannel channel,
         final String consumerGroup) {
         if (null == consumerGroup) {
             log.error("notifyConsumerIdsChanged consumerGroup is null");
@@ -175,9 +176,9 @@ public class Broker2Client {
             this.brokerController.getConsumerManager().getConsumerGroupInfo(group);
 
         if (consumerGroupInfo != null && !consumerGroupInfo.getAllChannel().isEmpty()) {
-            ConcurrentMap<Channel, ClientChannelInfo> channelInfoTable =
+            ConcurrentMap<RemotingChannel, ClientChannelInfo> channelInfoTable =
                 consumerGroupInfo.getChannelInfoTable();
-            for (Map.Entry<Channel, ClientChannelInfo> entry : channelInfoTable.entrySet()) {
+            for (Map.Entry<RemotingChannel, ClientChannelInfo> entry : channelInfoTable.entrySet()) {
                 int version = entry.getValue().getVersion();
                 if (version >= MQVersion.Version.V3_0_7_SNAPSHOT.ordinal()) {
                     try {
@@ -193,7 +194,7 @@ public class Broker2Client {
                     response.setRemark("the client does not support this feature. version="
                         + MQVersion.getVersionDesc(version));
                     log.warn("[reset-offset] the client does not support this feature. version={}",
-                        RemotingHelper.parseChannelRemoteAddr(entry.getKey()), MQVersion.getVersionDesc(version));
+                        RemotingHelper.parseChannelRemoteAddr(entry.getKey().remoteAddress()), MQVersion.getVersionDesc(version));
                     return response;
                 }
             }
@@ -238,7 +239,7 @@ public class Broker2Client {
 
         Map<String, Map<MessageQueue, Long>> consumerStatusTable =
             new HashMap<String, Map<MessageQueue, Long>>();
-        ConcurrentMap<Channel, ClientChannelInfo> channelInfoTable =
+        ConcurrentMap<RemotingChannel, ClientChannelInfo> channelInfoTable =
             this.brokerController.getConsumerManager().getConsumerGroupInfo(group).getChannelInfoTable();
         if (null == channelInfoTable || channelInfoTable.isEmpty()) {
             result.setCode(ResponseCode.SYSTEM_ERROR);
@@ -246,7 +247,7 @@ public class Broker2Client {
             return result;
         }
 
-        for (Map.Entry<Channel, ClientChannelInfo> entry : channelInfoTable.entrySet()) {
+        for (Map.Entry<RemotingChannel, ClientChannelInfo> entry : channelInfoTable.entrySet()) {
             int version = entry.getValue().getVersion();
             String clientId = entry.getValue().getClientId();
             if (version < MQVersion.Version.V3_0_7_SNAPSHOT.ordinal()) {
@@ -254,7 +255,7 @@ public class Broker2Client {
                 result.setRemark("the client does not support this feature. version="
                     + MQVersion.getVersionDesc(version));
                 log.warn("[get-consumer-status] the client does not support this feature. version={}",
-                    RemotingHelper.parseChannelRemoteAddr(entry.getKey()), MQVersion.getVersionDesc(version));
+                    RemotingHelper.parseChannelRemoteAddr(entry.getKey().remoteAddress()), MQVersion.getVersionDesc(version));
                 return result;
             } else if (UtilAll.isBlank(originClientId) || originClientId.equals(clientId)) {
                 try {
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java b/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
index 9edfcb8..2c204ce 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
@@ -55,7 +55,7 @@ import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
+import org.apache.rocketmq.remoting.ClientConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
 public class BrokerOuterAPI {
@@ -66,11 +66,11 @@ public class BrokerOuterAPI {
     private BrokerFixedThreadPoolExecutor brokerOuterExecutor = new BrokerFixedThreadPoolExecutor(4, 10, 1, TimeUnit.MINUTES,
         new ArrayBlockingQueue<Runnable>(32), new ThreadFactoryImpl("brokerOutApi_thread_", true));
 
-    public BrokerOuterAPI(final NettyClientConfig nettyClientConfig) {
+    public BrokerOuterAPI(final ClientConfig nettyClientConfig) {
         this(nettyClientConfig, null);
     }
 
-    public BrokerOuterAPI(final NettyClientConfig nettyClientConfig, RPCHook rpcHook) {
+    public BrokerOuterAPI(final ClientConfig nettyClientConfig, RPCHook rpcHook) {
         this.remotingClient = RemotingClientFactory.createInstance().init(nettyClientConfig, null);
         this.remotingClient.registerRPCHook(rpcHook);
     }
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java
index aa072e8..bd7625a 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/AbstractSendMessageProcessor.java
@@ -42,7 +42,7 @@ import org.apache.rocketmq.common.sysflag.TopicSysFlag;
 import org.apache.rocketmq.common.utils.ChannelUtil;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.RequestProcessor;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.store.MessageExtBrokerInner;
 
@@ -52,7 +52,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Random;
 
-public abstract class AbstractSendMessageProcessor implements NettyRequestProcessor {
+public abstract class AbstractSendMessageProcessor implements RequestProcessor {
     protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
 
     protected final static int DLQ_NUMS_PER_GROUP = 1;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
index 341907a..a83c488 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
@@ -17,7 +17,6 @@
 package org.apache.rocketmq.broker.processor;
 
 import com.alibaba.fastjson.JSON;
-import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandlerContext;
 import java.io.UnsupportedEncodingException;
 import java.net.UnknownHostException;
@@ -103,10 +102,12 @@ import org.apache.rocketmq.common.stats.StatsItem;
 import org.apache.rocketmq.common.stats.StatsSnapshot;
 import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
 import org.apache.rocketmq.filter.util.BitsArray;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
 import org.apache.rocketmq.remoting.serialize.LanguageCode;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
@@ -117,7 +118,7 @@ import org.apache.rocketmq.store.MessageFilter;
 import org.apache.rocketmq.store.MessageStore;
 import org.apache.rocketmq.store.SelectMappedBufferResult;
 
-public class AdminBrokerProcessor implements NettyRequestProcessor {
+public class AdminBrokerProcessor implements RequestProcessor {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
     private final BrokerController brokerController;
 
@@ -126,8 +127,10 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx,
+    public RemotingCommand processRequest(RemotingChannel remotingChannel,
         RemotingCommand request) throws RemotingCommandException {
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl)remotingChannel;
+        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
         switch (request.getCode()) {
             case RequestCode.UPDATE_AND_CREATE_TOPIC:
                 return this.updateAndCreateTopic(ctx, request);
@@ -593,14 +596,14 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
             bodydata.setMessageModel(consumerGroupInfo.getMessageModel());
             bodydata.getSubscriptionTable().putAll(consumerGroupInfo.getSubscriptionTable());
 
-            Iterator<Map.Entry<Channel, ClientChannelInfo>> it = consumerGroupInfo.getChannelInfoTable().entrySet().iterator();
+            Iterator<Map.Entry<RemotingChannel, ClientChannelInfo>> it = consumerGroupInfo.getChannelInfoTable().entrySet().iterator();
             while (it.hasNext()) {
                 ClientChannelInfo info = it.next().getValue();
                 Connection connection = new Connection();
                 connection.setClientId(info.getClientId());
                 connection.setLanguage(info.getLanguage());
                 connection.setVersion(info.getVersion());
-                connection.setClientAddr(RemotingHelper.parseChannelRemoteAddr(info.getChannel()));
+                connection.setClientAddr(RemotingHelper.parseChannelRemoteAddr(info.getChannel().remoteAddress()));
 
                 bodydata.getConnectionSet().add(connection);
             }
@@ -625,17 +628,17 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
             (GetProducerConnectionListRequestHeader) request.decodeCommandCustomHeader(GetProducerConnectionListRequestHeader.class);
 
         ProducerConnection bodydata = new ProducerConnection();
-        HashMap<Channel, ClientChannelInfo> channelInfoHashMap =
+        HashMap<RemotingChannel, ClientChannelInfo> channelInfoHashMap =
             this.brokerController.getProducerManager().getGroupChannelTable().get(requestHeader.getProducerGroup());
         if (channelInfoHashMap != null) {
-            Iterator<Map.Entry<Channel, ClientChannelInfo>> it = channelInfoHashMap.entrySet().iterator();
+            Iterator<Map.Entry<RemotingChannel, ClientChannelInfo>> it = channelInfoHashMap.entrySet().iterator();
             while (it.hasNext()) {
                 ClientChannelInfo info = it.next().getValue();
                 Connection connection = new Connection();
                 connection.setClientId(info.getClientId());
                 connection.setLanguage(info.getLanguage());
                 connection.setVersion(info.getVersion());
-                connection.setClientAddr(RemotingHelper.parseChannelRemoteAddr(info.getChannel()));
+                connection.setClientAddr(RemotingHelper.parseChannelRemoteAddr(info.getChannel().remoteAddress()));
 
                 bodydata.getConnectionSet().add(connection);
             }
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java
index f0d155f..03dec03 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java
@@ -37,12 +37,15 @@ import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
 import org.apache.rocketmq.common.sysflag.TopicSysFlag;
 import org.apache.rocketmq.filter.FilterFactory;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
+import org.apache.rocketmq.remoting.netty.NettyChannelImpl;
+import org.apache.rocketmq.remoting.RequestProcessor;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
-public class ClientManageProcessor implements NettyRequestProcessor {
+public class ClientManageProcessor implements RequestProcessor {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
     private final BrokerController brokerController;
 
@@ -51,8 +54,11 @@ public class ClientManageProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request)
-        throws RemotingCommandException {
+    public RemotingCommand processRequest(RemotingChannel remotingChannel,
+        RemotingCommand request) throws RemotingCommandException  {
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl)remotingChannel;
+        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
+
         switch (request.getCode()) {
             case RequestCode.HEART_BEAT:
                 return this.heartBeat(ctx, request);
@@ -76,7 +82,7 @@ public class ClientManageProcessor implements NettyRequestProcessor {
         HeartbeatData heartbeatData = HeartbeatData.decode(request.getBody(), HeartbeatData.class);
         log.info("heart beat request:{}", heartbeatData);
         ClientChannelInfo clientChannelInfo = new ClientChannelInfo(
-            ctx.channel(),
+            new NettyChannelImpl(ctx.channel()),
             heartbeatData.getClientID(),
             request.getLanguage(),
             request.getVersion()
@@ -137,7 +143,7 @@ public class ClientManageProcessor implements NettyRequestProcessor {
                 .decodeCommandCustomHeader(UnregisterClientRequestHeader.class);
 
         ClientChannelInfo clientChannelInfo = new ClientChannelInfo(
-            ctx.channel(),
+            new NettyChannelImpl(ctx.channel()),
             requestHeader.getClientID(),
             request.getLanguage(),
             request.getVersion());
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/ConsumerManageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/ConsumerManageProcessor.java
index 028d21b..421c531 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/ConsumerManageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/ConsumerManageProcessor.java
@@ -32,12 +32,14 @@ import org.apache.rocketmq.common.protocol.header.QueryConsumerOffsetResponseHea
 import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader;
 import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetResponseHeader;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
-public class ConsumerManageProcessor implements NettyRequestProcessor {
+public class ConsumerManageProcessor implements RequestProcessor {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
 
     private final BrokerController brokerController;
@@ -47,8 +49,11 @@ public class ConsumerManageProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request)
-        throws RemotingCommandException {
+    public RemotingCommand processRequest(RemotingChannel remotingChannel,
+        RemotingCommand request) throws RemotingCommandException {
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl) remotingChannel;
+        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
+
         switch (request.getCode()) {
             case RequestCode.GET_CONSUMER_LIST_BY_GROUP:
                 return this.getConsumerListByGroup(ctx, request);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/EndTransactionProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/EndTransactionProcessor.java
index c9e85ed..8d72ac1 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/EndTransactionProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/EndTransactionProcessor.java
@@ -30,9 +30,11 @@ import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader;
 import org.apache.rocketmq.common.sysflag.MessageSysFlag;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.store.MessageExtBrokerInner;
 import org.apache.rocketmq.store.PutMessageResult;
@@ -41,7 +43,7 @@ import org.apache.rocketmq.store.config.BrokerRole;
 /**
  * EndTransaction processor: process commit and rollback message
  */
-public class EndTransactionProcessor implements NettyRequestProcessor {
+public class EndTransactionProcessor implements RequestProcessor {
     private static final InternalLogger LOGGER = InternalLoggerFactory.getLogger(LoggerName.TRANSACTION_LOGGER_NAME);
     private final BrokerController brokerController;
 
@@ -50,11 +52,14 @@ public class EndTransactionProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) throws
-        RemotingCommandException {
+    public RemotingCommand processRequest(RemotingChannel remotingChannel,
+        RemotingCommand request) throws RemotingCommandException {
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl) remotingChannel;
+        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
+
         final RemotingCommand response = RemotingCommand.createResponseCommand(null);
         final EndTransactionRequestHeader requestHeader =
-            (EndTransactionRequestHeader)request.decodeCommandCustomHeader(EndTransactionRequestHeader.class);
+            (EndTransactionRequestHeader) request.decodeCommandCustomHeader(EndTransactionRequestHeader.class);
         LOGGER.info("Transaction request:{}", requestHeader);
         if (BrokerRole.SLAVE == brokerController.getMessageStoreConfig().getBrokerRole()) {
             response.setCode(ResponseCode.SLAVE_NOT_AVAILABLE);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/ForwardRequestProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/ForwardRequestProcessor.java
index b0f0a05..f47a453 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/ForwardRequestProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/ForwardRequestProcessor.java
@@ -16,15 +16,16 @@
  */
 package org.apache.rocketmq.broker.processor;
 
-import io.netty.channel.ChannelHandlerContext;
 import org.apache.rocketmq.broker.BrokerController;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.RemotingChannel;
+import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
-public class ForwardRequestProcessor implements NettyRequestProcessor {
+public class ForwardRequestProcessor implements RequestProcessor {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
 
     private final BrokerController brokerController;
@@ -34,7 +35,8 @@ public class ForwardRequestProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) {
+    public RemotingCommand processRequest(RemotingChannel remotingChannel,
+        RemotingCommand request) throws RemotingCommandException {
         return null;
     }
 
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java
index 10c0112..391b599 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java
@@ -53,10 +53,12 @@ import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
 import org.apache.rocketmq.common.protocol.topic.OffsetMovedEvent;
 import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
 import org.apache.rocketmq.common.sysflag.PullSysFlag;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.common.RemotingUtil;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
 import org.apache.rocketmq.remoting.netty.RequestTask;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.store.GetMessageResult;
@@ -66,7 +68,7 @@ import org.apache.rocketmq.store.PutMessageResult;
 import org.apache.rocketmq.store.config.BrokerRole;
 import org.apache.rocketmq.store.stats.BrokerStatsManager;
 
-public class PullMessageProcessor implements NettyRequestProcessor {
+public class PullMessageProcessor implements RequestProcessor {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
     private final BrokerController brokerController;
     private List<ConsumeMessageHook> consumeMessageHookList;
@@ -76,8 +78,11 @@ public class PullMessageProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(final ChannelHandlerContext ctx,
+    public RemotingCommand processRequest(RemotingChannel remotingChannel,
         RemotingCommand request) throws RemotingCommandException {
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl) remotingChannel;
+        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
+
         return this.processRequest(ctx.channel(), request, true);
     }
 
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/QueryMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/QueryMessageProcessor.java
index a5ca872..5d7f794 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/QueryMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/QueryMessageProcessor.java
@@ -32,13 +32,15 @@ import org.apache.rocketmq.common.protocol.ResponseCode;
 import org.apache.rocketmq.common.protocol.header.QueryMessageRequestHeader;
 import org.apache.rocketmq.common.protocol.header.QueryMessageResponseHeader;
 import org.apache.rocketmq.common.protocol.header.ViewMessageRequestHeader;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.store.QueryMessageResult;
 import org.apache.rocketmq.store.SelectMappedBufferResult;
 
-public class QueryMessageProcessor implements NettyRequestProcessor {
+public class QueryMessageProcessor implements RequestProcessor {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
 
     private final BrokerController brokerController;
@@ -48,8 +50,10 @@ public class QueryMessageProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request)
-        throws RemotingCommandException {
+    public RemotingCommand processRequest(RemotingChannel remotingChannel,
+        RemotingCommand request) throws RemotingCommandException {
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl) remotingChannel;
+        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
         switch (request.getCode()) {
             case RequestCode.QUERY_MESSAGE:
                 return this.queryMessage(ctx, request);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java
index 5f1c2f1..6bb378e 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java
@@ -41,8 +41,10 @@ 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.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.store.MessageExtBrokerInner;
 import org.apache.rocketmq.store.PutMessageResult;
@@ -53,7 +55,7 @@ import java.net.SocketAddress;
 import java.util.List;
 import java.util.Map;
 
-public class SendMessageProcessor extends AbstractSendMessageProcessor implements NettyRequestProcessor {
+public class SendMessageProcessor extends AbstractSendMessageProcessor implements RequestProcessor {
 
     private List<ConsumeMessageHook> consumeMessageHookList;
 
@@ -62,8 +64,11 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
     }
 
     @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx,
+    public RemotingCommand processRequest(RemotingChannel remotingChannel,
         RemotingCommand request) throws RemotingCommandException {
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl) remotingChannel;
+        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
+
         SendMessageContext mqtraceContext;
         switch (request.getCode()) {
             case RequestCode.CONSUMER_SEND_MSG_BACK:
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/SnodePullMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/SnodePullMessageProcessor.java
index 788c498..c08ebcd 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/SnodePullMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/SnodePullMessageProcessor.java
@@ -48,10 +48,12 @@ import org.apache.rocketmq.common.protocol.topic.OffsetMovedEvent;
 import org.apache.rocketmq.common.sysflag.PullSysFlag;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.common.RemotingUtil;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
 import org.apache.rocketmq.remoting.netty.RequestTask;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.store.GetMessageResult;
@@ -61,7 +63,7 @@ import org.apache.rocketmq.store.PutMessageResult;
 import org.apache.rocketmq.store.config.BrokerRole;
 import org.apache.rocketmq.store.stats.BrokerStatsManager;
 
-public class SnodePullMessageProcessor implements NettyRequestProcessor {
+public class SnodePullMessageProcessor implements RequestProcessor {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
     private final BrokerController brokerController;
     private List<ConsumeMessageHook> consumeMessageHookList;
@@ -71,8 +73,11 @@ public class SnodePullMessageProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(final ChannelHandlerContext ctx,
+    public RemotingCommand processRequest(RemotingChannel remotingChannel,
         RemotingCommand request) throws RemotingCommandException {
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl) remotingChannel;
+        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
+
         return this.processRequest(ctx.channel(), request, true);
     }
 
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/transaction/AbstractTransactionalMessageCheckListener.java b/broker/src/main/java/org/apache/rocketmq/broker/transaction/AbstractTransactionalMessageCheckListener.java
index 659c6af..152e067 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/transaction/AbstractTransactionalMessageCheckListener.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/transaction/AbstractTransactionalMessageCheckListener.java
@@ -30,6 +30,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
+import org.apache.rocketmq.remoting.RemotingChannel;
 
 public abstract class AbstractTransactionalMessageCheckListener {
     private static final InternalLogger LOGGER = InternalLoggerFactory.getLogger(LoggerName.TRANSACTION_LOGGER_NAME);
@@ -63,7 +64,7 @@ public abstract class AbstractTransactionalMessageCheckListener {
         msgExt.setQueueId(Integer.parseInt(msgExt.getUserProperty(MessageConst.PROPERTY_REAL_QUEUE_ID)));
         msgExt.setStoreSize(0);
         String groupId = msgExt.getProperty(MessageConst.PROPERTY_PRODUCER_GROUP);
-        Channel channel = brokerController.getProducerManager().getAvaliableChannel(groupId);
+        RemotingChannel channel = brokerController.getProducerManager().getAvaliableChannel(groupId);
         if (channel != null) {
             brokerController.getBroker2Client().checkProducerTransactionState(groupId, channel, checkTransactionStateRequestHeader, msgExt);
         } else {
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/BrokerControllerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/BrokerControllerTest.java
index 56abf08..84139b4 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/BrokerControllerTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/BrokerControllerTest.java
@@ -20,8 +20,8 @@ package org.apache.rocketmq.broker;
 import java.io.File;
 import org.apache.rocketmq.common.BrokerConfig;
 import org.apache.rocketmq.common.UtilAll;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.ClientConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.store.config.MessageStoreConfig;
 import org.junit.After;
 import org.junit.Test;
@@ -34,8 +34,8 @@ public class BrokerControllerTest {
     public void testBrokerRestart() throws Exception {
         BrokerController brokerController = new BrokerController(
             new BrokerConfig(),
-            new NettyServerConfig(),
-            new NettyClientConfig(),
+            new ServerConfig(),
+            new ClientConfig(),
             new MessageStoreConfig());
         assertThat(brokerController.initialize());
         brokerController.start();
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/BrokerOuterAPITest.java b/broker/src/test/java/org/apache/rocketmq/broker/BrokerOuterAPITest.java
index 30fe3a2..5ca8a86 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/BrokerOuterAPITest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/BrokerOuterAPITest.java
@@ -31,8 +31,8 @@ import org.apache.rocketmq.common.protocol.ResponseCode;
 import org.apache.rocketmq.common.protocol.body.TopicConfigSerializeWrapper;
 import org.apache.rocketmq.common.protocol.header.namesrv.QueryDataVersionResponseHeader;
 import org.apache.rocketmq.common.protocol.header.namesrv.RegisterBrokerResponseHeader;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.ClientConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingClient;
 import org.apache.rocketmq.store.MessageStore;
@@ -57,7 +57,7 @@ public class BrokerOuterAPITest {
     @Mock
     private ChannelHandlerContext handlerContext;
     @Spy
-    private BrokerController brokerController = new BrokerController(new BrokerConfig(), new NettyServerConfig(), new NettyClientConfig(), new MessageStoreConfig());
+    private BrokerController brokerController = new BrokerController(new BrokerConfig(), new ServerConfig(), new ClientConfig(), new MessageStoreConfig());
     @Mock
     private MessageStore messageStore;
     private String clusterName = "clusterName";
@@ -75,7 +75,7 @@ public class BrokerOuterAPITest {
     private BrokerOuterAPI brokerOuterAPI;
 
     public void init() throws Exception {
-        brokerOuterAPI = new BrokerOuterAPI(new NettyClientConfig(), null);
+        brokerOuterAPI = new BrokerOuterAPI(new ClientConfig(), null);
         Field field = BrokerOuterAPI.class.getDeclaredField("remotingClient");
         field.setAccessible(true);
         field.set(brokerOuterAPI, nettyRemotingClient);
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/client/ProducerManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/client/ProducerManagerTest.java
index 08dbb9c..2b01e7a 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/client/ProducerManagerTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/client/ProducerManagerTest.java
@@ -20,6 +20,7 @@ import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
 import java.lang.reflect.Field;
 import java.util.HashMap;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -37,7 +38,7 @@ public class ProducerManagerTest {
     private ClientChannelInfo clientInfo;
 
     @Mock
-    private Channel channel;
+    private RemotingChannel channel;
 
     @Before
     public void init() {
@@ -54,7 +55,7 @@ public class ProducerManagerTest {
         field.setAccessible(true);
         long CHANNEL_EXPIRED_TIMEOUT = field.getLong(producerManager);
         clientInfo.setLastUpdateTimestamp(System.currentTimeMillis() - CHANNEL_EXPIRED_TIMEOUT - 10);
-        when(channel.close()).thenReturn(mock(ChannelFuture.class));
+//        when(channel.close()).thenReturn(mock(ChannelFuture.class));
         producerManager.scanNotActiveChannel();
         assertThat(producerManager.getGroupChannelTable().get(group).get(channel)).isNull();
     }
@@ -63,14 +64,14 @@ public class ProducerManagerTest {
     public void doChannelCloseEvent() throws Exception {
         producerManager.registerProducer(group, clientInfo);
         assertThat(producerManager.getGroupChannelTable().get(group).get(channel)).isNotNull();
-        producerManager.doChannelCloseEvent("127.0.0.1", channel);
+//        producerManager.doChannelCloseEvent("127.0.0.1", channel);
         assertThat(producerManager.getGroupChannelTable().get(group).get(channel)).isNull();
     }
 
     @Test
     public void testRegisterProducer() throws Exception {
         producerManager.registerProducer(group, clientInfo);
-        HashMap<Channel, ClientChannelInfo> channelMap = producerManager.getGroupChannelTable().get(group);
+        HashMap<RemotingChannel, ClientChannelInfo> channelMap = producerManager.getGroupChannelTable().get(group);
         assertThat(channelMap).isNotNull();
         assertThat(channelMap.get(channel)).isEqualTo(clientInfo);
     }
@@ -78,7 +79,7 @@ public class ProducerManagerTest {
     @Test
     public void unregisterProducer() throws Exception {
         producerManager.registerProducer(group, clientInfo);
-        HashMap<Channel, ClientChannelInfo> channelMap = producerManager.getGroupChannelTable().get(group);
+        HashMap<RemotingChannel, ClientChannelInfo> channelMap = producerManager.getGroupChannelTable().get(group);
         assertThat(channelMap).isNotNull();
         assertThat(channelMap.get(channel)).isEqualTo(clientInfo);
 
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/ClientManageProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/ClientManageProcessorTest.java
index 9ee9035..1be0309 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/ClientManageProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/ClientManageProcessorTest.java
@@ -16,7 +16,6 @@
  */
 package org.apache.rocketmq.broker.processor;
 
-import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandlerContext;
 import java.util.HashMap;
 import java.util.UUID;
@@ -28,9 +27,12 @@ import org.apache.rocketmq.common.protocol.RequestCode;
 import org.apache.rocketmq.common.protocol.ResponseCode;
 import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader;
 import org.apache.rocketmq.common.protocol.heartbeat.ConsumerData;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
+import org.apache.rocketmq.remoting.netty.NettyChannelImpl;
+import org.apache.rocketmq.remoting.ClientConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.remoting.serialize.LanguageCode;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.store.config.MessageStoreConfig;
@@ -43,17 +45,16 @@ import org.mockito.junit.MockitoJUnitRunner;
 
 import static org.apache.rocketmq.broker.processor.PullMessageProcessorTest.createConsumerData;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
 public class ClientManageProcessorTest {
     private ClientManageProcessor clientManageProcessor;
     @Spy
-    private BrokerController brokerController = new BrokerController(new BrokerConfig(), new NettyServerConfig(), new NettyClientConfig(), new MessageStoreConfig());
+    private BrokerController brokerController = new BrokerController(new BrokerConfig(), new ServerConfig(), new ClientConfig(), new MessageStoreConfig());
     @Mock
     private ChannelHandlerContext handlerContext;
     @Mock
-    private Channel channel;
+    private NettyChannelImpl channel;
 
     private ClientChannelInfo clientChannelInfo;
     private String clientId = UUID.randomUUID().toString();
@@ -62,7 +63,7 @@ public class ClientManageProcessorTest {
 
     @Before
     public void init() {
-        when(handlerContext.channel()).thenReturn(channel);
+//        when(handlerContext.channel()).thenReturn(channel);
         clientManageProcessor = new ClientManageProcessor(brokerController);
         clientChannelInfo = new ClientChannelInfo(channel, clientId, LanguageCode.JAVA, 100);
         brokerController.getProducerManager().registerProducer(group, clientChannelInfo);
@@ -81,12 +82,13 @@ public class ClientManageProcessorTest {
     @Test
     public void processRequest_UnRegisterProducer() throws Exception {
         brokerController.getProducerManager().registerProducer(group, clientChannelInfo);
-        HashMap<Channel, ClientChannelInfo> channelMap = brokerController.getProducerManager().getGroupChannelTable().get(group);
+        HashMap<RemotingChannel, ClientChannelInfo> channelMap = brokerController.getProducerManager().getGroupChannelTable().get(group);
         assertThat(channelMap).isNotNull();
         assertThat(channelMap.get(channel)).isEqualTo(clientChannelInfo);
 
         RemotingCommand request = createUnRegisterProducerCommand();
-        RemotingCommand response = clientManageProcessor.processRequest(handlerContext, request);
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand response = clientManageProcessor.processRequest(nettyChannelHandlerContext, request);
         assertThat(response).isNotNull();
         assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
 
@@ -100,8 +102,9 @@ public class ClientManageProcessorTest {
         assertThat(consumerGroupInfo).isNotNull();
 
         RemotingCommand request = createUnRegisterConsumerCommand();
-        RemotingCommand response = clientManageProcessor.processRequest(handlerContext, request);
-        assertThat(response).isNotNull();
+
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand response = clientManageProcessor.processRequest(nettyChannelHandlerContext, request);        assertThat(response).isNotNull();
         assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
 
         consumerGroupInfo = brokerController.getConsumerManager().getConsumerGroupInfo(group);
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/EndTransactionProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/EndTransactionProcessorTest.java
index 7d8aa13..82c0a7d 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/EndTransactionProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/EndTransactionProcessorTest.java
@@ -29,8 +29,9 @@ import org.apache.rocketmq.common.protocol.ResponseCode;
 import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader;
 import org.apache.rocketmq.common.sysflag.MessageSysFlag;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
+import org.apache.rocketmq.remoting.ClientConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.store.AppendMessageResult;
 import org.apache.rocketmq.store.AppendMessageStatus;
@@ -60,7 +61,7 @@ public class EndTransactionProcessorTest {
 
     @Spy
     private BrokerController
-        brokerController = new BrokerController(new BrokerConfig(), new NettyServerConfig(), new NettyClientConfig(),
+        brokerController = new BrokerController(new BrokerConfig(), new ServerConfig(), new ClientConfig(),
         new MessageStoreConfig());
 
     @Mock
@@ -76,7 +77,7 @@ public class EndTransactionProcessorTest {
         endTransactionProcessor = new EndTransactionProcessor(brokerController);
     }
 
-    private OperationResult createResponse(int status){
+    private OperationResult createResponse(int status) {
         OperationResult response = new OperationResult();
         response.setPrepareMessage(createDefaultMessageExt());
         response.setResponseCode(status);
@@ -90,7 +91,9 @@ public class EndTransactionProcessorTest {
         when(messageStore.putMessage(any(MessageExtBrokerInner.class))).thenReturn(new PutMessageResult
             (PutMessageStatus.PUT_OK, new AppendMessageResult(AppendMessageStatus.PUT_OK)));
         RemotingCommand request = createEndTransactionMsgCommand(MessageSysFlag.TRANSACTION_COMMIT_TYPE, false);
-        RemotingCommand response = endTransactionProcessor.processRequest(handlerContext, request);
+
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand response = endTransactionProcessor.processRequest(nettyChannelHandlerContext, request);
         assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
     }
 
@@ -100,14 +103,16 @@ public class EndTransactionProcessorTest {
         when(messageStore.putMessage(any(MessageExtBrokerInner.class))).thenReturn(new PutMessageResult
             (PutMessageStatus.PUT_OK, new AppendMessageResult(AppendMessageStatus.PUT_OK)));
         RemotingCommand request = createEndTransactionMsgCommand(MessageSysFlag.TRANSACTION_COMMIT_TYPE, true);
-        RemotingCommand response = endTransactionProcessor.processRequest(handlerContext, request);
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand response = endTransactionProcessor.processRequest(nettyChannelHandlerContext, request);
         assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
     }
 
     @Test
     public void testProcessRequest_NotType() throws RemotingCommandException {
         RemotingCommand request = createEndTransactionMsgCommand(MessageSysFlag.TRANSACTION_NOT_TYPE, true);
-        RemotingCommand response = endTransactionProcessor.processRequest(handlerContext, request);
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand response = endTransactionProcessor.processRequest(nettyChannelHandlerContext, request);
         assertThat(response).isNull();
     }
 
@@ -115,7 +120,8 @@ public class EndTransactionProcessorTest {
     public void testProcessRequest_RollBack() throws RemotingCommandException {
         when(transactionMsgService.rollbackMessage(any(EndTransactionRequestHeader.class))).thenReturn(createResponse(ResponseCode.SUCCESS));
         RemotingCommand request = createEndTransactionMsgCommand(MessageSysFlag.TRANSACTION_ROLLBACK_TYPE, true);
-        RemotingCommand response = endTransactionProcessor.processRequest(handlerContext, request);
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand response = endTransactionProcessor.processRequest(nettyChannelHandlerContext, request);
         assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
     }
 
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java
index dc7b567..48d09bc 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java
@@ -16,7 +16,6 @@
  */
 package org.apache.rocketmq.broker.processor;
 
-import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandlerContext;
 import java.net.InetSocketAddress;
 import java.util.ArrayList;
@@ -38,9 +37,11 @@ import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
 import org.apache.rocketmq.common.protocol.heartbeat.ConsumerData;
 import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
 import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
+import org.apache.rocketmq.remoting.ClientConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.store.GetMessageResult;
 import org.apache.rocketmq.store.GetMessageStatus;
@@ -65,7 +66,7 @@ import static org.mockito.Mockito.when;
 public class PullMessageProcessorTest {
     private PullMessageProcessor pullMessageProcessor;
     @Spy
-    private BrokerController brokerController = new BrokerController(new BrokerConfig(), new NettyServerConfig(), new NettyClientConfig(), new MessageStoreConfig());
+    private BrokerController brokerController = new BrokerController(new BrokerConfig(), new ServerConfig(), new ClientConfig(), new MessageStoreConfig());
     @Mock
     private ChannelHandlerContext handlerContext;
     @Mock
@@ -78,9 +79,9 @@ public class PullMessageProcessorTest {
     public void init() {
         brokerController.setMessageStore(messageStore);
         pullMessageProcessor = new PullMessageProcessor(brokerController);
-        Channel mockChannel = mock(Channel.class);
+        RemotingChannel mockChannel = mock(RemotingChannel.class);
         when(mockChannel.remoteAddress()).thenReturn(new InetSocketAddress(1024));
-        when(handlerContext.channel()).thenReturn(mockChannel);
+//        when(handlerContext.channel()).thenReturn(mockChannel);
         brokerController.getTopicConfigManager().getTopicConfigTable().put(topic, new TopicConfig());
         clientChannelInfo = new ClientChannelInfo(mockChannel);
         ConsumerData consumerData = createConsumerData(group, topic);
@@ -98,7 +99,8 @@ public class PullMessageProcessorTest {
     public void testProcessRequest_TopicNotExist() throws RemotingCommandException {
         brokerController.getTopicConfigManager().getTopicConfigTable().remove(topic);
         final RemotingCommand request = createPullMsgCommand(RequestCode.PULL_MESSAGE);
-        RemotingCommand response = pullMessageProcessor.processRequest(handlerContext, request);
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand response = pullMessageProcessor.processRequest(nettyChannelHandlerContext, request);
         assertThat(response).isNotNull();
         assertThat(response.getCode()).isEqualTo(ResponseCode.TOPIC_NOT_EXIST);
         assertThat(response.getRemark()).contains("topic[" + topic + "] not exist");
@@ -108,7 +110,9 @@ public class PullMessageProcessorTest {
     public void testProcessRequest_SubNotExist() throws RemotingCommandException {
         brokerController.getConsumerManager().unregisterConsumer(group, clientChannelInfo, false);
         final RemotingCommand request = createPullMsgCommand(RequestCode.PULL_MESSAGE);
-        RemotingCommand response = pullMessageProcessor.processRequest(handlerContext, request);
+
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand response = pullMessageProcessor.processRequest(nettyChannelHandlerContext, request);
         assertThat(response).isNotNull();
         assertThat(response.getCode()).isEqualTo(ResponseCode.SUBSCRIPTION_NOT_EXIST);
         assertThat(response.getRemark()).contains("consumer's group info not exist");
@@ -118,7 +122,8 @@ public class PullMessageProcessorTest {
     public void testProcessRequest_SubNotLatest() throws RemotingCommandException {
         final RemotingCommand request = createPullMsgCommand(RequestCode.PULL_MESSAGE);
         request.addExtField("subVersion", String.valueOf(101));
-        RemotingCommand response = pullMessageProcessor.processRequest(handlerContext, request);
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand response = pullMessageProcessor.processRequest(nettyChannelHandlerContext, request);
         assertThat(response).isNotNull();
         assertThat(response.getCode()).isEqualTo(ResponseCode.SUBSCRIPTION_NOT_LATEST);
         assertThat(response.getRemark()).contains("subscription not latest");
@@ -130,7 +135,9 @@ public class PullMessageProcessorTest {
         when(messageStore.getMessage(anyString(), anyString(), anyInt(), anyLong(), anyInt(), any(ExpressionMessageFilter.class))).thenReturn(getMessageResult);
 
         final RemotingCommand request = createPullMsgCommand(RequestCode.PULL_MESSAGE);
-        RemotingCommand response = pullMessageProcessor.processRequest(handlerContext, request);
+
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand response = pullMessageProcessor.processRequest(nettyChannelHandlerContext, request);
         assertThat(response).isNotNull();
         assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
     }
@@ -159,7 +166,9 @@ public class PullMessageProcessorTest {
         consumeMessageHookList.add(consumeMessageHook);
         pullMessageProcessor.registerConsumeMessageHook(consumeMessageHookList);
         final RemotingCommand request = createPullMsgCommand(RequestCode.PULL_MESSAGE);
-        RemotingCommand response = pullMessageProcessor.processRequest(handlerContext, request);
+
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand response = pullMessageProcessor.processRequest(nettyChannelHandlerContext, request);
         assertThat(response).isNotNull();
         assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
         assertThat(messageContext[0]).isNotNull();
@@ -175,7 +184,9 @@ public class PullMessageProcessorTest {
         when(messageStore.getMessage(anyString(), anyString(), anyInt(), anyLong(), anyInt(), any(ExpressionMessageFilter.class))).thenReturn(getMessageResult);
 
         final RemotingCommand request = createPullMsgCommand(RequestCode.PULL_MESSAGE);
-        RemotingCommand response = pullMessageProcessor.processRequest(handlerContext, request);
+
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand response = pullMessageProcessor.processRequest(nettyChannelHandlerContext, request);
         assertThat(response).isNotNull();
         assertThat(response.getCode()).isEqualTo(ResponseCode.PULL_RETRY_IMMEDIATELY);
     }
@@ -187,7 +198,9 @@ public class PullMessageProcessorTest {
         when(messageStore.getMessage(anyString(), anyString(), anyInt(), anyLong(), anyInt(), any(ExpressionMessageFilter.class))).thenReturn(getMessageResult);
 
         final RemotingCommand request = createPullMsgCommand(RequestCode.PULL_MESSAGE);
-        RemotingCommand response = pullMessageProcessor.processRequest(handlerContext, request);
+
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand response = pullMessageProcessor.processRequest(nettyChannelHandlerContext, request);
         assertThat(response).isNotNull();
         assertThat(response.getCode()).isEqualTo(ResponseCode.PULL_OFFSET_MOVED);
     }
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/SendMessageProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/SendMessageProcessorTest.java
index 2f56422..ac8a106 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/SendMessageProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/SendMessageProcessorTest.java
@@ -33,8 +33,9 @@ import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHead
 import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader;
 import org.apache.rocketmq.common.sysflag.MessageSysFlag;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
+import org.apache.rocketmq.remoting.ClientConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.store.AppendMessageResult;
 import org.apache.rocketmq.store.AppendMessageStatus;
@@ -70,7 +71,7 @@ public class SendMessageProcessorTest {
     @Mock
     private ChannelHandlerContext handlerContext;
     @Spy
-    private BrokerController brokerController = new BrokerController(new BrokerConfig(), new NettyServerConfig(), new NettyClientConfig(), new MessageStoreConfig());
+    private BrokerController brokerController = new BrokerController(new BrokerConfig(), new ServerConfig(), new ClientConfig(), new MessageStoreConfig());
     @Mock
     private MessageStore messageStore;
 
@@ -181,7 +182,9 @@ public class SendMessageProcessorTest {
         final RemotingCommand request = createSendMsgBackCommand(RequestCode.CONSUMER_SEND_MSG_BACK);
 
         sendMessageProcessor = new SendMessageProcessor(brokerController);
-        final RemotingCommand response = sendMessageProcessor.processRequest(handlerContext, request);
+
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand response = sendMessageProcessor.processRequest(nettyChannelHandlerContext, request);
         assertThat(response).isNotNull();
         assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
     }
@@ -199,7 +202,10 @@ public class SendMessageProcessorTest {
                 return null;
             }
         }).when(handlerContext).writeAndFlush(any(Object.class));
-        RemotingCommand responseToReturn = sendMessageProcessor.processRequest(handlerContext, request);
+
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand responseToReturn = sendMessageProcessor.processRequest(nettyChannelHandlerContext, request);
+
         if (responseToReturn != null) {
             assertThat(response[0]).isNull();
             response[0] = responseToReturn;
@@ -207,6 +213,7 @@ public class SendMessageProcessorTest {
         assertThat(response[0].getCode()).isEqualTo(ResponseCode.SUCCESS);
 
     }
+
     private RemotingCommand createSendTransactionMsgCommand(int requestCode) {
         SendMessageRequestHeader header = createSendMsgRequestHeader();
         int sysFlag = header.getSysFlag();
@@ -267,7 +274,9 @@ public class SendMessageProcessorTest {
                 return null;
             }
         }).when(handlerContext).writeAndFlush(any(Object.class));
-        RemotingCommand responseToReturn = sendMessageProcessor.processRequest(handlerContext, request);
+
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(handlerContext);
+        RemotingCommand responseToReturn = sendMessageProcessor.processRequest(nettyChannelHandlerContext, request);
         if (responseToReturn != null) {
             assertThat(response[0]).isNull();
             response[0] = responseToReturn;
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/DefaultTransactionalMessageCheckListenerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/DefaultTransactionalMessageCheckListenerTest.java
index 17bf00b..63844f9 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/DefaultTransactionalMessageCheckListenerTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/DefaultTransactionalMessageCheckListenerTest.java
@@ -21,8 +21,8 @@ import org.apache.rocketmq.common.BrokerConfig;
 import org.apache.rocketmq.common.message.MessageAccessor;
 import org.apache.rocketmq.common.message.MessageConst;
 import org.apache.rocketmq.common.message.MessageExt;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.ClientConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.store.MessageExtBrokerInner;
 import org.apache.rocketmq.store.config.MessageStoreConfig;
 import org.junit.Before;
@@ -37,8 +37,8 @@ public class DefaultTransactionalMessageCheckListenerTest {
     private DefaultTransactionalMessageCheckListener listener;
 
     @Spy
-    private BrokerController brokerController = new BrokerController(new BrokerConfig(), new NettyServerConfig(),
-        new NettyClientConfig(), new MessageStoreConfig());
+    private BrokerController brokerController = new BrokerController(new BrokerConfig(), new ServerConfig(),
+        new ClientConfig(), new MessageStoreConfig());
 
 
     @Before
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageBridgeTest.java b/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageBridgeTest.java
index b1c669c..f605986 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageBridgeTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageBridgeTest.java
@@ -25,8 +25,8 @@ import org.apache.rocketmq.common.message.MessageAccessor;
 import org.apache.rocketmq.common.message.MessageConst;
 import org.apache.rocketmq.common.message.MessageExt;
 import org.apache.rocketmq.common.message.MessageQueue;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.ClientConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.store.AppendMessageResult;
 import org.apache.rocketmq.store.AppendMessageStatus;
 import org.apache.rocketmq.store.GetMessageResult;
@@ -61,8 +61,8 @@ public class TransactionalMessageBridgeTest {
     private TransactionalMessageBridge transactionBridge;
 
     @Spy
-    private BrokerController brokerController = new BrokerController(new BrokerConfig(), new NettyServerConfig(),
-        new NettyClientConfig(), new MessageStoreConfig());
+    private BrokerController brokerController = new BrokerController(new BrokerConfig(), new ServerConfig(),
+        new ClientConfig(), new MessageStoreConfig());
 
     @Mock
     private MessageStore messageStore;
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImplTest.java b/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImplTest.java
index 47eccbe..d7df525 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImplTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImplTest.java
@@ -30,8 +30,8 @@ import org.apache.rocketmq.common.message.MessageQueue;
 import org.apache.rocketmq.common.protocol.ResponseCode;
 import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader;
 import org.apache.rocketmq.common.sysflag.MessageSysFlag;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.ClientConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.store.AppendMessageResult;
 import org.apache.rocketmq.store.AppendMessageStatus;
 import org.apache.rocketmq.store.MessageExtBrokerInner;
@@ -70,8 +70,8 @@ public class TransactionalMessageServiceImplTest {
     private TransactionalMessageBridge bridge;
 
     @Spy
-    private BrokerController brokerController = new BrokerController(new BrokerConfig(), new NettyServerConfig(),
-        new NettyClientConfig(), new MessageStoreConfig());
+    private BrokerController brokerController = new BrokerController(new BrokerConfig(), new ServerConfig(),
+        new ClientConfig(), new MessageStoreConfig());
 
     @Mock
     private AbstractTransactionalMessageCheckListener listener;
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyClientConfig.java b/remoting/src/main/java/org/apache/rocketmq/remoting/ClientConfig.java
similarity index 100%
rename from remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyClientConfig.java
rename to remoting/src/main/java/org/apache/rocketmq/remoting/ClientConfig.java
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingChannel.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingChannel.java
new file mode 100644
index 0000000..c8f00f7
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingChannel.java
@@ -0,0 +1,78 @@
+/*
+ * 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.remoting;
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import org.apache.rocketmq.remoting.api.command.RemotingCommand;
+
+public interface RemotingChannel {
+    /**
+     * Returns the local address where this {@code RemotingChannel} is bound to.  The returned
+     * {@link SocketAddress} is supposed to be down-cast into more concrete
+     * type such as {@link InetSocketAddress} to retrieve the detailed
+     * information.
+     *
+     * @return the local address of this channel.
+     * {@code null} if this channel is not bound.
+     */
+    SocketAddress localAddress();
+
+    /**
+     * Returns the remote address where this {@code RemotingChannel} is connected to.  The
+     * returned {@link SocketAddress} is supposed to be down-cast into more
+     * concrete type such as {@link InetSocketAddress} to retrieve the detailed
+     * information.
+     *
+     * @return the remote address of this channel.
+     * {@code null} if this channel is not connected.
+     */
+    SocketAddress remoteAddress();
+
+    /**
+     * Returns {@code true} if and only if the I/O thread will perform the
+     * requested write operation immediately.  Any write requests made when
+     * this method returns {@code false} are queued until the I/O thread is
+     * ready to process the queued write requests.
+     */
+    boolean isWritable();
+
+    /**
+     * Returns {@code true} if the {@code RemotingChannel} is active and so connected.
+     */
+    boolean isActive();
+
+    /**
+     * Requests to close the {@code RemotingChannel} immediately.
+     */
+    void close();
+
+    /**
+     * Writes a response {@code RemotingCommand} to remote.
+     *
+     * @param command the response command
+     */
+    void reply(RemotingCommand command);
+
+    /**
+     * Writes a response {@code ChunkRegion} to remote.
+     *
+     * @param fileRegion the response chunk file region
+     */
+    void reply(ChunkRegion fileRegion);
+}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRequestProcessor.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RequestProcessor.java
similarity index 100%
copy from remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRequestProcessor.java
copy to remoting/src/main/java/org/apache/rocketmq/remoting/RequestProcessor.java
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyServerConfig.java b/remoting/src/main/java/org/apache/rocketmq/remoting/ServerConfig.java
similarity index 100%
rename from remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyServerConfig.java
rename to remoting/src/main/java/org/apache/rocketmq/remoting/ServerConfig.java
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRequestProcessor.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelHandlerContextImpl.java
similarity index 67%
rename from remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRequestProcessor.java
rename to remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelHandlerContextImpl.java
index 040f768..9eb489a 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRequestProcessor.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelHandlerContextImpl.java
@@ -1,4 +1,4 @@
-/*
+package org.apache.rocketmq.remoting.netty;/*
  * 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.
@@ -14,17 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.rocketmq.remoting.netty;
 
-import io.netty.channel.ChannelHandlerContext;
-import org.apache.rocketmq.remoting.protocol.RemotingCommand;
-
-/**
- * Common remoting command processor
- */
-public interface NettyRequestProcessor {
-    RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request)
-        throws Exception;
-
-    boolean rejectRequest();
+public class NettyChannelHandlerContextImpl {
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelImpl.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelImpl.java
new file mode 100644
index 0000000..e4be7ca
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelImpl.java
@@ -0,0 +1,94 @@
+/*
+ * 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.remoting.netty;
+
+import io.netty.channel.Channel;
+import java.net.SocketAddress;
+import org.apache.rocketmq.remoting.api.channel.ChunkRegion;
+import org.apache.rocketmq.remoting.api.channel.RemotingChannel;
+import org.apache.rocketmq.remoting.api.command.RemotingCommand;
+
+public class NettyChannelImpl implements RemotingChannel {
+    private final io.netty.channel.Channel channel;
+
+    public NettyChannelImpl(Channel channel) {
+        this.channel = channel;
+    }
+
+    @Override
+    public SocketAddress localAddress() {
+        return channel.localAddress();
+    }
+
+    @Override
+    public SocketAddress remoteAddress() {
+        return channel.remoteAddress();
+    }
+
+    @Override
+    public boolean isWritable() {
+        return channel.isWritable();
+    }
+
+    @Override
+    public boolean isActive() {
+        return channel.isActive();
+    }
+
+    @Override
+    public void close() {
+        channel.close();
+    }
+
+    @Override
+    public void reply(final RemotingCommand command) {
+        channel.writeAndFlush(command);
+    }
+
+    @Override
+    public void reply(final ChunkRegion fileRegion) {
+        channel.writeAndFlush(fileRegion);
+    }
+
+    public io.netty.channel.Channel getChannel() {
+        return channel;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        final NettyChannelImpl that = (NettyChannelImpl) o;
+
+        return channel != null ? channel.equals(that.channel) : that.channel == null;
+
+    }
+
+    @Override
+    public int hashCode() {
+        return channel != null ? channel.hashCode() : 0;
+    }
+
+    @Override
+    public String toString() {
+        return "NettyChannelImpl [channel=" + channel + "]";
+    }
+}


[rocketmq] 14/14: Modify license header

Posted by du...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a commit to branch snode
in repository https://gitbox.apache.org/repos/asf/rocketmq.git

commit cd4403ce5a6d2747cae924e643371198478b16d3
Author: duhenglucky <du...@gmail.com>
AuthorDate: Thu Jan 3 00:44:09 2019 +0800

    Modify license header
---
 .../apache/rocketmq/broker/processor/PullMessageProcessorTest.java    | 3 +++
 snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java    | 4 ++--
 snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java       | 4 ++--
 snode/src/main/java/org/apache/rocketmq/snode/client/PushSession.java | 4 ++--
 snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java | 4 ++--
 .../main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java   | 4 ++--
 .../main/java/org/apache/rocketmq/snode/exception/SnodeException.java | 4 ++--
 .../java/org/apache/rocketmq/snode/interceptor/ExceptionContext.java  | 4 ++--
 .../java/org/apache/rocketmq/snode/interceptor/InterceptorGroup.java  | 4 ++--
 .../java/org/apache/rocketmq/snode/interceptor/RequestContext.java    | 4 ++--
 .../java/org/apache/rocketmq/snode/interceptor/ResponseContext.java   | 4 ++--
 .../org/apache/rocketmq/snode/processor/PullMessageProcessor.java     | 4 ++--
 .../org/apache/rocketmq/snode/processor/SendMessageProcessor.java     | 4 ++--
 .../src/main/java/org/apache/rocketmq/snode/service/EnodeService.java | 4 ++--
 .../src/main/java/org/apache/rocketmq/snode/service/NnodeService.java | 4 ++--
 .../src/main/java/org/apache/rocketmq/snode/service/PushService.java  | 4 ++--
 .../main/java/org/apache/rocketmq/snode/service/ScheduledService.java | 4 ++--
 .../java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java | 4 ++--
 .../java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java | 4 ++--
 .../org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java  | 4 ++--
 20 files changed, 41 insertions(+), 38 deletions(-)

diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java
index 48d09bc..a5a32c4 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.rocketmq.broker.processor;
 
+import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandlerContext;
 import java.net.InetSocketAddress;
 import java.util.ArrayList;
@@ -70,6 +71,8 @@ public class PullMessageProcessorTest {
     @Mock
     private ChannelHandlerContext handlerContext;
     @Mock
+    private Channel channel;
+    @Mock
     private MessageStore messageStore;
     private ClientChannelInfo clientChannelInfo;
     private String group = "FooBarGroup";
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java b/snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
index 66d792d..0bc06e0 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode;
 import java.util.List;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.ExecutorService;
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java b/snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java
index f745ede..8e51f50 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode;
 import ch.qos.logback.classic.LoggerContext;
 import ch.qos.logback.classic.joran.JoranConfigurator;
 import ch.qos.logback.core.joran.spi.JoranException;
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/client/PushSession.java b/snode/src/main/java/org/apache/rocketmq/snode/client/PushSession.java
index c08bab5..7511025 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/client/PushSession.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/client/PushSession.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.client;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.client;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.client;
 import io.netty.channel.Channel;
 import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
 
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java b/snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java
index 6ef55b1..c171d9b 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.config;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.config;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.config;
 import org.apache.rocketmq.common.MixAll;
 import org.apache.rocketmq.common.annotation.ImportantField;
 import org.apache.rocketmq.common.constant.LoggerName;
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java b/snode/src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java
index 1f5c7dd..65838f3 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.constant;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.constant;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.constant;
 public class SnodeConstant {
     public static final long heartbeatTimeout = 3000;
 
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/exception/SnodeException.java b/snode/src/main/java/org/apache/rocketmq/snode/exception/SnodeException.java
index e9bd114..84cba64 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/exception/SnodeException.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/exception/SnodeException.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.exception;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.exception;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.exception;
 import org.apache.rocketmq.common.UtilAll;
 import org.apache.rocketmq.common.help.FAQUrl;
 
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/interceptor/ExceptionContext.java b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/ExceptionContext.java
index 569633d..192f249 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/interceptor/ExceptionContext.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/ExceptionContext.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.interceptor;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.interceptor;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.interceptor;
 import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/interceptor/InterceptorGroup.java b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/InterceptorGroup.java
index 4582894..fcee7a5 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/interceptor/InterceptorGroup.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/InterceptorGroup.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.interceptor;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.interceptor;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.interceptor;
 import java.util.ArrayList;
 import java.util.List;
 
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/interceptor/RequestContext.java b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/RequestContext.java
index 796358b..5f32e6b 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/interceptor/RequestContext.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/RequestContext.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.interceptor;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.interceptor;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.interceptor;
 import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/interceptor/ResponseContext.java b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/ResponseContext.java
index 2634426..9901981 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/interceptor/ResponseContext.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/ResponseContext.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.interceptor;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.interceptor;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.interceptor;
 import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java b/snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
index f5d080f..2abc196 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.processor;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.processor;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.processor;
 import java.util.concurrent.CompletableFuture;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.common.help.FAQUrl;
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java b/snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
index 2c45bb7..9477895 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.processor;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.processor;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.processor;
 import java.util.concurrent.CompletableFuture;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.InternalLogger;
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java b/snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java
index 4c3f894..0105027 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.service;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.service;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.service;
 import java.util.concurrent.CompletableFuture;
 import org.apache.rocketmq.client.exception.MQBrokerException;
 import org.apache.rocketmq.common.TopicConfig;
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/service/NnodeService.java b/snode/src/main/java/org/apache/rocketmq/snode/service/NnodeService.java
index 21bc6ed..b4da238 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/service/NnodeService.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/service/NnodeService.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.service;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.service;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.service;
 import java.util.Set;
 import org.apache.rocketmq.client.exception.MQClientException;
 import org.apache.rocketmq.common.protocol.body.ClusterInfo;
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/service/PushService.java b/snode/src/main/java/org/apache/rocketmq/snode/service/PushService.java
index e9bfe2b..5c0870a 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/service/PushService.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/service/PushService.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.service;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.service;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.service;
 import org.apache.rocketmq.common.message.Message;
 
 public interface PushService {
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/service/ScheduledService.java b/snode/src/main/java/org/apache/rocketmq/snode/service/ScheduledService.java
index dc86688..f332f81 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/service/ScheduledService.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/service/ScheduledService.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.service;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.service;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.service;
 public interface ScheduledService {
     void startScheduleTask();
     void shutdown();
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
index 5e28ebe..f6d157a 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.service.impl;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.service.impl;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.service.impl;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java
index 78fd624..286abc8 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.service.impl;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.service.impl;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.service.impl;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java
index 384a0c2..4de080b 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.service.impl;/*
+/*
  * 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.
@@ -14,7 +14,7 @@ package org.apache.rocketmq.snode.service.impl;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.service.impl;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ThreadFactory;


[rocketmq] 01/14: Refactor remoting module

Posted by du...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a commit to branch snode
in repository https://gitbox.apache.org/repos/asf/rocketmq.git

commit fa2f611470e9d1ca168270bb0d18217c96001897
Author: duhengforever <du...@gmail.com>
AuthorDate: Wed Dec 12 11:30:56 2018 +0800

    Refactor remoting module
---
 .../apache/rocketmq/broker/BrokerController.java   |  10 +-
 .../rocketmq/broker/client/ClientChannelInfo.java  |   2 +-
 .../broker/filter/ConsumerFilterManager.java       |   2 +-
 .../broker/offset/ConsumerOffsetManager.java       |   2 +-
 .../apache/rocketmq/broker/out/BrokerOuterAPI.java |  12 +-
 .../broker/pagecache/ManyMessageTransfer.java      |  30 +
 .../broker/pagecache/OneMessageTransfer.java       |  29 +
 .../broker/pagecache/QueryMessageTransfer.java     |  29 +
 .../broker/processor/AdminBrokerProcessor.java     |   4 +-
 .../subscription/SubscriptionGroupManager.java     |   2 +-
 .../apache/rocketmq/broker/BrokerOuterAPITest.java |   2 +-
 .../processor/ClientManageProcessorTest.java       |   6 +-
 .../processor/EndTransactionProcessorTest.java     |   2 +-
 .../broker/processor/PullMessageProcessorTest.java |   2 +-
 .../broker/processor/SendMessageProcessorTest.java |   6 +-
 .../org/apache/rocketmq/client/ClientConfig.java   |   2 +-
 .../consumer/store/OffsetSerializeWrapper.java     |   2 +-
 .../rocketmq/client/impl/MQClientAPIImpl.java      |   7 +-
 .../client/producer/DefaultMQProducer.java         |   1 -
 .../client/producer/DefaultMQProducerTest.java     |   2 +-
 .../org/apache/rocketmq/common/DataVersion.java    |   2 +-
 .../apache/rocketmq/common/admin/ConsumeStats.java |   2 +-
 .../rocketmq/common/admin/TopicStatsTable.java     |   2 +-
 .../rocketmq/common/protocol/MQProtosHelper.java   |  49 --
 .../common/protocol/body/BrokerStatsData.java      |   2 +-
 .../protocol/body/CheckClientRequestBody.java      |   2 +-
 .../rocketmq/common/protocol/body/ClusterInfo.java |   2 +-
 .../rocketmq/common/protocol/body/Connection.java  |   2 +-
 .../common/protocol/body/ConsumeByWho.java         |   2 +-
 .../body/ConsumeMessageDirectlyResult.java         |   2 +-
 .../common/protocol/body/ConsumeStatsList.java     |   2 +-
 .../common/protocol/body/ConsumerConnection.java   |   2 +-
 .../body/ConsumerOffsetSerializeWrapper.java       |   2 +-
 .../common/protocol/body/ConsumerRunningInfo.java  |   2 +-
 .../protocol/body/GetConsumerStatusBody.java       |   2 +-
 .../rocketmq/common/protocol/body/GroupList.java   |   2 +-
 .../rocketmq/common/protocol/body/KVTable.java     |   2 +-
 .../common/protocol/body/LockBatchRequestBody.java |   2 +-
 .../protocol/body/LockBatchResponseBody.java       |   2 +-
 .../common/protocol/body/ProducerConnection.java   |   2 +-
 .../body/QueryConsumeQueueResponseBody.java        |   2 +-
 .../protocol/body/QueryConsumeTimeSpanBody.java    |   2 +-
 .../protocol/body/QueryCorrectionOffsetBody.java   |   2 +-
 .../common/protocol/body/RegisterBrokerBody.java   |   2 +-
 .../common/protocol/body/ResetOffsetBody.java      |   2 +-
 .../common/protocol/body/ResetOffsetBodyForC.java  |   2 +-
 .../protocol/body/SubscriptionGroupWrapper.java    |   2 +-
 .../protocol/body/TopicConfigSerializeWrapper.java |   2 +-
 .../rocketmq/common/protocol/body/TopicList.java   |   2 +-
 .../protocol/body/UnlockBatchRequestBody.java      |   2 +-
 .../header/GetConsumerListByGroupResponseBody.java |   2 +-
 .../common/protocol/heartbeat/HeartbeatData.java   |   2 +-
 .../common/protocol/route/TopicRouteData.java      |   2 +-
 .../common/protocol/topic/OffsetMovedEvent.java    |   2 +-
 .../common/protocol/ConsumeStatusTest.java         |   2 +-
 .../apache/rocketmq/namesrv/NamesrvController.java |  10 +-
 .../namesrv/kvconfig/KVConfigSerializeWrapper.java |   2 +-
 .../namesrv/processor/DefaultRequestProcessor.java |   4 +-
 .../rocketmq/consumer/PullConsumerImpl.java        |   2 +-
 .../rocketmq/consumer/PushConsumerImpl.java        |   2 +-
 .../rocketmq/producer/AbstractOMSProducer.java     |   2 +-
 pom.xml                                            |   7 +-
 remoting/pom.xml                                   |   4 +
 .../apache/rocketmq/remoting/RemotingClient.java   |   3 +
 .../rocketmq/remoting/RemotingClientFactory.java   |  33 +
 .../apache/rocketmq/remoting/RemotingServer.java   |   5 +
 .../rocketmq/remoting/RemotingServerFactory.java   |  40 ++
 .../rocketmq/remoting/common/RemotingHelper.java   |  92 ---
 .../ChannelMetrics.java}                           |  13 +-
 .../remoting/netty/ChannelStatisticsHandler.java   |  60 ++
 .../rocketmq/remoting/netty/CodecHelper.java       | 283 ++++++++
 .../rocketmq/remoting/netty/FileRegionEncoder.java |   2 +-
 .../rocketmq/remoting/netty/NettyLogger.java       |  28 +-
 .../remoting/netty/NettyRemotingAbstract.java      |  67 +-
 .../remoting/netty/NettyRemotingClient.java        | 710 ---------------------
 .../rocketmq/remoting/netty/NettyServerConfig.java |  29 +-
 .../remoting/protocol/RemotingCommand.java         | 346 ++--------
 .../remoting/protocol/RemotingCommandType.java     |   2 +-
 .../{protocol => serialize}/LanguageCode.java      |   5 +-
 .../remoting/serialize/MsgPackSerializable.java    |  40 ++
 .../RemotingSerializable.java                      |  25 +-
 .../RocketMQSerializable.java                      |  26 +-
 .../{protocol => serialize}/SerializeType.java     |   8 +-
 .../Serializer.java}                               |  16 +-
 .../remoting/serialize/SerializerFactory.java      |  26 +
 .../transport/NettyRemotingClientAbstract.java     | 411 ++++++++++++
 .../transport/NettyRemotingServerAbstract.java     |  93 +++
 .../remoting/transport/http2/Http2ClientImpl.java  | 293 +++++++++
 .../remoting/transport/http2/Http2Handler.java     | 143 +++++
 .../remoting/transport/http2/Http2ServerImpl.java  | 242 +++++++
 .../rocketmq}/NettyDecoder.java                    |   6 +-
 .../rocketmq}/NettyEncoder.java                    |  10 +-
 .../transport/rocketmq/NettyRemotingClient.java    | 315 +++++++++
 .../rocketmq}/NettyRemotingServer.java             | 249 ++------
 .../apache/rocketmq/remoting/util/JvmUtils.java    |  94 +++
 .../rocketmq/remoting/util/RemotingUtil.java       |   6 +
 .../rocketmq/remoting/util/ServiceProvider.java    | 200 ++++++
 .../apache/rocketmq/remoting/util/ThreadUtils.java | 181 ++++++
 .../org.apache.rocketmq.remoting.RemotingClient    |   2 +
 .../org.apache.rocketmq.remoting.RemotingServer    |   2 +
 .../rocketmq/remoting/RemotingServerTest.java      |   6 +-
 .../java/org/apache/rocketmq/remoting/TlsTest.java |   4 +-
 .../remoting/netty/NettyRemotingAbstractTest.java  |   1 +
 .../remoting/netty/NettyRemotingClientTest.java    |   1 +
 .../remoting/protocol/RemotingCommandTest.java     |  95 +--
 .../protocol/RemotingSerializableTest.java         |   1 +
 .../protocol/RocketMQSerializableTest.java         |   3 +
 .../schedule/DelayOffsetSerializeWrapper.java      |   2 +-
 .../tools/command/topic/AllocateMQSubCommand.java  |   2 +-
 .../rocketmq/tools/monitor/MonitorServiceTest.java |   2 +-
 110 files changed, 2993 insertions(+), 1534 deletions(-)

diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
index e7ef46d..3e9762a 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
@@ -84,13 +84,14 @@ import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.RPCHook;
 import org.apache.rocketmq.remoting.RemotingServer;
+import org.apache.rocketmq.remoting.RemotingServerFactory;
 import org.apache.rocketmq.remoting.common.TlsMode;
 import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyRemotingServer;
 import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
 import org.apache.rocketmq.remoting.netty.NettyServerConfig;
 import org.apache.rocketmq.remoting.netty.RequestTask;
 import org.apache.rocketmq.remoting.netty.TlsSystemConfig;
+import org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingServer;
 import org.apache.rocketmq.srvutil.FileWatchService;
 import org.apache.rocketmq.store.DefaultMessageStore;
 import org.apache.rocketmq.store.MessageArrivingListener;
@@ -245,10 +246,15 @@ public class BrokerController {
         result = result && this.messageStore.load();
 
         if (result) {
-            this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.clientHousekeepingService);
+            this.remotingServer = RemotingServerFactory.getRemotingServer();
+            this.remotingServer.init(this.nettyServerConfig, this.clientHousekeepingService);
+//            this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.clientHousekeepingService);
             NettyServerConfig fastConfig = (NettyServerConfig) this.nettyServerConfig.clone();
             fastConfig.setListenPort(nettyServerConfig.getListenPort() - 2);
             this.fastRemotingServer = new NettyRemotingServer(fastConfig, this.clientHousekeepingService);
+//            this.fastRemotingServer = RemotingServerFactory.getRemotingServer();
+//            this.fastRemotingServer.init(this.nettyServerConfig, this.clientHousekeepingService);
+
             this.sendMessageExecutor = new BrokerFixedThreadPoolExecutor(
                 this.brokerConfig.getSendMessageThreadPoolNums(),
                 this.brokerConfig.getSendMessageThreadPoolNums(),
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ClientChannelInfo.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ClientChannelInfo.java
index edcba96..7c5e25b 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/ClientChannelInfo.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ClientChannelInfo.java
@@ -17,7 +17,7 @@
 package org.apache.rocketmq.broker.client;
 
 import io.netty.channel.Channel;
-import org.apache.rocketmq.remoting.protocol.LanguageCode;
+import org.apache.rocketmq.remoting.serialize.LanguageCode;
 
 public class ClientChannelInfo {
     private final Channel channel;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java b/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java
index e9c5286..fbaf337 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java
@@ -29,7 +29,7 @@ import org.apache.rocketmq.filter.FilterFactory;
 import org.apache.rocketmq.common.filter.ExpressionType;
 import org.apache.rocketmq.filter.util.BloomFilter;
 import org.apache.rocketmq.filter.util.BloomFilterData;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 import java.util.Collection;
 import java.util.HashSet;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java b/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java
index ebc9dd8..7c415f3 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java
@@ -31,7 +31,7 @@ import org.apache.rocketmq.common.UtilAll;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class ConsumerOffsetManager extends ConfigManager {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java b/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
index 4dee01c..d157021 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
@@ -31,8 +31,6 @@ import org.apache.rocketmq.common.MixAll;
 import org.apache.rocketmq.common.ThreadFactoryImpl;
 import org.apache.rocketmq.common.UtilAll;
 import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.logging.InternalLogger;
-import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.common.namesrv.RegisterBrokerResult;
 import org.apache.rocketmq.common.namesrv.TopAddressing;
 import org.apache.rocketmq.common.protocol.RequestCode;
@@ -47,15 +45,17 @@ import org.apache.rocketmq.common.protocol.header.namesrv.QueryDataVersionRespon
 import org.apache.rocketmq.common.protocol.header.namesrv.RegisterBrokerRequestHeader;
 import org.apache.rocketmq.common.protocol.header.namesrv.RegisterBrokerResponseHeader;
 import org.apache.rocketmq.common.protocol.header.namesrv.UnRegisterBrokerRequestHeader;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.RPCHook;
 import org.apache.rocketmq.remoting.RemotingClient;
+import org.apache.rocketmq.remoting.RemotingClientFactory;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
 import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyRemotingClient;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
 public class BrokerOuterAPI {
@@ -71,7 +71,9 @@ public class BrokerOuterAPI {
     }
 
     public BrokerOuterAPI(final NettyClientConfig nettyClientConfig, RPCHook rpcHook) {
-        this.remotingClient = new NettyRemotingClient(nettyClientConfig);
+        this.remotingClient = RemotingClientFactory.getClient();
+        this.remotingClient.init(nettyClientConfig, null);
+//        this.remotingClient = new NettyRemotingClient(nettyClientConfig);
         this.remotingClient.registerRPCHook(rpcHook);
     }
 
@@ -147,7 +149,7 @@ public class BrokerOuterAPI {
                     @Override
                     public void run() {
                         try {
-                            RegisterBrokerResult result = registerBroker(namesrvAddr,oneway, timeoutMills,requestHeader,body);
+                            RegisterBrokerResult result = registerBroker(namesrvAddr, oneway, timeoutMills, requestHeader, body);
                             if (result != null) {
                                 registerBrokerResultList.add(result);
                             }
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/pagecache/ManyMessageTransfer.java b/broker/src/main/java/org/apache/rocketmq/broker/pagecache/ManyMessageTransfer.java
index 968bcfb..849d205 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/pagecache/ManyMessageTransfer.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/pagecache/ManyMessageTransfer.java
@@ -84,4 +84,34 @@ public class ManyMessageTransfer extends AbstractReferenceCounted implements Fil
     protected void deallocate() {
         this.getMessageResult.release();
     }
+
+
+
+    @Override
+    public long transferred() {
+        return transferred;
+    }
+
+
+    @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;
+    }
 }
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/pagecache/OneMessageTransfer.java b/broker/src/main/java/org/apache/rocketmq/broker/pagecache/OneMessageTransfer.java
index b795d2d..18b57ad 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/pagecache/OneMessageTransfer.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/pagecache/OneMessageTransfer.java
@@ -73,4 +73,33 @@ public class OneMessageTransfer extends AbstractReferenceCounted implements File
     protected void deallocate() {
         this.selectMappedBufferResult.release();
     }
+
+
+    @Override
+    public long transferred() {
+        return transferred;
+    }
+
+
+    @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;
+    }
 }
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/pagecache/QueryMessageTransfer.java b/broker/src/main/java/org/apache/rocketmq/broker/pagecache/QueryMessageTransfer.java
index e8f3099..b02fb07 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/pagecache/QueryMessageTransfer.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/pagecache/QueryMessageTransfer.java
@@ -84,4 +84,33 @@ public class QueryMessageTransfer extends AbstractReferenceCounted implements Fi
     protected void deallocate() {
         this.queryMessageResult.release();
     }
+
+
+    @Override
+    public long transferred() {
+        return transferred;
+    }
+
+
+    @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;
+    }
 }
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
index 73fe439..341907a 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
@@ -107,9 +107,9 @@ import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
-import org.apache.rocketmq.remoting.protocol.LanguageCode;
+import org.apache.rocketmq.remoting.serialize.LanguageCode;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 import org.apache.rocketmq.store.ConsumeQueue;
 import org.apache.rocketmq.store.ConsumeQueueExt;
 import org.apache.rocketmq.store.DefaultMessageStore;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java b/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java
index 41f7a8a..3df07f8 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java
@@ -29,7 +29,7 @@ import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class SubscriptionGroupManager extends ConfigManager {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/BrokerOuterAPITest.java b/broker/src/test/java/org/apache/rocketmq/broker/BrokerOuterAPITest.java
index 68d58ef..30fe3a2 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/BrokerOuterAPITest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/BrokerOuterAPITest.java
@@ -32,9 +32,9 @@ import org.apache.rocketmq.common.protocol.body.TopicConfigSerializeWrapper;
 import org.apache.rocketmq.common.protocol.header.namesrv.QueryDataVersionResponseHeader;
 import org.apache.rocketmq.common.protocol.header.namesrv.RegisterBrokerResponseHeader;
 import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyRemotingClient;
 import org.apache.rocketmq.remoting.netty.NettyServerConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingClient;
 import org.apache.rocketmq.store.MessageStore;
 import org.apache.rocketmq.store.config.MessageStoreConfig;
 import org.junit.Test;
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/ClientManageProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/ClientManageProcessorTest.java
index 147c732..9ee9035 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/ClientManageProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/ClientManageProcessorTest.java
@@ -31,7 +31,7 @@ import org.apache.rocketmq.common.protocol.heartbeat.ConsumerData;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 import org.apache.rocketmq.remoting.netty.NettyClientConfig;
 import org.apache.rocketmq.remoting.netty.NettyServerConfig;
-import org.apache.rocketmq.remoting.protocol.LanguageCode;
+import org.apache.rocketmq.remoting.serialize.LanguageCode;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.store.config.MessageStoreConfig;
 import org.junit.Before;
@@ -115,7 +115,7 @@ public class ClientManageProcessorTest {
         RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UNREGISTER_CLIENT, requestHeader);
         request.setLanguage(LanguageCode.JAVA);
         request.setVersion(100);
-        request.makeCustomHeaderToNet();
+//        request.makeCustomHeaderToNet();
         return request;
     }
 
@@ -126,7 +126,7 @@ public class ClientManageProcessorTest {
         RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UNREGISTER_CLIENT, requestHeader);
         request.setLanguage(LanguageCode.JAVA);
         request.setVersion(100);
-        request.makeCustomHeaderToNet();
+//        request.makeCustomHeaderToNet();
         return request;
     }
 }
\ No newline at end of file
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/EndTransactionProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/EndTransactionProcessorTest.java
index 019cc6a..7d8aa13 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/EndTransactionProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/EndTransactionProcessorTest.java
@@ -146,7 +146,7 @@ public class EndTransactionProcessorTest {
     private RemotingCommand createEndTransactionMsgCommand(int status, boolean isCheckMsg) {
         EndTransactionRequestHeader header = createEndTransactionRequestHeader(status, isCheckMsg);
         RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.END_TRANSACTION, header);
-        request.makeCustomHeaderToNet();
+//        request.makeCustomHeaderToNet();
         return request;
     }
 }
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java
index c96f708..dc7b567 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java
@@ -204,7 +204,7 @@ public class PullMessageProcessorTest {
         requestHeader.setSysFlag(0);
         requestHeader.setSubVersion(100L);
         RemotingCommand request = RemotingCommand.createRequestCommand(requestCode, requestHeader);
-        request.makeCustomHeaderToNet();
+//        request.makeCustomHeaderToNet();
         return request;
     }
 
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/SendMessageProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/SendMessageProcessorTest.java
index 792fd0f..2f56422 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/SendMessageProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/SendMessageProcessorTest.java
@@ -217,7 +217,7 @@ public class SendMessageProcessorTest {
         header.setSysFlag(sysFlag);
         RemotingCommand request = RemotingCommand.createRequestCommand(requestCode, header);
         request.setBody(new byte[] {'a'});
-        request.makeCustomHeaderToNet();
+//        request.makeCustomHeaderToNet();
         return request;
     }
 
@@ -240,7 +240,7 @@ public class SendMessageProcessorTest {
 
         RemotingCommand request = RemotingCommand.createRequestCommand(requestCode, requestHeader);
         request.setBody(new byte[] {'a'});
-        request.makeCustomHeaderToNet();
+//        request.makeCustomHeaderToNet();
         return request;
     }
 
@@ -253,7 +253,7 @@ public class SendMessageProcessorTest {
         requestHeader.setOffset(123L);
 
         RemotingCommand request = RemotingCommand.createRequestCommand(requestCode, requestHeader);
-        request.makeCustomHeaderToNet();
+//        request.makeCustomHeaderToNet();
         return request;
     }
 
diff --git a/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java b/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java
index d798164..562810f 100644
--- a/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java
+++ b/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java
@@ -20,7 +20,7 @@ import org.apache.rocketmq.common.MixAll;
 import org.apache.rocketmq.common.UtilAll;
 import org.apache.rocketmq.remoting.common.RemotingUtil;
 import org.apache.rocketmq.remoting.netty.TlsSystemConfig;
-import org.apache.rocketmq.remoting.protocol.LanguageCode;
+import org.apache.rocketmq.remoting.serialize.LanguageCode;
 
 /**
  * Client Common configuration
diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/store/OffsetSerializeWrapper.java b/client/src/main/java/org/apache/rocketmq/client/consumer/store/OffsetSerializeWrapper.java
index 7dfd97a..2c8d973 100644
--- a/client/src/main/java/org/apache/rocketmq/client/consumer/store/OffsetSerializeWrapper.java
+++ b/client/src/main/java/org/apache/rocketmq/client/consumer/store/OffsetSerializeWrapper.java
@@ -20,7 +20,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicLong;
 import org.apache.rocketmq.common.message.MessageQueue;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 /**
  * Wrapper class for offset serialization
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
index 1837204..0fa1ae7 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
@@ -146,11 +146,11 @@ import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
 import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyRemotingClient;
 import org.apache.rocketmq.remoting.netty.ResponseFuture;
-import org.apache.rocketmq.remoting.protocol.LanguageCode;
+import org.apache.rocketmq.remoting.serialize.LanguageCode;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
+import org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingClient;
 
 public class MQClientAPIImpl {
 
@@ -1210,6 +1210,7 @@ public class MQClientAPIImpl {
         RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINTO_BY_TOPIC, requestHeader);
 
         RemotingCommand response = this.remotingClient.invokeSync(null, request, timeoutMillis);
+        log.info("getTopicRouteInfoFromNameServer response: " + response);
         assert response != null;
         switch (response.getCode()) {
             case ResponseCode.TOPIC_NOT_EXIST: {
diff --git a/client/src/main/java/org/apache/rocketmq/client/producer/DefaultMQProducer.java b/client/src/main/java/org/apache/rocketmq/client/producer/DefaultMQProducer.java
index 9732d0e..2e6078f 100644
--- a/client/src/main/java/org/apache/rocketmq/client/producer/DefaultMQProducer.java
+++ b/client/src/main/java/org/apache/rocketmq/client/producer/DefaultMQProducer.java
@@ -35,7 +35,6 @@ import org.apache.rocketmq.common.message.MessageId;
 import org.apache.rocketmq.common.message.MessageQueue;
 import org.apache.rocketmq.remoting.RPCHook;
 import org.apache.rocketmq.remoting.exception.RemotingException;
-import org.apache.rocketmq.remoting.netty.NettyRemotingClient;
 
 /**
  * This class is the entry point for applications intending to send messages.
diff --git a/client/src/test/java/org/apache/rocketmq/client/producer/DefaultMQProducerTest.java b/client/src/test/java/org/apache/rocketmq/client/producer/DefaultMQProducerTest.java
index c225afd..49223f0 100644
--- a/client/src/test/java/org/apache/rocketmq/client/producer/DefaultMQProducerTest.java
+++ b/client/src/test/java/org/apache/rocketmq/client/producer/DefaultMQProducerTest.java
@@ -45,7 +45,7 @@ import org.apache.rocketmq.common.protocol.route.BrokerData;
 import org.apache.rocketmq.common.protocol.route.QueueData;
 import org.apache.rocketmq.common.protocol.route.TopicRouteData;
 import org.apache.rocketmq.remoting.exception.RemotingException;
-import org.apache.rocketmq.remoting.netty.NettyRemotingClient;
+import org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingClient;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
diff --git a/common/src/main/java/org/apache/rocketmq/common/DataVersion.java b/common/src/main/java/org/apache/rocketmq/common/DataVersion.java
index e54000d..a2756e8 100644
--- a/common/src/main/java/org/apache/rocketmq/common/DataVersion.java
+++ b/common/src/main/java/org/apache/rocketmq/common/DataVersion.java
@@ -17,7 +17,7 @@
 package org.apache.rocketmq.common;
 
 import java.util.concurrent.atomic.AtomicLong;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class DataVersion extends RemotingSerializable {
     private long timestamp = System.currentTimeMillis();
diff --git a/common/src/main/java/org/apache/rocketmq/common/admin/ConsumeStats.java b/common/src/main/java/org/apache/rocketmq/common/admin/ConsumeStats.java
index 6b1c492..a4d14a6 100644
--- a/common/src/main/java/org/apache/rocketmq/common/admin/ConsumeStats.java
+++ b/common/src/main/java/org/apache/rocketmq/common/admin/ConsumeStats.java
@@ -20,7 +20,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map.Entry;
 import org.apache.rocketmq.common.message.MessageQueue;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class ConsumeStats extends RemotingSerializable {
     private HashMap<MessageQueue, OffsetWrapper> offsetTable = new HashMap<MessageQueue, OffsetWrapper>();
diff --git a/common/src/main/java/org/apache/rocketmq/common/admin/TopicStatsTable.java b/common/src/main/java/org/apache/rocketmq/common/admin/TopicStatsTable.java
index 729075c..e30fd78 100644
--- a/common/src/main/java/org/apache/rocketmq/common/admin/TopicStatsTable.java
+++ b/common/src/main/java/org/apache/rocketmq/common/admin/TopicStatsTable.java
@@ -18,7 +18,7 @@ package org.apache.rocketmq.common.admin;
 
 import java.util.HashMap;
 import org.apache.rocketmq.common.message.MessageQueue;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class TopicStatsTable extends RemotingSerializable {
     private HashMap<MessageQueue, TopicOffset> offsetTable = new HashMap<MessageQueue, TopicOffset>();
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/MQProtosHelper.java b/common/src/main/java/org/apache/rocketmq/common/protocol/MQProtosHelper.java
deleted file mode 100644
index d8c1ced..0000000
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/MQProtosHelper.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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;
-
-import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.logging.InternalLogger;
-import org.apache.rocketmq.logging.InternalLoggerFactory;
-import org.apache.rocketmq.common.protocol.header.namesrv.RegisterBrokerRequestHeader;
-import org.apache.rocketmq.remoting.common.RemotingHelper;
-import org.apache.rocketmq.remoting.protocol.RemotingCommand;
-
-public class MQProtosHelper {
-    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.COMMON_LOGGER_NAME);
-
-    public static boolean registerBrokerToNameServer(final String nsaddr, final String brokerAddr,
-        final long timeoutMillis) {
-        RegisterBrokerRequestHeader requestHeader = new RegisterBrokerRequestHeader();
-        requestHeader.setBrokerAddr(brokerAddr);
-
-        RemotingCommand request =
-            RemotingCommand.createRequestCommand(RequestCode.REGISTER_BROKER, requestHeader);
-
-        try {
-            RemotingCommand response = RemotingHelper.invokeSync(nsaddr, request, timeoutMillis);
-            if (response != null) {
-                return ResponseCode.SUCCESS == response.getCode();
-            }
-        } catch (Exception e) {
-            log.error("Failed to register broker", e);
-        }
-
-        return false;
-    }
-}
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/BrokerStatsData.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/BrokerStatsData.java
index c4ff63d..4a6e0ae 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/BrokerStatsData.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/BrokerStatsData.java
@@ -17,7 +17,7 @@
 
 package org.apache.rocketmq.common.protocol.body;
 
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class BrokerStatsData extends RemotingSerializable {
 
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/CheckClientRequestBody.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/CheckClientRequestBody.java
index a78ce55..b98ce95 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/CheckClientRequestBody.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/CheckClientRequestBody.java
@@ -18,7 +18,7 @@
 package org.apache.rocketmq.common.protocol.body;
 
 import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class CheckClientRequestBody extends RemotingSerializable {
 
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ClusterInfo.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ClusterInfo.java
index 76c64a8..566bf93 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ClusterInfo.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ClusterInfo.java
@@ -22,7 +22,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Set;
 import org.apache.rocketmq.common.protocol.route.BrokerData;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class ClusterInfo extends RemotingSerializable {
     private HashMap<String/* brokerName */, BrokerData> brokerAddrTable;
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/Connection.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/Connection.java
index b42737f..dd0bf81 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/Connection.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/Connection.java
@@ -17,7 +17,7 @@
 
 package org.apache.rocketmq.common.protocol.body;
 
-import org.apache.rocketmq.remoting.protocol.LanguageCode;
+import org.apache.rocketmq.remoting.serialize.LanguageCode;
 
 public class Connection {
     private String clientId;
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeByWho.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeByWho.java
index 7b20d76..f600991 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeByWho.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeByWho.java
@@ -17,7 +17,7 @@
 package org.apache.rocketmq.common.protocol.body;
 
 import java.util.HashSet;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class ConsumeByWho extends RemotingSerializable {
     private HashSet<String> consumedGroup = new HashSet<String>();
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeMessageDirectlyResult.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeMessageDirectlyResult.java
index 674df60..02e37af 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeMessageDirectlyResult.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeMessageDirectlyResult.java
@@ -17,7 +17,7 @@
 
 package org.apache.rocketmq.common.protocol.body;
 
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class ConsumeMessageDirectlyResult extends RemotingSerializable {
     private boolean order = false;
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeStatsList.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeStatsList.java
index 7b35a80..28c5a7d 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeStatsList.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeStatsList.java
@@ -20,7 +20,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import org.apache.rocketmq.common.admin.ConsumeStats;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class ConsumeStatsList extends RemotingSerializable {
     private List<Map<String/*subscriptionGroupName*/, List<ConsumeStats>>> consumeStatsList = new ArrayList<Map<String/*subscriptionGroupName*/, List<ConsumeStats>>>();
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerConnection.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerConnection.java
index 3a0356c..d3ac81e 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerConnection.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerConnection.java
@@ -24,7 +24,7 @@ import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
 import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
 import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
 import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class ConsumerConnection extends RemotingSerializable {
     private HashSet<Connection> connectionSet = new HashSet<Connection>();
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerOffsetSerializeWrapper.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerOffsetSerializeWrapper.java
index 5b08d78..9fe7382 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerOffsetSerializeWrapper.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerOffsetSerializeWrapper.java
@@ -19,7 +19,7 @@ package org.apache.rocketmq.common.protocol.body;
 
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class ConsumerOffsetSerializeWrapper extends RemotingSerializable {
     private ConcurrentMap<String/* topic@group */, ConcurrentMap<Integer, Long>> offsetTable =
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerRunningInfo.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerRunningInfo.java
index d7942eb..c0be419 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerRunningInfo.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerRunningInfo.java
@@ -25,7 +25,7 @@ import java.util.TreeSet;
 import org.apache.rocketmq.common.message.MessageQueue;
 import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
 import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class ConsumerRunningInfo extends RemotingSerializable {
     public static final String PROP_NAMESERVER_ADDR = "PROP_NAMESERVER_ADDR";
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/GetConsumerStatusBody.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/GetConsumerStatusBody.java
index 6234a77..f654843 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/GetConsumerStatusBody.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/GetConsumerStatusBody.java
@@ -20,7 +20,7 @@ package org.apache.rocketmq.common.protocol.body;
 import java.util.HashMap;
 import java.util.Map;
 import org.apache.rocketmq.common.message.MessageQueue;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 @Deprecated
 public class GetConsumerStatusBody extends RemotingSerializable {
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/GroupList.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/GroupList.java
index 862a739..97ffb74 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/GroupList.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/GroupList.java
@@ -17,7 +17,7 @@
 package org.apache.rocketmq.common.protocol.body;
 
 import java.util.HashSet;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class GroupList extends RemotingSerializable {
     private HashSet<String> groupList = new HashSet<String>();
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/KVTable.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/KVTable.java
index 28aafc4..e1290fd 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/KVTable.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/KVTable.java
@@ -17,7 +17,7 @@
 package org.apache.rocketmq.common.protocol.body;
 
 import java.util.HashMap;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class KVTable extends RemotingSerializable {
     private HashMap<String, String> table = new HashMap<String, String>();
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/LockBatchRequestBody.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/LockBatchRequestBody.java
index 480862b..0851687 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/LockBatchRequestBody.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/LockBatchRequestBody.java
@@ -20,7 +20,7 @@ package org.apache.rocketmq.common.protocol.body;
 import java.util.HashSet;
 import java.util.Set;
 import org.apache.rocketmq.common.message.MessageQueue;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class LockBatchRequestBody extends RemotingSerializable {
     private String consumerGroup;
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/LockBatchResponseBody.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/LockBatchResponseBody.java
index 5018f20..56bd1a4 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/LockBatchResponseBody.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/LockBatchResponseBody.java
@@ -20,7 +20,7 @@ package org.apache.rocketmq.common.protocol.body;
 import java.util.HashSet;
 import java.util.Set;
 import org.apache.rocketmq.common.message.MessageQueue;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class LockBatchResponseBody extends RemotingSerializable {
 
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ProducerConnection.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ProducerConnection.java
index 14d7110..b5d3a2e 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ProducerConnection.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ProducerConnection.java
@@ -18,7 +18,7 @@
 package org.apache.rocketmq.common.protocol.body;
 
 import java.util.HashSet;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class ProducerConnection extends RemotingSerializable {
     private HashSet<Connection> connectionSet = new HashSet<Connection>();
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryConsumeQueueResponseBody.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryConsumeQueueResponseBody.java
index be93da9..7f53e05 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryConsumeQueueResponseBody.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryConsumeQueueResponseBody.java
@@ -18,7 +18,7 @@
 package org.apache.rocketmq.common.protocol.body;
 
 import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 import java.util.List;
 
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryConsumeTimeSpanBody.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryConsumeTimeSpanBody.java
index cae2109..82b4e85 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryConsumeTimeSpanBody.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryConsumeTimeSpanBody.java
@@ -19,7 +19,7 @@ package org.apache.rocketmq.common.protocol.body;
 
 import java.util.ArrayList;
 import java.util.List;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class QueryConsumeTimeSpanBody extends RemotingSerializable {
     List<QueueTimeSpan> consumeTimeSpanSet = new ArrayList<QueueTimeSpan>();
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryCorrectionOffsetBody.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryCorrectionOffsetBody.java
index f7c866a..c7ccd12 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryCorrectionOffsetBody.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryCorrectionOffsetBody.java
@@ -18,7 +18,7 @@ package org.apache.rocketmq.common.protocol.body;
 
 import java.util.HashMap;
 import java.util.Map;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class QueryCorrectionOffsetBody extends RemotingSerializable {
     private Map<Integer, Long> correctionOffsets = new HashMap<Integer, Long>();
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/RegisterBrokerBody.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/RegisterBrokerBody.java
index 4065c08..d3f8833 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/RegisterBrokerBody.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/RegisterBrokerBody.java
@@ -36,7 +36,7 @@ import org.apache.rocketmq.common.TopicConfig;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class RegisterBrokerBody extends RemotingSerializable {
 
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ResetOffsetBody.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ResetOffsetBody.java
index b28e74b..df72758 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ResetOffsetBody.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ResetOffsetBody.java
@@ -19,7 +19,7 @@ package org.apache.rocketmq.common.protocol.body;
 
 import java.util.Map;
 import org.apache.rocketmq.common.message.MessageQueue;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class ResetOffsetBody extends RemotingSerializable {
     private Map<MessageQueue, Long> offsetTable;
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ResetOffsetBodyForC.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ResetOffsetBodyForC.java
index fa812ed..e15322f 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ResetOffsetBodyForC.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ResetOffsetBodyForC.java
@@ -19,7 +19,7 @@ package org.apache.rocketmq.common.protocol.body;
 
 import java.util.List;
 import org.apache.rocketmq.common.message.MessageQueueForC;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class ResetOffsetBodyForC extends RemotingSerializable {
 
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/SubscriptionGroupWrapper.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/SubscriptionGroupWrapper.java
index e05f759..d966980 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/SubscriptionGroupWrapper.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/SubscriptionGroupWrapper.java
@@ -21,7 +21,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import org.apache.rocketmq.common.DataVersion;
 import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class SubscriptionGroupWrapper extends RemotingSerializable {
     private ConcurrentMap<String, SubscriptionGroupConfig> subscriptionGroupTable =
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/TopicConfigSerializeWrapper.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/TopicConfigSerializeWrapper.java
index ce12302..d944b27 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/TopicConfigSerializeWrapper.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/TopicConfigSerializeWrapper.java
@@ -21,7 +21,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import org.apache.rocketmq.common.DataVersion;
 import org.apache.rocketmq.common.TopicConfig;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class TopicConfigSerializeWrapper extends RemotingSerializable {
     private ConcurrentMap<String, TopicConfig> topicConfigTable =
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/TopicList.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/TopicList.java
index baf8312..3a3e13e 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/TopicList.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/TopicList.java
@@ -18,7 +18,7 @@ package org.apache.rocketmq.common.protocol.body;
 
 import java.util.HashSet;
 import java.util.Set;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class TopicList extends RemotingSerializable {
     private Set<String> topicList = new HashSet<String>();
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/UnlockBatchRequestBody.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/UnlockBatchRequestBody.java
index baf4071..d8c73a2 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/UnlockBatchRequestBody.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/UnlockBatchRequestBody.java
@@ -20,7 +20,7 @@ package org.apache.rocketmq.common.protocol.body;
 import java.util.HashSet;
 import java.util.Set;
 import org.apache.rocketmq.common.message.MessageQueue;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class UnlockBatchRequestBody extends RemotingSerializable {
     private String consumerGroup;
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerListByGroupResponseBody.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerListByGroupResponseBody.java
index da39e77..2ab1578 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerListByGroupResponseBody.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetConsumerListByGroupResponseBody.java
@@ -18,7 +18,7 @@
 package org.apache.rocketmq.common.protocol.header;
 
 import java.util.List;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class GetConsumerListByGroupResponseBody extends RemotingSerializable {
     private List<String> consumerIdList;
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/HeartbeatData.java b/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/HeartbeatData.java
index 47ae542..03151f5 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/HeartbeatData.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/HeartbeatData.java
@@ -22,7 +22,7 @@ package org.apache.rocketmq.common.protocol.heartbeat;
 
 import java.util.HashSet;
 import java.util.Set;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class HeartbeatData extends RemotingSerializable {
     private String clientID;
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/route/TopicRouteData.java b/common/src/main/java/org/apache/rocketmq/common/protocol/route/TopicRouteData.java
index e8f54b8..ed9d644 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/route/TopicRouteData.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/route/TopicRouteData.java
@@ -23,7 +23,7 @@ package org.apache.rocketmq.common.protocol.route;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class TopicRouteData extends RemotingSerializable {
     private String orderTopicConf;
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/topic/OffsetMovedEvent.java b/common/src/main/java/org/apache/rocketmq/common/protocol/topic/OffsetMovedEvent.java
index 1c03c07..a769f95 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/topic/OffsetMovedEvent.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/topic/OffsetMovedEvent.java
@@ -18,7 +18,7 @@
 package org.apache.rocketmq.common.protocol.topic;
 
 import org.apache.rocketmq.common.message.MessageQueue;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class OffsetMovedEvent extends RemotingSerializable {
     private String consumerGroup;
diff --git a/common/src/test/java/org/apache/rocketmq/common/protocol/ConsumeStatusTest.java b/common/src/test/java/org/apache/rocketmq/common/protocol/ConsumeStatusTest.java
index 4a2e790..5f22d82 100644
--- a/common/src/test/java/org/apache/rocketmq/common/protocol/ConsumeStatusTest.java
+++ b/common/src/test/java/org/apache/rocketmq/common/protocol/ConsumeStatusTest.java
@@ -18,7 +18,7 @@
 package org.apache.rocketmq.common.protocol;
 
 import org.apache.rocketmq.common.protocol.body.ConsumeStatus;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 import org.junit.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java
index a6654f2..6faccf7 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java
@@ -32,13 +32,13 @@ import org.apache.rocketmq.namesrv.processor.DefaultRequestProcessor;
 import org.apache.rocketmq.namesrv.routeinfo.BrokerHousekeepingService;
 import org.apache.rocketmq.namesrv.routeinfo.RouteInfoManager;
 import org.apache.rocketmq.remoting.RemotingServer;
+import org.apache.rocketmq.remoting.RemotingServerFactory;
 import org.apache.rocketmq.remoting.common.TlsMode;
-import org.apache.rocketmq.remoting.netty.NettyRemotingServer;
 import org.apache.rocketmq.remoting.netty.NettyServerConfig;
 import org.apache.rocketmq.remoting.netty.TlsSystemConfig;
+import org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingServer;
 import org.apache.rocketmq.srvutil.FileWatchService;
 
-
 public class NamesrvController {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME);
 
@@ -77,7 +77,9 @@ public class NamesrvController {
 
         this.kvConfigManager.load();
 
-        this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.brokerHousekeepingService);
+        this.remotingServer = RemotingServerFactory.getRemotingServer();
+        this.remotingServer.init(this.nettyServerConfig, this.brokerHousekeepingService);
+//        this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.brokerHousekeepingService);
 
         this.remotingExecutor =
             Executors.newFixedThreadPool(nettyServerConfig.getServerWorkerThreads(), new ThreadFactoryImpl("RemotingExecutorThread_"));
@@ -111,6 +113,7 @@ public class NamesrvController {
                     },
                     new FileWatchService.Listener() {
                         boolean certChanged, keyChanged = false;
+
                         @Override
                         public void onChanged(String path) {
                             if (path.equals(TlsSystemConfig.tlsServerTrustCertPath)) {
@@ -129,6 +132,7 @@ public class NamesrvController {
                                 reloadServerSslContext();
                             }
                         }
+
                         private void reloadServerSslContext() {
                             ((NettyRemotingServer) remotingServer).loadSslContext();
                         }
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/kvconfig/KVConfigSerializeWrapper.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/kvconfig/KVConfigSerializeWrapper.java
index 3b53e19..59b2161 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/kvconfig/KVConfigSerializeWrapper.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/kvconfig/KVConfigSerializeWrapper.java
@@ -17,7 +17,7 @@
 package org.apache.rocketmq.namesrv.kvconfig;
 
 import java.util.HashMap;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class KVConfigSerializeWrapper extends RemotingSerializable {
     private HashMap<String/* Namespace */, HashMap<String/* Key */, String/* Value */>> configTable;
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
index 467078c..dc32445 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
@@ -69,7 +69,7 @@ public class DefaultRequestProcessor implements NettyRequestProcessor {
     @Override
     public RemotingCommand processRequest(ChannelHandlerContext ctx,
         RemotingCommand request) throws RemotingCommandException {
-
+        log.info("receive remoting command: " + request);
         if (ctx != null) {
             log.debug("receive request, {} {} {}",
                 request.getCode(),
@@ -280,7 +280,7 @@ public class DefaultRequestProcessor implements NettyRequestProcessor {
         final RegisterBrokerResponseHeader responseHeader = (RegisterBrokerResponseHeader) response.readCustomHeader();
         final RegisterBrokerRequestHeader requestHeader =
             (RegisterBrokerRequestHeader) request.decodeCommandCustomHeader(RegisterBrokerRequestHeader.class);
-
+        log.info("requestHeader:  " + requestHeader );
         if (!checksum(ctx, request, requestHeader)) {
             response.setCode(ResponseCode.SYSTEM_ERROR);
             response.setRemark("crc32 not match");
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PullConsumerImpl.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PullConsumerImpl.java
index d673510..1ce127f 100644
--- a/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PullConsumerImpl.java
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PullConsumerImpl.java
@@ -37,7 +37,7 @@ import org.apache.rocketmq.client.log.ClientLogger;
 import org.apache.rocketmq.common.message.MessageExt;
 import org.apache.rocketmq.common.message.MessageQueue;
 import org.apache.rocketmq.logging.InternalLogger;
-import org.apache.rocketmq.remoting.protocol.LanguageCode;
+import org.apache.rocketmq.remoting.serialize.LanguageCode;
 
 public class PullConsumerImpl implements PullConsumer {
     private final DefaultMQPullConsumer rocketmqPullConsumer;
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PushConsumerImpl.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PushConsumerImpl.java
index d5d394a..46f9a45 100644
--- a/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PushConsumerImpl.java
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PushConsumerImpl.java
@@ -39,7 +39,7 @@ import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
 import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
 import org.apache.rocketmq.client.exception.MQClientException;
 import org.apache.rocketmq.common.message.MessageExt;
-import org.apache.rocketmq.remoting.protocol.LanguageCode;
+import org.apache.rocketmq.remoting.serialize.LanguageCode;
 
 public class PushConsumerImpl implements PushConsumer {
     private final DefaultMQPushConsumer rocketmqPushConsumer;
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/AbstractOMSProducer.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/AbstractOMSProducer.java
index 3db8590..95daef3 100644
--- a/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/AbstractOMSProducer.java
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/AbstractOMSProducer.java
@@ -37,7 +37,7 @@ import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.common.protocol.ResponseCode;
 import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
-import org.apache.rocketmq.remoting.protocol.LanguageCode;
+import org.apache.rocketmq.remoting.serialize.LanguageCode;
 
 import static io.openmessaging.rocketmq.utils.OMSUtil.buildInstanceName;
 
diff --git a/pom.xml b/pom.xml
index 0a8fef8..0a8a41e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -544,7 +544,7 @@
             <dependency>
                 <groupId>io.netty</groupId>
                 <artifactId>netty-all</artifactId>
-                <version>4.0.42.Final</version>
+                <version>4.1.32.Final</version>
             </dependency>
             <dependency>
                 <groupId>com.alibaba</groupId>
@@ -552,6 +552,11 @@
                 <version>1.2.51</version>
             </dependency>
             <dependency>
+                <groupId>org.msgpack</groupId>
+                <artifactId>msgpack</artifactId>
+                <version>0.6.12</version>
+            </dependency>
+            <dependency>
                 <groupId>org.javassist</groupId>
                 <artifactId>javassist</artifactId>
                 <version>3.20.0-GA</version>
diff --git a/remoting/pom.xml b/remoting/pom.xml
index 55d92f3..26e5bfc 100644
--- a/remoting/pom.xml
+++ b/remoting/pom.xml
@@ -38,6 +38,10 @@
             <artifactId>fastjson</artifactId>
         </dependency>
         <dependency>
+        <groupId>org.msgpack</groupId>
+        <artifactId>msgpack</artifactId>
+        </dependency>
+        <dependency>
             <groupId>io.netty</groupId>
             <artifactId>netty-all</artifactId>
         </dependency>
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java
index c0754db..ab4e914 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java
@@ -22,6 +22,7 @@ import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
+import org.apache.rocketmq.remoting.netty.NettyClientConfig;
 import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
@@ -51,4 +52,6 @@ public interface RemotingClient extends RemotingService {
     ExecutorService getCallbackExecutor();
 
     boolean isChannelWritable(final String addr);
+
+    void init(NettyClientConfig nettyClientConfig, ChannelEventListener channelEventListener);
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClientFactory.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClientFactory.java
new file mode 100644
index 0000000..5e87ec9
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClientFactory.java
@@ -0,0 +1,33 @@
+package org.apache.rocketmq.remoting;
+
+import java.util.Map;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.util.RemotingUtil;
+import org.apache.rocketmq.remoting.util.ServiceProvider;
+
+public class RemotingClientFactory {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
+
+    private RemotingClientFactory() {
+    }
+
+    private static Map<String, RemotingClient> clients;
+
+    private static final String CLIENT_LOCATION = "META-INF/service/org.apache.rocketmq.remoting.RemotingClient";
+
+    static {
+        log.info("begin load client");
+        clients = ServiceProvider.load(CLIENT_LOCATION, RemotingClient.class);
+        log.info("end load client, size:{}", clients.size());
+    }
+
+    public static RemotingClient getClient(String protocolType) {
+        return clients.get(protocolType);
+    }
+
+    public static RemotingClient getClient() {
+        return clients.get(RemotingUtil.DEFAULT_PROTOCOL);
+    }
+}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java
index a12c089..6a5fb91 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java
@@ -23,6 +23,7 @@ import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
 import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.netty.NettyServerConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
 public interface RemotingServer extends RemotingService {
@@ -36,6 +37,8 @@ public interface RemotingServer extends RemotingService {
 
     Pair<NettyRequestProcessor, ExecutorService> getProcessorPair(final int requestCode);
 
+    void push(final String addr, final String sessionId, RemotingCommand remotingCommand);
+
     RemotingCommand invokeSync(final Channel channel, final RemotingCommand request,
         final long timeoutMillis) throws InterruptedException, RemotingSendRequestException,
         RemotingTimeoutException;
@@ -48,4 +51,6 @@ public interface RemotingServer extends RemotingService {
         throws InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException,
         RemotingSendRequestException;
 
+    void init(NettyServerConfig nettyServerConfig, ChannelEventListener channelEventListener);
+
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java
new file mode 100644
index 0000000..e7a7700
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java
@@ -0,0 +1,40 @@
+package org.apache.rocketmq.remoting;
+
+import java.util.Map;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.util.RemotingUtil;
+import org.apache.rocketmq.remoting.util.ServiceProvider;
+
+public class RemotingServerFactory {
+
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
+
+    private RemotingServerFactory() {
+    }
+
+    private static Map<String, RemotingServer> servers;
+
+//    private static Map<String/*protocolType*/, String/*path*/ >
+
+    private static final String SERVER_LOCATION = "META-INF/service/org.apache.rocketmq.remoting.RemotingServer";
+
+    static {
+        log.info("begin load server");
+        servers = ServiceProvider.load(SERVER_LOCATION, RemotingClient.class);
+        log.info("end load server, size:{}", servers.size());
+    }
+
+    public static RemotingServer getRemotingServer() {
+        return getRemotingServer(RemotingUtil.DEFAULT_PROTOCOL);
+    }
+
+    public static RemotingServer getRemotingServer(String protocolType) {
+        return servers.get(protocolType);
+    }
+
+//    public static RemotingServer createNewInstance(String protocolType){
+//        return ServiceProvider.load()
+//    }
+}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingHelper.java b/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingHelper.java
index 585b60b..0414996 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingHelper.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingHelper.java
@@ -58,98 +58,6 @@ public class RemotingHelper {
         return isa;
     }
 
-    public static RemotingCommand invokeSync(final String addr, final RemotingCommand request,
-        final long timeoutMillis) throws InterruptedException, RemotingConnectException,
-        RemotingSendRequestException, RemotingTimeoutException {
-        long beginTime = System.currentTimeMillis();
-        SocketAddress socketAddress = RemotingUtil.string2SocketAddress(addr);
-        SocketChannel socketChannel = RemotingUtil.connect(socketAddress);
-        if (socketChannel != null) {
-            boolean sendRequestOK = false;
-
-            try {
-
-                socketChannel.configureBlocking(true);
-
-                //bugfix  http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4614802
-                socketChannel.socket().setSoTimeout((int) timeoutMillis);
-
-                ByteBuffer byteBufferRequest = request.encode();
-                while (byteBufferRequest.hasRemaining()) {
-                    int length = socketChannel.write(byteBufferRequest);
-                    if (length > 0) {
-                        if (byteBufferRequest.hasRemaining()) {
-                            if ((System.currentTimeMillis() - beginTime) > timeoutMillis) {
-
-                                throw new RemotingSendRequestException(addr);
-                            }
-                        }
-                    } else {
-                        throw new RemotingSendRequestException(addr);
-                    }
-
-                    Thread.sleep(1);
-                }
-
-                sendRequestOK = true;
-
-                ByteBuffer byteBufferSize = ByteBuffer.allocate(4);
-                while (byteBufferSize.hasRemaining()) {
-                    int length = socketChannel.read(byteBufferSize);
-                    if (length > 0) {
-                        if (byteBufferSize.hasRemaining()) {
-                            if ((System.currentTimeMillis() - beginTime) > timeoutMillis) {
-
-                                throw new RemotingTimeoutException(addr, timeoutMillis);
-                            }
-                        }
-                    } else {
-                        throw new RemotingTimeoutException(addr, timeoutMillis);
-                    }
-
-                    Thread.sleep(1);
-                }
-
-                int size = byteBufferSize.getInt(0);
-                ByteBuffer byteBufferBody = ByteBuffer.allocate(size);
-                while (byteBufferBody.hasRemaining()) {
-                    int length = socketChannel.read(byteBufferBody);
-                    if (length > 0) {
-                        if (byteBufferBody.hasRemaining()) {
-                            if ((System.currentTimeMillis() - beginTime) > timeoutMillis) {
-
-                                throw new RemotingTimeoutException(addr, timeoutMillis);
-                            }
-                        }
-                    } else {
-                        throw new RemotingTimeoutException(addr, timeoutMillis);
-                    }
-
-                    Thread.sleep(1);
-                }
-
-                byteBufferBody.flip();
-                return RemotingCommand.decode(byteBufferBody);
-            } catch (IOException e) {
-                log.error("invokeSync failure", e);
-
-                if (sendRequestOK) {
-                    throw new RemotingTimeoutException(addr, timeoutMillis);
-                } else {
-                    throw new RemotingSendRequestException(addr);
-                }
-            } finally {
-                try {
-                    socketChannel.close();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-        } else {
-            throw new RemotingConnectException(addr);
-        }
-    }
-
     public static String parseChannelRemoteAddr(final Channel channel) {
         if (null == channel) {
             return "";
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommandType.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/ChannelMetrics.java
old mode 100644
new mode 100755
similarity index 80%
copy from remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommandType.java
copy to remoting/src/main/java/org/apache/rocketmq/remoting/netty/ChannelMetrics.java
index 01c853b..c56b93d
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommandType.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/ChannelMetrics.java
@@ -14,9 +14,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.rocketmq.remoting.protocol;
 
-public enum RemotingCommandType {
-    REQUEST_COMMAND,
-    RESPONSE_COMMAND;
+package org.apache.rocketmq.remoting.netty;
+
+import io.netty.channel.group.ChannelGroup;
+
+public interface ChannelMetrics {
+
+    Integer getChannelCount();
+
+    ChannelGroup getChannels();
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/ChannelStatisticsHandler.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/ChannelStatisticsHandler.java
new file mode 100755
index 0000000..6aa5fd9
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/ChannelStatisticsHandler.java
@@ -0,0 +1,60 @@
+/*
+ * 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.remoting.netty;
+
+import io.netty.channel.ChannelDuplexHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.group.ChannelGroup;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ChannelStatisticsHandler extends ChannelDuplexHandler implements ChannelMetrics {
+    public static final String NAME = ChannelStatisticsHandler.class.getSimpleName();
+    private final AtomicInteger channelCount = new AtomicInteger(0);
+    private final ChannelGroup allChannels;
+
+    public ChannelStatisticsHandler(ChannelGroup allChannels) {
+        this.allChannels = allChannels;
+    }
+
+    @Override
+    public void channelActive(ChannelHandlerContext ctx) throws Exception {
+        // connect
+        channelCount.incrementAndGet();
+        allChannels.add(ctx.channel());
+        super.channelActive(ctx);
+    }
+
+    @Override
+    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+        // disconnect
+        channelCount.decrementAndGet();
+        allChannels.remove(ctx.channel());
+        super.channelInactive(ctx);
+    }
+
+    @Override
+    public Integer getChannelCount() {
+        return channelCount.get();
+    }
+
+    @Override
+    public ChannelGroup getChannels() {
+        return allChannels;
+    }
+
+}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/CodecHelper.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/CodecHelper.java
new file mode 100644
index 0000000..d0e3632
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/CodecHelper.java
@@ -0,0 +1,283 @@
+package org.apache.rocketmq.remoting.netty;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.rocketmq.remoting.CommandCustomHeader;
+import org.apache.rocketmq.remoting.annotation.CFNotNull;
+import org.apache.rocketmq.remoting.exception.RemotingCommandException;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RocketMQSerializable;
+import org.apache.rocketmq.remoting.serialize.SerializeType;
+import org.apache.rocketmq.remoting.serialize.Serializer;
+import org.apache.rocketmq.remoting.serialize.SerializerFactory;
+
+public class CodecHelper {
+    public static final String REMOTING_VERSION_KEY = "rocketmq.remoting.version";
+    protected static final Map<Class<? extends CommandCustomHeader>, Field[]> CLASS_HASH_MAP =
+        new HashMap<Class<? extends CommandCustomHeader>, Field[]>();
+    protected static final Map<Class, String> CANONICAL_NAME_CACHE = new HashMap<Class, String>();
+    private static final Map<Field, Boolean> NULLABLE_FIELD_CACHE = new HashMap<Field, Boolean>();
+    private static final String STRING_CANONICAL_NAME = String.class.getCanonicalName();
+    private static final String DOUBLE_CANONICAL_NAME_1 = Double.class.getCanonicalName();
+    private static final String DOUBLE_CANONICAL_NAME_2 = double.class.getCanonicalName();
+    private static final String INTEGER_CANONICAL_NAME_1 = Integer.class.getCanonicalName();
+    private static final String INTEGER_CANONICAL_NAME_2 = int.class.getCanonicalName();
+    private static final String LONG_CANONICAL_NAME_1 = Long.class.getCanonicalName();
+    private static final String LONG_CANONICAL_NAME_2 = long.class.getCanonicalName();
+    private static final String BOOLEAN_CANONICAL_NAME_1 = Boolean.class.getCanonicalName();
+    private static final String BOOLEAN_CANONICAL_NAME_2 = boolean.class.getCanonicalName();
+
+    public static RemotingCommand decode(final byte[] array) {
+        ByteBuffer byteBuffer = ByteBuffer.wrap(array);
+        return decode(byteBuffer);
+    }
+
+    public static RemotingCommand decode(final ByteBuffer byteBuffer) {
+        int length = byteBuffer.limit();
+        int oriHeaderLen = byteBuffer.getInt();
+        int headerLength = getHeaderLength(oriHeaderLen);
+
+        byte[] headerData = new byte[headerLength];
+        byteBuffer.get(headerData);
+        RemotingCommand cmd = headerDecode(headerData, getProtocolType(oriHeaderLen));
+        System.out.println("cmd: " + cmd);
+        int bodyLength = length - 4 - headerLength;
+        byte[] bodyData = null;
+        if (bodyLength > 0) {
+            bodyData = new byte[bodyLength];
+            byteBuffer.get(bodyData);
+        }
+        cmd.setBody(bodyData);
+        return cmd;
+    }
+
+    public static int getHeaderLength(int length) {
+        return length & 0xFFFFFF;
+    }
+
+    private static RemotingCommand headerDecode(byte[] headerData, SerializeType type) {
+        Serializer serializer = SerializerFactory.get(type);
+        if (serializer != null) {
+            RemotingCommand remotingCommand = serializer.deserializer(headerData);
+            return remotingCommand;
+        }
+        return null;
+    }
+
+    public static SerializeType getProtocolType(int source) {
+        return SerializeType.valueOf((byte) ((source >> 24) & 0xFF));
+    }
+
+    public static byte[] markProtocolType(int source, SerializeType type) {
+        byte[] result = new byte[4];
+
+        result[0] = type.getCode();
+        result[1] = (byte) ((source >> 16) & 0xFF);
+        result[2] = (byte) ((source >> 8) & 0xFF);
+        result[3] = (byte) (source & 0xFF);
+        return result;
+    }
+
+    public static CommandCustomHeader decodeCommandCustomHeader(RemotingCommand remotingCommand,
+        Class<? extends CommandCustomHeader> classHeader) throws RemotingCommandException {
+        CommandCustomHeader objectHeader;
+        try {
+            objectHeader = classHeader.newInstance();
+        } catch (InstantiationException e) {
+            return null;
+        } catch (IllegalAccessException e) {
+            return null;
+        }
+
+        if (remotingCommand.getExtFields() != null) {
+            Field[] fields = getClazzFields(classHeader);
+            for (Field field : fields) {
+                if (!Modifier.isStatic(field.getModifiers())) {
+                    String fieldName = field.getName();
+                    if (!fieldName.startsWith("this")) {
+                        try {
+                            String value = remotingCommand.getExtFields().get(fieldName);
+                            if (null == value) {
+                                if (!isFieldNullable(field)) {
+                                    throw new RemotingCommandException("the custom field <" + fieldName + "> is null");
+                                }
+                                continue;
+                            }
+
+                            field.setAccessible(true);
+                            String type = getCanonicalName(field.getType());
+                            Object valueParsed;
+
+                            if (type.equals(STRING_CANONICAL_NAME)) {
+                                valueParsed = value;
+                            } else if (type.equals(INTEGER_CANONICAL_NAME_1) || type.equals(INTEGER_CANONICAL_NAME_2)) {
+                                valueParsed = Integer.parseInt(value);
+                            } else if (type.equals(LONG_CANONICAL_NAME_1) || type.equals(LONG_CANONICAL_NAME_2)) {
+                                valueParsed = Long.parseLong(value);
+                            } else if (type.equals(BOOLEAN_CANONICAL_NAME_1) || type.equals(BOOLEAN_CANONICAL_NAME_2)) {
+                                valueParsed = Boolean.parseBoolean(value);
+                            } else if (type.equals(DOUBLE_CANONICAL_NAME_1) || type.equals(DOUBLE_CANONICAL_NAME_2)) {
+                                valueParsed = Double.parseDouble(value);
+                            } else {
+                                throw new RemotingCommandException("the custom field <" + fieldName + "> type is not supported");
+                            }
+
+                            field.set(objectHeader, valueParsed);
+
+                        } catch (Throwable e) {
+                        }
+                    }
+                }
+            }
+
+            objectHeader.checkFields();
+        }
+
+        return objectHeader;
+    }
+
+    private static Field[] getClazzFields(Class<? extends CommandCustomHeader> classHeader) {
+        Field[] field = CLASS_HASH_MAP.get(classHeader);
+
+        if (field == null) {
+            field = classHeader.getDeclaredFields();
+            synchronized (CLASS_HASH_MAP) {
+                CLASS_HASH_MAP.put(classHeader, field);
+            }
+        }
+        return field;
+    }
+
+    private static boolean isFieldNullable(Field field) {
+        if (!NULLABLE_FIELD_CACHE.containsKey(field)) {
+            Annotation annotation = field.getAnnotation(CFNotNull.class);
+            synchronized (NULLABLE_FIELD_CACHE) {
+                NULLABLE_FIELD_CACHE.put(field, annotation == null);
+            }
+        }
+        return NULLABLE_FIELD_CACHE.get(field);
+    }
+
+    private static String getCanonicalName(Class clazz) {
+        String name = CANONICAL_NAME_CACHE.get(clazz);
+
+        if (name == null) {
+            name = clazz.getCanonicalName();
+            synchronized (CANONICAL_NAME_CACHE) {
+                CANONICAL_NAME_CACHE.put(clazz, name);
+            }
+        }
+        return name;
+    }
+
+    public static ByteBuffer encode(RemotingCommand remotingCommand) {
+        // 1> header length size
+        int length = 4;
+
+        // 2> header data length
+        byte[] headerData = headerEncode(remotingCommand);
+        length += headerData.length;
+
+        // 3> body data length
+        if (remotingCommand.getBody() != null) {
+            length += remotingCommand.getBody().length;
+        }
+
+        ByteBuffer result = ByteBuffer.allocate(4 + length);
+
+        // length
+        result.putInt(length);
+
+        // header length
+        result.put(markProtocolType(headerData.length, remotingCommand.getSerializeTypeCurrentRPC()));
+
+        // header data
+        result.put(headerData);
+
+        // body data;
+        if (remotingCommand.getBody() != null) {
+            result.put(remotingCommand.getBody());
+        }
+
+        result.flip();
+
+        return result;
+    }
+
+    private static byte[] headerEncode(RemotingCommand remotingCommand) {
+        makeCustomHeaderToNet(remotingCommand);
+        Serializer serializer = SerializerFactory.get(remotingCommand.getSerializeTypeCurrentRPC());
+        if (serializer == null) {
+            serializer = SerializerFactory.get(SerializeType.JSON);
+        }
+        return serializer.serializer(remotingCommand);
+    }
+
+    public static void makeCustomHeaderToNet(RemotingCommand remotingCommand) {
+        if (remotingCommand.getCustomHeader() != null) {
+            Field[] fields = getClazzFields(remotingCommand.getCustomHeader().getClass());
+            HashMap extFields = remotingCommand.getExtFields();
+
+            if (null == extFields) {
+                remotingCommand.setExtFields(new HashMap<String, String>());
+            }
+            for (Field field : fields) {
+                if (!Modifier.isStatic(field.getModifiers())) {
+                    String name = field.getName();
+                    if (!name.startsWith("this")) {
+                        Object value = null;
+                        try {
+                            field.setAccessible(true);
+                            value = field.get(remotingCommand.getCustomHeader());
+                        } catch (Exception e) {
+                        }
+
+                        if (value != null) {
+                            remotingCommand.getExtFields().put(name, value.toString());
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public static ByteBuffer encodeHeader(RemotingCommand remotingCommand) {
+        int bodyLength = remotingCommand.getBody() != null ? remotingCommand.getBody().length : 0;
+        return encodeHeader(bodyLength, remotingCommand);
+    }
+
+    public static ByteBuffer encodeHeader(final int bodyLength, RemotingCommand remotingCommand) {
+        // 1> header length size
+        int length = 4;
+
+        // 2> header data length
+        byte[] headerData;
+        headerData = headerEncode(remotingCommand);
+
+        length += headerData.length;
+
+        // 3> body data length
+        length += bodyLength;
+
+        ByteBuffer result = ByteBuffer.allocate(4 + length - bodyLength);
+
+        // length
+        result.putInt(length);
+
+        // header length
+        result.put(markProtocolType(headerData.length, remotingCommand.getSerializeTypeCurrentRPC()));
+
+        // header data
+        result.put(headerData);
+
+        result.flip();
+
+        return result;
+    }
+
+}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/FileRegionEncoder.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/FileRegionEncoder.java
index 2bd15ae..0c5e52d 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/FileRegionEncoder.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/FileRegionEncoder.java
@@ -68,7 +68,7 @@ public class FileRegionEncoder extends MessageToByteEncoder<FileRegion> {
         long toTransfer = msg.count();
 
         while (true) {
-            long transferred = msg.transfered();
+            long transferred = msg.transferred();
             if (toTransfer - transferred <= 0) {
                 break;
             }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyLogger.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyLogger.java
index 4b4e86e..ccd1b14 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyLogger.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyLogger.java
@@ -17,13 +17,11 @@
 
 package org.apache.rocketmq.remoting.netty;
 
-
 import io.netty.util.internal.logging.InternalLogLevel;
+import java.util.concurrent.atomic.AtomicBoolean;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 
-import java.util.concurrent.atomic.AtomicBoolean;
-
 public class NettyLogger {
 
     private static AtomicBoolean nettyLoggerSeted = new AtomicBoolean(false);
@@ -52,6 +50,30 @@ public class NettyLogger {
 
         private InternalLogger logger = null;
 
+        @Override public void trace(Throwable throwable) {
+
+        }
+
+        @Override public void debug(Throwable throwable) {
+
+        }
+
+        @Override public void info(Throwable throwable) {
+
+        }
+
+        @Override public void warn(Throwable throwable) {
+
+        }
+
+        @Override public void error(Throwable throwable) {
+
+        }
+
+        @Override public void log(InternalLogLevel level, Throwable throwable) {
+
+        }
+
         public NettyBridgeLogger(String name) {
             logger = InternalLoggerFactory.getLogger(name);
         }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
index 8dccebc..17053ff 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
@@ -17,11 +17,15 @@
 package org.apache.rocketmq.remoting.netty;
 
 import io.netty.channel.Channel;
+import io.netty.channel.ChannelDuplexHandler;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
 import io.netty.handler.ssl.SslContext;
 import io.netty.handler.ssl.SslHandler;
+import io.netty.handler.timeout.IdleState;
+import io.netty.handler.timeout.IdleStateEvent;
 import java.net.SocketAddress;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -33,13 +37,16 @@ import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import org.apache.rocketmq.remoting.ChannelEventListener;
 import org.apache.rocketmq.remoting.InvokeCallback;
 import org.apache.rocketmq.remoting.RPCHook;
+import org.apache.rocketmq.remoting.RemotingServer;
 import org.apache.rocketmq.remoting.common.Pair;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.common.RemotingUtil;
 import org.apache.rocketmq.remoting.common.SemaphoreReleaseOnlyOnce;
 import org.apache.rocketmq.remoting.common.ServiceThread;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
@@ -49,6 +56,7 @@ import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.remoting.protocol.RemotingSysResponseCode;
+import org.apache.rocketmq.remoting.util.ThreadUtils;
 
 public abstract class NettyRemotingAbstract {
 
@@ -60,12 +68,12 @@ public abstract class NettyRemotingAbstract {
     /**
      * Semaphore to limit maximum number of on-going one-way requests, which protects system memory footprint.
      */
-    protected final Semaphore semaphoreOneway;
+    protected Semaphore semaphoreOneway;
 
     /**
      * Semaphore to limit maximum number of on-going asynchronous requests, which protects system memory footprint.
      */
-    protected final Semaphore semaphoreAsync;
+    protected Semaphore semaphoreAsync;
 
     /**
      * This map caches all on-going requests.
@@ -83,10 +91,11 @@ public abstract class NettyRemotingAbstract {
     /**
      * Executor to feed netty events to user defined {@link ChannelEventListener}.
      */
-    protected final NettyEventExecutor nettyEventExecutor = new NettyEventExecutor();
+    protected NettyEventExecutor nettyEventExecutor = new NettyEventExecutor();
 
     /**
-     * The default request processor to use in case there is no exact match in {@link #processorTable} per request code.
+     * The default request processor to use in case there is no exact match in {@link #processorTable} per request
+     * code.
      */
     protected Pair<NettyRequestProcessor, ExecutorService> defaultRequestProcessor;
 
@@ -99,6 +108,13 @@ public abstract class NettyRemotingAbstract {
         NettyLogger.initNettyLogger();
     }
 
+    protected ScheduledExecutorService houseKeepingService = ThreadUtils.newSingleThreadScheduledExecutor("HouseKeepingService", true);
+
+    public NettyRemotingAbstract() {
+        this.semaphoreOneway = new Semaphore(65535, true);
+        this.semaphoreAsync = new Semaphore(65535, true);
+    }
+
     /**
      * Constructor, specifying capacity of one-way and asynchronous semaphores.
      *
@@ -110,6 +126,11 @@ public abstract class NettyRemotingAbstract {
         this.semaphoreAsync = new Semaphore(permitsAsync, true);
     }
 
+    public void init(final int permitsOneway, final int permitsAsync) {
+        this.semaphoreOneway = new Semaphore(permitsOneway, true);
+        this.semaphoreAsync = new Semaphore(permitsAsync, true);
+    }
+
     /**
      * Custom channel event listener.
      *
@@ -329,6 +350,15 @@ public abstract class NettyRemotingAbstract {
      */
     public abstract ExecutorService getCallbackExecutor();
 
+    protected void startUpHouseKeepingService() {
+        this.houseKeepingService.scheduleAtFixedRate(new Runnable() {
+            @Override
+            public void run() {
+                scanResponseTable();
+            }
+        }, 3000, 1000, TimeUnit.MICROSECONDS);
+    }
+
     /**
      * <p>
      * This method is periodically invoked to scan and expire deprecated request.
@@ -358,6 +388,21 @@ public abstract class NettyRemotingAbstract {
         }
     }
 
+    public void start() {
+        if (getChannelEventListener() != null) {
+            nettyEventExecutor.start();
+        }
+    }
+
+    public void shutdown() {
+        if (this.nettyEventExecutor != null) {
+            this.nettyEventExecutor.shutdown();
+        }
+        if (this.houseKeepingService != null) {
+            this.houseKeepingService.shutdown();
+        }
+    }
+
     public RemotingCommand invokeSyncImpl(final Channel channel, final RemotingCommand request,
         final long timeoutMillis)
         throws InterruptedException, RemotingSendRequestException, RemotingTimeoutException {
@@ -410,7 +455,7 @@ public abstract class NettyRemotingAbstract {
             final SemaphoreReleaseOnlyOnce once = new SemaphoreReleaseOnlyOnce(this.semaphoreAsync);
             long costTime = System.currentTimeMillis() - beginStartTime;
             if (timeoutMillis < costTime) {
-                throw new RemotingTooMuchRequestException("invokeAsyncImpl call timeout");
+                throw new RemotingTimeoutException("invokeAsyncImpl call timeout");
             }
 
             final ResponseFuture responseFuture = new ResponseFuture(channel, opaque, timeoutMillis - costTime, invokeCallback, once);
@@ -465,6 +510,7 @@ public abstract class NettyRemotingAbstract {
 
     /**
      * mark the request of the specified channel as fail and to invoke fail callback immediately
+     *
      * @param channel the channel which is close already
      */
     protected void failFast(final Channel channel) {
@@ -570,4 +616,15 @@ public abstract class NettyRemotingAbstract {
             return NettyEventExecutor.class.getSimpleName();
         }
     }
+
+    public class NettyServerHandler extends SimpleChannelInboundHandler<RemotingCommand> {
+
+        @Override
+        protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception {
+            processMessageReceived(ctx, msg);
+        }
+    }
+
+
+
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
deleted file mode 100644
index 33c2eed..0000000
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
+++ /dev/null
@@ -1,710 +0,0 @@
-/*
- * 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.remoting.netty;
-
-import io.netty.bootstrap.Bootstrap;
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelDuplexHandler;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.ChannelOption;
-import io.netty.channel.ChannelPipeline;
-import io.netty.channel.ChannelPromise;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.SimpleChannelInboundHandler;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.channel.socket.SocketChannel;
-import io.netty.channel.socket.nio.NioSocketChannel;
-import io.netty.handler.timeout.IdleState;
-import io.netty.handler.timeout.IdleStateEvent;
-import io.netty.handler.timeout.IdleStateHandler;
-import io.netty.util.concurrent.DefaultEventExecutorGroup;
-import java.io.IOException;
-import java.net.SocketAddress;
-import java.security.cert.CertificateException;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-import org.apache.rocketmq.remoting.ChannelEventListener;
-import org.apache.rocketmq.remoting.InvokeCallback;
-import org.apache.rocketmq.remoting.RPCHook;
-import org.apache.rocketmq.remoting.RemotingClient;
-import org.apache.rocketmq.remoting.common.Pair;
-import org.apache.rocketmq.remoting.common.RemotingHelper;
-import org.apache.rocketmq.remoting.common.RemotingUtil;
-import org.apache.rocketmq.remoting.exception.RemotingConnectException;
-import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
-import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
-import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
-import org.apache.rocketmq.logging.InternalLogger;
-import org.apache.rocketmq.logging.InternalLoggerFactory;
-import org.apache.rocketmq.remoting.protocol.RemotingCommand;
-
-public class NettyRemotingClient extends NettyRemotingAbstract implements RemotingClient {
-    private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
-
-    private static final long LOCK_TIMEOUT_MILLIS = 3000;
-
-    private final NettyClientConfig nettyClientConfig;
-    private final Bootstrap bootstrap = new Bootstrap();
-    private final EventLoopGroup eventLoopGroupWorker;
-    private final Lock lockChannelTables = new ReentrantLock();
-    private final ConcurrentMap<String /* addr */, ChannelWrapper> channelTables = new ConcurrentHashMap<String, ChannelWrapper>();
-
-    private final Timer timer = new Timer("ClientHouseKeepingService", true);
-
-    private final AtomicReference<List<String>> namesrvAddrList = new AtomicReference<List<String>>();
-    private final AtomicReference<String> namesrvAddrChoosed = new AtomicReference<String>();
-    private final AtomicInteger namesrvIndex = new AtomicInteger(initValueIndex());
-    private final Lock lockNamesrvChannel = new ReentrantLock();
-
-    private final ExecutorService publicExecutor;
-
-    /**
-     * Invoke the callback methods in this executor when process response.
-     */
-    private ExecutorService callbackExecutor;
-    private final ChannelEventListener channelEventListener;
-    private DefaultEventExecutorGroup defaultEventExecutorGroup;
-    private RPCHook rpcHook;
-
-    public NettyRemotingClient(final NettyClientConfig nettyClientConfig) {
-        this(nettyClientConfig, null);
-    }
-
-    public NettyRemotingClient(final NettyClientConfig nettyClientConfig,
-        final ChannelEventListener channelEventListener) {
-        super(nettyClientConfig.getClientOnewaySemaphoreValue(), nettyClientConfig.getClientAsyncSemaphoreValue());
-        this.nettyClientConfig = nettyClientConfig;
-        this.channelEventListener = channelEventListener;
-
-        int publicThreadNums = nettyClientConfig.getClientCallbackExecutorThreads();
-        if (publicThreadNums <= 0) {
-            publicThreadNums = 4;
-        }
-
-        this.publicExecutor = Executors.newFixedThreadPool(publicThreadNums, new ThreadFactory() {
-            private AtomicInteger threadIndex = new AtomicInteger(0);
-
-            @Override
-            public Thread newThread(Runnable r) {
-                return new Thread(r, "NettyClientPublicExecutor_" + this.threadIndex.incrementAndGet());
-            }
-        });
-
-        this.eventLoopGroupWorker = new NioEventLoopGroup(1, new ThreadFactory() {
-            private AtomicInteger threadIndex = new AtomicInteger(0);
-
-            @Override
-            public Thread newThread(Runnable r) {
-                return new Thread(r, String.format("NettyClientSelector_%d", this.threadIndex.incrementAndGet()));
-            }
-        });
-
-        if (nettyClientConfig.isUseTLS()) {
-            try {
-                sslContext = TlsHelper.buildSslContext(true);
-                log.info("SSL enabled for client");
-            } catch (IOException e) {
-                log.error("Failed to create SSLContext", e);
-            } catch (CertificateException e) {
-                log.error("Failed to create SSLContext", e);
-                throw new RuntimeException("Failed to create SSLContext", e);
-            }
-        }
-    }
-
-    private static int initValueIndex() {
-        Random r = new Random();
-
-        return Math.abs(r.nextInt() % 999) % 999;
-    }
-
-    @Override
-    public void start() {
-        this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(
-            nettyClientConfig.getClientWorkerThreads(),
-            new ThreadFactory() {
-
-                private AtomicInteger threadIndex = new AtomicInteger(0);
-
-                @Override
-                public Thread newThread(Runnable r) {
-                    return new Thread(r, "NettyClientWorkerThread_" + this.threadIndex.incrementAndGet());
-                }
-            });
-
-        Bootstrap handler = this.bootstrap.group(this.eventLoopGroupWorker).channel(NioSocketChannel.class)
-            .option(ChannelOption.TCP_NODELAY, true)
-            .option(ChannelOption.SO_KEEPALIVE, false)
-            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, nettyClientConfig.getConnectTimeoutMillis())
-            .option(ChannelOption.SO_SNDBUF, nettyClientConfig.getClientSocketSndBufSize())
-            .option(ChannelOption.SO_RCVBUF, nettyClientConfig.getClientSocketRcvBufSize())
-            .handler(new ChannelInitializer<SocketChannel>() {
-                @Override
-                public void initChannel(SocketChannel ch) throws Exception {
-                    ChannelPipeline pipeline = ch.pipeline();
-                    if (nettyClientConfig.isUseTLS()) {
-                        if (null != sslContext) {
-                            pipeline.addFirst(defaultEventExecutorGroup, "sslHandler", sslContext.newHandler(ch.alloc()));
-                            log.info("Prepend SSL handler");
-                        } else {
-                            log.warn("Connections are insecure as SSLContext is null!");
-                        }
-                    }
-                    pipeline.addLast(
-                        defaultEventExecutorGroup,
-                        new NettyEncoder(),
-                        new NettyDecoder(),
-                        new IdleStateHandler(0, 0, nettyClientConfig.getClientChannelMaxIdleTimeSeconds()),
-                        new NettyConnectManageHandler(),
-                        new NettyClientHandler());
-                }
-            });
-
-        this.timer.scheduleAtFixedRate(new TimerTask() {
-            @Override
-            public void run() {
-                try {
-                    NettyRemotingClient.this.scanResponseTable();
-                } catch (Throwable e) {
-                    log.error("scanResponseTable exception", e);
-                }
-            }
-        }, 1000 * 3, 1000);
-
-        if (this.channelEventListener != null) {
-            this.nettyEventExecutor.start();
-        }
-    }
-
-    @Override
-    public void shutdown() {
-        try {
-            this.timer.cancel();
-
-            for (ChannelWrapper cw : this.channelTables.values()) {
-                this.closeChannel(null, cw.getChannel());
-            }
-
-            this.channelTables.clear();
-
-            this.eventLoopGroupWorker.shutdownGracefully();
-
-            if (this.nettyEventExecutor != null) {
-                this.nettyEventExecutor.shutdown();
-            }
-
-            if (this.defaultEventExecutorGroup != null) {
-                this.defaultEventExecutorGroup.shutdownGracefully();
-            }
-        } catch (Exception e) {
-            log.error("NettyRemotingClient shutdown exception, ", e);
-        }
-
-        if (this.publicExecutor != null) {
-            try {
-                this.publicExecutor.shutdown();
-            } catch (Exception e) {
-                log.error("NettyRemotingServer shutdown exception, ", e);
-            }
-        }
-    }
-
-    public void closeChannel(final String addr, final Channel channel) {
-        if (null == channel)
-            return;
-
-        final String addrRemote = null == addr ? RemotingHelper.parseChannelRemoteAddr(channel) : addr;
-
-        try {
-            if (this.lockChannelTables.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
-                try {
-                    boolean removeItemFromTable = true;
-                    final ChannelWrapper prevCW = this.channelTables.get(addrRemote);
-
-                    log.info("closeChannel: begin close the channel[{}] Found: {}", addrRemote, prevCW != null);
-
-                    if (null == prevCW) {
-                        log.info("closeChannel: the channel[{}] has been removed from the channel table before", addrRemote);
-                        removeItemFromTable = false;
-                    } else if (prevCW.getChannel() != channel) {
-                        log.info("closeChannel: the channel[{}] has been closed before, and has been created again, nothing to do.",
-                            addrRemote);
-                        removeItemFromTable = false;
-                    }
-
-                    if (removeItemFromTable) {
-                        this.channelTables.remove(addrRemote);
-                        log.info("closeChannel: the channel[{}] was removed from channel table", addrRemote);
-                    }
-
-                    RemotingUtil.closeChannel(channel);
-                } catch (Exception e) {
-                    log.error("closeChannel: close the channel exception", e);
-                } finally {
-                    this.lockChannelTables.unlock();
-                }
-            } else {
-                log.warn("closeChannel: try to lock channel table, but timeout, {}ms", LOCK_TIMEOUT_MILLIS);
-            }
-        } catch (InterruptedException e) {
-            log.error("closeChannel exception", e);
-        }
-    }
-
-    @Override
-    public void registerRPCHook(RPCHook rpcHook) {
-        this.rpcHook = rpcHook;
-    }
-
-    public void closeChannel(final Channel channel) {
-        if (null == channel)
-            return;
-
-        try {
-            if (this.lockChannelTables.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
-                try {
-                    boolean removeItemFromTable = true;
-                    ChannelWrapper prevCW = null;
-                    String addrRemote = null;
-                    for (Map.Entry<String, ChannelWrapper> entry : channelTables.entrySet()) {
-                        String key = entry.getKey();
-                        ChannelWrapper prev = entry.getValue();
-                        if (prev.getChannel() != null) {
-                            if (prev.getChannel() == channel) {
-                                prevCW = prev;
-                                addrRemote = key;
-                                break;
-                            }
-                        }
-                    }
-
-                    if (null == prevCW) {
-                        log.info("eventCloseChannel: the channel[{}] has been removed from the channel table before", addrRemote);
-                        removeItemFromTable = false;
-                    }
-
-                    if (removeItemFromTable) {
-                        this.channelTables.remove(addrRemote);
-                        log.info("closeChannel: the channel[{}] was removed from channel table", addrRemote);
-                        RemotingUtil.closeChannel(channel);
-                    }
-                } catch (Exception e) {
-                    log.error("closeChannel: close the channel exception", e);
-                } finally {
-                    this.lockChannelTables.unlock();
-                }
-            } else {
-                log.warn("closeChannel: try to lock channel table, but timeout, {}ms", LOCK_TIMEOUT_MILLIS);
-            }
-        } catch (InterruptedException e) {
-            log.error("closeChannel exception", e);
-        }
-    }
-
-    @Override
-    public void updateNameServerAddressList(List<String> addrs) {
-        List<String> old = this.namesrvAddrList.get();
-        boolean update = false;
-
-        if (!addrs.isEmpty()) {
-            if (null == old) {
-                update = true;
-            } else if (addrs.size() != old.size()) {
-                update = true;
-            } else {
-                for (int i = 0; i < addrs.size() && !update; i++) {
-                    if (!old.contains(addrs.get(i))) {
-                        update = true;
-                    }
-                }
-            }
-
-            if (update) {
-                Collections.shuffle(addrs);
-                log.info("name server address updated. NEW : {} , OLD: {}", addrs, old);
-                this.namesrvAddrList.set(addrs);
-            }
-        }
-    }
-
-    @Override
-    public RemotingCommand invokeSync(String addr, final RemotingCommand request, long timeoutMillis)
-        throws InterruptedException, RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException {
-        long beginStartTime = System.currentTimeMillis();
-        final Channel channel = this.getAndCreateChannel(addr);
-        if (channel != null && channel.isActive()) {
-            try {
-                if (this.rpcHook != null) {
-                    this.rpcHook.doBeforeRequest(addr, request);
-                }
-                long costTime = System.currentTimeMillis() - beginStartTime;
-                if (timeoutMillis < costTime) {
-                    throw new RemotingTimeoutException("invokeSync call timeout");
-                }
-                RemotingCommand response = this.invokeSyncImpl(channel, request, timeoutMillis - costTime);
-                if (this.rpcHook != null) {
-                    this.rpcHook.doAfterResponse(RemotingHelper.parseChannelRemoteAddr(channel), request, response);
-                }
-                return response;
-            } catch (RemotingSendRequestException e) {
-                log.warn("invokeSync: send request exception, so close the channel[{}]", addr);
-                this.closeChannel(addr, channel);
-                throw e;
-            } catch (RemotingTimeoutException e) {
-                if (nettyClientConfig.isClientCloseSocketIfTimeout()) {
-                    this.closeChannel(addr, channel);
-                    log.warn("invokeSync: close socket because of timeout, {}ms, {}", timeoutMillis, addr);
-                }
-                log.warn("invokeSync: wait response timeout exception, the channel[{}]", addr);
-                throw e;
-            }
-        } else {
-            this.closeChannel(addr, channel);
-            throw new RemotingConnectException(addr);
-        }
-    }
-
-    private Channel getAndCreateChannel(final String addr) throws InterruptedException {
-        if (null == addr) {
-            return getAndCreateNameserverChannel();
-        }
-
-        ChannelWrapper cw = this.channelTables.get(addr);
-        if (cw != null && cw.isOK()) {
-            return cw.getChannel();
-        }
-
-        return this.createChannel(addr);
-    }
-
-    private Channel getAndCreateNameserverChannel() throws InterruptedException {
-        String addr = this.namesrvAddrChoosed.get();
-        if (addr != null) {
-            ChannelWrapper cw = this.channelTables.get(addr);
-            if (cw != null && cw.isOK()) {
-                return cw.getChannel();
-            }
-        }
-
-        final List<String> addrList = this.namesrvAddrList.get();
-        if (this.lockNamesrvChannel.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
-            try {
-                addr = this.namesrvAddrChoosed.get();
-                if (addr != null) {
-                    ChannelWrapper cw = this.channelTables.get(addr);
-                    if (cw != null && cw.isOK()) {
-                        return cw.getChannel();
-                    }
-                }
-
-                if (addrList != null && !addrList.isEmpty()) {
-                    for (int i = 0; i < addrList.size(); i++) {
-                        int index = this.namesrvIndex.incrementAndGet();
-                        index = Math.abs(index);
-                        index = index % addrList.size();
-                        String newAddr = addrList.get(index);
-
-                        this.namesrvAddrChoosed.set(newAddr);
-                        log.info("new name server is chosen. OLD: {} , NEW: {}. namesrvIndex = {}", addr, newAddr, namesrvIndex);
-                        Channel channelNew = this.createChannel(newAddr);
-                        if (channelNew != null) {
-                            return channelNew;
-                        }
-                    }
-                }
-            } catch (Exception e) {
-                log.error("getAndCreateNameserverChannel: create name server channel exception", e);
-            } finally {
-                this.lockNamesrvChannel.unlock();
-            }
-        } else {
-            log.warn("getAndCreateNameserverChannel: try to lock name server, but timeout, {}ms", LOCK_TIMEOUT_MILLIS);
-        }
-
-        return null;
-    }
-
-    private Channel createChannel(final String addr) throws InterruptedException {
-        ChannelWrapper cw = this.channelTables.get(addr);
-        if (cw != null && cw.isOK()) {
-            cw.getChannel().close();
-            channelTables.remove(addr);
-        }
-
-        if (this.lockChannelTables.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
-            try {
-                boolean createNewConnection;
-                cw = this.channelTables.get(addr);
-                if (cw != null) {
-
-                    if (cw.isOK()) {
-                        cw.getChannel().close();
-                        this.channelTables.remove(addr);
-                        createNewConnection = true;
-                    } else if (!cw.getChannelFuture().isDone()) {
-                        createNewConnection = false;
-                    } else {
-                        this.channelTables.remove(addr);
-                        createNewConnection = true;
-                    }
-                } else {
-                    createNewConnection = true;
-                }
-
-                if (createNewConnection) {
-                    ChannelFuture channelFuture = this.bootstrap.connect(RemotingHelper.string2SocketAddress(addr));
-                    log.info("createChannel: begin to connect remote host[{}] asynchronously", addr);
-                    cw = new ChannelWrapper(channelFuture);
-                    this.channelTables.put(addr, cw);
-                }
-            } catch (Exception e) {
-                log.error("createChannel: create channel exception", e);
-            } finally {
-                this.lockChannelTables.unlock();
-            }
-        } else {
-            log.warn("createChannel: try to lock channel table, but timeout, {}ms", LOCK_TIMEOUT_MILLIS);
-        }
-
-        if (cw != null) {
-            ChannelFuture channelFuture = cw.getChannelFuture();
-            if (channelFuture.awaitUninterruptibly(this.nettyClientConfig.getConnectTimeoutMillis())) {
-                if (cw.isOK()) {
-                    log.info("createChannel: connect remote host[{}] success, {}", addr, channelFuture.toString());
-                    return cw.getChannel();
-                } else {
-                    log.warn("createChannel: connect remote host[" + addr + "] failed, " + channelFuture.toString(), channelFuture.cause());
-                }
-            } else {
-                log.warn("createChannel: connect remote host[{}] timeout {}ms, {}", addr, this.nettyClientConfig.getConnectTimeoutMillis(),
-                    channelFuture.toString());
-            }
-        }
-
-        return null;
-    }
-
-    @Override
-    public void invokeAsync(String addr, RemotingCommand request, long timeoutMillis, InvokeCallback invokeCallback)
-        throws InterruptedException, RemotingConnectException, RemotingTooMuchRequestException, RemotingTimeoutException,
-        RemotingSendRequestException {
-        long beginStartTime = System.currentTimeMillis();
-        final Channel channel = this.getAndCreateChannel(addr);
-        if (channel != null && channel.isActive()) {
-            try {
-                if (this.rpcHook != null) {
-                    this.rpcHook.doBeforeRequest(addr, request);
-                }
-                long costTime = System.currentTimeMillis() - beginStartTime;
-                if (timeoutMillis < costTime) {
-                    throw new RemotingTooMuchRequestException("invokeAsync call timeout");
-                }
-                this.invokeAsyncImpl(channel, request, timeoutMillis - costTime, invokeCallback);
-            } catch (RemotingSendRequestException e) {
-                log.warn("invokeAsync: send request exception, so close the channel[{}]", addr);
-                this.closeChannel(addr, channel);
-                throw e;
-            }
-        } else {
-            this.closeChannel(addr, channel);
-            throw new RemotingConnectException(addr);
-        }
-    }
-
-    @Override
-    public void invokeOneway(String addr, RemotingCommand request, long timeoutMillis) throws InterruptedException,
-        RemotingConnectException, RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
-        final Channel channel = this.getAndCreateChannel(addr);
-        if (channel != null && channel.isActive()) {
-            try {
-                if (this.rpcHook != null) {
-                    this.rpcHook.doBeforeRequest(addr, request);
-                }
-                this.invokeOnewayImpl(channel, request, timeoutMillis);
-            } catch (RemotingSendRequestException e) {
-                log.warn("invokeOneway: send request exception, so close the channel[{}]", addr);
-                this.closeChannel(addr, channel);
-                throw e;
-            }
-        } else {
-            this.closeChannel(addr, channel);
-            throw new RemotingConnectException(addr);
-        }
-    }
-
-    @Override
-    public void registerProcessor(int requestCode, NettyRequestProcessor processor, ExecutorService executor) {
-        ExecutorService executorThis = executor;
-        if (null == executor) {
-            executorThis = this.publicExecutor;
-        }
-
-        Pair<NettyRequestProcessor, ExecutorService> pair = new Pair<NettyRequestProcessor, ExecutorService>(processor, executorThis);
-        this.processorTable.put(requestCode, pair);
-    }
-
-    @Override
-    public boolean isChannelWritable(String addr) {
-        ChannelWrapper cw = this.channelTables.get(addr);
-        if (cw != null && cw.isOK()) {
-            return cw.isWritable();
-        }
-        return true;
-    }
-
-    @Override
-    public List<String> getNameServerAddressList() {
-        return this.namesrvAddrList.get();
-    }
-
-    @Override
-    public ChannelEventListener getChannelEventListener() {
-        return channelEventListener;
-    }
-
-    @Override
-    public RPCHook getRPCHook() {
-        return this.rpcHook;
-    }
-
-    @Override
-    public ExecutorService getCallbackExecutor() {
-        return callbackExecutor != null ? callbackExecutor : publicExecutor;
-    }
-
-    @Override
-    public void setCallbackExecutor(final ExecutorService callbackExecutor) {
-        this.callbackExecutor = callbackExecutor;
-    }
-
-    static class ChannelWrapper {
-        private final ChannelFuture channelFuture;
-
-        public ChannelWrapper(ChannelFuture channelFuture) {
-            this.channelFuture = channelFuture;
-        }
-
-        public boolean isOK() {
-            return this.channelFuture.channel() != null && this.channelFuture.channel().isActive();
-        }
-
-        public boolean isWritable() {
-            return this.channelFuture.channel().isWritable();
-        }
-
-        private Channel getChannel() {
-            return this.channelFuture.channel();
-        }
-
-        public ChannelFuture getChannelFuture() {
-            return channelFuture;
-        }
-    }
-
-    class NettyClientHandler extends SimpleChannelInboundHandler<RemotingCommand> {
-
-        @Override
-        protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception {
-            processMessageReceived(ctx, msg);
-        }
-    }
-
-    class NettyConnectManageHandler extends ChannelDuplexHandler {
-        @Override
-        public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
-            ChannelPromise promise) throws Exception {
-            final String local = localAddress == null ? "UNKNOWN" : RemotingHelper.parseSocketAddressAddr(localAddress);
-            final String remote = remoteAddress == null ? "UNKNOWN" : RemotingHelper.parseSocketAddressAddr(remoteAddress);
-            log.info("NETTY CLIENT PIPELINE: CONNECT  {} => {}", local, remote);
-
-            super.connect(ctx, remoteAddress, localAddress, promise);
-
-            if (NettyRemotingClient.this.channelEventListener != null) {
-                NettyRemotingClient.this.putNettyEvent(new NettyEvent(NettyEventType.CONNECT, remote, ctx.channel()));
-            }
-        }
-
-        @Override
-        public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
-            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
-            log.info("NETTY CLIENT PIPELINE: DISCONNECT {}", remoteAddress);
-            closeChannel(ctx.channel());
-            super.disconnect(ctx, promise);
-
-            if (NettyRemotingClient.this.channelEventListener != null) {
-                NettyRemotingClient.this.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress, ctx.channel()));
-            }
-        }
-
-        @Override
-        public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
-            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
-            log.info("NETTY CLIENT PIPELINE: CLOSE {}", remoteAddress);
-            closeChannel(ctx.channel());
-            super.close(ctx, promise);
-            NettyRemotingClient.this.failFast(ctx.channel());
-            if (NettyRemotingClient.this.channelEventListener != null) {
-                NettyRemotingClient.this.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress, ctx.channel()));
-            }
-        }
-
-        @Override
-        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
-            if (evt instanceof IdleStateEvent) {
-                IdleStateEvent event = (IdleStateEvent) evt;
-                if (event.state().equals(IdleState.ALL_IDLE)) {
-                    final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
-                    log.warn("NETTY CLIENT PIPELINE: IDLE exception [{}]", remoteAddress);
-                    closeChannel(ctx.channel());
-                    if (NettyRemotingClient.this.channelEventListener != null) {
-                        NettyRemotingClient.this
-                            .putNettyEvent(new NettyEvent(NettyEventType.IDLE, remoteAddress, ctx.channel()));
-                    }
-                }
-            }
-
-            ctx.fireUserEventTriggered(evt);
-        }
-
-        @Override
-        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
-            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
-            log.warn("NETTY CLIENT PIPELINE: exceptionCaught {}", remoteAddress);
-            log.warn("NETTY CLIENT PIPELINE: exceptionCaught exception.", cause);
-            closeChannel(ctx.channel());
-            if (NettyRemotingClient.this.channelEventListener != null) {
-                NettyRemotingClient.this.putNettyEvent(new NettyEvent(NettyEventType.EXCEPTION, remoteAddress, ctx.channel()));
-            }
-        }
-    }
-}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyServerConfig.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyServerConfig.java
index a5e2a23..b3f55cd 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyServerConfig.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyServerConfig.java
@@ -19,7 +19,7 @@ package org.apache.rocketmq.remoting.netty;
 public class NettyServerConfig implements Cloneable {
     private int listenPort = 8888;
     private int serverWorkerThreads = 8;
-    private int serverCallbackExecutorThreads = 0;
+    private int serverCallbackExecutorThreads = 8;
     private int serverSelectorThreads = 3;
     private int serverOnewaySemaphoreValue = 256;
     private int serverAsyncSemaphoreValue = 64;
@@ -28,6 +28,33 @@ public class NettyServerConfig implements Cloneable {
     private int serverSocketSndBufSize = NettySystemConfig.socketSndbufSize;
     private int serverSocketRcvBufSize = NettySystemConfig.socketRcvbufSize;
     private boolean serverPooledByteBufAllocatorEnable = true;
+    private int serverAcceptorThreads = 1;
+    private int connectionChannelReaderIdleSeconds = 0;
+    private int connectionChannelWriterIdleSeconds = 0;
+
+    public int getConnectionChannelReaderIdleSeconds() {
+        return connectionChannelReaderIdleSeconds;
+    }
+
+    public void setConnectionChannelReaderIdleSeconds(int connectionChannelReaderIdleSeconds) {
+        this.connectionChannelReaderIdleSeconds = connectionChannelReaderIdleSeconds;
+    }
+
+    public int getConnectionChannelWriterIdleSeconds() {
+        return connectionChannelWriterIdleSeconds;
+    }
+
+    public void setConnectionChannelWriterIdleSeconds(int connectionChannelWriterIdleSeconds) {
+        this.connectionChannelWriterIdleSeconds = connectionChannelWriterIdleSeconds;
+    }
+
+    public int getServerAcceptorThreads() {
+        return serverAcceptorThreads;
+    }
+
+    public void setServerAcceptorThreads(int serverAcceptorThreads) {
+        this.serverAcceptorThreads = serverAcceptorThreads;
+    }
 
     /**
      * make make install
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java
index cadcab1..d392e79 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java
@@ -17,43 +17,41 @@
 package org.apache.rocketmq.remoting.protocol;
 
 import com.alibaba.fastjson.annotation.JSONField;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
 import java.nio.ByteBuffer;
 import java.util.HashMap;
-import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.CommandCustomHeader;
-import org.apache.rocketmq.remoting.annotation.CFNotNull;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.logging.InternalLogger;
-import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.netty.CodecHelper;
+import org.apache.rocketmq.remoting.serialize.LanguageCode;
+import org.apache.rocketmq.remoting.serialize.SerializeType;
+import org.msgpack.annotation.Message;
 
+@Message
 public class RemotingCommand {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
+
     public static final String SERIALIZE_TYPE_PROPERTY = "rocketmq.serialize.type";
     public static final String SERIALIZE_TYPE_ENV = "ROCKETMQ_SERIALIZE_TYPE";
     public static final String REMOTING_VERSION_KEY = "rocketmq.remoting.version";
-    private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
-    private static final int RPC_TYPE = 0; // 0, REQUEST_COMMAND
-    private static final int RPC_ONEWAY = 1; // 0, RPC
-    private static final Map<Class<? extends CommandCustomHeader>, Field[]> CLASS_HASH_MAP =
-        new HashMap<Class<? extends CommandCustomHeader>, Field[]>();
-    private static final Map<Class, String> CANONICAL_NAME_CACHE = new HashMap<Class, String>();
-    // 1, Oneway
-    // 1, RESPONSE_COMMAND
-    private static final Map<Field, Boolean> NULLABLE_FIELD_CACHE = new HashMap<Field, Boolean>();
-    private static final String STRING_CANONICAL_NAME = String.class.getCanonicalName();
-    private static final String DOUBLE_CANONICAL_NAME_1 = Double.class.getCanonicalName();
-    private static final String DOUBLE_CANONICAL_NAME_2 = double.class.getCanonicalName();
-    private static final String INTEGER_CANONICAL_NAME_1 = Integer.class.getCanonicalName();
-    private static final String INTEGER_CANONICAL_NAME_2 = int.class.getCanonicalName();
-    private static final String LONG_CANONICAL_NAME_1 = Long.class.getCanonicalName();
-    private static final String LONG_CANONICAL_NAME_2 = long.class.getCanonicalName();
-    private static final String BOOLEAN_CANONICAL_NAME_1 = Boolean.class.getCanonicalName();
-    private static final String BOOLEAN_CANONICAL_NAME_2 = boolean.class.getCanonicalName();
+
+    /**
+     * REQUEST_COMMAND
+     */
+    private static final int RPC_TYPE = 0;
+
+    /**
+     * One way
+     */
+    private static final int RPC_ONEWAY = 1;
+
+
+
     private static volatile int configVersion = -1;
+
     private static AtomicInteger requestId = new AtomicInteger(0);
 
     private static SerializeType serializeTypeConfigInThisServer = SerializeType.JSON;
@@ -74,15 +72,16 @@ public class RemotingCommand {
     private int version = 0;
     private int opaque = requestId.getAndIncrement();
     private int flag = 0;
+
     private String remark;
     private HashMap<String, String> extFields;
-    private transient CommandCustomHeader customHeader;
+    private CommandCustomHeader customHeader;
 
     private SerializeType serializeTypeCurrentRPC = serializeTypeConfigInThisServer;
 
     private transient byte[] body;
 
-    protected RemotingCommand() {
+    public RemotingCommand() {
     }
 
     public static RemotingCommand createRequestCommand(int code, CommandCustomHeader customHeader) {
@@ -132,59 +131,12 @@ public class RemotingCommand {
         return cmd;
     }
 
-    public static RemotingCommand createResponseCommand(int code, String remark) {
-        return createResponseCommand(code, remark, null);
-    }
-
-    public static RemotingCommand decode(final byte[] array) {
-        ByteBuffer byteBuffer = ByteBuffer.wrap(array);
-        return decode(byteBuffer);
-    }
-
-    public static RemotingCommand decode(final ByteBuffer byteBuffer) {
-        int length = byteBuffer.limit();
-        int oriHeaderLen = byteBuffer.getInt();
-        int headerLength = getHeaderLength(oriHeaderLen);
-
-        byte[] headerData = new byte[headerLength];
-        byteBuffer.get(headerData);
-
-        RemotingCommand cmd = headerDecode(headerData, getProtocolType(oriHeaderLen));
-
-        int bodyLength = length - 4 - headerLength;
-        byte[] bodyData = null;
-        if (bodyLength > 0) {
-            bodyData = new byte[bodyLength];
-            byteBuffer.get(bodyData);
-        }
-        cmd.body = bodyData;
-
-        return cmd;
-    }
-
-    public static int getHeaderLength(int length) {
-        return length & 0xFFFFFF;
-    }
-
-    private static RemotingCommand headerDecode(byte[] headerData, SerializeType type) {
-        switch (type) {
-            case JSON:
-                RemotingCommand resultJson = RemotingSerializable.decode(headerData, RemotingCommand.class);
-                resultJson.setSerializeTypeCurrentRPC(type);
-                return resultJson;
-            case ROCKETMQ:
-                RemotingCommand resultRMQ = RocketMQSerializable.rocketMQProtocolDecode(headerData);
-                resultRMQ.setSerializeTypeCurrentRPC(type);
-                return resultRMQ;
-            default:
-                break;
-        }
-
-        return null;
+    public CommandCustomHeader getCustomHeader() {
+        return customHeader;
     }
 
-    public static SerializeType getProtocolType(int source) {
-        return SerializeType.valueOf((byte) ((source >> 24) & 0xFF));
+    public static RemotingCommand createResponseCommand(int code, String remark) {
+        return createResponseCommand(code, remark, null);
     }
 
     public static int createNewRequestId() {
@@ -208,16 +160,6 @@ public class RemotingCommand {
         return true;
     }
 
-    public static byte[] markProtocolType(int source, SerializeType type) {
-        byte[] result = new byte[4];
-
-        result[0] = type.getCode();
-        result[1] = (byte) ((source >> 16) & 0xFF);
-        result[2] = (byte) ((source >> 8) & 0xFF);
-        result[3] = (byte) (source & 0xFF);
-        return result;
-    }
-
     public void markResponseType() {
         int bits = 1 << RPC_TYPE;
         this.flag |= bits;
@@ -227,206 +169,13 @@ public class RemotingCommand {
         return customHeader;
     }
 
-    public void writeCustomHeader(CommandCustomHeader customHeader) {
-        this.customHeader = customHeader;
-    }
-
     public CommandCustomHeader decodeCommandCustomHeader(
         Class<? extends CommandCustomHeader> classHeader) throws RemotingCommandException {
-        CommandCustomHeader objectHeader;
-        try {
-            objectHeader = classHeader.newInstance();
-        } catch (InstantiationException e) {
-            return null;
-        } catch (IllegalAccessException e) {
-            return null;
-        }
-
-        if (this.extFields != null) {
-
-            Field[] fields = getClazzFields(classHeader);
-            for (Field field : fields) {
-                if (!Modifier.isStatic(field.getModifiers())) {
-                    String fieldName = field.getName();
-                    if (!fieldName.startsWith("this")) {
-                        try {
-                            String value = this.extFields.get(fieldName);
-                            if (null == value) {
-                                if (!isFieldNullable(field)) {
-                                    throw new RemotingCommandException("the custom field <" + fieldName + "> is null");
-                                }
-                                continue;
-                            }
-
-                            field.setAccessible(true);
-                            String type = getCanonicalName(field.getType());
-                            Object valueParsed;
-
-                            if (type.equals(STRING_CANONICAL_NAME)) {
-                                valueParsed = value;
-                            } else if (type.equals(INTEGER_CANONICAL_NAME_1) || type.equals(INTEGER_CANONICAL_NAME_2)) {
-                                valueParsed = Integer.parseInt(value);
-                            } else if (type.equals(LONG_CANONICAL_NAME_1) || type.equals(LONG_CANONICAL_NAME_2)) {
-                                valueParsed = Long.parseLong(value);
-                            } else if (type.equals(BOOLEAN_CANONICAL_NAME_1) || type.equals(BOOLEAN_CANONICAL_NAME_2)) {
-                                valueParsed = Boolean.parseBoolean(value);
-                            } else if (type.equals(DOUBLE_CANONICAL_NAME_1) || type.equals(DOUBLE_CANONICAL_NAME_2)) {
-                                valueParsed = Double.parseDouble(value);
-                            } else {
-                                throw new RemotingCommandException("the custom field <" + fieldName + "> type is not supported");
-                            }
-
-                            field.set(objectHeader, valueParsed);
-
-                        } catch (Throwable e) {
-                            log.error("Failed field [{}] decoding", fieldName, e);
-                        }
-                    }
-                }
-            }
-
-            objectHeader.checkFields();
-        }
-
-        return objectHeader;
-    }
-
-    private Field[] getClazzFields(Class<? extends CommandCustomHeader> classHeader) {
-        Field[] field = CLASS_HASH_MAP.get(classHeader);
-
-        if (field == null) {
-            field = classHeader.getDeclaredFields();
-            synchronized (CLASS_HASH_MAP) {
-                CLASS_HASH_MAP.put(classHeader, field);
-            }
-        }
-        return field;
-    }
-
-    private boolean isFieldNullable(Field field) {
-        if (!NULLABLE_FIELD_CACHE.containsKey(field)) {
-            Annotation annotation = field.getAnnotation(CFNotNull.class);
-            synchronized (NULLABLE_FIELD_CACHE) {
-                NULLABLE_FIELD_CACHE.put(field, annotation == null);
-            }
-        }
-        return NULLABLE_FIELD_CACHE.get(field);
-    }
-
-    private String getCanonicalName(Class clazz) {
-        String name = CANONICAL_NAME_CACHE.get(clazz);
-
-        if (name == null) {
-            name = clazz.getCanonicalName();
-            synchronized (CANONICAL_NAME_CACHE) {
-                CANONICAL_NAME_CACHE.put(clazz, name);
-            }
-        }
-        return name;
-    }
-
-    public ByteBuffer encode() {
-        // 1> header length size
-        int length = 4;
-
-        // 2> header data length
-        byte[] headerData = this.headerEncode();
-        length += headerData.length;
-
-        // 3> body data length
-        if (this.body != null) {
-            length += body.length;
-        }
-
-        ByteBuffer result = ByteBuffer.allocate(4 + length);
-
-        // length
-        result.putInt(length);
-
-        // header length
-        result.put(markProtocolType(headerData.length, serializeTypeCurrentRPC));
-
-        // header data
-        result.put(headerData);
-
-        // body data;
-        if (this.body != null) {
-            result.put(this.body);
-        }
-
-        result.flip();
-
-        return result;
-    }
-
-    private byte[] headerEncode() {
-        this.makeCustomHeaderToNet();
-        if (SerializeType.ROCKETMQ == serializeTypeCurrentRPC) {
-            return RocketMQSerializable.rocketMQProtocolEncode(this);
-        } else {
-            return RemotingSerializable.encode(this);
-        }
-    }
-
-    public void makeCustomHeaderToNet() {
-        if (this.customHeader != null) {
-            Field[] fields = getClazzFields(customHeader.getClass());
-            if (null == this.extFields) {
-                this.extFields = new HashMap<String, String>();
-            }
-
-            for (Field field : fields) {
-                if (!Modifier.isStatic(field.getModifiers())) {
-                    String name = field.getName();
-                    if (!name.startsWith("this")) {
-                        Object value = null;
-                        try {
-                            field.setAccessible(true);
-                            value = field.get(this.customHeader);
-                        } catch (Exception e) {
-                            log.error("Failed to access field [{}]", name, e);
-                        }
-
-                        if (value != null) {
-                            this.extFields.put(name, value.toString());
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    public ByteBuffer encodeHeader() {
-        return encodeHeader(this.body != null ? this.body.length : 0);
+        return CodecHelper.decodeCommandCustomHeader(this, classHeader);
     }
 
     public ByteBuffer encodeHeader(final int bodyLength) {
-        // 1> header length size
-        int length = 4;
-
-        // 2> header data length
-        byte[] headerData;
-        headerData = this.headerEncode();
-
-        length += headerData.length;
-
-        // 3> body data length
-        length += bodyLength;
-
-        ByteBuffer result = ByteBuffer.allocate(4 + length - bodyLength);
-
-        // length
-        result.putInt(length);
-
-        // header length
-        result.put(markProtocolType(headerData.length, serializeTypeCurrentRPC));
-
-        // header data
-        result.put(headerData);
-
-        result.flip();
-
-        return result;
+        return CodecHelper.encodeHeader(bodyLength, this);
     }
 
     public void markOnewayRPC() {
@@ -440,14 +189,6 @@ public class RemotingCommand {
         return (this.flag & bits) == bits;
     }
 
-    public int getCode() {
-        return code;
-    }
-
-    public void setCode(int code) {
-        this.code = code;
-    }
-
     @JSONField(serialize = false)
     public RemotingCommandType getType() {
         if (this.isResponseType()) {
@@ -463,6 +204,14 @@ public class RemotingCommand {
         return (this.flag & bits) == bits;
     }
 
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
     public LanguageCode getLanguage() {
         return language;
     }
@@ -526,11 +275,8 @@ public class RemotingCommand {
         extFields.put(key, value);
     }
 
-    @Override
-    public String toString() {
-        return "RemotingCommand [code=" + code + ", language=" + language + ", version=" + version + ", opaque=" + opaque + ", flag(B)="
-            + Integer.toBinaryString(flag) + ", remark=" + remark + ", extFields=" + extFields + ", serializeTypeCurrentRPC="
-            + serializeTypeCurrentRPC + "]";
+    public void setCustomHeader(CommandCustomHeader customHeader) {
+        this.customHeader = customHeader;
     }
 
     public SerializeType getSerializeTypeCurrentRPC() {
@@ -540,4 +286,12 @@ public class RemotingCommand {
     public void setSerializeTypeCurrentRPC(SerializeType serializeTypeCurrentRPC) {
         this.serializeTypeCurrentRPC = serializeTypeCurrentRPC;
     }
+
+    @Override
+    public String toString() {
+        return "RemotingCommand [code=" + code + ", language=" + language + ", version=" + version + ", opaque=" + opaque + ", flag(B)="
+            + Integer.toBinaryString(flag) + ", remark=" + remark + ", extFields=" + extFields + ", serializeTypeCurrentRPC="
+            + serializeTypeCurrentRPC + "]";
+    }
+
 }
\ No newline at end of file
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommandType.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommandType.java
index 01c853b..a6a7ec4 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommandType.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommandType.java
@@ -18,5 +18,5 @@ package org.apache.rocketmq.remoting.protocol;
 
 public enum RemotingCommandType {
     REQUEST_COMMAND,
-    RESPONSE_COMMAND;
+    RESPONSE_COMMAND
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/LanguageCode.java b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/LanguageCode.java
similarity index 92%
rename from remoting/src/main/java/org/apache/rocketmq/remoting/protocol/LanguageCode.java
rename to remoting/src/main/java/org/apache/rocketmq/remoting/serialize/LanguageCode.java
index 4382af3..246a17b 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/LanguageCode.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/LanguageCode.java
@@ -15,8 +15,11 @@
  * limitations under the License.
  */
 
-package org.apache.rocketmq.remoting.protocol;
+package org.apache.rocketmq.remoting.serialize;
 
+import org.msgpack.annotation.MessagePackOrdinalEnum;
+
+@MessagePackOrdinalEnum
 public enum LanguageCode {
     JAVA((byte) 0),
     CPP((byte) 1),
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/MsgPackSerializable.java b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/MsgPackSerializable.java
new file mode 100644
index 0000000..6c7ba78
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/MsgPackSerializable.java
@@ -0,0 +1,40 @@
+package org.apache.rocketmq.remoting.serialize;
+
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.msgpack.MessagePack;
+
+public class MsgPackSerializable implements Serializer {
+    private final MessagePack messagePack = new MessagePack();
+
+//    public MsgPackSerializable(){
+//        messagePack.register(LanguageCode.class);
+//        messagePack.register(SerializeType.class);
+//    }
+    @Override
+    public SerializeType type() {
+        return SerializeType.MSGPACK;
+    }
+
+    @Override
+    public <T> T deserializer(byte[] content, Class<T> c) {
+        try {
+            return messagePack.read(content, c);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public RemotingCommand deserializer(byte[] content) {
+        return deserializer(content, RemotingCommand.class);
+    }
+
+    @Override
+    public byte[] serializer(Object object) {
+        try {
+            return messagePack.write(object);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingSerializable.java b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/RemotingSerializable.java
similarity index 76%
rename from remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingSerializable.java
rename to remoting/src/main/java/org/apache/rocketmq/remoting/serialize/RemotingSerializable.java
index f80ff14..01e9b5c 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingSerializable.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/RemotingSerializable.java
@@ -14,12 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.rocketmq.remoting.protocol;
+package org.apache.rocketmq.remoting.serialize;
 
 import com.alibaba.fastjson.JSON;
 import java.nio.charset.Charset;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
-public abstract class RemotingSerializable {
+public class RemotingSerializable implements Serializer {
     private final static Charset CHARSET_UTF8 = Charset.forName("UTF-8");
 
     public static byte[] encode(final Object obj) {
@@ -58,4 +59,24 @@ public abstract class RemotingSerializable {
     public String toJson(final boolean prettyFormat) {
         return toJson(this, prettyFormat);
     }
+
+    @Override
+    public SerializeType type() {
+        return SerializeType.JSON;
+    }
+
+    @Override
+    public <T> T deserializer(byte[] content, Class<T> c) {
+        return decode(content, c);
+    }
+
+    @Override
+    public byte[] serializer(Object object) {
+        return encode(object);
+    }
+
+    @Override
+    public RemotingCommand deserializer(byte[] content) {
+        return decode(content, RemotingCommand.class);
+    }
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RocketMQSerializable.java b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/RocketMQSerializable.java
similarity index 91%
rename from remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RocketMQSerializable.java
rename to remoting/src/main/java/org/apache/rocketmq/remoting/serialize/RocketMQSerializable.java
index 66119e0..f903bde 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RocketMQSerializable.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/RocketMQSerializable.java
@@ -14,15 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.rocketmq.remoting.protocol;
+package org.apache.rocketmq.remoting.serialize;
 
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
-public class RocketMQSerializable {
+public class RocketMQSerializable implements Serializer {
     private static final Charset CHARSET_UTF8 = Charset.forName("UTF-8");
 
     public static byte[] rocketMQProtocolEncode(RemotingCommand cmd) {
@@ -201,4 +202,25 @@ public class RocketMQSerializable {
         }
         return true;
     }
+
+    @Override
+    public SerializeType type() {
+        return SerializeType.ROCKETMQ;
+    }
+
+    @Override
+    public <T> T deserializer(byte[] content, Class<T> c) {
+        //Fixme
+        return null;
+    }
+
+    @Override
+    public byte[] serializer(Object object) {
+        return rocketMQProtocolEncode((RemotingCommand) object);
+    }
+
+    @Override
+    public RemotingCommand deserializer(byte[] content) {
+        return rocketMQProtocolDecode(content);
+    }
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/SerializeType.java b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/SerializeType.java
similarity index 87%
rename from remoting/src/main/java/org/apache/rocketmq/remoting/protocol/SerializeType.java
rename to remoting/src/main/java/org/apache/rocketmq/remoting/serialize/SerializeType.java
index b040f8f..fc5ddba 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/SerializeType.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/SerializeType.java
@@ -15,11 +15,15 @@
  * limitations under the License.
  */
 
-package org.apache.rocketmq.remoting.protocol;
+package org.apache.rocketmq.remoting.serialize;
 
+import org.msgpack.annotation.MessagePackOrdinalEnum;
+
+@MessagePackOrdinalEnum
 public enum SerializeType {
     JSON((byte) 0),
-    ROCKETMQ((byte) 1);
+    ROCKETMQ((byte) 1),
+    MSGPACK((byte) 2);
 
     private byte code;
 
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommandType.java b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/Serializer.java
similarity index 70%
copy from remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommandType.java
copy to remoting/src/main/java/org/apache/rocketmq/remoting/serialize/Serializer.java
index 01c853b..b3f5888 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommandType.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/Serializer.java
@@ -14,9 +14,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.rocketmq.remoting.protocol;
 
-public enum RemotingCommandType {
-    REQUEST_COMMAND,
-    RESPONSE_COMMAND;
+package org.apache.rocketmq.remoting.serialize;
+
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+
+public interface Serializer {
+    SerializeType type();
+
+    <T> T deserializer(final byte[] content, final Class<T> c);
+
+    byte[] serializer(final Object object);
+
+    RemotingCommand deserializer(final byte[] content);
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/SerializerFactory.java b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/SerializerFactory.java
new file mode 100644
index 0000000..e015478
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/serialize/SerializerFactory.java
@@ -0,0 +1,26 @@
+package org.apache.rocketmq.remoting.serialize;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class SerializerFactory {
+
+    private static Map<Enum<SerializeType>, Serializer> serializerMap = new ConcurrentHashMap<Enum<SerializeType>, Serializer>();
+
+    private SerializerFactory() {
+    }
+
+    static {
+        register(SerializeType.JSON, new RemotingSerializable());
+        register(SerializeType.ROCKETMQ, new RocketMQSerializable());
+        register(SerializeType.MSGPACK, new MsgPackSerializable());
+    }
+
+    public static void register(SerializeType type, Serializer serialization) {
+        serializerMap.putIfAbsent(type, serialization);
+    }
+
+    public static Serializer get(SerializeType type) {
+        return serializerMap.get(type);
+    }
+}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingClientAbstract.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingClientAbstract.java
new file mode 100644
index 0000000..6dab218
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingClientAbstract.java
@@ -0,0 +1,411 @@
+/*
+ * 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.remoting.transport;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelDuplexHandler;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPromise;
+import io.netty.handler.timeout.IdleState;
+import io.netty.handler.timeout.IdleStateEvent;
+import java.net.SocketAddress;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Timer;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.common.RemotingUtil;
+import org.apache.rocketmq.remoting.netty.NettyEvent;
+import org.apache.rocketmq.remoting.netty.NettyEventType;
+import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract;
+
+public abstract class NettyRemotingClientAbstract extends NettyRemotingAbstract {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
+    protected final ConcurrentMap<String, ChannelWrapper> channelTables = new ConcurrentHashMap<String, ChannelWrapper>();
+
+    protected final AtomicReference<List<String>> namesrvAddrList = new AtomicReference<List<String>>();
+    private final AtomicReference<String> namesrvAddrChoosed = new AtomicReference<String>();
+    private final AtomicInteger namesrvIndex = new AtomicInteger(initValueIndex());
+    private final Lock lockNamesrvChannel = new ReentrantLock();
+
+    private final Lock lockChannelTables = new ReentrantLock();
+    private static final long LOCK_TIMEOUT_MILLIS = 3000;
+
+    public abstract Bootstrap getBootstrap();
+
+    public NettyRemotingClientAbstract() {
+        super();
+    }
+
+    public NettyRemotingClientAbstract(final int permitsOneway, final int permitsAsync) {
+        super(permitsOneway, permitsAsync);
+    }
+
+    private static int initValueIndex() {
+        Random r = new Random();
+
+        return Math.abs(r.nextInt() % 999) % 999;
+    }
+
+    public void closeChannel(final String addr, final Channel channel) {
+        if (null == channel) {
+            return;
+        }
+
+        final String addrRemote = null == addr ? RemotingHelper.parseChannelRemoteAddr(channel) : addr;
+
+        try {
+            if (this.lockChannelTables.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
+                try {
+                    boolean removeItemFromTable = true;
+                    final ChannelWrapper prevCW = this.channelTables.get(addrRemote);
+
+                    log.info("closeChannel: begin close the channel[{}] Found: {}", addrRemote, prevCW != null);
+
+                    if (null == prevCW) {
+                        log.info("closeChannel: the channel[{}] has been removed from the channel table before", addrRemote);
+                        removeItemFromTable = false;
+                    } else if (prevCW.getChannel() != channel) {
+                        log.info("closeChannel: the channel[{}] has been closed before, and has been created again, nothing to do.",
+                            addrRemote);
+                        removeItemFromTable = false;
+                    }
+
+                    if (removeItemFromTable) {
+                        this.channelTables.remove(addrRemote);
+                        log.info("closeChannel: the channel[{}] was removed from channel table", addrRemote);
+                    }
+
+                    RemotingUtil.closeChannel(channel);
+                } catch (Exception e) {
+                    log.error("closeChannel: close the channel exception", e);
+                } finally {
+                    this.lockChannelTables.unlock();
+                }
+            } else {
+                log.warn("closeChannel: try to lock channel table, but timeout, {}ms", LOCK_TIMEOUT_MILLIS);
+            }
+        } catch (InterruptedException e) {
+            log.error("closeChannel exception", e);
+        }
+    }
+
+    public void clearChannels() {
+        for (ChannelWrapper cw : this.channelTables.values()) {
+            this.closeChannel(null, cw.getChannel());
+        }
+        this.channelTables.clear();
+    }
+
+    public void closeChannel(final Channel channel) {
+        if (null == channel) {
+            return;
+        }
+
+        try {
+            if (this.lockChannelTables.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
+                try {
+                    boolean removeItemFromTable = true;
+                    ChannelWrapper prevCW = null;
+                    String addrRemote = null;
+                    for (Map.Entry<String, ChannelWrapper> entry : channelTables.entrySet()) {
+                        String key = entry.getKey();
+                        ChannelWrapper prev = entry.getValue();
+                        if (prev.getChannel() != null) {
+                            if (prev.getChannel() == channel) {
+                                prevCW = prev;
+                                addrRemote = key;
+                                break;
+                            }
+                        }
+                    }
+
+                    if (null == prevCW) {
+                        log.info("eventCloseChannel: the channel[{}] has been removed from the channel table before", addrRemote);
+                        removeItemFromTable = false;
+                    }
+
+                    if (removeItemFromTable) {
+                        this.channelTables.remove(addrRemote);
+                        log.info("closeChannel: the channel[{}] was removed from channel table", addrRemote);
+                        RemotingUtil.closeChannel(channel);
+                    }
+                } catch (Exception e) {
+                    log.error("closeChannel: close the channel exception", e);
+                } finally {
+                    this.lockChannelTables.unlock();
+                }
+            } else {
+                log.warn("closeChannel: try to lock channel table, but timeout, {}ms", LOCK_TIMEOUT_MILLIS);
+            }
+        } catch (InterruptedException e) {
+            log.error("closeChannel exception", e);
+        }
+    }
+
+    protected Channel getAndCreateChannel(final String addr, long timeout) throws InterruptedException {
+        if (null == addr) {
+            return getAndCreateNameserverChannel(timeout);
+        }
+
+        ChannelWrapper cw = this.channelTables.get(addr);
+        if (cw != null && cw.isOK()) {
+            return cw.getChannel();
+        }
+
+        return this.createChannel(addr, timeout);
+    }
+
+    private Channel getAndCreateNameserverChannel(long timeout) throws InterruptedException {
+        String addr = this.namesrvAddrChoosed.get();
+        if (addr != null) {
+            ChannelWrapper cw = this.channelTables.get(addr);
+            if (cw != null && cw.isOK()) {
+                return cw.getChannel();
+            }
+        }
+
+        final List<String> addrList = this.namesrvAddrList.get();
+        if (this.lockNamesrvChannel.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
+            try {
+                addr = this.namesrvAddrChoosed.get();
+                if (addr != null) {
+                    ChannelWrapper cw = this.channelTables.get(addr);
+                    if (cw != null && cw.isOK()) {
+                        return cw.getChannel();
+                    }
+                }
+
+                if (addrList != null && !addrList.isEmpty()) {
+                    for (int i = 0; i < addrList.size(); i++) {
+                        int index = this.namesrvIndex.incrementAndGet();
+                        index = Math.abs(index);
+                        index = index % addrList.size();
+                        String newAddr = addrList.get(index);
+
+                        this.namesrvAddrChoosed.set(newAddr);
+                        log.info("new name server is chosen. OLD: {} , NEW: {}. namesrvIndex = {}", addr, newAddr, namesrvIndex);
+                        Channel channelNew = this.createChannel(newAddr, timeout);
+                        if (channelNew != null) {
+                            return channelNew;
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                log.error("getAndCreateNameserverChannel: create name server channel exception", e);
+            } finally {
+                this.lockNamesrvChannel.unlock();
+            }
+        } else {
+            log.warn("getAndCreateNameserverChannel: try to lock name server, but timeout, {}ms", LOCK_TIMEOUT_MILLIS);
+        }
+
+        return null;
+    }
+
+    private Channel createChannel(final String addr, long timeout) throws InterruptedException {
+        ChannelWrapper cw = this.channelTables.get(addr);
+        if (cw != null && cw.isOK()) {
+            cw.getChannel().close();
+            channelTables.remove(addr);
+        }
+
+        if (this.lockChannelTables.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
+            try {
+                boolean createNewConnection;
+                cw = this.channelTables.get(addr);
+                if (cw != null) {
+
+                    if (cw.isOK()) {
+                        cw.getChannel().close();
+                        this.channelTables.remove(addr);
+                        createNewConnection = true;
+                    } else if (!cw.getChannelFuture().isDone()) {
+                        createNewConnection = false;
+                    } else {
+                        this.channelTables.remove(addr);
+                        createNewConnection = true;
+                    }
+                } else {
+                    createNewConnection = true;
+                }
+
+                if (createNewConnection) {
+                    if (getBootstrap() != null) {
+                        ChannelFuture channelFuture = getBootstrap().connect(RemotingHelper.string2SocketAddress(addr));
+                        log.info("createChannel: begin to connect remote host[{}] asynchronously", addr);
+                        cw = new ChannelWrapper(channelFuture);
+                        this.channelTables.put(addr, cw);
+                    }
+                }
+            } catch (Exception e) {
+                log.error("createChannel: create channel exception", e);
+            } finally {
+                this.lockChannelTables.unlock();
+            }
+        } else {
+            log.warn("createChannel: try to lock channel table, but timeout, {}ms", LOCK_TIMEOUT_MILLIS);
+        }
+
+        if (cw != null) {
+            ChannelFuture channelFuture = cw.getChannelFuture();
+            if (channelFuture.awaitUninterruptibly(timeout)) {
+                if (cw.isOK()) {
+                    log.info("createChannel: connect remote host[{}] success, {}", addr, channelFuture.toString());
+                    return cw.getChannel();
+                } else {
+                    log.warn("createChannel: connect remote host[" + addr + "] failed, " + channelFuture.toString(), channelFuture.cause());
+                }
+            } else {
+                log.warn("createChannel: connect remote host[{}] timeout {}ms, {}", addr, timeout,
+                    channelFuture.toString());
+            }
+        }
+
+        return null;
+    }
+
+    public void updateNameServerAddressList(List<String> addrs) {
+        List<String> old = this.namesrvAddrList.get();
+        boolean update = false;
+
+        if (!addrs.isEmpty()) {
+            if (null == old) {
+                update = true;
+            } else if (addrs.size() != old.size()) {
+                update = true;
+            } else {
+                for (int i = 0; i < addrs.size() && !update; i++) {
+                    if (!old.contains(addrs.get(i))) {
+                        update = true;
+                    }
+                }
+            }
+
+            if (update) {
+                Collections.shuffle(addrs);
+                log.info("name server address updated. NEW : {} , OLD: {}", addrs, old);
+                this.namesrvAddrList.set(addrs);
+            }
+        }
+    }
+
+    public static class ChannelWrapper {
+        private final ChannelFuture channelFuture;
+
+        public ChannelWrapper(ChannelFuture channelFuture) {
+            this.channelFuture = channelFuture;
+        }
+
+        public boolean isOK() {
+            return this.channelFuture.channel() != null && this.channelFuture.channel().isActive();
+        }
+
+        public boolean isWritable() {
+            return this.channelFuture.channel().isWritable();
+        }
+
+        public Channel getChannel() {
+            return this.channelFuture.channel();
+        }
+
+        public ChannelFuture getChannelFuture() {
+            return channelFuture;
+        }
+    }
+
+    public class NettyConnectManageHandler extends ChannelDuplexHandler {
+        @Override
+        public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
+            ChannelPromise promise) throws Exception {
+            final String local = localAddress == null ? "UNKNOWN" : RemotingHelper.parseSocketAddressAddr(localAddress);
+            final String remote = remoteAddress == null ? "UNKNOWN" : RemotingHelper.parseSocketAddressAddr(remoteAddress);
+            log.info("NETTY CLIENT PIPELINE: CONNECT  {} => {}", local, remote);
+
+            super.connect(ctx, remoteAddress, localAddress, promise);
+
+            if (getChannelEventListener() != null) {
+                putNettyEvent(new NettyEvent(NettyEventType.CONNECT, remote, ctx.channel()));
+            }
+        }
+
+        @Override
+        public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
+            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
+            log.info("NETTY CLIENT PIPELINE: DISCONNECT {}", remoteAddress);
+            closeChannel(ctx.channel());
+            super.disconnect(ctx, promise);
+
+            if (getChannelEventListener() != null) {
+                putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress, ctx.channel()));
+            }
+        }
+
+        @Override
+        public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
+            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
+            log.info("NETTY CLIENT PIPELINE: CLOSE {}", remoteAddress);
+            closeChannel(ctx.channel());
+            super.close(ctx, promise);
+            failFast(ctx.channel());
+            if (getChannelEventListener() != null) {
+                putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress, ctx.channel()));
+            }
+        }
+
+        @Override
+        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+            if (evt instanceof IdleStateEvent) {
+                IdleStateEvent event = (IdleStateEvent) evt;
+                if (event.state().equals(IdleState.ALL_IDLE)) {
+                    final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
+                    log.warn("NETTY CLIENT PIPELINE: IDLE exception [{}]", remoteAddress);
+                    closeChannel(ctx.channel());
+                    if (getChannelEventListener() != null) {
+                        putNettyEvent(new NettyEvent(NettyEventType.IDLE, remoteAddress, ctx.channel()));
+                    }
+                }
+            }
+
+            ctx.fireUserEventTriggered(evt);
+        }
+
+        @Override
+        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
+            log.warn("NETTY CLIENT PIPELINE: exceptionCaught {}", remoteAddress);
+            log.warn("NETTY CLIENT PIPELINE: exceptionCaught exception.", cause);
+            closeChannel(ctx.channel());
+            if (getChannelEventListener() != null) {
+                putNettyEvent(new NettyEvent(NettyEventType.EXCEPTION, remoteAddress, ctx.channel()));
+            }
+        }
+    }
+
+}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingServerAbstract.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingServerAbstract.java
new file mode 100644
index 0000000..e8d8471
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingServerAbstract.java
@@ -0,0 +1,93 @@
+package org.apache.rocketmq.remoting.transport;
+
+import io.netty.channel.ChannelDuplexHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.timeout.IdleState;
+import io.netty.handler.timeout.IdleStateEvent;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.common.RemotingUtil;
+import org.apache.rocketmq.remoting.netty.NettyEvent;
+import org.apache.rocketmq.remoting.netty.NettyEventType;
+import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract;
+
+public abstract class NettyRemotingServerAbstract extends NettyRemotingAbstract {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
+
+    public NettyRemotingServerAbstract() {
+        super();
+    }
+
+    public NettyRemotingServerAbstract(final int permitsOneway, final int permitsAsync) {
+        super(permitsOneway, permitsAsync);
+    }
+
+    public class NettyConnectManageHandler extends ChannelDuplexHandler {
+        @Override
+        public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
+            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
+            log.info("NETTY SERVER PIPELINE: channelRegistered {}", remoteAddress);
+            super.channelRegistered(ctx);
+        }
+
+        @Override
+        public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
+            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
+            log.info("NETTY SERVER PIPELINE: channelUnregistered, the channel[{}]", remoteAddress);
+            super.channelUnregistered(ctx);
+        }
+
+        @Override
+        public void channelActive(ChannelHandlerContext ctx) throws Exception {
+            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
+            log.info("NETTY SERVER PIPELINE: channelActive, the channel[{}]", remoteAddress);
+            super.channelActive(ctx);
+
+            if (getChannelEventListener() != null) {
+                putNettyEvent(new NettyEvent(NettyEventType.CONNECT, remoteAddress, ctx.channel()));
+            }
+        }
+
+        @Override
+        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
+            log.info("NETTY SERVER PIPELINE: channelInactive, the channel[{}]", remoteAddress);
+            super.channelInactive(ctx);
+
+            if (getChannelEventListener() != null) {
+                putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress, ctx.channel()));
+            }
+        }
+
+        @Override
+        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+            if (evt instanceof IdleStateEvent) {
+                IdleStateEvent event = (IdleStateEvent) evt;
+                if (event.state().equals(IdleState.ALL_IDLE)) {
+                    final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
+                    log.warn("NETTY SERVER PIPELINE: IDLE exception [{}]", remoteAddress);
+                    RemotingUtil.closeChannel(ctx.channel());
+                    if (getChannelEventListener() != null) {
+                        putNettyEvent(new NettyEvent(NettyEventType.IDLE, remoteAddress, ctx.channel()));
+                    }
+                }
+            }
+
+            ctx.fireUserEventTriggered(evt);
+        }
+
+        @Override
+        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
+            log.warn("NETTY SERVER PIPELINE: exceptionCaught {}", remoteAddress);
+            log.warn("NETTY SERVER PIPELINE: exceptionCaught exception.", cause);
+
+            if (getChannelEventListener() != null) {
+                putNettyEvent(new NettyEvent(NettyEventType.EXCEPTION, remoteAddress, ctx.channel()));
+            }
+
+            RemotingUtil.closeChannel(ctx.channel());
+        }
+    }
+}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java
new file mode 100644
index 0000000..b294958
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java
@@ -0,0 +1,293 @@
+package org.apache.rocketmq.remoting.transport.http2;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.http2.Http2SecurityUtil;
+import io.netty.handler.ssl.OpenSsl;
+import io.netty.handler.ssl.SslContextBuilder;
+import io.netty.handler.ssl.SslProvider;
+import io.netty.handler.ssl.SupportedCipherSuiteFilter;
+import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
+import io.netty.handler.timeout.IdleStateHandler;
+import io.netty.util.concurrent.DefaultEventExecutorGroup;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import javax.net.ssl.SSLException;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.ChannelEventListener;
+import org.apache.rocketmq.remoting.InvokeCallback;
+import org.apache.rocketmq.remoting.RPCHook;
+import org.apache.rocketmq.remoting.RemotingClient;
+import org.apache.rocketmq.remoting.common.Pair;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.exception.RemotingConnectException;
+import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
+import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
+import org.apache.rocketmq.remoting.netty.NettyClientConfig;
+import org.apache.rocketmq.remoting.transport.rocketmq.NettyDecoder;
+import org.apache.rocketmq.remoting.transport.rocketmq.NettyEncoder;
+import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.transport.NettyRemotingClientAbstract;
+import org.apache.rocketmq.remoting.util.ThreadUtils;
+
+public class Http2ClientImpl extends NettyRemotingClientAbstract implements RemotingClient {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
+    private NettyClientConfig nettyClientConfig;
+    private final Bootstrap bootstrap = new Bootstrap();
+    private EventLoopGroup ioGroup;
+    private ExecutorService publicExecutor;
+    private ExecutorService callbackExecutor;
+    private ChannelEventListener channelEventListener;
+    private DefaultEventExecutorGroup defaultEventExecutorGroup;
+    private RPCHook rpcHook;
+
+    public Http2ClientImpl(final NettyClientConfig clientConfig,
+        final ChannelEventListener channelEventListener) {
+        super(clientConfig.getClientOnewaySemaphoreValue(), clientConfig.getClientAsyncSemaphoreValue());
+        init(clientConfig, channelEventListener);
+    }
+
+    public Http2ClientImpl(){
+        super();
+    }
+
+    @Override
+    public void init(NettyClientConfig clientConfig, ChannelEventListener channelEventListener) {
+        this.nettyClientConfig = clientConfig;
+        this.channelEventListener = channelEventListener;
+        this.ioGroup = new NioEventLoopGroup(clientConfig.getClientWorkerThreads(), ThreadUtils.newGenericThreadFactory("NettyClientEpollIoThreads",
+            clientConfig.getClientWorkerThreads()));
+        this.publicExecutor = ThreadUtils.newFixedThreadPool(
+            clientConfig.getClientCallbackExecutorThreads(),
+            10000, "Remoting-PublicExecutor", true);
+        this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(clientConfig.getClientWorkerThreads(),
+            ThreadUtils.newGenericThreadFactory("NettyClientWorkerThreads", clientConfig.getClientWorkerThreads()));
+        buildSslContext();
+    }
+
+    private void buildSslContext() {
+        SslProvider provider = OpenSsl.isAvailable() ? SslProvider.OPENSSL : SslProvider.JDK;
+        try {
+            sslContext = SslContextBuilder.forClient()
+                .sslProvider(provider)
+                /* NOTE: the cipher filter may not include all ciphers required by the HTTP/2 specification.
+                 * Please refer to the HTTP/2 specification for cipher requirements. */
+                .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
+                .trustManager(InsecureTrustManagerFactory.INSTANCE)
+                .build();
+        } catch (SSLException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void start() {
+        super.start();
+        this.bootstrap.group(this.ioGroup).channel(NioSocketChannel.class)
+            .option(ChannelOption.TCP_NODELAY, true)
+            .option(ChannelOption.SO_KEEPALIVE, false)
+            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, nettyClientConfig.getConnectTimeoutMillis())
+            .option(ChannelOption.SO_SNDBUF, nettyClientConfig.getClientSocketSndBufSize())
+            .option(ChannelOption.SO_RCVBUF, nettyClientConfig.getClientSocketRcvBufSize())
+            .handler(new ChannelInitializer<SocketChannel>() {
+                @Override
+                public void initChannel(SocketChannel ch) throws Exception {
+                    ChannelPipeline pipeline = ch.pipeline();
+                    pipeline.addLast(
+                        defaultEventExecutorGroup,
+                        Http2Handler.newHandler(false),
+                        new NettyEncoder(),
+                        new NettyDecoder(),
+                        new IdleStateHandler(0, 0, nettyClientConfig.getClientChannelMaxIdleTimeSeconds()),
+                        new NettyConnectManageHandler(),
+                        new NettyClientHandler());
+                }
+            });
+        startUpHouseKeepingService();
+    }
+
+    @Override
+    public void shutdown() {
+        super.shutdown();
+        try {
+
+            for (ChannelWrapper cw : this.channelTables.values()) {
+                this.closeChannel(null, cw.getChannel());
+            }
+
+            this.channelTables.clear();
+            if (this.ioGroup != null) {
+                this.ioGroup.shutdownGracefully();
+            }
+
+            if (this.defaultEventExecutorGroup != null) {
+                this.defaultEventExecutorGroup.shutdownGracefully();
+            }
+        } catch (Exception e) {
+            log.error("Http2ClientImpl shutdown exception, ", e);
+        }
+
+        if (this.publicExecutor != null) {
+            try {
+                this.publicExecutor.shutdown();
+            } catch (Exception e) {
+                log.error("NettyRemotingServer shutdown exception, ", e);
+            }
+        }
+    }
+
+    @Override
+    public void registerRPCHook(RPCHook rpcHook) {
+        this.rpcHook = rpcHook;
+    }
+
+    @Override
+    public void updateNameServerAddressList(List<String> addrs) {
+        super.updateNameServerAddressList(addrs);
+    }
+
+    @Override
+    public RemotingCommand invokeSync(String addr, final RemotingCommand request, long timeoutMillis)
+        throws InterruptedException, RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException {
+        final Channel channel = this.getAndCreateChannel(addr, timeoutMillis);
+        if (channel != null && channel.isActive()) {
+            try {
+                if (this.rpcHook != null) {
+                    this.rpcHook.doBeforeRequest(addr, request);
+                }
+                RemotingCommand response = this.invokeSyncImpl(channel, request, timeoutMillis);
+                if (this.rpcHook != null) {
+                    this.rpcHook.doAfterResponse(RemotingHelper.parseChannelRemoteAddr(channel), request, response);
+                }
+                return response;
+            } catch (RemotingSendRequestException e) {
+                log.warn("invokeSync: send request exception, so close the channel[{}]", addr);
+                this.closeChannel(addr, channel);
+                throw e;
+            } catch (RemotingTimeoutException e) {
+                if (nettyClientConfig.isClientCloseSocketIfTimeout()) {
+                    this.closeChannel(addr, channel);
+                    log.warn("invokeSync: close socket because of timeout, {}ms, {}", timeoutMillis, addr);
+                }
+                log.warn("invokeSync: wait response timeout exception, the channel[{}]", addr);
+                throw e;
+            }
+        } else {
+            this.closeChannel(addr, channel);
+            throw new RemotingConnectException(addr);
+        }
+    }
+
+    @Override
+    public void invokeAsync(String addr, RemotingCommand request, long timeoutMillis, InvokeCallback invokeCallback)
+        throws InterruptedException, RemotingConnectException, RemotingTooMuchRequestException, RemotingTimeoutException,
+        RemotingSendRequestException {
+        final Channel channel = this.getAndCreateChannel(addr, timeoutMillis);
+        if (channel != null && channel.isActive()) {
+            try {
+                if (this.rpcHook != null) {
+                    this.rpcHook.doBeforeRequest(addr, request);
+                }
+                this.invokeAsyncImpl(channel, request, timeoutMillis, invokeCallback);
+            } catch (RemotingSendRequestException e) {
+                log.warn("invokeAsync: send request exception, so close the channel[{}]", addr);
+                this.closeChannel(addr, channel);
+                throw e;
+            }
+        } else {
+            this.closeChannel(addr, channel);
+            throw new RemotingConnectException(addr);
+        }
+    }
+
+    @Override
+    public void invokeOneway(String addr, RemotingCommand request, long timeoutMillis) throws InterruptedException,
+        RemotingConnectException, RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
+        final Channel channel = this.getAndCreateChannel(addr, timeoutMillis);
+        if (channel != null && channel.isActive()) {
+            try {
+                if (this.rpcHook != null) {
+                    this.rpcHook.doBeforeRequest(addr, request);
+                }
+                this.invokeOnewayImpl(channel, request, timeoutMillis);
+            } catch (RemotingSendRequestException e) {
+                log.warn("invokeOneway: send request exception, so close the channel[{}]", addr);
+                this.closeChannel(addr, channel);
+                throw e;
+            }
+        } else {
+            this.closeChannel(addr, channel);
+            throw new RemotingConnectException(addr);
+        }
+    }
+
+    @Override
+    public Bootstrap getBootstrap() {
+        return this.bootstrap;
+    }
+
+    @Override
+    public void registerProcessor(int requestCode, NettyRequestProcessor processor, ExecutorService executor) {
+        ExecutorService executorThis = executor;
+        if (null == executor) {
+            executorThis = this.publicExecutor;
+        }
+
+        Pair<NettyRequestProcessor, ExecutorService> pair = new Pair<NettyRequestProcessor, ExecutorService>(processor, executorThis);
+        this.processorTable.put(requestCode, pair);
+    }
+
+    @Override
+    public boolean isChannelWritable(String addr) {
+        ChannelWrapper cw = this.channelTables.get(addr);
+        if (cw != null && cw.isOK()) {
+            return cw.isWritable();
+        }
+        return true;
+    }
+
+    @Override
+    public List<String> getNameServerAddressList() {
+        return this.namesrvAddrList.get();
+    }
+
+    @Override
+    public ChannelEventListener getChannelEventListener() {
+        return channelEventListener;
+    }
+
+    @Override
+    public RPCHook getRPCHook() {
+        return this.rpcHook;
+    }
+
+    @Override
+    public ExecutorService getCallbackExecutor() {
+        return callbackExecutor != null ? callbackExecutor : publicExecutor;
+    }
+
+    @Override
+    public void setCallbackExecutor(final ExecutorService callbackExecutor) {
+        this.callbackExecutor = callbackExecutor;
+    }
+
+    class NettyClientHandler extends SimpleChannelInboundHandler<RemotingCommand> {
+        @Override
+        protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception {
+            processMessageReceived(ctx, msg);
+        }
+    }
+
+}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2Handler.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2Handler.java
new file mode 100644
index 0000000..2f4c8a1
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2Handler.java
@@ -0,0 +1,143 @@
+/*
+ * 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.remoting.transport.http2;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPromise;
+import io.netty.handler.codec.http2.DefaultHttp2Connection;
+import io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder;
+import io.netty.handler.codec.http2.DefaultHttp2ConnectionEncoder;
+import io.netty.handler.codec.http2.DefaultHttp2FrameReader;
+import io.netty.handler.codec.http2.DefaultHttp2FrameWriter;
+import io.netty.handler.codec.http2.DefaultHttp2Headers;
+import io.netty.handler.codec.http2.DefaultHttp2HeadersDecoder;
+import io.netty.handler.codec.http2.DefaultHttp2LocalFlowController;
+import io.netty.handler.codec.http2.Http2Connection;
+import io.netty.handler.codec.http2.Http2ConnectionDecoder;
+import io.netty.handler.codec.http2.Http2ConnectionEncoder;
+import io.netty.handler.codec.http2.Http2ConnectionHandler;
+import io.netty.handler.codec.http2.Http2Exception;
+import io.netty.handler.codec.http2.Http2FrameAdapter;
+import io.netty.handler.codec.http2.Http2FrameReader;
+import io.netty.handler.codec.http2.Http2FrameWriter;
+import io.netty.handler.codec.http2.Http2Headers;
+import io.netty.handler.codec.http2.Http2HeadersDecoder;
+import io.netty.handler.codec.http2.Http2Settings;
+import io.netty.handler.codec.http2.StreamBufferingEncoder;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+
+import static io.netty.handler.codec.http.HttpResponseStatus.OK;
+import static io.netty.handler.codec.http2.DefaultHttp2LocalFlowController.DEFAULT_WINDOW_UPDATE_RATIO;
+
+public class Http2Handler extends Http2ConnectionHandler {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
+
+    private boolean isServer;
+    private int lastStreamId;
+
+    private Http2Handler(final Http2ConnectionDecoder decoder, final Http2ConnectionEncoder encoder,
+        final Http2Settings initialSettings, final boolean isServer) {
+        super(decoder, encoder, initialSettings);
+        decoder.frameListener(new FrameListener());
+        this.isServer = isServer;
+    }
+
+    public static Http2Handler newHandler(final boolean isServer) {
+        log.info("isServer: " + isServer);
+        Http2HeadersDecoder headersDecoder = new DefaultHttp2HeadersDecoder(true);
+        Http2FrameReader frameReader = new DefaultHttp2FrameReader(headersDecoder);
+        Http2FrameWriter frameWriter = new DefaultHttp2FrameWriter();
+
+        Http2Connection connection = new DefaultHttp2Connection(isServer);
+
+        Http2ConnectionEncoder encoder = new StreamBufferingEncoder(
+            new DefaultHttp2ConnectionEncoder(connection, frameWriter));
+
+        connection.local().flowController(new DefaultHttp2LocalFlowController(connection,
+            DEFAULT_WINDOW_UPDATE_RATIO, true));
+
+        Http2ConnectionDecoder decoder = new DefaultHttp2ConnectionDecoder(connection, encoder,
+            frameReader);
+
+        Http2Settings settings = new Http2Settings();
+
+        if (!isServer) {
+            settings.pushEnabled(true);
+        }
+
+        settings.initialWindowSize(1048576 * 10); //10MiB
+        settings.maxConcurrentStreams(Integer.MAX_VALUE);
+
+        return newHandler(decoder, encoder, settings, isServer);
+    }
+
+    private static Http2Handler newHandler(final Http2ConnectionDecoder decoder, final Http2ConnectionEncoder encoder,
+        final Http2Settings settings, boolean isServer) {
+        return new Http2Handler(decoder, encoder, settings, isServer);
+    }
+
+    @Override
+    public void write(final ChannelHandlerContext ctx, final Object msg,
+        final ChannelPromise promise) throws Exception {
+        if (isServer) {
+            assert msg instanceof ByteBuf;
+            sendAPushPromise(ctx, lastStreamId, lastStreamId + 1, (ByteBuf) msg);
+        } else {
+
+            final Http2Headers headers = new DefaultHttp2Headers();
+
+            try {
+                long threadId = Thread.currentThread().getId();
+                long streamId = (threadId % 2 == 0) ? threadId + 1 : threadId + 2;
+                encoder().writeHeaders(ctx, (int) streamId, headers, 0, false, promise);
+                encoder().writeData(ctx, (int) streamId, (ByteBuf) msg, 0, false, ctx.newPromise());
+                ctx.flush();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+        }
+    }
+
+    private void sendAPushPromise(ChannelHandlerContext ctx, int streamId, int pushPromiseStreamId,
+        ByteBuf payload) throws Http2Exception {
+
+        encoder().writePushPromise(ctx, streamId, pushPromiseStreamId,
+            new DefaultHttp2Headers().status(OK.codeAsText()), 0, ctx.newPromise());
+
+        Http2Headers headers = new DefaultHttp2Headers();
+        headers.status(OK.codeAsText());
+        encoder().writeHeaders(ctx, pushPromiseStreamId, headers, 0, false, ctx.newPromise());
+        encoder().writeData(ctx, pushPromiseStreamId, payload, 0, false, ctx.newPromise());
+    }
+
+    private class FrameListener extends Http2FrameAdapter {
+        @Override
+        public int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding,
+            boolean endOfStream) throws Http2Exception {
+            //Http2Handler.this.onDataRead(ctx, streamId, data, endOfStream);
+            data.retain();
+            Http2Handler.this.lastStreamId = streamId;
+            ctx.fireChannelRead(data);
+            return data.readableBytes() + padding;
+        }
+    }
+}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java
new file mode 100644
index 0000000..02c4fb6
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java
@@ -0,0 +1,242 @@
+package org.apache.rocketmq.remoting.transport.http2;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.buffer.PooledByteBufAllocator;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.epoll.EpollEventLoopGroup;
+import io.netty.channel.epoll.EpollServerSocketChannel;
+import io.netty.channel.group.ChannelGroup;
+import io.netty.channel.group.DefaultChannelGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.ServerSocketChannel;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.handler.codec.http2.Http2SecurityUtil;
+import io.netty.handler.ssl.OpenSsl;
+import io.netty.handler.ssl.SslContextBuilder;
+import io.netty.handler.ssl.SslProvider;
+import io.netty.handler.ssl.SupportedCipherSuiteFilter;
+import io.netty.handler.ssl.util.SelfSignedCertificate;
+import io.netty.handler.timeout.IdleStateHandler;
+import io.netty.util.concurrent.DefaultEventExecutorGroup;
+import io.netty.util.concurrent.EventExecutorGroup;
+import io.netty.util.concurrent.GlobalEventExecutor;
+import java.net.InetSocketAddress;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.ChannelEventListener;
+import org.apache.rocketmq.remoting.InvokeCallback;
+import org.apache.rocketmq.remoting.RPCHook;
+import org.apache.rocketmq.remoting.RemotingServer;
+import org.apache.rocketmq.remoting.common.Pair;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
+import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
+import org.apache.rocketmq.remoting.netty.ChannelStatisticsHandler;
+import org.apache.rocketmq.remoting.transport.rocketmq.NettyDecoder;
+import org.apache.rocketmq.remoting.transport.rocketmq.NettyEncoder;
+import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.transport.NettyRemotingServerAbstract;
+import org.apache.rocketmq.remoting.util.JvmUtils;
+import org.apache.rocketmq.remoting.util.ThreadUtils;
+
+public class Http2ServerImpl extends NettyRemotingServerAbstract implements RemotingServer {
+    private static final InternalLogger LOG = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
+
+    private ServerBootstrap serverBootstrap;
+    private EventLoopGroup bossGroup;
+    private EventLoopGroup ioGroup;
+    private EventExecutorGroup workerGroup;
+    private Class<? extends ServerSocketChannel> socketChannelClass;
+    private NettyServerConfig serverConfig;
+    private ChannelEventListener channelEventListener;
+    private ExecutorService publicExecutor;
+    private int port;
+    private RPCHook rpcHook;
+
+    public Http2ServerImpl(NettyServerConfig nettyServerConfig, ChannelEventListener channelEventListener) {
+        super(nettyServerConfig.getServerOnewaySemaphoreValue(), nettyServerConfig.getServerAsyncSemaphoreValue());
+        init(nettyServerConfig, channelEventListener);
+    }
+
+    public Http2ServerImpl() {
+        super();
+    }
+
+    @Override
+    public void init(NettyServerConfig nettyServerConfig, ChannelEventListener channelEventListener) {
+        super.init(nettyServerConfig.getServerOnewaySemaphoreValue(), nettyServerConfig.getServerAsyncSemaphoreValue());
+        this.serverBootstrap = new ServerBootstrap();
+        this.serverConfig = nettyServerConfig;
+        this.channelEventListener = channelEventListener;
+        this.publicExecutor = ThreadUtils.newFixedThreadPool(
+            serverConfig.getServerCallbackExecutorThreads(),
+            10000, "Remoting-PublicExecutor", true);
+        if (JvmUtils.isLinux() && this.serverConfig.isUseEpollNativeSelector()) {
+            this.ioGroup = new EpollEventLoopGroup(serverConfig.getServerSelectorThreads(), ThreadUtils.newGenericThreadFactory("NettyEpollIoThreads",
+                serverConfig.getServerSelectorThreads()));
+            this.bossGroup = new EpollEventLoopGroup(serverConfig.getServerAcceptorThreads(), ThreadUtils.newGenericThreadFactory("NettyBossThreads",
+                serverConfig.getServerAcceptorThreads()));
+            this.socketChannelClass = EpollServerSocketChannel.class;
+        } else {
+            this.bossGroup = new NioEventLoopGroup(serverConfig.getServerAcceptorThreads(), ThreadUtils.newGenericThreadFactory("NettyBossThreads",
+                serverConfig.getServerAcceptorThreads()));
+            this.ioGroup = new NioEventLoopGroup(serverConfig.getServerSelectorThreads(), ThreadUtils.newGenericThreadFactory("NettyNioIoThreads",
+                serverConfig.getServerSelectorThreads()));
+            this.socketChannelClass = NioServerSocketChannel.class;
+        }
+
+        this.workerGroup = new DefaultEventExecutorGroup(serverConfig.getServerWorkerThreads(),
+            ThreadUtils.newGenericThreadFactory("NettyWorkerThreads", serverConfig.getServerWorkerThreads()));
+        this.port = nettyServerConfig.getListenPort();
+        buildHttp2SslContext();
+    }
+
+    private void buildHttp2SslContext() {
+        try {
+            SslProvider provider = OpenSsl.isAvailable() ? SslProvider.OPENSSL : SslProvider.JDK;
+            SelfSignedCertificate ssc;
+            //NOTE: the cipher filter may not include all ciphers required by the HTTP/2 specification.
+            //Please refer to the HTTP/2 specification for cipher requirements.
+            ssc = new SelfSignedCertificate();
+            sslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
+                .sslProvider(provider)
+                .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE).build();
+        } catch (Exception e) {
+            LOG.error("Can not build SSL context !", e);
+        }
+    }
+
+    @Override
+    public void registerProcessor(int requestCode, NettyRequestProcessor processor, ExecutorService executor) {
+        ExecutorService executorThis = executor;
+        if (null == executor) {
+            executorThis = this.publicExecutor;
+        }
+        Pair<NettyRequestProcessor, ExecutorService> pair = new Pair<NettyRequestProcessor, ExecutorService>(processor, executorThis);
+        this.processorTable.put(requestCode, pair);
+    }
+
+    @Override
+    public void registerDefaultProcessor(NettyRequestProcessor processor, ExecutorService executor) {
+        this.defaultRequestProcessor = new Pair<NettyRequestProcessor, ExecutorService>(processor, executor);
+    }
+
+    @Override
+    public int localListenPort() {
+        return this.port;
+    }
+
+    @Override
+    public Pair<NettyRequestProcessor, ExecutorService> getProcessorPair(int requestCode) {
+        return processorTable.get(requestCode);
+    }
+
+    @Override
+    public void push(String addr, String sessionId, RemotingCommand remotingCommand) {
+
+    }
+
+    @Override
+    public RemotingCommand invokeSync(final Channel channel, final RemotingCommand request, final long timeoutMillis)
+        throws InterruptedException, RemotingSendRequestException, RemotingTimeoutException {
+        return this.invokeSyncImpl(channel, request, timeoutMillis);
+    }
+
+    @Override
+    public void invokeAsync(Channel channel, RemotingCommand request, long timeoutMillis, InvokeCallback invokeCallback)
+        throws InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
+        this.invokeAsyncImpl(channel, request, timeoutMillis, invokeCallback);
+    }
+
+    @Override
+    public void invokeOneway(Channel channel, RemotingCommand request, long timeoutMillis) throws InterruptedException,
+        RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
+        this.invokeOnewayImpl(channel, request, timeoutMillis);
+    }
+
+    private void applyOptions(ServerBootstrap bootstrap) {
+        if (null != serverConfig) {
+            bootstrap.option(ChannelOption.SO_BACKLOG, 1024)
+                .option(ChannelOption.SO_REUSEADDR, true)
+                .option(ChannelOption.SO_KEEPALIVE, false)
+                .childOption(ChannelOption.TCP_NODELAY, true)
+                .childOption(ChannelOption.SO_SNDBUF, serverConfig.getServerSocketSndBufSize())
+                .childOption(ChannelOption.SO_RCVBUF, serverConfig.getServerSocketRcvBufSize());
+        }
+
+        if (serverConfig.isServerPooledByteBufAllocatorEnable()) {
+            bootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
+        }
+    }
+
+    @Override
+    public void start() {
+        super.start();
+        final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
+        this.serverBootstrap.group(this.bossGroup, this.ioGroup).
+            channel(socketChannelClass).childHandler(new ChannelInitializer<SocketChannel>() {
+            @Override
+            public void initChannel(SocketChannel ch) throws Exception {
+                channels.add(ch);
+
+                ChannelPipeline cp = ch.pipeline();
+
+                cp.addLast(ChannelStatisticsHandler.NAME, new ChannelStatisticsHandler(channels));
+
+                cp.addLast(workerGroup,
+                    Http2Handler.newHandler(true),
+                    new NettyEncoder(),
+                    new NettyDecoder(),
+                    new IdleStateHandler(serverConfig.getConnectionChannelReaderIdleSeconds(),
+                        serverConfig.getConnectionChannelWriterIdleSeconds(),
+                        serverConfig.getServerChannelMaxIdleTimeSeconds()),
+                    new NettyConnectManageHandler(),
+                    new NettyServerHandler());
+            }
+        });
+
+        applyOptions(serverBootstrap);
+
+        ChannelFuture channelFuture = this.serverBootstrap.bind(this.port).syncUninterruptibly();
+        this.port = ((InetSocketAddress) channelFuture.channel().localAddress()).getPort();
+        startUpHouseKeepingService();
+    }
+
+    @Override
+    public void shutdown() {
+        super.shutdown();
+        ThreadUtils.shutdownGracefully(publicExecutor, 2000, TimeUnit.MILLISECONDS);
+    }
+
+    @Override
+    public void registerRPCHook(RPCHook rpcHook) {
+        this.rpcHook = rpcHook;
+    }
+
+    @Override
+    public RPCHook getRPCHook() {
+        return this.rpcHook;
+    }
+
+    @Override
+    public ExecutorService getCallbackExecutor() {
+        return this.publicExecutor;
+    }
+
+    @Override
+    public ChannelEventListener getChannelEventListener() {
+        return this.channelEventListener;
+    }
+
+}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyDecoder.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyDecoder.java
similarity index 93%
rename from remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyDecoder.java
rename to remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyDecoder.java
index f64ab2d..70858a9 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyDecoder.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyDecoder.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.rocketmq.remoting.netty;
+package org.apache.rocketmq.remoting.transport.rocketmq;
 
 import io.netty.buffer.ByteBuf;
 import io.netty.channel.ChannelHandlerContext;
@@ -24,6 +24,7 @@ import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.common.RemotingUtil;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.netty.CodecHelper;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
 public class NettyDecoder extends LengthFieldBasedFrameDecoder {
@@ -46,8 +47,7 @@ public class NettyDecoder extends LengthFieldBasedFrameDecoder {
             }
 
             ByteBuffer byteBuffer = frame.nioBuffer();
-
-            return RemotingCommand.decode(byteBuffer);
+            return CodecHelper.decode(byteBuffer);
         } catch (Exception e) {
             log.error("decode exception, " + RemotingHelper.parseChannelRemoteAddr(ctx.channel()), e);
             RemotingUtil.closeChannel(ctx.channel());
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyEncoder.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyEncoder.java
similarity index 88%
rename from remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyEncoder.java
rename to remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyEncoder.java
index 8c3c56a..8285dee 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyEncoder.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyEncoder.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.rocketmq.remoting.netty;
+package org.apache.rocketmq.remoting.transport.rocketmq;
 
 import io.netty.buffer.ByteBuf;
 import io.netty.channel.ChannelHandlerContext;
@@ -24,17 +24,17 @@ import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.common.RemotingUtil;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.netty.CodecHelper;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
 public class NettyEncoder extends MessageToByteEncoder<RemotingCommand> {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
 
     @Override
-    public void encode(ChannelHandlerContext ctx, RemotingCommand remotingCommand, ByteBuf out)
-        throws Exception {
+    public void encode(ChannelHandlerContext ctx, RemotingCommand remotingCommand, ByteBuf out) {
         try {
-            ByteBuffer header = remotingCommand.encodeHeader();
-            out.writeBytes(header);
+            ByteBuffer byteBuffer = CodecHelper.encodeHeader(remotingCommand);
+            out.writeBytes(byteBuffer);
             byte[] body = remotingCommand.getBody();
             if (body != null) {
                 out.writeBytes(body);
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java
new file mode 100644
index 0000000..14666d2
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java
@@ -0,0 +1,315 @@
+/*
+ * 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.remoting.transport.rocketmq;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.timeout.IdleStateHandler;
+import io.netty.util.concurrent.DefaultEventExecutorGroup;
+import java.io.IOException;
+import java.security.cert.CertificateException;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import javax.xml.ws.AsyncHandler;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.ChannelEventListener;
+import org.apache.rocketmq.remoting.InvokeCallback;
+import org.apache.rocketmq.remoting.RPCHook;
+import org.apache.rocketmq.remoting.RemotingClient;
+import org.apache.rocketmq.remoting.common.Pair;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.exception.RemotingConnectException;
+import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
+import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
+import org.apache.rocketmq.remoting.netty.NettyClientConfig;
+import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.netty.TlsHelper;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.transport.NettyRemotingClientAbstract;
+import org.apache.rocketmq.remoting.util.ThreadUtils;
+
+public class NettyRemotingClient extends NettyRemotingClientAbstract implements RemotingClient {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
+
+    private NettyClientConfig nettyClientConfig;
+    private Bootstrap bootstrap = new Bootstrap();
+    private EventLoopGroup eventLoopGroupWorker;
+
+    private ExecutorService publicExecutor;
+
+    private ExecutorService asyncExecutor;
+    /**
+     * Invoke the callback methods in this executor when process response.
+     */
+    private ExecutorService callbackExecutor;
+    private ChannelEventListener channelEventListener;
+    private DefaultEventExecutorGroup defaultEventExecutorGroup;
+    private RPCHook rpcHook;
+
+    public NettyRemotingClient() {
+        super();
+    }
+
+    public NettyRemotingClient(final NettyClientConfig nettyClientConfig) {
+        this(nettyClientConfig, null);
+    }
+
+    public NettyRemotingClient(final NettyClientConfig nettyClientConfig,
+        final ChannelEventListener channelEventListener) {
+        super(nettyClientConfig.getClientOnewaySemaphoreValue(), nettyClientConfig.getClientAsyncSemaphoreValue());
+        init(nettyClientConfig, channelEventListener);
+    }
+
+    @Override
+    public void init(NettyClientConfig nettyClientConfig, ChannelEventListener channelEventListener) {
+        this.nettyClientConfig = nettyClientConfig;
+        this.channelEventListener = channelEventListener;
+        this.eventLoopGroupWorker = new NioEventLoopGroup(nettyClientConfig.getClientWorkerThreads(), ThreadUtils.newGenericThreadFactory("NettyClientEpollIoThreads",
+            nettyClientConfig.getClientWorkerThreads()));
+        this.publicExecutor = ThreadUtils.newFixedThreadPool(
+            nettyClientConfig.getClientCallbackExecutorThreads(),
+            10000, "Remoting-PublicExecutor", true);
+        this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(nettyClientConfig.getClientWorkerThreads(),
+            ThreadUtils.newGenericThreadFactory("NettyClientWorkerThreads", nettyClientConfig.getClientWorkerThreads()));
+        if (nettyClientConfig.isUseTLS()) {
+            try {
+                sslContext = TlsHelper.buildSslContext(true);
+                log.info("SSL enabled for client");
+            } catch (IOException e) {
+                log.error("Failed to create SSLContext", e);
+            } catch (CertificateException e) {
+                log.error("Failed to create SSLContext", e);
+                throw new RuntimeException("Failed to create SSLContext", e);
+            }
+        }
+    }
+
+    @Override
+    public Bootstrap getBootstrap() {
+        return this.bootstrap;
+    }
+
+    @Override
+    public void start() {
+        bootstrap = this.bootstrap.group(this.eventLoopGroupWorker).channel(NioSocketChannel.class)
+            .option(ChannelOption.TCP_NODELAY, true)
+            .option(ChannelOption.SO_KEEPALIVE, false)
+            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, nettyClientConfig.getConnectTimeoutMillis())
+            .option(ChannelOption.SO_SNDBUF, nettyClientConfig.getClientSocketSndBufSize())
+            .option(ChannelOption.SO_RCVBUF, nettyClientConfig.getClientSocketRcvBufSize())
+            .handler(new ChannelInitializer<SocketChannel>() {
+                @Override
+                public void initChannel(SocketChannel ch) throws Exception {
+                    ChannelPipeline pipeline = ch.pipeline();
+                    if (nettyClientConfig.isUseTLS()) {
+                        if (null != sslContext) {
+                            pipeline.addFirst(defaultEventExecutorGroup, "sslHandler", sslContext.newHandler(ch.alloc()));
+                            log.info("Prepend SSL handler");
+                        } else {
+                            log.warn("Connections are insecure as SSLContext is null!");
+                        }
+                    }
+                    pipeline.addLast(
+                        defaultEventExecutorGroup,
+                        new NettyEncoder(),
+                        new NettyDecoder(),
+                        new IdleStateHandler(0, 0, nettyClientConfig.getClientChannelMaxIdleTimeSeconds()),
+                        new NettyConnectManageHandler(),
+                        new NettyClientHandler());
+                }
+            });
+        startUpHouseKeepingService();
+    }
+
+    @Override
+    public void shutdown() {
+        super.shutdown();
+        try {
+            clearChannels();
+            if (this.eventLoopGroupWorker != null) {
+                this.eventLoopGroupWorker.shutdownGracefully();
+            }
+            if (this.defaultEventExecutorGroup != null) {
+                this.defaultEventExecutorGroup.shutdownGracefully();
+            }
+            if (this.publicExecutor != null) {
+                this.publicExecutor.shutdown();
+            }
+        } catch (Exception e) {
+            log.error("NettyRemotingClient shutdown exception, ", e);
+        }
+    }
+
+    @Override
+    public void registerRPCHook(RPCHook rpcHook) {
+        this.rpcHook = rpcHook;
+    }
+
+    @Override
+    public void updateNameServerAddressList(List<String> addrs) {
+        super.updateNameServerAddressList(addrs);
+    }
+
+    @Override
+    public RemotingCommand invokeSync(String addr, final RemotingCommand request, long timeoutMillis)
+        throws InterruptedException, RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException {
+        long beginStartTime = System.currentTimeMillis();
+        final Channel channel = this.getAndCreateChannel(addr, timeoutMillis);
+        if (channel != null && channel.isActive()) {
+            try {
+                if (this.rpcHook != null) {
+                    this.rpcHook.doBeforeRequest(addr, request);
+                }
+                long costTime = System.currentTimeMillis() - beginStartTime;
+                if (timeoutMillis < costTime) {
+                    throw new RemotingTimeoutException("invokeSync call timeout");
+                }
+                RemotingCommand response = this.invokeSyncImpl(channel, request, timeoutMillis - costTime);
+                if (this.rpcHook != null) {
+                    this.rpcHook.doAfterResponse(RemotingHelper.parseChannelRemoteAddr(channel), request, response);
+                }
+                return response;
+            } catch (RemotingSendRequestException e) {
+                log.warn("invokeSync: send request exception, so close the channel[{}]", addr);
+                this.closeChannel(addr, channel);
+                throw e;
+            } catch (RemotingTimeoutException e) {
+                if (nettyClientConfig.isClientCloseSocketIfTimeout()) {
+                    this.closeChannel(addr, channel);
+                    log.warn("invokeSync: close socket because of timeout, {}ms, {}", timeoutMillis, addr);
+                }
+                log.warn("invokeSync: wait response timeout exception, the channel[{}]", addr);
+                throw e;
+            }
+        } else {
+            this.closeChannel(addr, channel);
+            throw new RemotingConnectException(addr);
+        }
+    }
+
+    @Override
+    public void invokeAsync(String addr, RemotingCommand request, long timeoutMillis, InvokeCallback invokeCallback)
+        throws InterruptedException, RemotingConnectException, RemotingTooMuchRequestException, RemotingTimeoutException,
+        RemotingSendRequestException {
+        long beginStartTime = System.currentTimeMillis();
+        final Channel channel = this.getAndCreateChannel(addr, timeoutMillis);
+        if (channel != null && channel.isActive()) {
+            try {
+                if (this.rpcHook != null) {
+                    this.rpcHook.doBeforeRequest(addr, request);
+                }
+                long costTime = System.currentTimeMillis() - beginStartTime;
+                if (timeoutMillis < costTime) {
+                    throw new RemotingTooMuchRequestException("invokeAsync call timeout");
+                }
+                this.invokeAsyncImpl(channel, request, timeoutMillis - costTime, invokeCallback);
+            } catch (RemotingSendRequestException e) {
+                log.warn("invokeAsync: send request exception, so close the channel[{}]", addr);
+                this.closeChannel(addr, channel);
+                throw e;
+            }
+        } else {
+            this.closeChannel(addr, channel);
+            throw new RemotingConnectException(addr);
+        }
+    }
+
+    @Override
+    public void invokeOneway(String addr, RemotingCommand request, long timeoutMillis) throws InterruptedException,
+        RemotingConnectException, RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
+        final Channel channel = this.getAndCreateChannel(addr, timeoutMillis);
+        if (channel != null && channel.isActive()) {
+            try {
+                if (this.rpcHook != null) {
+                    this.rpcHook.doBeforeRequest(addr, request);
+                }
+                this.invokeOnewayImpl(channel, request, timeoutMillis);
+            } catch (RemotingSendRequestException e) {
+                log.warn("invokeOneway: send request exception, so close the channel[{}]", addr);
+                this.closeChannel(addr, channel);
+                throw e;
+            }
+        } else {
+            this.closeChannel(addr, channel);
+            throw new RemotingConnectException(addr);
+        }
+    }
+
+    @Override
+    public void registerProcessor(int requestCode, NettyRequestProcessor processor, ExecutorService executor) {
+        ExecutorService executorThis = executor;
+        if (null == executor) {
+            executorThis = this.publicExecutor;
+        }
+
+        Pair<NettyRequestProcessor, ExecutorService> pair = new Pair<NettyRequestProcessor, ExecutorService>(processor, executorThis);
+        this.processorTable.put(requestCode, pair);
+    }
+
+    @Override
+    public boolean isChannelWritable(String addr) {
+        ChannelWrapper cw = this.channelTables.get(addr);
+        if (cw != null && cw.isOK()) {
+            return cw.isWritable();
+        }
+        return true;
+    }
+
+    @Override
+    public List<String> getNameServerAddressList() {
+        return this.namesrvAddrList.get();
+    }
+
+    @Override
+    public ChannelEventListener getChannelEventListener() {
+        return channelEventListener;
+    }
+
+    @Override
+    public RPCHook getRPCHook() {
+        return this.rpcHook;
+    }
+
+    @Override
+    public ExecutorService getCallbackExecutor() {
+        return callbackExecutor != null ? callbackExecutor : publicExecutor;
+    }
+
+    @Override
+    public void setCallbackExecutor(final ExecutorService callbackExecutor) {
+        this.callbackExecutor = callbackExecutor;
+    }
+
+    class NettyClientHandler extends SimpleChannelInboundHandler<RemotingCommand> {
+        @Override
+        protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception {
+            processMessageReceived(ctx, msg);
+        }
+    }
+
+}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java
similarity index 59%
rename from remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java
rename to remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java
index 1984842..9e7d419 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java
@@ -14,66 +14,64 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.rocketmq.remoting.netty;
+package org.apache.rocketmq.remoting.transport.rocketmq;
 
 import io.netty.bootstrap.ServerBootstrap;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.PooledByteBufAllocator;
 import io.netty.channel.Channel;
-import io.netty.channel.ChannelDuplexHandler;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelOption;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.SimpleChannelInboundHandler;
-import io.netty.channel.epoll.Epoll;
 import io.netty.channel.epoll.EpollEventLoopGroup;
 import io.netty.channel.epoll.EpollServerSocketChannel;
 import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.ServerSocketChannel;
 import io.netty.channel.socket.SocketChannel;
 import io.netty.channel.socket.nio.NioServerSocketChannel;
-import io.netty.handler.timeout.IdleState;
-import io.netty.handler.timeout.IdleStateEvent;
 import io.netty.handler.timeout.IdleStateHandler;
 import io.netty.util.concurrent.DefaultEventExecutorGroup;
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.security.cert.CertificateException;
 import java.util.NoSuchElementException;
-import java.util.Timer;
-import java.util.TimerTask;
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.ChannelEventListener;
 import org.apache.rocketmq.remoting.InvokeCallback;
 import org.apache.rocketmq.remoting.RPCHook;
 import org.apache.rocketmq.remoting.RemotingServer;
 import org.apache.rocketmq.remoting.common.Pair;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
-import org.apache.rocketmq.remoting.common.RemotingUtil;
 import org.apache.rocketmq.remoting.common.TlsMode;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
-import org.apache.rocketmq.logging.InternalLogger;
-import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.netty.FileRegionEncoder;
+import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.netty.TlsHelper;
+import org.apache.rocketmq.remoting.netty.TlsSystemConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.transport.NettyRemotingServerAbstract;
+import org.apache.rocketmq.remoting.util.JvmUtils;
+import org.apache.rocketmq.remoting.util.ThreadUtils;
 
-public class NettyRemotingServer extends NettyRemotingAbstract implements RemotingServer {
+public class NettyRemotingServer extends NettyRemotingServerAbstract implements RemotingServer {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
-    private final ServerBootstrap serverBootstrap;
-    private final EventLoopGroup eventLoopGroupSelector;
-    private final EventLoopGroup eventLoopGroupBoss;
-    private final NettyServerConfig nettyServerConfig;
-
-    private final ExecutorService publicExecutor;
-    private final ChannelEventListener channelEventListener;
+    private ServerBootstrap serverBootstrap;
+    private EventLoopGroup eventLoopGroupSelector;
+    private EventLoopGroup eventLoopGroupBoss;
+    private NettyServerConfig nettyServerConfig;
 
-    private final Timer timer = new Timer("ServerHouseKeepingService", true);
+    private ExecutorService publicExecutor;
+    private ChannelEventListener channelEventListener;
     private DefaultEventExecutorGroup defaultEventExecutorGroup;
+    private Class<? extends ServerSocketChannel> socketChannelClass;
 
     private RPCHook rpcHook;
 
@@ -83,69 +81,56 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti
     private static final String TLS_HANDLER_NAME = "sslHandler";
     private static final String FILE_REGION_ENCODER_NAME = "fileRegionEncoder";
 
+    public NettyRemotingServer() {
+        super();
+    }
+
     public NettyRemotingServer(final NettyServerConfig nettyServerConfig) {
         this(nettyServerConfig, null);
     }
 
     public NettyRemotingServer(final NettyServerConfig nettyServerConfig,
         final ChannelEventListener channelEventListener) {
-        super(nettyServerConfig.getServerOnewaySemaphoreValue(), nettyServerConfig.getServerAsyncSemaphoreValue());
+        init(nettyServerConfig, channelEventListener);
+    }
+
+    @Override
+    public void init(NettyServerConfig serverConfig, ChannelEventListener channelEventListener) {
+        this.nettyServerConfig = serverConfig;
+        super.init(nettyServerConfig.getServerOnewaySemaphoreValue(), nettyServerConfig.getServerAsyncSemaphoreValue());
         this.serverBootstrap = new ServerBootstrap();
-        this.nettyServerConfig = nettyServerConfig;
+        this.nettyServerConfig = serverConfig;
         this.channelEventListener = channelEventListener;
 
         int publicThreadNums = nettyServerConfig.getServerCallbackExecutorThreads();
         if (publicThreadNums <= 0) {
             publicThreadNums = 4;
         }
-
-        this.publicExecutor = Executors.newFixedThreadPool(publicThreadNums, new ThreadFactory() {
-            private AtomicInteger threadIndex = new AtomicInteger(0);
-
-            @Override
-            public Thread newThread(Runnable r) {
-                return new Thread(r, "NettyServerPublicExecutor_" + this.threadIndex.incrementAndGet());
-            }
-        });
-
-        this.eventLoopGroupBoss = new NioEventLoopGroup(1, new ThreadFactory() {
-            private AtomicInteger threadIndex = new AtomicInteger(0);
-
-            @Override
-            public Thread newThread(Runnable r) {
-                return new Thread(r, String.format("NettyBoss_%d", this.threadIndex.incrementAndGet()));
-            }
-        });
-
-        if (useEpoll()) {
-            this.eventLoopGroupSelector = new EpollEventLoopGroup(nettyServerConfig.getServerSelectorThreads(), new ThreadFactory() {
-                private AtomicInteger threadIndex = new AtomicInteger(0);
-                private int threadTotal = nettyServerConfig.getServerSelectorThreads();
-
-                @Override
-                public Thread newThread(Runnable r) {
-                    return new Thread(r, String.format("NettyServerEPOLLSelector_%d_%d", threadTotal, this.threadIndex.incrementAndGet()));
-                }
-            });
+        this.publicExecutor = ThreadUtils.newFixedThreadPool(
+            publicThreadNums,
+            10000, "Remoting-PublicExecutor", true);
+        if (JvmUtils.isUseEpoll() && this.nettyServerConfig.isUseEpollNativeSelector()) {
+            this.eventLoopGroupSelector = new EpollEventLoopGroup(serverConfig.getServerSelectorThreads(), ThreadUtils.newGenericThreadFactory("NettyEpollIoThreads",
+                serverConfig.getServerSelectorThreads()));
+            this.eventLoopGroupBoss = new EpollEventLoopGroup(serverConfig.getServerAcceptorThreads(), ThreadUtils.newGenericThreadFactory("NettyBossThreads",
+                serverConfig.getServerAcceptorThreads()));
+            this.socketChannelClass = EpollServerSocketChannel.class;
         } else {
-            this.eventLoopGroupSelector = new NioEventLoopGroup(nettyServerConfig.getServerSelectorThreads(), new ThreadFactory() {
-                private AtomicInteger threadIndex = new AtomicInteger(0);
-                private int threadTotal = nettyServerConfig.getServerSelectorThreads();
-
-                @Override
-                public Thread newThread(Runnable r) {
-                    return new Thread(r, String.format("NettyServerNIOSelector_%d_%d", threadTotal, this.threadIndex.incrementAndGet()));
-                }
-            });
+            this.eventLoopGroupBoss = new NioEventLoopGroup(serverConfig.getServerAcceptorThreads(), ThreadUtils.newGenericThreadFactory("NettyBossThreads",
+                serverConfig.getServerAcceptorThreads()));
+            this.eventLoopGroupSelector = new NioEventLoopGroup(serverConfig.getServerSelectorThreads(), ThreadUtils.newGenericThreadFactory("NettyNioIoThreads",
+                serverConfig.getServerSelectorThreads()));
+            this.socketChannelClass = NioServerSocketChannel.class;
         }
-
+        this.port = nettyServerConfig.getListenPort();
+        this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(serverConfig.getServerWorkerThreads(),
+            ThreadUtils.newGenericThreadFactory("NettyWorkerThreads", serverConfig.getServerWorkerThreads()));
         loadSslContext();
     }
 
     public void loadSslContext() {
         TlsMode tlsMode = TlsSystemConfig.tlsMode;
         log.info("Server is running in TLS {} mode", tlsMode.getName());
-
         if (tlsMode != TlsMode.DISABLED) {
             try {
                 sslContext = TlsHelper.buildSslContext(false);
@@ -158,36 +143,19 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti
         }
     }
 
-    private boolean useEpoll() {
-        return RemotingUtil.isLinuxPlatform()
-            && nettyServerConfig.isUseEpollNativeSelector()
-            && Epoll.isAvailable();
-    }
-
     @Override
     public void start() {
-        this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(
-            nettyServerConfig.getServerWorkerThreads(),
-            new ThreadFactory() {
-
-                private AtomicInteger threadIndex = new AtomicInteger(0);
-
-                @Override
-                public Thread newThread(Runnable r) {
-                    return new Thread(r, "NettyServerCodecThread_" + this.threadIndex.incrementAndGet());
-                }
-            });
-
+        super.start();
         ServerBootstrap childHandler =
             this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupSelector)
-                .channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
+                .channel(socketChannelClass)
                 .option(ChannelOption.SO_BACKLOG, 1024)
                 .option(ChannelOption.SO_REUSEADDR, true)
                 .option(ChannelOption.SO_KEEPALIVE, false)
                 .childOption(ChannelOption.TCP_NODELAY, true)
                 .childOption(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSndBufSize())
                 .childOption(ChannelOption.SO_RCVBUF, nettyServerConfig.getServerSocketRcvBufSize())
-                .localAddress(new InetSocketAddress(this.nettyServerConfig.getListenPort()))
+                .localAddress(new InetSocketAddress(this.port))
                 .childHandler(new ChannelInitializer<SocketChannel>() {
                     @Override
                     public void initChannel(SocketChannel ch) throws Exception {
@@ -197,7 +165,9 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti
                             .addLast(defaultEventExecutorGroup,
                                 new NettyEncoder(),
                                 new NettyDecoder(),
-                                new IdleStateHandler(0, 0, nettyServerConfig.getServerChannelMaxIdleTimeSeconds()),
+                                new IdleStateHandler(nettyServerConfig.getConnectionChannelReaderIdleSeconds(),
+                                    nettyServerConfig.getConnectionChannelWriterIdleSeconds(),
+                                    nettyServerConfig.getServerChannelMaxIdleTimeSeconds()),
                                 new NettyConnectManageHandler(),
                                 new NettyServerHandler()
                             );
@@ -215,46 +185,25 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti
         } catch (InterruptedException e1) {
             throw new RuntimeException("this.serverBootstrap.bind().sync() InterruptedException", e1);
         }
-
-        if (this.channelEventListener != null) {
-            this.nettyEventExecutor.start();
-        }
-
-        this.timer.scheduleAtFixedRate(new TimerTask() {
-
-            @Override
-            public void run() {
-                try {
-                    NettyRemotingServer.this.scanResponseTable();
-                } catch (Throwable e) {
-                    log.error("scanResponseTable exception", e);
-                }
-            }
-        }, 1000 * 3, 1000);
+        startUpHouseKeepingService();
     }
 
     @Override
     public void shutdown() {
         try {
-            if (this.timer != null) {
-                this.timer.cancel();
+            super.shutdown();
+            if (this.eventLoopGroupBoss != null) {
+                this.eventLoopGroupBoss.shutdownGracefully();
             }
-
-            this.eventLoopGroupBoss.shutdownGracefully();
-
-            this.eventLoopGroupSelector.shutdownGracefully();
-
-            if (this.nettyEventExecutor != null) {
-                this.nettyEventExecutor.shutdown();
+            if (this.eventLoopGroupSelector != null) {
+                this.eventLoopGroupSelector.shutdownGracefully();
             }
-
             if (this.defaultEventExecutorGroup != null) {
                 this.defaultEventExecutorGroup.shutdownGracefully();
             }
         } catch (Exception e) {
             log.error("NettyRemotingServer shutdown exception, ", e);
         }
-
         if (this.publicExecutor != null) {
             try {
                 this.publicExecutor.shutdown();
@@ -390,80 +339,8 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti
         }
     }
 
-    class NettyServerHandler extends SimpleChannelInboundHandler<RemotingCommand> {
-
-        @Override
-        protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception {
-            processMessageReceived(ctx, msg);
-        }
-    }
-
-    class NettyConnectManageHandler extends ChannelDuplexHandler {
-        @Override
-        public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
-            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
-            log.info("NETTY SERVER PIPELINE: channelRegistered {}", remoteAddress);
-            super.channelRegistered(ctx);
-        }
-
-        @Override
-        public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
-            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
-            log.info("NETTY SERVER PIPELINE: channelUnregistered, the channel[{}]", remoteAddress);
-            super.channelUnregistered(ctx);
-        }
-
-        @Override
-        public void channelActive(ChannelHandlerContext ctx) throws Exception {
-            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
-            log.info("NETTY SERVER PIPELINE: channelActive, the channel[{}]", remoteAddress);
-            super.channelActive(ctx);
-
-            if (NettyRemotingServer.this.channelEventListener != null) {
-                NettyRemotingServer.this.putNettyEvent(new NettyEvent(NettyEventType.CONNECT, remoteAddress, ctx.channel()));
-            }
-        }
-
-        @Override
-        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
-            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
-            log.info("NETTY SERVER PIPELINE: channelInactive, the channel[{}]", remoteAddress);
-            super.channelInactive(ctx);
-
-            if (NettyRemotingServer.this.channelEventListener != null) {
-                NettyRemotingServer.this.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress, ctx.channel()));
-            }
-        }
-
-        @Override
-        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
-            if (evt instanceof IdleStateEvent) {
-                IdleStateEvent event = (IdleStateEvent) evt;
-                if (event.state().equals(IdleState.ALL_IDLE)) {
-                    final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
-                    log.warn("NETTY SERVER PIPELINE: IDLE exception [{}]", remoteAddress);
-                    RemotingUtil.closeChannel(ctx.channel());
-                    if (NettyRemotingServer.this.channelEventListener != null) {
-                        NettyRemotingServer.this
-                            .putNettyEvent(new NettyEvent(NettyEventType.IDLE, remoteAddress, ctx.channel()));
-                    }
-                }
-            }
-
-            ctx.fireUserEventTriggered(evt);
-        }
-
-        @Override
-        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
-            final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
-            log.warn("NETTY SERVER PIPELINE: exceptionCaught {}", remoteAddress);
-            log.warn("NETTY SERVER PIPELINE: exceptionCaught exception.", cause);
-
-            if (NettyRemotingServer.this.channelEventListener != null) {
-                NettyRemotingServer.this.putNettyEvent(new NettyEvent(NettyEventType.EXCEPTION, remoteAddress, ctx.channel()));
-            }
+    @Override
+    public void push(String addr, String sessionId, RemotingCommand remotingCommand) {
 
-            RemotingUtil.closeChannel(ctx.channel());
-        }
     }
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/util/JvmUtils.java b/remoting/src/main/java/org/apache/rocketmq/remoting/util/JvmUtils.java
new file mode 100644
index 0000000..e889a91
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/util/JvmUtils.java
@@ -0,0 +1,94 @@
+/*
+ * 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.remoting.util;
+
+import io.netty.channel.epoll.Epoll;
+import java.io.File;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.Random;
+
+public final class JvmUtils {
+    public static final String OS_NAME = System.getProperty("os.name").toLowerCase();
+    //public static final String OS_VERSION = System.getProperty("os.version").toLowerCase();
+
+    /**
+     * A constructor to stop this class being constructed.
+     */
+    private JvmUtils() {
+        // Unused
+    }
+
+    public static boolean isWindows() {
+        return OS_NAME.startsWith("win");
+    }
+
+    public static boolean isWindows10() {
+        return OS_NAME.startsWith("win") && OS_NAME.endsWith("10");
+    }
+
+    public static boolean isMacOSX() {
+        return OS_NAME.contains("mac");
+    }
+
+    public static boolean isLinux() {
+        return OS_NAME.startsWith("linux");
+    }
+
+    public static boolean isUseEpoll() {
+        return isLinux() && Epoll.isAvailable();
+    }
+
+    public static boolean isUnix() {
+        return OS_NAME.contains("nix") ||
+            OS_NAME.contains("nux") ||
+            OS_NAME.contains("aix") ||
+            OS_NAME.contains("bsd") ||
+            OS_NAME.contains("sun") ||
+            OS_NAME.contains("hpux");
+    }
+
+    public static boolean isSolaris() {
+        return OS_NAME.startsWith("sun");
+    }
+
+    public static int getProcessId() {
+        String pid = null;
+        final File self = new File("/proc/self");
+        try {
+            if (self.exists()) {
+                pid = self.getCanonicalFile().getName();
+            }
+        } catch (IOException ignored) {
+            //Ignore it
+        }
+
+        if (pid == null) {
+            pid = ManagementFactory.getRuntimeMXBean().getName().split("@", 0)[0];
+        }
+
+        if (pid == null) {
+            int rpid = new Random().nextInt(1 << 16);
+            return rpid;
+        } else {
+            return Integer.parseInt(pid);
+        }
+    }
+
+}
+
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/util/RemotingUtil.java b/remoting/src/main/java/org/apache/rocketmq/remoting/util/RemotingUtil.java
new file mode 100644
index 0000000..ccd037f
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/util/RemotingUtil.java
@@ -0,0 +1,6 @@
+package org.apache.rocketmq.remoting.util;
+
+public class RemotingUtil {
+    public static final String REMOTING_CHARSET = "UTF-8";
+    public static final String DEFAULT_PROTOCOL = "rocketmq";
+}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/util/ServiceProvider.java b/remoting/src/main/java/org/apache/rocketmq/remoting/util/ServiceProvider.java
new file mode 100644
index 0000000..d3a2312
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/util/ServiceProvider.java
@@ -0,0 +1,200 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.remoting.util;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+
+public class ServiceProvider {
+
+    private static final InternalLogger LOG = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
+
+    /**
+     * A reference to the classloader that loaded this class. It's more efficient to compute it once and cache it here.
+     */
+    private static ClassLoader thisClassLoader;
+
+    /**
+     * JDK1.3+ <a href= "http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service%20Provider" > 'Service Provider' specification</a>.
+     */
+
+    static {
+        thisClassLoader = getClassLoader(ServiceProvider.class);
+    }
+
+    /**
+     * Returns a string that uniquely identifies the specified object, including its class.
+     * <p>
+     * The returned string is of form "classname@hashcode", ie is the same as the return value of the Object.toString()
+     * method, but works even when the specified object's class has overidden the toString method.
+     *
+     * @param o may be null.
+     * @return a string of form classname@hashcode, or "null" if param o is null.
+     */
+    protected static String objectId(Object o) {
+        if (o == null) {
+            return "null";
+        } else {
+            return o.getClass().getName() + "@" + System.identityHashCode(o);
+        }
+    }
+
+    protected static ClassLoader getClassLoader(Class<?> clazz) {
+        try {
+            return clazz.getClassLoader();
+        } catch (SecurityException e) {
+            LOG.error("Unable to get classloader for class {} due to security restrictions !",
+                clazz, e.getMessage());
+            throw e;
+        }
+    }
+
+    public static ClassLoader getContextClassLoader() {
+        ClassLoader classLoader = null;
+        try {
+            classLoader = Thread.currentThread().getContextClassLoader();
+        } catch (SecurityException ex) {
+            /**
+             * The getContextClassLoader() method throws SecurityException when the context
+             * class loader isn't an ancestor of the calling class's class
+             * loader, or if security permissions are restricted.
+             */
+        }
+        return classLoader;
+    }
+
+    public static InputStream getResourceAsStream(ClassLoader loader, String name) {
+        if (loader != null) {
+            return loader.getResourceAsStream(name);
+        } else {
+            return ClassLoader.getSystemResourceAsStream(name);
+        }
+    }
+
+    public static <T> Map<String, T> load(String path, Class<?> clazz) {
+        LOG.info("Looking for a resource file of name [{}] ...", path);
+        Map<String, T> services = new ConcurrentHashMap<String, T>();
+        try {
+
+            final InputStream is = getResourceAsStream(getContextClassLoader(), path);
+            if (is != null) {
+                BufferedReader reader;
+                try {
+                    reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+                } catch (java.io.UnsupportedEncodingException e) {
+                    reader = new BufferedReader(new InputStreamReader(is));
+                }
+                String serviceName = reader.readLine();
+                while (serviceName != null && !"".equals(serviceName)) {
+                    LOG.info(
+                        "Creating an instance as specified by file {} which was present in the path of the context classloader.",
+                        path);
+                    String[] service = serviceName.split("=");
+                    if (service.length != 2) {
+                        continue;
+                    } else {
+                        if (services.containsKey(service[0])) {
+                            continue;
+                        } else {
+                            LOG.info("Begin to load protocol: " + service[0]);
+                            services.put(service[0], (T) initService(getContextClassLoader(), service[1], clazz));
+                        }
+                    }
+                    serviceName = reader.readLine();
+                }
+                reader.close();
+            } else {
+                // is == null
+                LOG.warn("No resource file with name [{}] found.", path);
+            }
+        } catch (Exception e) {
+            LOG.error("Error occured when looking for resource file " + path, e);
+        }
+        return services;
+    }
+
+    public static <T> T loadClass(String name, String path, Class<?> clazz) {
+        final InputStream is = getResourceAsStream(getContextClassLoader(), name);
+        if (is != null) {
+            BufferedReader reader;
+            try {
+                try {
+                    reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+                } catch (java.io.UnsupportedEncodingException e) {
+                    reader = new BufferedReader(new InputStreamReader(is));
+                }
+                String serviceName = reader.readLine();
+                reader.close();
+                if (serviceName != null && !"".equals(serviceName)) {
+                    return initService(getContextClassLoader(), serviceName, clazz);
+                } else {
+                    LOG.warn("ServiceName is empty!");
+                    return null;
+                }
+            } catch (Exception e) {
+                LOG.warn("Error occurred when looking for resource file " + name, e);
+            }
+        }
+        return null;
+    }
+
+    protected static <T> T initService(ClassLoader classLoader, String serviceName, Class<?> clazz) {
+        Class<?> serviceClazz = null;
+        try {
+            if (classLoader != null) {
+                try {
+                    // Warning: must typecast here & allow exception to be generated/caught & recast properly
+                    serviceClazz = classLoader.loadClass(serviceName);
+                    if (clazz.isAssignableFrom(serviceClazz)) {
+                        LOG.info("Loaded class {} from classloader {}", serviceClazz.getName(),
+                            objectId(classLoader));
+                    } else {
+                        // This indicates a problem with the ClassLoader tree. An incompatible ClassLoader was used to load the implementation.
+                        LOG.error(
+                            "Class {} loaded from classloader {} does not extend {} as loaded by this classloader.",
+                            new Object[] {
+                                serviceClazz.getName(),
+                                objectId(serviceClazz.getClassLoader()), clazz.getName()});
+                    }
+                    return (T) serviceClazz.newInstance();
+                } catch (ClassNotFoundException ex) {
+                    if (classLoader == thisClassLoader) {
+                        // Nothing more to try, onwards.
+                        LOG.warn("Unable to locate any class {} via classloader", serviceName,
+                            objectId(classLoader));
+                        throw ex;
+                    }
+                    // Ignore exception, continue
+                } catch (NoClassDefFoundError e) {
+                    if (classLoader == thisClassLoader) {
+                        // Nothing more to try, onwards.
+                        LOG.warn(
+                            "Class {} cannot be loaded via classloader {}.it depends on some other class that cannot be found.",
+                            serviceClazz, objectId(classLoader));
+                        throw e;
+                    }
+                    // Ignore exception, continue
+                }
+            }
+        } catch (Exception e) {
+            LOG.error("Unable to init service.", e);
+        }
+        return (T) serviceClazz;
+    }
+}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/util/ThreadUtils.java b/remoting/src/main/java/org/apache/rocketmq/remoting/util/ThreadUtils.java
new file mode 100644
index 0000000..954e692
--- /dev/null
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/util/ThreadUtils.java
@@ -0,0 +1,181 @@
+/*
+ * 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.remoting.util;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public final class ThreadUtils {
+
+    /**
+     * A constructor to stop this class being constructed.
+     */
+    private ThreadUtils() {
+        // Unused
+
+    }
+
+    public static ExecutorService newThreadPoolExecutor(int corePoolSize,
+        int maximumPoolSize,
+        long keepAliveTime,
+        TimeUnit unit,
+        BlockingQueue<Runnable> workQueue,
+        String processName, boolean isDaemon) {
+        return new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, newGenericThreadFactory(processName, isDaemon));
+    }
+
+    public static ExecutorService newFixedThreadPool(int nThreads, int workQueueCapacity, String processName, boolean isDaemon) {
+        return new ThreadPoolExecutor(
+            nThreads,
+            nThreads,
+            0,
+            TimeUnit.MILLISECONDS,
+            new LinkedBlockingQueue<Runnable>(workQueueCapacity),
+            newGenericThreadFactory(processName, isDaemon));
+    }
+
+    public static ExecutorService newSingleThreadExecutor(String processName, boolean isDaemon) {
+        return Executors.newSingleThreadExecutor(newGenericThreadFactory(processName, isDaemon));
+    }
+
+    public static ScheduledExecutorService newSingleThreadScheduledExecutor(String processName, boolean isDaemon) {
+        return Executors.newSingleThreadScheduledExecutor(newGenericThreadFactory(processName, isDaemon));
+    }
+
+    public static ScheduledExecutorService newFixedThreadScheduledPool(int nThreads, String processName,
+        boolean isDaemon) {
+        return Executors.newScheduledThreadPool(nThreads, newGenericThreadFactory(processName, isDaemon));
+    }
+
+    public static ThreadFactory newGenericThreadFactory(String processName) {
+        return newGenericThreadFactory(processName, false);
+    }
+
+    public static ThreadFactory newGenericThreadFactory(String processName, int threads) {
+        return newGenericThreadFactory(processName, threads, false);
+    }
+
+    public static ThreadFactory newGenericThreadFactory(final String processName, final boolean isDaemon) {
+        return new ThreadFactory() {
+            private AtomicInteger threadIndex = new AtomicInteger(0);
+
+            @Override
+            public Thread newThread(Runnable r) {
+                Thread thread = new Thread(r, String.format("%s_%d", processName, this.threadIndex.incrementAndGet()));
+                thread.setDaemon(isDaemon);
+                return thread;
+            }
+        };
+    }
+
+    public static ThreadFactory newGenericThreadFactory(final String processName, final int threads,
+        final boolean isDaemon) {
+        return new ThreadFactory() {
+            private AtomicInteger threadIndex = new AtomicInteger(0);
+
+            @Override
+            public Thread newThread(Runnable r) {
+                Thread thread = new Thread(r, String.format("%s_%d_%d", processName, threads, this.threadIndex.incrementAndGet()));
+                thread.setDaemon(isDaemon);
+                return thread;
+            }
+        };
+    }
+
+    /**
+     * Create a new thread
+     *
+     * @param name The name of the thread
+     * @param runnable The work for the thread to do
+     * @param daemon Should the thread block JVM stop?
+     * @return The unstarted thread
+     */
+    public static Thread newThread(String name, Runnable runnable, boolean daemon) {
+        Thread thread = new Thread(runnable, name);
+        thread.setDaemon(daemon);
+        thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+            public void uncaughtException(Thread t, Throwable e) {
+            }
+        });
+        return thread;
+    }
+
+    /**
+     * Shutdown passed thread using isAlive and join.
+     *
+     * @param t Thread to stop
+     */
+    public static void shutdownGracefully(final Thread t) {
+        shutdownGracefully(t, 0);
+    }
+
+    /**
+     * Shutdown passed thread using isAlive and join.
+     *
+     * @param millis Pass 0 if we're to wait forever.
+     * @param t Thread to stop
+     */
+    public static void shutdownGracefully(final Thread t, final long millis) {
+        if (t == null)
+            return;
+        while (t.isAlive()) {
+            try {
+                t.interrupt();
+                t.join(millis);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+            }
+        }
+    }
+
+    /**
+     * An implementation of the graceful stop sequence recommended by
+     * {@link ExecutorService}.
+     *
+     * @param executor executor
+     * @param timeout timeout
+     * @param timeUnit timeUnit
+     */
+    public static void shutdownGracefully(ExecutorService executor, long timeout, TimeUnit timeUnit) {
+        // Disable new tasks from being submitted.
+        executor.shutdown();
+        try {
+            // Wait a while for existing tasks to terminate.
+            if (!executor
+                .awaitTermination(timeout, timeUnit)) {
+                executor.shutdownNow();
+                // Wait a while for tasks to respond to being cancelled.
+                if (!executor.awaitTermination(timeout, timeUnit)) {
+
+                }
+            }
+        } catch (InterruptedException ie) {
+            // (Re-)Cancel if current thread also interrupted.
+            executor.shutdownNow();
+            // Preserve interrupt status.
+            Thread.currentThread().interrupt();
+        }
+    }
+}
diff --git a/remoting/src/main/resources/META-INF/service/org.apache.rocketmq.remoting.RemotingClient b/remoting/src/main/resources/META-INF/service/org.apache.rocketmq.remoting.RemotingClient
new file mode 100644
index 0000000..b0ca8ec
--- /dev/null
+++ b/remoting/src/main/resources/META-INF/service/org.apache.rocketmq.remoting.RemotingClient
@@ -0,0 +1,2 @@
+rocketmq=org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingClient
+http2=org.apache.rocketmq.remoting.transport.http2.Http2ClientImpl
\ No newline at end of file
diff --git a/remoting/src/main/resources/META-INF/service/org.apache.rocketmq.remoting.RemotingServer b/remoting/src/main/resources/META-INF/service/org.apache.rocketmq.remoting.RemotingServer
new file mode 100644
index 0000000..5079c88
--- /dev/null
+++ b/remoting/src/main/resources/META-INF/service/org.apache.rocketmq.remoting.RemotingServer
@@ -0,0 +1,2 @@
+rocketmq=org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingServer
+http2=org.apache.rocketmq.remoting.transport.http2.Http2ServerImpl
\ No newline at end of file
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/RemotingServerTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/RemotingServerTest.java
index 0ecfaaa..b41dc37 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/RemotingServerTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/RemotingServerTest.java
@@ -27,13 +27,13 @@ import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
 import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyRemotingClient;
-import org.apache.rocketmq.remoting.netty.NettyRemotingServer;
 import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
 import org.apache.rocketmq.remoting.netty.NettyServerConfig;
 import org.apache.rocketmq.remoting.netty.ResponseFuture;
-import org.apache.rocketmq.remoting.protocol.LanguageCode;
+import org.apache.rocketmq.remoting.serialize.LanguageCode;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingClient;
+import org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingServer;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/TlsTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/TlsTest.java
index 13bb172..50409f2 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/TlsTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/TlsTest.java
@@ -25,10 +25,10 @@ import java.io.PrintWriter;
 import org.apache.rocketmq.remoting.common.TlsMode;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyRemotingServer;
 import org.apache.rocketmq.remoting.netty.TlsHelper;
-import org.apache.rocketmq.remoting.protocol.LanguageCode;
+import org.apache.rocketmq.remoting.serialize.LanguageCode;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingServer;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstractTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstractTest.java
index c3da3e9..2b96abd 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstractTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstractTest.java
@@ -20,6 +20,7 @@ import java.util.concurrent.Semaphore;
 import org.apache.rocketmq.remoting.InvokeCallback;
 import org.apache.rocketmq.remoting.common.SemaphoreReleaseOnlyOnce;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingClient;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Spy;
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingClientTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingClientTest.java
index 6b5633d..d0a7ed7 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingClientTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingClientTest.java
@@ -19,6 +19,7 @@ package org.apache.rocketmq.remoting.netty;
 import java.lang.reflect.Field;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingClient;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.junit.MockitoJUnitRunner;
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingCommandTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingCommandTest.java
index 2bd41ce..243d7f3 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingCommandTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingCommandTest.java
@@ -18,10 +18,11 @@ package org.apache.rocketmq.remoting.protocol;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
-import java.nio.ByteBuffer;
 import org.apache.rocketmq.remoting.CommandCustomHeader;
 import org.apache.rocketmq.remoting.annotation.CFNotNull;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
+import org.apache.rocketmq.remoting.netty.CodecHelper;
+import org.apache.rocketmq.remoting.serialize.SerializeType;
 import org.junit.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -31,7 +32,7 @@ public class RemotingCommandTest {
     public void testMarkProtocolType_JSONProtocolType() {
         int source = 261;
         SerializeType type = SerializeType.JSON;
-        byte[] result = RemotingCommand.markProtocolType(source, type);
+        byte[] result = CodecHelper.markProtocolType(source, type);
         assertThat(result).isEqualTo(new byte[] {0, 0, 1, 5});
     }
 
@@ -39,13 +40,13 @@ public class RemotingCommandTest {
     public void testMarkProtocolType_ROCKETMQProtocolType() {
         int source = 16777215;
         SerializeType type = SerializeType.ROCKETMQ;
-        byte[] result = RemotingCommand.markProtocolType(source, type);
+        byte[] result = CodecHelper.markProtocolType(source, type);
         assertThat(result).isEqualTo(new byte[] {1, -1, -1, -1});
     }
 
     @Test
     public void testCreateRequestCommand_RegisterBroker() {
-        System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, "2333");
+        System.setProperty(CodecHelper.REMOTING_VERSION_KEY, "2333");
 
         int code = 103; //org.apache.rocketmq.common.protocol.RequestCode.REGISTER_BROKER
         CommandCustomHeader header = new SampleCommandCustomHeader();
@@ -57,7 +58,7 @@ public class RemotingCommandTest {
 
     @Test
     public void testCreateResponseCommand_SuccessWithHeader() {
-        System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, "2333");
+        System.setProperty(CodecHelper.REMOTING_VERSION_KEY, "2333");
 
         int code = RemotingSysResponseCode.SUCCESS;
         String remark = "Sample remark";
@@ -70,7 +71,7 @@ public class RemotingCommandTest {
 
     @Test
     public void testCreateResponseCommand_SuccessWithoutHeader() {
-        System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, "2333");
+        System.setProperty(CodecHelper.REMOTING_VERSION_KEY, "2333");
 
         int code = RemotingSysResponseCode.SUCCESS;
         String remark = "Sample remark";
@@ -83,7 +84,7 @@ public class RemotingCommandTest {
 
     @Test
     public void testCreateResponseCommand_FailToCreateCommand() {
-        System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, "2333");
+        System.setProperty(CodecHelper.REMOTING_VERSION_KEY, "2333");
 
         int code = RemotingSysResponseCode.SUCCESS;
         String remark = "Sample remark";
@@ -93,7 +94,7 @@ public class RemotingCommandTest {
 
     @Test
     public void testCreateResponseCommand_SystemError() {
-        System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, "2333");
+        System.setProperty(CodecHelper.REMOTING_VERSION_KEY, "2333");
 
         RemotingCommand cmd = RemotingCommand.createResponseCommand(SampleCommandCustomHeader.class);
         assertThat(cmd.getCode()).isEqualTo(RemotingSysResponseCode.SYSTEM_ERROR);
@@ -102,86 +103,8 @@ public class RemotingCommandTest {
         assertThat(cmd.getFlag() & 0x01).isEqualTo(1); //flag bit 0: 1 presents response
     }
 
-    @Test
-    public void testEncodeAndDecode_EmptyBody() {
-        System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, "2333");
-
-        int code = 103; //org.apache.rocketmq.common.protocol.RequestCode.REGISTER_BROKER
-        CommandCustomHeader header = new SampleCommandCustomHeader();
-        RemotingCommand cmd = RemotingCommand.createRequestCommand(code, header);
-
-        ByteBuffer buffer = cmd.encode();
-
-        //Simulate buffer being read in NettyDecoder
-        buffer.getInt();
-        byte[] bytes = new byte[buffer.limit() - 4];
-        buffer.get(bytes, 0, buffer.limit() - 4);
-        buffer = ByteBuffer.wrap(bytes);
-
-        RemotingCommand decodedCommand = RemotingCommand.decode(buffer);
-
-        assertThat(decodedCommand.getSerializeTypeCurrentRPC()).isEqualTo(SerializeType.JSON);
-        assertThat(decodedCommand.getBody()).isNull();
-    }
-
-    @Test
-    public void testEncodeAndDecode_FilledBody() {
-        System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, "2333");
-
-        int code = 103; //org.apache.rocketmq.common.protocol.RequestCode.REGISTER_BROKER
-        CommandCustomHeader header = new SampleCommandCustomHeader();
-        RemotingCommand cmd = RemotingCommand.createRequestCommand(code, header);
-        cmd.setBody(new byte[] {0, 1, 2, 3, 4});
 
-        ByteBuffer buffer = cmd.encode();
 
-        //Simulate buffer being read in NettyDecoder
-        buffer.getInt();
-        byte[] bytes = new byte[buffer.limit() - 4];
-        buffer.get(bytes, 0, buffer.limit() - 4);
-        buffer = ByteBuffer.wrap(bytes);
-
-        RemotingCommand decodedCommand = RemotingCommand.decode(buffer);
-
-        assertThat(decodedCommand.getSerializeTypeCurrentRPC()).isEqualTo(SerializeType.JSON);
-        assertThat(decodedCommand.getBody()).isEqualTo(new byte[] {0, 1, 2, 3, 4});
-    }
-
-    @Test
-    public void testEncodeAndDecode_FilledBodyWithExtFields() throws RemotingCommandException {
-        System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, "2333");
-
-        int code = 103; //org.apache.rocketmq.common.protocol.RequestCode.REGISTER_BROKER
-        CommandCustomHeader header = new ExtFieldsHeader();
-        RemotingCommand cmd = RemotingCommand.createRequestCommand(code, header);
-
-        cmd.addExtField("key", "value");
-
-        ByteBuffer buffer = cmd.encode();
-
-        //Simulate buffer being read in NettyDecoder
-        buffer.getInt();
-        byte[] bytes = new byte[buffer.limit() - 4];
-        buffer.get(bytes, 0, buffer.limit() - 4);
-        buffer = ByteBuffer.wrap(bytes);
-
-        RemotingCommand decodedCommand = RemotingCommand.decode(buffer);
-
-        assertThat(decodedCommand.getExtFields().get("stringValue")).isEqualTo("bilibili");
-        assertThat(decodedCommand.getExtFields().get("intValue")).isEqualTo("2333");
-        assertThat(decodedCommand.getExtFields().get("longValue")).isEqualTo("23333333");
-        assertThat(decodedCommand.getExtFields().get("booleanValue")).isEqualTo("true");
-        assertThat(decodedCommand.getExtFields().get("doubleValue")).isEqualTo("0.618");
-
-        assertThat(decodedCommand.getExtFields().get("key")).isEqualTo("value");
-
-        CommandCustomHeader decodedHeader = decodedCommand.decodeCommandCustomHeader(ExtFieldsHeader.class);
-        assertThat(((ExtFieldsHeader) decodedHeader).getStringValue()).isEqualTo("bilibili");
-        assertThat(((ExtFieldsHeader) decodedHeader).getIntValue()).isEqualTo(2333);
-        assertThat(((ExtFieldsHeader) decodedHeader).getLongValue()).isEqualTo(23333333l);
-        assertThat(((ExtFieldsHeader) decodedHeader).isBooleanValue()).isEqualTo(true);
-        assertThat(((ExtFieldsHeader) decodedHeader).getDoubleValue()).isBetween(0.617, 0.619);
-    }
 
     @Test
     public void testNotNullField() throws Exception {
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingSerializableTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingSerializableTest.java
index 3e8b7a9..7ad6db7 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingSerializableTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingSerializableTest.java
@@ -18,6 +18,7 @@ package org.apache.rocketmq.remoting.protocol;
 
 import java.util.Arrays;
 import java.util.List;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 import org.junit.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RocketMQSerializableTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RocketMQSerializableTest.java
index f1db54f..66bdf73 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RocketMQSerializableTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RocketMQSerializableTest.java
@@ -17,6 +17,9 @@
 package org.apache.rocketmq.remoting.protocol;
 
 import java.util.HashMap;
+import org.apache.rocketmq.remoting.serialize.LanguageCode;
+import org.apache.rocketmq.remoting.serialize.RocketMQSerializable;
+import org.apache.rocketmq.remoting.serialize.SerializeType;
 import org.junit.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
diff --git a/store/src/main/java/org/apache/rocketmq/store/schedule/DelayOffsetSerializeWrapper.java b/store/src/main/java/org/apache/rocketmq/store/schedule/DelayOffsetSerializeWrapper.java
index 7021992..d0c4fcb 100644
--- a/store/src/main/java/org/apache/rocketmq/store/schedule/DelayOffsetSerializeWrapper.java
+++ b/store/src/main/java/org/apache/rocketmq/store/schedule/DelayOffsetSerializeWrapper.java
@@ -18,7 +18,7 @@ package org.apache.rocketmq.store.schedule;
 
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 
 public class DelayOffsetSerializeWrapper extends RemotingSerializable {
     private ConcurrentMap<Integer /* level */, Long/* offset */> offsetTable =
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/topic/AllocateMQSubCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/topic/AllocateMQSubCommand.java
index a9b9ab0..f517e2a 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/topic/AllocateMQSubCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/topic/AllocateMQSubCommand.java
@@ -28,7 +28,7 @@ import org.apache.rocketmq.client.impl.factory.MQClientInstance;
 import org.apache.rocketmq.common.message.MessageQueue;
 import org.apache.rocketmq.common.protocol.route.TopicRouteData;
 import org.apache.rocketmq.remoting.RPCHook;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
 import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
 import org.apache.rocketmq.tools.command.SubCommand;
 import org.apache.rocketmq.tools.command.SubCommandException;
diff --git a/tools/src/test/java/org/apache/rocketmq/tools/monitor/MonitorServiceTest.java b/tools/src/test/java/org/apache/rocketmq/tools/monitor/MonitorServiceTest.java
index 4989a9b..eae3cfb 100644
--- a/tools/src/test/java/org/apache/rocketmq/tools/monitor/MonitorServiceTest.java
+++ b/tools/src/test/java/org/apache/rocketmq/tools/monitor/MonitorServiceTest.java
@@ -52,7 +52,7 @@ import org.apache.rocketmq.common.protocol.route.BrokerData;
 import org.apache.rocketmq.common.protocol.route.QueueData;
 import org.apache.rocketmq.common.protocol.route.TopicRouteData;
 import org.apache.rocketmq.remoting.exception.RemotingException;
-import org.apache.rocketmq.remoting.protocol.LanguageCode;
+import org.apache.rocketmq.remoting.serialize.LanguageCode;
 import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
 import org.apache.rocketmq.tools.admin.DefaultMQAdminExtImpl;
 import org.junit.AfterClass;


[rocketmq] 07/14: Add subscription, consumer offset, sendback etc. management module

Posted by du...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a commit to branch snode
in repository https://gitbox.apache.org/repos/asf/rocketmq.git

commit 20da514fe758fb23ccc8d18cfa68c7cc348887d9
Author: duhenglucky <du...@gmail.com>
AuthorDate: Sat Dec 29 19:41:02 2018 +0800

    Add subscription, consumer offset, sendback etc. management module
---
 .../apache/rocketmq/broker/BrokerController.java   |   2 +-
 .../rocketmq/broker/longpolling/PullRequest.java   |  19 ++
 .../broker/longpolling/PullRequestHoldService.java |  45 ++--
 .../broker/processor/SendMessageProcessor.java     |  34 +--
 .../processor/SnodePullMessageProcessor.java       |  73 ++---
 .../org/apache/rocketmq/client/ClientConfig.java   |   2 +-
 .../consumer/store/RemoteBrokerOffsetStore.java    |  11 +-
 .../rocketmq/client/impl/MQClientAPIImpl.java      |  10 +-
 .../impl/consumer/DefaultMQPullConsumerImpl.java   |   2 +-
 .../impl/consumer/DefaultMQPushConsumerImpl.java   |   2 +-
 .../client/impl/factory/MQClientInstance.java      |  10 +-
 .../impl/producer/DefaultMQProducerImpl.java       |   2 +-
 .../org/apache/rocketmq/common/BrokerConfig.java   |  12 +
 .../rocketmq/common/protocol/ResponseCode.java     |   4 +
 .../header/ConsumerSendMsgBackRequestHeader.java   |  25 +-
 .../protocol/header/GetMaxOffsetRequestHeader.java |  10 +
 .../protocol/header/GetMinOffsetRequestHeader.java |  11 +
 .../header/QueryConsumerOffsetRequestHeader.java   |  10 +
 .../protocol/header/SearchOffsetRequestHeader.java |   9 +
 .../protocol/header/SendMessageRequestHeader.java  |  29 +-
 .../header/SendMessageRequestHeaderV2.java         |   4 +-
 .../header/UpdateConsumerOffsetRequestHeader.java  |  10 +
 .../rocketmq/example/quickstart/Consumer.java      |   3 +-
 .../namesrv/processor/DefaultRequestProcessor.java |   1 -
 .../remoting/netty/NettyRemotingAbstract.java      |   3 +-
 .../transport/rocketmq/NettyRemotingClient.java    |   1 +
 .../org/apache/rocketmq/snode/SnodeController.java | 110 ++++++--
 .../snode/client/ClientHousekeepingService.java    |   2 +-
 .../rocketmq/snode/client/ConsumerGroupInfo.java   |  10 +-
 .../rocketmq/snode/client/ConsumerManager.java     |  23 +-
 .../client/DefaultConsumerIdsChangeListener.java   |   2 +-
 .../rocketmq/snode/client/ProducerManager.java     |  74 +++---
 .../snode/client/SubscriptionGroupManager.java     |  20 +-
 .../apache/rocketmq/snode/config/SnodeConfig.java  |  12 +
 .../rocketmq/snode/constant/SnodeConstant.java     |   2 +
 .../SnodeException.java}                           |  29 +-
 .../snode/offset/ConsumerOffsetManager.java        | 243 +++++++++++++++++
 .../snode/processor/ConsumerManageProcessor.java   | 115 +++++++-
 .../snode/processor/HearbeatProcessor.java         |  64 ++++-
 .../snode/processor/PullMessageProcessor.java      |  56 +++-
 .../snode/processor/SendMessageProcessor.java      |   3 +-
 .../{SnodeOuterService.java => EnodeService.java}  |  33 ++-
 .../rocketmq/snode/service/NnodeService.java       |  47 ++++
 .../snode/service/impl/EnodeServiceImpl.java       | 295 +++++++++++++++++++++
 .../snode/service/impl/NnodeServiceImpl.java       | 208 +++++++++++++++
 .../snode/service/impl/ScheduledServiceImpl.java   |  51 +++-
 .../snode/service/impl/SnodeOuterServiceImpl.java  | 280 -------------------
 47 files changed, 1503 insertions(+), 520 deletions(-)

diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
index 9639f65..eff8fd4 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
@@ -515,7 +515,7 @@ public class BrokerController {
          */
         this.remotingServer.registerProcessor(RequestCode.PULL_MESSAGE, this.pullMessageProcessor, this.pullMessageExecutor);
         this.pullMessageProcessor.registerConsumeMessageHook(consumeMessageHookList);
-        this.remotingServer.registerProcessor(RequestCode.SNODE_PULL_MESSAGE, this.snodePullMessageProcessor,pullMessageExecutor);
+        this.remotingServer.registerProcessor(RequestCode.SNODE_PULL_MESSAGE, this.snodePullMessageProcessor, pullMessageExecutor);
         this.snodePullMessageProcessor.registerConsumeMessageHook(consumeMessageHookList);
         /**
          * QueryMessageProcessor
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequest.java b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequest.java
index 045ab9b..e64b0e9 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequest.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequest.java
@@ -29,6 +29,7 @@ public class PullRequest {
     private final long pullFromThisOffset;
     private final SubscriptionData subscriptionData;
     private final MessageFilter messageFilter;
+    private final boolean snodeRequest;
 
     public PullRequest(RemotingCommand requestCommand, Channel clientChannel, long timeoutMillis, long suspendTimestamp,
         long pullFromThisOffset, SubscriptionData subscriptionData,
@@ -40,6 +41,20 @@ public class PullRequest {
         this.pullFromThisOffset = pullFromThisOffset;
         this.subscriptionData = subscriptionData;
         this.messageFilter = messageFilter;
+        this.snodeRequest = false;
+    }
+
+    public PullRequest(RemotingCommand requestCommand, Channel clientChannel, long timeoutMillis, long suspendTimestamp,
+        long pullFromThisOffset, SubscriptionData subscriptionData,
+        MessageFilter messageFilter, boolean snodeRequest) {
+        this.requestCommand = requestCommand;
+        this.clientChannel = clientChannel;
+        this.timeoutMillis = timeoutMillis;
+        this.suspendTimestamp = suspendTimestamp;
+        this.pullFromThisOffset = pullFromThisOffset;
+        this.subscriptionData = subscriptionData;
+        this.messageFilter = messageFilter;
+        this.snodeRequest = snodeRequest;
     }
 
     public RemotingCommand getRequestCommand() {
@@ -69,4 +84,8 @@ public class PullRequest {
     public MessageFilter getMessageFilter() {
         return messageFilter;
     }
+
+    public boolean isSnodeRequest() {
+        return snodeRequest;
+    }
 }
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
index af6addc..ee02017 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
@@ -127,34 +127,37 @@ public class PullRequestHoldService extends ServiceThread {
                     if (newestOffset <= request.getPullFromThisOffset()) {
                         newestOffset = this.brokerController.getMessageStore().getMaxOffsetInQueue(topic, queueId);
                     }
+                    try {
+                        if (newestOffset > request.getPullFromThisOffset()) {
+                            boolean match = request.getMessageFilter().isMatchedByConsumeQueue(tagsCode,
+                                new ConsumeQueueExt.CqExtUnit(tagsCode, msgStoreTime, filterBitMap));
+                            // match by bit map, need eval again when properties is not null.
+                            if (match && properties != null) {
+                                match = request.getMessageFilter().isMatchedByCommitLog(null, properties);
+                            }
 
-                    if (newestOffset > request.getPullFromThisOffset()) {
-                        boolean match = request.getMessageFilter().isMatchedByConsumeQueue(tagsCode,
-                            new ConsumeQueueExt.CqExtUnit(tagsCode, msgStoreTime, filterBitMap));
-                        // match by bit map, need eval again when properties is not null.
-                        if (match && properties != null) {
-                            match = request.getMessageFilter().isMatchedByCommitLog(null, properties);
-                        }
-
-                        if (match) {
-                            try {
-                                if (request.getMessageFilter() == null && request.getSubscriptionData() == null) {
-                                    this.brokerController.getSnodePullMessageProcessor().executeRequestWhenWakeup(request.getClientChannel(),
-                                        request.getRequestCommand());
-                                } else {
-                                    this.brokerController.getPullMessageProcessor().executeRequestWhenWakeup(request.getClientChannel(),
-                                        request.getRequestCommand());
+                            if (match) {
+                                try {
+                                    if (request.isSnodeRequest()) {
+                                        this.brokerController.getSnodePullMessageProcessor().executeRequestWhenWakeup(request.getClientChannel(),
+                                            request.getRequestCommand());
+                                    } else {
+                                        this.brokerController.getPullMessageProcessor().executeRequestWhenWakeup(request.getClientChannel(),
+                                            request.getRequestCommand());
+                                    }
+                                } catch (Throwable e) {
+                                    log.error("execute request when wakeup failed.", e);
                                 }
-                            } catch (Throwable e) {
-                                log.error("execute request when wakeup failed.", e);
+                                continue;
                             }
-                            continue;
                         }
+                    } catch (Exception ex) {
+                        log.error("Error occurred:{}", ex);
                     }
 
                     if (System.currentTimeMillis() >= (request.getSuspendTimestamp() + request.getTimeoutMillis())) {
                         try {
-                            if (request.getMessageFilter() == null && request.getSubscriptionData() == null) {
+                            if (request.isSnodeRequest()) {
                                 this.brokerController.getSnodePullMessageProcessor().executeRequestWhenWakeup(request.getClientChannel(),
                                     request.getRequestCommand());
                             } else {
@@ -166,7 +169,6 @@ public class PullRequestHoldService extends ServiceThread {
                         }
                         continue;
                     }
-
                     replayList.add(request);
                 }
 
@@ -177,3 +179,4 @@ public class PullRequestHoldService extends ServiceThread {
         }
     }
 }
+
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java
index b7e7a61..5f1c2f1 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/SendMessageProcessor.java
@@ -63,7 +63,7 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
 
     @Override
     public RemotingCommand processRequest(ChannelHandlerContext ctx,
-                                          RemotingCommand request) throws RemotingCommandException {
+        RemotingCommand request) throws RemotingCommandException {
         SendMessageContext mqtraceContext;
         switch (request.getCode()) {
             case RequestCode.CONSUMER_SEND_MSG_BACK:
@@ -99,7 +99,7 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
         throws RemotingCommandException {
         final RemotingCommand response = RemotingCommand.createResponseCommand(null);
         final ConsumerSendMsgBackRequestHeader requestHeader =
-            (ConsumerSendMsgBackRequestHeader)request.decodeCommandCustomHeader(ConsumerSendMsgBackRequestHeader.class);
+            (ConsumerSendMsgBackRequestHeader) request.decodeCommandCustomHeader(ConsumerSendMsgBackRequestHeader.class);
 
         if (this.hasConsumeMessageHook() && !UtilAll.isBlank(requestHeader.getOriginMsgId())) {
 
@@ -249,8 +249,8 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
     }
 
     private boolean handleRetryAndDLQ(SendMessageRequestHeader requestHeader, RemotingCommand response,
-                                      RemotingCommand request,
-                                      MessageExt msg, TopicConfig topicConfig) {
+        RemotingCommand request,
+        MessageExt msg, TopicConfig topicConfig) {
         String newTopic = requestHeader.getTopic();
         if (null != newTopic && newTopic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) {
             String groupName = newTopic.substring(MixAll.RETRY_GROUP_TOPIC_PREFIX.length());
@@ -293,12 +293,12 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
     }
 
     private RemotingCommand sendMessage(final ChannelHandlerContext ctx,
-                                        final RemotingCommand request,
-                                        final SendMessageContext sendMessageContext,
-                                        final SendMessageRequestHeader requestHeader) throws RemotingCommandException {
+        final RemotingCommand request,
+        final SendMessageContext sendMessageContext,
+        final SendMessageRequestHeader requestHeader) throws RemotingCommandException {
 
         final RemotingCommand response = RemotingCommand.createResponseCommand(SendMessageResponseHeader.class);
-        final SendMessageResponseHeader responseHeader = (SendMessageResponseHeader)response.readCustomHeader();
+        final SendMessageResponseHeader responseHeader = (SendMessageResponseHeader) response.readCustomHeader();
 
         response.setOpaque(request.getOpaque());
 
@@ -366,9 +366,9 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
     }
 
     private RemotingCommand handlePutMessageResult(PutMessageResult putMessageResult, RemotingCommand response,
-                                                   RemotingCommand request, MessageExt msg,
-                                                   SendMessageResponseHeader responseHeader, SendMessageContext sendMessageContext, ChannelHandlerContext ctx,
-                                                   int queueIdInt) {
+        RemotingCommand request, MessageExt msg,
+        SendMessageResponseHeader responseHeader, SendMessageContext sendMessageContext, ChannelHandlerContext ctx,
+        int queueIdInt) {
         if (putMessageResult == null) {
             response.setCode(ResponseCode.SYSTEM_ERROR);
             response.setRemark("store putMessage return null");
@@ -448,7 +448,7 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
 
                 int commercialBaseCount = brokerController.getBrokerConfig().getCommercialBaseCount();
                 int wroteSize = putMessageResult.getAppendMessageResult().getWroteBytes();
-                int incValue = (int)Math.ceil(wroteSize / BrokerStatsManager.SIZE_PER_COUNT) * commercialBaseCount;
+                int incValue = (int) Math.ceil(wroteSize / BrokerStatsManager.SIZE_PER_COUNT) * commercialBaseCount;
 
                 sendMessageContext.setCommercialSendStats(BrokerStatsManager.StatsType.SEND_SUCCESS);
                 sendMessageContext.setCommercialSendTimes(incValue);
@@ -459,7 +459,7 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
         } else {
             if (hasSendMessageHook()) {
                 int wroteSize = request.getBody().length;
-                int incValue = (int)Math.ceil(wroteSize / BrokerStatsManager.SIZE_PER_COUNT);
+                int incValue = (int) Math.ceil(wroteSize / BrokerStatsManager.SIZE_PER_COUNT);
 
                 sendMessageContext.setCommercialSendStats(BrokerStatsManager.StatsType.SEND_FAILURE);
                 sendMessageContext.setCommercialSendTimes(incValue);
@@ -471,12 +471,12 @@ public class SendMessageProcessor extends AbstractSendMessageProcessor implement
     }
 
     private RemotingCommand sendBatchMessage(final ChannelHandlerContext ctx,
-                                             final RemotingCommand request,
-                                             final SendMessageContext sendMessageContext,
-                                             final SendMessageRequestHeader requestHeader) throws RemotingCommandException {
+        final RemotingCommand request,
+        final SendMessageContext sendMessageContext,
+        final SendMessageRequestHeader requestHeader) throws RemotingCommandException {
 
         final RemotingCommand response = RemotingCommand.createResponseCommand(SendMessageResponseHeader.class);
-        final SendMessageResponseHeader responseHeader = (SendMessageResponseHeader)response.readCustomHeader();
+        final SendMessageResponseHeader responseHeader = (SendMessageResponseHeader) response.readCustomHeader();
 
         response.setOpaque(request.getOpaque());
 
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/SnodePullMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/SnodePullMessageProcessor.java
index 8beb6fa..788c498 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/SnodePullMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/SnodePullMessageProcessor.java
@@ -24,7 +24,6 @@ import io.netty.channel.FileRegion;
 import java.nio.ByteBuffer;
 import java.util.List;
 import org.apache.rocketmq.broker.BrokerController;
-import org.apache.rocketmq.broker.client.ConsumerGroupInfo;
 import org.apache.rocketmq.broker.filter.ConsumerFilterData;
 import org.apache.rocketmq.broker.filter.ConsumerFilterManager;
 import org.apache.rocketmq.broker.filter.ExpressionForRetryMessageFilter;
@@ -34,22 +33,18 @@ import org.apache.rocketmq.broker.mqtrace.ConsumeMessageContext;
 import org.apache.rocketmq.broker.mqtrace.ConsumeMessageHook;
 import org.apache.rocketmq.broker.pagecache.ManyMessageTransfer;
 import org.apache.rocketmq.common.MixAll;
-import org.apache.rocketmq.common.TopicConfig;
 import org.apache.rocketmq.common.TopicFilterType;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.common.constant.PermName;
 import org.apache.rocketmq.common.filter.ExpressionType;
 import org.apache.rocketmq.common.filter.FilterAPI;
-import org.apache.rocketmq.common.help.FAQUrl;
 import org.apache.rocketmq.common.message.MessageDecoder;
 import org.apache.rocketmq.common.message.MessageQueue;
 import org.apache.rocketmq.common.protocol.ResponseCode;
 import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader;
 import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader;
-import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
 import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
 import org.apache.rocketmq.common.protocol.topic.OffsetMovedEvent;
-import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
 import org.apache.rocketmq.common.sysflag.PullSysFlag;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
@@ -95,23 +90,50 @@ public class SnodePullMessageProcessor implements NettyRequestProcessor {
 
         response.setOpaque(request.getOpaque());
 
-        log.info("receive PullMessage request command, {}", request);
         final boolean hasSuspendFlag = PullSysFlag.hasSuspendFlag(requestHeader.getSysFlag());
         final boolean hasCommitOffsetFlag = PullSysFlag.hasCommitOffsetFlag(requestHeader.getSysFlag());
-        final boolean hasSubscriptionFlag = PullSysFlag.hasSubscriptionFlag(requestHeader.getSysFlag());
+
+        ConsumerFilterData consumerFilterData = null;
+        SubscriptionData subscriptionData;
+        try {
+            subscriptionData = FilterAPI.build(
+                requestHeader.getTopic(), requestHeader.getSubscription(), requestHeader.getExpressionType()
+            );
+            if (!ExpressionType.isTagType(subscriptionData.getExpressionType())) {
+                consumerFilterData = ConsumerFilterManager.build(
+                    requestHeader.getTopic(), requestHeader.getConsumerGroup(), requestHeader.getSubscription(),
+                    requestHeader.getExpressionType(), requestHeader.getSubVersion()
+                );
+                assert consumerFilterData != null;
+            }
+        } catch (Exception e) {
+            log.warn("Parse the consumer's subscription[{}] failed, group: {}", requestHeader.getSubscription(),
+                requestHeader.getConsumerGroup());
+            response.setCode(ResponseCode.SUBSCRIPTION_PARSE_FAILED);
+            response.setRemark("parse the consumer's subscription failed");
+            return response;
+        }
 
         final long suspendTimeoutMillisLong = hasSuspendFlag ? requestHeader.getSuspendTimeoutMillis() : 0;
         if (!PermName.isReadable(this.brokerController.getBrokerConfig().getBrokerPermission())) {
             response.setCode(ResponseCode.NO_PERMISSION);
-            response.setRemark(String.format("the broker[%s] pulling message is forbidden", this.brokerController.getBrokerConfig().getBrokerIP1()));
+            response.setRemark(String.format("The broker[%s] pulling message is forbidden", this.brokerController.getBrokerConfig().getBrokerIP1()));
             return response;
         }
 
+        MessageFilter messageFilter;
+        if (this.brokerController.getBrokerConfig().isFilterSupportRetry()) {
+            messageFilter = new ExpressionForRetryMessageFilter(subscriptionData, consumerFilterData,
+                this.brokerController.getConsumerFilterManager());
+        } else {
+            messageFilter = new ExpressionMessageFilter(subscriptionData, consumerFilterData,
+                this.brokerController.getConsumerFilterManager());
+        }
+
         final GetMessageResult getMessageResult =
             this.brokerController.getMessageStore().getMessage(requestHeader.getConsumerGroup(), requestHeader.getTopic(),
-                requestHeader.getQueueId(), requestHeader.getQueueOffset(), requestHeader.getMaxMsgNums(), null);
+                requestHeader.getQueueId(), requestHeader.getQueueOffset(), requestHeader.getMaxMsgNums(), messageFilter);
 
-        log.info("Get message response:{}",getMessageResult);
         if (getMessageResult != null) {
             response.setRemark(getMessageResult.getStatus().name());
             responseHeader.setNextBeginOffset(getMessageResult.getNextBeginOffset());
@@ -136,19 +158,6 @@ public class SnodePullMessageProcessor implements NettyRequestProcessor {
                     break;
             }
 
-//            if (this.brokerController.getBrokerConfig().isSlaveReadEnable()) {
-//                // consume too slow ,redirect to another machine
-//                if (getMessageResult.isSuggestPullingFromSlave()) {
-//                    responseHeader.setSuggestWhichBrokerId(subscriptionGroupConfig.getWhichBrokerWhenConsumeSlowly());
-//                }
-//                // consume ok
-//                else {
-//                    responseHeader.setSuggestWhichBrokerId(subscriptionGroupConfig.getBrokerId());
-//                }
-//            } else {
-//                responseHeader.setSuggestWhichBrokerId(MixAll.MASTER_ID);
-//            }
-
             switch (getMessageResult.getStatus()) {
                 case FOUND:
                     response.setCode(ResponseCode.SUCCESS);
@@ -162,7 +171,7 @@ public class SnodePullMessageProcessor implements NettyRequestProcessor {
                         response.setCode(ResponseCode.PULL_OFFSET_MOVED);
 
                         // XXX: warn and notify me
-                        log.info("the broker store no queue data, fix the request offset {} to {}, Topic: {} QueueId: {} Consumer Group: {}",
+                        log.info("The broker store no queue data, fix the request offset {} to {}, Topic: {} QueueId: {} Consumer Group: {}",
                             requestHeader.getQueueOffset(),
                             getMessageResult.getNextBeginOffset(),
                             requestHeader.getTopic(),
@@ -182,7 +191,7 @@ public class SnodePullMessageProcessor implements NettyRequestProcessor {
                 case OFFSET_OVERFLOW_BADLY:
                     response.setCode(ResponseCode.PULL_OFFSET_MOVED);
                     // XXX: warn and notify me
-                    log.info("the request offset: {} over flow badly, broker max offset: {}, consumer: {}",
+                    log.info("The request offset: {} over flow badly, broker max offset: {}, consumer: {}",
                         requestHeader.getQueueOffset(), getMessageResult.getMaxOffset(), channel.remoteAddress());
                     break;
                 case OFFSET_OVERFLOW_ONE:
@@ -190,7 +199,7 @@ public class SnodePullMessageProcessor implements NettyRequestProcessor {
                     break;
                 case OFFSET_TOO_SMALL:
                     response.setCode(ResponseCode.PULL_OFFSET_MOVED);
-                    log.info("the request offset too small. group={}, topic={}, requestOffset={}, brokerMinOffset={}, clientIp={}",
+                    log.info("The request offset too small. group={}, topic={}, requestOffset={}, brokerMinOffset={}, clientIp={}",
                         requestHeader.getConsumerGroup(), requestHeader.getTopic(), requestHeader.getQueueOffset(),
                         getMessageResult.getMinOffset(), channel.remoteAddress());
                     break;
@@ -267,12 +276,12 @@ public class SnodePullMessageProcessor implements NettyRequestProcessor {
                                 public void operationComplete(ChannelFuture future) throws Exception {
                                     getMessageResult.release();
                                     if (!future.isSuccess()) {
-                                        log.error("transfer many message by pagecache failed, {}", channel.remoteAddress(), future.cause());
+                                        log.error("Transfer many message by pagecache failed, {}", channel.remoteAddress(), future.cause());
                                     }
                                 }
                             });
                         } catch (Throwable e) {
-                            log.error("transfer many message by pagecache exception", e);
+                            log.error("Transfer many message by pagecache exception", e);
                             getMessageResult.release();
                         }
 
@@ -291,7 +300,7 @@ public class SnodePullMessageProcessor implements NettyRequestProcessor {
                         long offset = requestHeader.getQueueOffset();
                         int queueId = requestHeader.getQueueId();
                         PullRequest pullRequest = new PullRequest(request, channel, pollingTimeMills,
-                            this.brokerController.getMessageStore().now(), offset, null, null);
+                            this.brokerController.getMessageStore().now(), offset, subscriptionData, messageFilter, true);
                         this.brokerController.getPullRequestHoldService().suspendPullRequest(topic, queueId, pullRequest);
                         response = null;
                         break;
@@ -407,7 +416,7 @@ public class SnodePullMessageProcessor implements NettyRequestProcessor {
     }
 
     public void executeRequestWhenWakeup(final Channel channel,
-        final RemotingCommand request) throws RemotingCommandException {
+        final RemotingCommand request) {
         Runnable run = new Runnable() {
             @Override
             public void run() {
@@ -422,7 +431,7 @@ public class SnodePullMessageProcessor implements NettyRequestProcessor {
                                 @Override
                                 public void operationComplete(ChannelFuture future) throws Exception {
                                     if (!future.isSuccess()) {
-                                        log.error("processRequestWrapper response to {} failed",
+                                        log.error("ProcessRequestWrapper snode response to {} failed",
                                             future.channel().remoteAddress(), future.cause());
                                         log.error(request.toString());
                                         log.error(response.toString());
@@ -430,7 +439,7 @@ public class SnodePullMessageProcessor implements NettyRequestProcessor {
                                 }
                             });
                         } catch (Throwable e) {
-                            log.error("processRequestWrapper process request over, but response failed", e);
+                            log.error("ProcessRequestWrapper snode process request over, but response failed", e);
                             log.error(request.toString());
                             log.error(response.toString());
                         }
diff --git a/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java b/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java
index 562810f..48fb934 100644
--- a/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java
+++ b/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java
@@ -45,7 +45,7 @@ public class ClientConfig {
     private int persistConsumerOffsetInterval = 1000 * 5;
     private boolean unitMode = false;
     private String unitName;
-    private boolean vipChannelEnabled = Boolean.parseBoolean(System.getProperty(SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "true"));
+    private boolean vipChannelEnabled = Boolean.parseBoolean(System.getProperty(SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "false"));
 
     private boolean useTLS = TlsSystemConfig.tlsEnable;
 
diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java b/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java
index c1524e1..f3e2f4e 100644
--- a/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java
+++ b/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java
@@ -16,6 +16,7 @@
  */
 package org.apache.rocketmq.client.consumer.store;
 
+import com.sun.org.apache.regexp.internal.RE;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -187,8 +188,7 @@ public class RemoteBrokerOffsetStore implements OffsetStore {
     }
 
     /**
-     * Update the Consumer Offset in one way, once the Master is off, updated to Slave,
-     * here need to be optimized.
+     * Update the Consumer Offset in one way, once the Master is off, updated to Slave, here need to be optimized.
      */
     private void updateConsumeOffsetToBroker(MessageQueue mq, long offset) throws RemotingException,
         MQBrokerException, InterruptedException, MQClientException {
@@ -196,8 +196,7 @@ public class RemoteBrokerOffsetStore implements OffsetStore {
     }
 
     /**
-     * Update the Consumer Offset synchronously, once the Master is off, updated to Slave,
-     * here need to be optimized.
+     * Update the Consumer Offset synchronously, once the Master is off, updated to Slave, here need to be optimized.
      */
     @Override
     public void updateConsumeOffsetToBroker(MessageQueue mq, long offset, boolean isOneway) throws RemotingException,
@@ -215,7 +214,7 @@ public class RemoteBrokerOffsetStore implements OffsetStore {
             requestHeader.setConsumerGroup(this.groupName);
             requestHeader.setQueueId(mq.getQueueId());
             requestHeader.setCommitOffset(offset);
-
+            requestHeader.setEnodeName(mq.getBrokerName());
             if (isOneway) {
                 this.mQClientFactory.getMQClientAPIImpl().updateConsumerOffsetOneway(
                     findBrokerResult.getBrokerAddr(), requestHeader, 1000 * 5);
@@ -242,7 +241,7 @@ public class RemoteBrokerOffsetStore implements OffsetStore {
             requestHeader.setTopic(mq.getTopic());
             requestHeader.setConsumerGroup(this.groupName);
             requestHeader.setQueueId(mq.getQueueId());
-
+            requestHeader.setEnodeName(mq.getBrokerName());
             return this.mQClientFactory.getMQClientAPIImpl().queryConsumerOffset(
                 findBrokerResult.getBrokerAddr(), requestHeader, 1000 * 5);
         } else {
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
index 6302cd0..a7aead1 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
@@ -353,8 +353,7 @@ public class MQClientAPIImpl {
         final long timeoutMillis,
         final RemotingCommand request
     ) throws RemotingException, MQBrokerException, InterruptedException {
-        String addrS = "localhost:11911";//TODO FIXME
-        RemotingCommand response = this.remotingClient.invokeSync(addrS, request, timeoutMillis);
+        RemotingCommand response = this.remotingClient.invokeSync(addr, request, timeoutMillis);
         assert response != null;
         return this.processSendResponse(brokerName, msg, response);
     }
@@ -566,7 +565,6 @@ public class MQClientAPIImpl {
     ) throws RemotingException, MQBrokerException, InterruptedException {
         requestHeader.setEnodeAddr(addr);
         RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SNODE_PULL_MESSAGE, requestHeader);
-         addr = "localhost:11911"; //TODO FIXME
         switch (communicationMode) {
             case ONEWAY:
                 assert false;
@@ -649,7 +647,6 @@ public class MQClientAPIImpl {
 
         PullMessageResponseHeader responseHeader =
             (PullMessageResponseHeader) response.decodeCommandCustomHeader(PullMessageResponseHeader.class);
-        log.info("response header: {}", responseHeader.getSuggestWhichBrokerId());
         return new PullResultExt(pullStatus, responseHeader.getNextBeginOffset(), responseHeader.getMinOffset(),
             responseHeader.getMaxOffset(), null, responseHeader.getSuggestWhichBrokerId(), response.getBody());
     }
@@ -734,8 +731,7 @@ public class MQClientAPIImpl {
         GetConsumerListByGroupRequestHeader requestHeader = new GetConsumerListByGroupRequestHeader();
         requestHeader.setConsumerGroup(consumerGroup);
         RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_CONSUMER_LIST_BY_GROUP, requestHeader);
-        String addrS = "localhost:11911";//TODO FIXME
-        RemotingCommand response = this.remotingClient.invokeSync(addrS,
+        RemotingCommand response = this.remotingClient.invokeSync(addr,
             request, timeoutMillis);
         assert response != null;
         switch (response.getCode()) {
@@ -940,6 +936,7 @@ public class MQClientAPIImpl {
     }
 
     public void consumerSendMessageBack(
+        final String brokerName,
         final String addr,
         final MessageExt msg,
         final String consumerGroup,
@@ -956,6 +953,7 @@ public class MQClientAPIImpl {
         requestHeader.setDelayLevel(delayLevel);
         requestHeader.setOriginMsgId(msg.getMsgId());
         requestHeader.setMaxReconsumeTimes(maxConsumeRetryTimes);
+        requestHeader.setEnodeName(brokerName);
 
         RemotingCommand response = this.remotingClient.invokeSync(MixAll.brokerVIPChannel(this.clientConfig.isVipChannelEnabled(), addr),
             request, timeoutMillis);
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java
index 420d89b..20a72d8 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java
@@ -495,7 +495,7 @@ public class DefaultMQPullConsumerImpl implements MQConsumerInner {
                 consumerGroup = this.defaultMQPullConsumer.getConsumerGroup();
             }
 
-            this.mQClientFactory.getMQClientAPIImpl().consumerSendMessageBack(brokerAddr, msg, consumerGroup, delayLevel, 3000,
+            this.mQClientFactory.getMQClientAPIImpl().consumerSendMessageBack(brokerName, brokerAddr, msg, consumerGroup, delayLevel, 3000,
                 this.defaultMQPullConsumer.getMaxReconsumeTimes());
         } catch (Exception e) {
             log.error("sendMessageBack Exception, " + this.defaultMQPullConsumer.getConsumerGroup(), e);
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
index 393ef92..2f3cc97 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
@@ -499,7 +499,7 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner {
         try {
             String brokerAddr = (null != brokerName) ? this.mQClientFactory.findBrokerAddressInPublish(brokerName)
                 : RemotingHelper.parseSocketAddressAddr(msg.getStoreHost());
-            this.mQClientFactory.getMQClientAPIImpl().consumerSendMessageBack(brokerAddr, msg,
+            this.mQClientFactory.getMQClientAPIImpl().consumerSendMessageBack(brokerName, brokerAddr, msg,
                 this.defaultMQPushConsumer.getConsumerGroup(), delayLevel, 5000, getMaxReconsumeTimes());
         } catch (Exception e) {
             log.error("sendMessageBack Exception, " + this.defaultMQPushConsumer.getConsumerGroup(), e);
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
index 984e2cc..4e9d9ba 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
@@ -537,8 +537,7 @@ public class MQClientInstance {
                             }
 
                             try {
-                                String addrS = "localhost:11911"; //TODO FIXME
-                                int version = this.mQClientAPIImpl.sendHearbeat(addrS, heartbeatData, 3000);
+                                int version = this.mQClientAPIImpl.sendHearbeat(addr, heartbeatData, 3000);
                                 if (!this.brokerVersionTable.containsKey(brokerName)) {
                                     this.brokerVersionTable.put(brokerName, new HashMap<String, Integer>(4));
                                 }
@@ -548,7 +547,7 @@ public class MQClientInstance {
                                     log.info(heartbeatData.toString());
                                 }
                             } catch (Exception e) {
-                                log.error("send heart beat error:{}",e);
+                                log.error("send heart beat error:{}", e);
                                 if (this.isBrokerInNameServer(addr)) {
                                     log.info("send heart beat to broker[{} {} {}] failed", brokerName, id, addr);
                                 } else {
@@ -722,9 +721,10 @@ public class MQClientInstance {
 
         return false;
     }
+
     /**
-     * This method will be removed in the version 5.0.0,because filterServer was removed,and method <code>subscribe(final String topic, final MessageSelector messageSelector)</code>
-     * is recommended.
+     * This method will be removed in the version 5.0.0,because filterServer was removed,and method
+     * <code>subscribe(final String topic, final MessageSelector messageSelector)</code> is recommended.
      */
     @Deprecated
     private void uploadFilterClassToAllFilterServer(final String consumerGroup, final String fullClassName,
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java
index 9ada834..291834f 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java
@@ -733,7 +733,7 @@ public class DefaultMQProducerImpl implements MQProducerInner {
                 requestHeader.setReconsumeTimes(0);
                 requestHeader.setUnitMode(this.isUnitMode());
                 requestHeader.setBatch(msg instanceof MessageBatch);
-                requestHeader.setEnodeAddr(brokerAddr);
+                requestHeader.setEnodeName(mq.getBrokerName());
                 if (requestHeader.getTopic().startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) {
                     String reconsumeTimes = MessageAccessor.getReconsumeTime(msg);
                     if (reconsumeTimes != null) {
diff --git a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java
index f81af21..de0b8e2 100644
--- a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java
+++ b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java
@@ -171,6 +171,18 @@ public class BrokerConfig {
     @ImportantField
     private long transactionCheckInterval = 60 * 1000;
 
+
+    @ImportantField
+    private boolean transactionEnable = true;
+
+    public boolean isTransactionEnable() {
+        return transactionEnable;
+    }
+
+    public void setTransactionEnable(boolean transactionEnable) {
+        this.transactionEnable = transactionEnable;
+    }
+
     public boolean isTraceOn() {
         return traceOn;
     }
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/ResponseCode.java b/common/src/main/java/org/apache/rocketmq/common/protocol/ResponseCode.java
index f62c4ea..97d433b 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/ResponseCode.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/ResponseCode.java
@@ -73,4 +73,8 @@ public class ResponseCode extends RemotingSysResponseCode {
     public static final int CONSUME_MSG_TIMEOUT = 207;
 
     public static final int NO_MESSAGE = 208;
+
+    public static final int QUERY_OFFSET_ERROR = 210;
+
+    public static final int PARAMETER_ERROR = 211;
 }
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java
index bd8fbb4..8ead5ef 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/ConsumerSendMsgBackRequestHeader.java
@@ -35,6 +35,8 @@ public class ConsumerSendMsgBackRequestHeader implements CommandCustomHeader {
     private boolean unitMode = false;
     private Integer maxReconsumeTimes;
 
+    private String enodeName;
+
     @Override
     public void checkFields() throws RemotingCommandException {
 
@@ -96,9 +98,24 @@ public class ConsumerSendMsgBackRequestHeader implements CommandCustomHeader {
         this.maxReconsumeTimes = maxReconsumeTimes;
     }
 
-    @Override
-    public String toString() {
-        return "ConsumerSendMsgBackRequestHeader [group=" + group + ", originTopic=" + originTopic + ", originMsgId=" + originMsgId
-            + ", delayLevel=" + delayLevel + ", unitMode=" + unitMode + ", maxReconsumeTimes=" + maxReconsumeTimes + "]";
+    public String getEnodeName() {
+        return enodeName;
+    }
+
+    public void setEnodeName(String enodeName) {
+        this.enodeName = enodeName;
+    }
+
+    @Override public String toString() {
+        return "ConsumerSendMsgBackRequestHeader{" +
+            "offset=" + offset +
+            ", group='" + group + '\'' +
+            ", delayLevel=" + delayLevel +
+            ", originMsgId='" + originMsgId + '\'' +
+            ", originTopic='" + originTopic + '\'' +
+            ", unitMode=" + unitMode +
+            ", maxReconsumeTimes=" + maxReconsumeTimes +
+            ", enodeName='" + enodeName + '\'' +
+            '}';
     }
 }
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMaxOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMaxOffsetRequestHeader.java
index 871309d..1b5f951 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMaxOffsetRequestHeader.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMaxOffsetRequestHeader.java
@@ -30,6 +30,8 @@ public class GetMaxOffsetRequestHeader implements CommandCustomHeader {
     @CFNotNull
     private Integer queueId;
 
+    private String enodeName;
+
     @Override
     public void checkFields() throws RemotingCommandException {
     }
@@ -49,4 +51,12 @@ public class GetMaxOffsetRequestHeader implements CommandCustomHeader {
     public void setQueueId(Integer queueId) {
         this.queueId = queueId;
     }
+
+    public String getEnodeName() {
+        return enodeName;
+    }
+
+    public void setEnodeName(String enodeName) {
+        this.enodeName = enodeName;
+    }
 }
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMinOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMinOffsetRequestHeader.java
index 6fb8ed4..1ac771b 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMinOffsetRequestHeader.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/GetMinOffsetRequestHeader.java
@@ -27,9 +27,12 @@ import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 public class GetMinOffsetRequestHeader implements CommandCustomHeader {
     @CFNotNull
     private String topic;
+
     @CFNotNull
     private Integer queueId;
 
+    private String enodeName;
+
     @Override
     public void checkFields() throws RemotingCommandException {
     }
@@ -49,4 +52,12 @@ public class GetMinOffsetRequestHeader implements CommandCustomHeader {
     public void setQueueId(Integer queueId) {
         this.queueId = queueId;
     }
+
+    public String getEnodeName() {
+        return enodeName;
+    }
+
+    public void setEnodeName(String enodeName) {
+        this.enodeName = enodeName;
+    }
 }
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/QueryConsumerOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/QueryConsumerOffsetRequestHeader.java
index 3b7f627..2034c97 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/QueryConsumerOffsetRequestHeader.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/QueryConsumerOffsetRequestHeader.java
@@ -32,6 +32,8 @@ public class QueryConsumerOffsetRequestHeader implements CommandCustomHeader {
     @CFNotNull
     private Integer queueId;
 
+    private String enodeName;
+
     @Override
     public void checkFields() throws RemotingCommandException {
     }
@@ -59,4 +61,12 @@ public class QueryConsumerOffsetRequestHeader implements CommandCustomHeader {
     public void setQueueId(Integer queueId) {
         this.queueId = queueId;
     }
+
+    public String getEnodeName() {
+        return enodeName;
+    }
+
+    public void setEnodeName(String enodeName) {
+        this.enodeName = enodeName;
+    }
 }
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SearchOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SearchOffsetRequestHeader.java
index 5ea2e24..4db36b5 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SearchOffsetRequestHeader.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SearchOffsetRequestHeader.java
@@ -32,6 +32,8 @@ public class SearchOffsetRequestHeader implements CommandCustomHeader {
     @CFNotNull
     private Long timestamp;
 
+    private String enodeName;
+
     @Override
     public void checkFields() throws RemotingCommandException {
 
@@ -61,4 +63,11 @@ public class SearchOffsetRequestHeader implements CommandCustomHeader {
         this.timestamp = timestamp;
     }
 
+    public String getEnodeName() {
+        return enodeName;
+    }
+
+    public void setEnodeName(String enodeName) {
+        this.enodeName = enodeName;
+    }
 }
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java
index a032911..bab833b 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java
@@ -53,7 +53,7 @@ public class SendMessageRequestHeader implements CommandCustomHeader {
 
     private Integer maxReconsumeTimes;
 
-    private String enodeAddr;
+    private String enodeName;
 
     @Override
     public void checkFields() throws RemotingCommandException {
@@ -163,11 +163,30 @@ public class SendMessageRequestHeader implements CommandCustomHeader {
         this.batch = batch;
     }
 
-    public String getEnodeAddr() {
-        return enodeAddr;
+    public String getEnodeName() {
+        return enodeName;
     }
 
-    public void setEnodeAddr(String enodeAddr) {
-        this.enodeAddr = enodeAddr;
+    public void setEnodeName(String enodeName) {
+        this.enodeName = enodeName;
+    }
+
+    @Override public String toString() {
+        return "SendMessageRequestHeader{" +
+            "producerGroup='" + producerGroup + '\'' +
+            ", topic='" + topic + '\'' +
+            ", defaultTopic='" + defaultTopic + '\'' +
+            ", defaultTopicQueueNums=" + defaultTopicQueueNums +
+            ", queueId=" + queueId +
+            ", sysFlag=" + sysFlag +
+            ", bornTimestamp=" + bornTimestamp +
+            ", flag=" + flag +
+            ", properties='" + properties + '\'' +
+            ", reconsumeTimes=" + reconsumeTimes +
+            ", unitMode=" + unitMode +
+            ", batch=" + batch +
+            ", maxReconsumeTimes=" + maxReconsumeTimes +
+            ", enodeName='" + enodeName + '\'' +
+            '}';
     }
 }
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeaderV2.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeaderV2.java
index 9602805..ed6babe 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeaderV2.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeaderV2.java
@@ -71,7 +71,7 @@ public class SendMessageRequestHeaderV2 implements CommandCustomHeader {
         v1.setUnitMode(v2.k);
         v1.setMaxReconsumeTimes(v2.l);
         v1.setBatch(v2.m);
-        v1.setEnodeAddr(v2.n);
+        v1.setEnodeName(v2.n);
         return v1;
     }
 
@@ -90,7 +90,7 @@ public class SendMessageRequestHeaderV2 implements CommandCustomHeader {
         v2.k = v1.isUnitMode();
         v2.l = v1.getMaxReconsumeTimes();
         v2.m = v1.isBatch();
-        v2.n = v1.getEnodeAddr();
+        v2.n = v1.getEnodeName();
         return v2;
     }
 
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java
index 3f44db6..dd4d3b4 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/UpdateConsumerOffsetRequestHeader.java
@@ -34,6 +34,8 @@ public class UpdateConsumerOffsetRequestHeader implements CommandCustomHeader {
     @CFNotNull
     private Long commitOffset;
 
+    private String enodeName;
+
     @Override
     public void checkFields() throws RemotingCommandException {
     }
@@ -69,4 +71,12 @@ public class UpdateConsumerOffsetRequestHeader implements CommandCustomHeader {
     public void setCommitOffset(Long commitOffset) {
         this.commitOffset = commitOffset;
     }
+
+    public String getEnodeName() {
+        return enodeName;
+    }
+
+    public void setEnodeName(String enodeName) {
+        this.enodeName = enodeName;
+    }
 }
diff --git a/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java b/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java
index 6d3b936..8d667a4 100644
--- a/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java
+++ b/example/src/main/java/org/apache/rocketmq/example/quickstart/Consumer.java
@@ -35,7 +35,7 @@ public class Consumer {
         /*
          * Instantiate with specified consumer group name.
          */
-        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_4");
+        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("RocketMQ5");
 
         /*
          * Specify name server addresses.
@@ -58,7 +58,6 @@ public class Consumer {
          * Subscribe one more more topics to consume.
          */
         consumer.subscribe("TopicTest", "*");
-
         /*
          *  Register callback to execute on arrival of messages fetched from brokers.
          */
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
index 3b12d49..0af8c98 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
@@ -379,7 +379,6 @@ public class DefaultRequestProcessor implements NettyRequestProcessor {
 
     private RemotingCommand getBrokerClusterInfo(ChannelHandlerContext ctx, RemotingCommand request) {
         final RemotingCommand response = RemotingCommand.createResponseCommand(null);
-
         byte[] content = this.namesrvController.getRouteInfoManager().getAllClusterInfo();
         response.setBody(content);
 
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
index cae2bf4..8d3f54b 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
@@ -296,8 +296,7 @@ public abstract class NettyRemotingAbstract {
                 responseFuture.release();
             }
         } else {
-            log.warn("receive response, but not matched any request, " + RemotingHelper.parseChannelRemoteAddr(ctx.channel()));
-            log.warn(cmd.toString());
+            log.warn("receive response, but not matched any request: {}, cmd: {}", RemotingHelper.parseChannelRemoteAddr(ctx.channel()), cmd);
         }
     }
 
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java
index 4e691f1..55a1d3d 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java
@@ -181,6 +181,7 @@ public class NettyRemotingClient extends NettyRemotingClientAbstract implements
         throws InterruptedException, RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException {
         long beginStartTime = System.currentTimeMillis();
         final Channel channel = this.getAndCreateChannel(addr, timeoutMillis);
+
         if (channel != null && channel.isActive()) {
             try {
                 if (this.rpcHook != null) {
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
index 50337df..cb8d662 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
@@ -26,6 +26,8 @@ import org.apache.rocketmq.common.protocol.RequestCode;
 import org.apache.rocketmq.common.utils.ThreadUtils;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingClient;
+import org.apache.rocketmq.remoting.RemotingClientFactory;
 import org.apache.rocketmq.remoting.RemotingServer;
 import org.apache.rocketmq.remoting.RemotingServerFactory;
 import org.apache.rocketmq.remoting.netty.NettyClientConfig;
@@ -37,14 +39,17 @@ import org.apache.rocketmq.snode.client.DefaultConsumerIdsChangeListener;
 import org.apache.rocketmq.snode.client.ProducerManager;
 import org.apache.rocketmq.snode.client.SubscriptionGroupManager;
 import org.apache.rocketmq.snode.config.SnodeConfig;
+import org.apache.rocketmq.snode.offset.ConsumerOffsetManager;
 import org.apache.rocketmq.snode.processor.ConsumerManageProcessor;
 import org.apache.rocketmq.snode.processor.HearbeatProcessor;
 import org.apache.rocketmq.snode.processor.PullMessageProcessor;
 import org.apache.rocketmq.snode.processor.SendMessageProcessor;
+import org.apache.rocketmq.snode.service.EnodeService;
+import org.apache.rocketmq.snode.service.NnodeService;
 import org.apache.rocketmq.snode.service.ScheduledService;
-import org.apache.rocketmq.snode.service.SnodeOuterService;
+import org.apache.rocketmq.snode.service.impl.EnodeServiceImpl;
+import org.apache.rocketmq.snode.service.impl.NnodeServiceImpl;
 import org.apache.rocketmq.snode.service.impl.ScheduledServiceImpl;
-import org.apache.rocketmq.snode.service.impl.SnodeOuterServiceImpl;
 
 public class SnodeController {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
@@ -52,17 +57,25 @@ public class SnodeController {
     private final SnodeConfig snodeConfig;
     private final NettyServerConfig nettyServerConfig;
     private final NettyClientConfig nettyClientConfig;
+    private RemotingClient remotingClient;
     private RemotingServer snodeServer;
-    private ExecutorService sendMessageExcutor;
+    private ExecutorService sendMessageExecutor;
     private ExecutorService heartbeatExecutor;
-    private ExecutorService pullMessageExcutor;
-    private SnodeOuterService snodeOuterService;
-    private ExecutorService consumerManagerExcutor;
+    private ExecutorService pullMessageExecutor;
+    private ExecutorService consumerManageExecutor;
+    private EnodeService enodeService;
+    private NnodeService nnodeService;
+    private ExecutorService consumerManagerExecutor;
     private ScheduledService scheduledService;
     private ProducerManager producerManager;
     private ConsumerManager consumerManager;
     private ClientHousekeepingService clientHousekeepingService;
     private SubscriptionGroupManager subscriptionGroupManager;
+    private ConsumerOffsetManager consumerOffsetManager;
+    private ConsumerManageProcessor consumerManageProcessor;
+    private SendMessageProcessor sendMessageProcessor;
+    private PullMessageProcessor pullMessageProcessor;
+    private HearbeatProcessor hearbeatProcessor;
 
     private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl(
         "SnodeControllerScheduledThread"));
@@ -73,9 +86,12 @@ public class SnodeController {
         this.nettyClientConfig = nettyClientConfig;
         this.nettyServerConfig = nettyServerConfig;
         this.snodeConfig = snodeConfig;
-        this.snodeOuterService = SnodeOuterServiceImpl.getInstance(this);
-        this.scheduledService = new ScheduledServiceImpl(this.snodeOuterService, this.snodeConfig);
-        this.sendMessageExcutor = ThreadUtils.newThreadPoolExecutor(
+        this.enodeService = new EnodeServiceImpl(this);
+        this.nnodeService = new NnodeServiceImpl(this);
+        this.scheduledService = new ScheduledServiceImpl(this);
+        this.remotingClient = RemotingClientFactory.createInstance().init(this.getNettyClientConfig(), null);
+
+        this.sendMessageExecutor = ThreadUtils.newThreadPoolExecutor(
             snodeConfig.getSnodeSendMessageMinPoolSize(),
             snodeConfig.getSnodeSendMessageMaxPoolSize(),
             3000,
@@ -84,7 +100,7 @@ public class SnodeController {
             "SnodeSendMessageThread",
             false);
 
-        this.pullMessageExcutor = ThreadUtils.newThreadPoolExecutor(
+        this.pullMessageExecutor = ThreadUtils.newThreadPoolExecutor(
             snodeConfig.getSnodeSendMessageMinPoolSize(),
             snodeConfig.getSnodeSendMessageMaxPoolSize(),
             3000,
@@ -102,7 +118,7 @@ public class SnodeController {
             "SnodeHeartbeatThread",
             true);
 
-        this.consumerManagerExcutor = ThreadUtils.newThreadPoolExecutor(
+        this.consumerManagerExecutor = ThreadUtils.newThreadPoolExecutor(
             snodeConfig.getSnodeSendMessageMinPoolSize(),
             snodeConfig.getSnodeSendMessageMaxPoolSize(),
             3000,
@@ -111,8 +127,17 @@ public class SnodeController {
             "SnodePullMessageThread",
             false);
 
+        this.consumerManageExecutor = ThreadUtils.newThreadPoolExecutor(
+            snodeConfig.getSnodeSendMessageMinPoolSize(),
+            snodeConfig.getSnodeSendMessageMaxPoolSize(),
+            3000,
+            TimeUnit.MILLISECONDS,
+            new ArrayBlockingQueue<Runnable>(snodeConfig.getSnodeSendThreadPoolQueueCapacity()),
+            "ConsumerManagerThread",
+            false);
+
         if (this.snodeConfig.getNamesrvAddr() != null) {
-            this.snodeOuterService.updateNameServerAddressList(this.snodeConfig.getNamesrvAddr());
+            this.nnodeService.updateNnodeAddressList(this.snodeConfig.getNamesrvAddr());
             log.info("Set user specified name server address: {}", this.snodeConfig.getNamesrvAddr());
         }
 
@@ -122,6 +147,11 @@ public class SnodeController {
         this.consumerManager = new ConsumerManager(consumerIdsChangeListener);
         this.subscriptionGroupManager = new SubscriptionGroupManager(this);
         this.clientHousekeepingService = new ClientHousekeepingService(this.producerManager, this.consumerManager);
+        this.consumerOffsetManager = new ConsumerOffsetManager(this);
+        this.consumerManageProcessor = new ConsumerManageProcessor(this);
+        this.sendMessageProcessor = new SendMessageProcessor(this);
+        this.hearbeatProcessor = new HearbeatProcessor(this);
+        this.pullMessageProcessor = new PullMessageProcessor(this);
     }
 
     public SnodeConfig getSnodeConfig() {
@@ -135,26 +165,34 @@ public class SnodeController {
     }
 
     public void registerProcessor() {
-        snodeServer.registerProcessor(RequestCode.SEND_MESSAGE_V2, new SendMessageProcessor(this), sendMessageExcutor);
-        snodeServer.registerProcessor(RequestCode.HEART_BEAT, new HearbeatProcessor(this), heartbeatExecutor);
-        snodeServer.registerProcessor(RequestCode.SNODE_PULL_MESSAGE, new PullMessageProcessor(this), pullMessageExcutor);
-        snodeServer.registerProcessor(RequestCode.GET_CONSUMER_LIST_BY_GROUP, new ConsumerManageProcessor(this), consumerManagerExcutor);
+        this.snodeServer.registerProcessor(RequestCode.SEND_MESSAGE_V2, sendMessageProcessor, this.sendMessageExecutor);
+        this.snodeServer.registerProcessor(RequestCode.CONSUMER_SEND_MSG_BACK, sendMessageProcessor, this.sendMessageExecutor);
+        this.snodeServer.registerProcessor(RequestCode.HEART_BEAT, hearbeatProcessor, this.heartbeatExecutor);
+        this.snodeServer.registerProcessor(RequestCode.UNREGISTER_CLIENT, hearbeatProcessor, this.heartbeatExecutor);
+        this.snodeServer.registerProcessor(RequestCode.SNODE_PULL_MESSAGE, pullMessageProcessor, this.pullMessageExecutor);
+        this.snodeServer.registerProcessor(RequestCode.GET_CONSUMER_LIST_BY_GROUP, consumerManageProcessor, this.consumerManageExecutor);
+        this.snodeServer.registerProcessor(RequestCode.UPDATE_CONSUMER_OFFSET, consumerManageProcessor, this.consumerManageExecutor);
+        this.snodeServer.registerProcessor(RequestCode.QUERY_CONSUMER_OFFSET, consumerManageProcessor, this.consumerManageExecutor);
+        this.snodeServer.registerProcessor(RequestCode.GET_MIN_OFFSET, consumerManageProcessor, this.consumerManageExecutor);
+        this.snodeServer.registerProcessor(RequestCode.GET_MAX_OFFSET, consumerManageProcessor, this.consumerManageExecutor);
+        this.snodeServer.registerProcessor(RequestCode.SEARCH_OFFSET_BY_TIMESTAMP, consumerManageProcessor, this.consumerManageExecutor);
     }
 
     public void start() {
         initialize();
         this.snodeServer.start();
-        this.snodeOuterService.start();
+        this.remotingClient.start();
         this.scheduledService.startScheduleTask();
         this.clientHousekeepingService.start(this.snodeConfig.getHouseKeepingInterval());
     }
 
     public void shutdown() {
-        this.sendMessageExcutor.shutdown();
-        this.pullMessageExcutor.shutdown();
+        this.sendMessageExecutor.shutdown();
+        this.pullMessageExecutor.shutdown();
         this.heartbeatExecutor.shutdown();
+        this.consumerManagerExecutor.shutdown();
         this.scheduledExecutorService.shutdown();
-        this.snodeOuterService.shutdown();
+        this.remotingClient.shutdown();
         this.scheduledService.shutdown();
         this.clientHousekeepingService.shutdown();
     }
@@ -195,11 +233,35 @@ public class SnodeController {
         return nettyClientConfig;
     }
 
-    public SnodeOuterService getSnodeOuterService() {
-        return snodeOuterService;
+    public EnodeService getEnodeService() {
+        return enodeService;
+    }
+
+    public void setEnodeService(EnodeService enodeService) {
+        this.enodeService = enodeService;
+    }
+
+    public NnodeService getNnodeService() {
+        return nnodeService;
+    }
+
+    public void setNnodeService(NnodeService nnodeService) {
+        this.nnodeService = nnodeService;
+    }
+
+    public RemotingClient getRemotingClient() {
+        return remotingClient;
+    }
+
+    public void setRemotingClient(RemotingClient remotingClient) {
+        this.remotingClient = remotingClient;
+    }
+
+    public ConsumerOffsetManager getConsumerOffsetManager() {
+        return consumerOffsetManager;
     }
 
-    public void setSnodeOuterService(SnodeOuterService snodeOuterService) {
-        this.snodeOuterService = snodeOuterService;
+    public void setConsumerOffsetManager(ConsumerOffsetManager consumerOffsetManager) {
+        this.consumerOffsetManager = consumerOffsetManager;
     }
 }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java
index e71ea0a..02598b9 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java
@@ -54,7 +54,7 @@ public class ClientHousekeepingService implements ChannelEventListener {
 
     private void scanExceptionChannel() {
         this.producerManager.scanNotActiveChannel();
-        //this.consumerManager.scanNotActiveChannel();
+        this.consumerManager.scanNotActiveChannel();
     }
 
     public void shutdown() {
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java
index 9b366a5..89b02fd 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java
@@ -36,9 +36,9 @@ public class ConsumerGroupInfo {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
     private final String groupName;
     private final ConcurrentMap<String/* Topic */, SubscriptionData> subscriptionTable =
-        new ConcurrentHashMap<String, SubscriptionData>();
+        new ConcurrentHashMap<>();
     private final ConcurrentMap<Channel, ClientChannelInfo> channelInfoTable =
-        new ConcurrentHashMap<Channel, ClientChannelInfo>(16);
+        new ConcurrentHashMap<>(16);
     private volatile ConsumeType consumeType;
     private volatile MessageModel messageModel;
     private volatile ConsumeFromWhere consumeFromWhere;
@@ -124,7 +124,7 @@ public class ConsumerGroupInfo {
         if (null == infoOld) {
             ClientChannelInfo prev = this.channelInfoTable.put(infoNew.getChannel(), infoNew);
             if (null == prev) {
-                log.info("new consumer connected, group: {} {} {} channel: {}", this.groupName, consumeType,
+                log.info("New consumer connected, group: {} {} {} channel: {}", this.groupName, consumeType,
                     messageModel, infoNew.toString());
                 updated = true;
             }
@@ -155,13 +155,13 @@ public class ConsumerGroupInfo {
                 SubscriptionData prev = this.subscriptionTable.putIfAbsent(sub.getTopic(), sub);
                 if (null == prev) {
                     updated = true;
-                    log.info("subscription changed, add new topic, group: {} {}",
+                    log.info("Subscription changed, add new topic, group: {} {}",
                         this.groupName,
                         sub.toString());
                 }
             } else if (sub.getSubVersion() > old.getSubVersion()) {
                 if (this.consumeType == ConsumeType.CONSUME_PASSIVELY) {
-                    log.info("subscription changed, group: {} OLD: {} NEW: {}",
+                    log.info("Subscription changed, group: {} OLD: {} NEW: {}",
                         this.groupName,
                         old.toString(),
                         sub.toString()
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java
index 8d3b665..a0bab83 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java
@@ -37,20 +37,18 @@ public class ConsumerManager {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
     private static final long CHANNEL_EXPIRED_TIMEOUT = 1000 * 120;
     private final ConcurrentMap<String/* Group */, ConsumerGroupInfo> consumerTable =
-        new ConcurrentHashMap<String, ConsumerGroupInfo>(1024);
+        new ConcurrentHashMap<>(1024);
     private final ConsumerIdsChangeListener consumerIdsChangeListener;
 
     public ConsumerManager(final ConsumerIdsChangeListener consumerIdsChangeListener) {
         this.consumerIdsChangeListener = consumerIdsChangeListener;
     }
 
-    public ClientChannelInfo findChannel(final String group, final String clientId) {
-        ConsumerGroupInfo consumerGroupInfo = this.consumerTable.get(group);
-        if (consumerGroupInfo != null) {
-            return consumerGroupInfo.findChannel(clientId);
-        }
-        return null;
-    }
+    /**
+     * public ClientChannelInfo findChannel(final String group, final String clientId) { ConsumerGroupInfo
+     * consumerGroupInfo = this.consumerTable.get(group); if (consumerGroupInfo != null) { return
+     * consumerGroupInfo.findChannel(clientId); } return null; }
+     **/
 
     public SubscriptionData findSubscriptionData(final String group, final String topic) {
         ConsumerGroupInfo consumerGroupInfo = this.getConsumerGroupInfo(group);
@@ -84,12 +82,11 @@ public class ConsumerManager {
                 if (info.getChannelInfoTable().isEmpty()) {
                     ConsumerGroupInfo remove = this.consumerTable.remove(next.getKey());
                     if (remove != null) {
-                        log.info("unregister consumer ok, no any connection, and remove consumer group, {}",
+                        log.info("Unregister consumer ok, no any connection, and remove consumer group, {}",
                             next.getKey());
                         this.consumerIdsChangeListener.handle(ConsumerGroupEvent.UNREGISTER, next.getKey());
                     }
                 }
-
                 this.consumerIdsChangeListener.handle(ConsumerGroupEvent.CHANGE, next.getKey(), info.getAllChannel());
             }
         }
@@ -130,7 +127,7 @@ public class ConsumerManager {
             if (consumerGroupInfo.getChannelInfoTable().isEmpty()) {
                 ConsumerGroupInfo remove = this.consumerTable.remove(group);
                 if (remove != null) {
-                    log.info("unregister consumer ok, no any connection, and remove consumer group, {}", group);
+                    log.info("Unregister consumer ok, no any connection, and remove consumer group, {}", group);
 
                     this.consumerIdsChangeListener.handle(ConsumerGroupEvent.UNREGISTER, group);
                 }
@@ -157,7 +154,7 @@ public class ConsumerManager {
                 long diff = System.currentTimeMillis() - clientChannelInfo.getLastUpdateTimestamp();
                 if (diff > CHANNEL_EXPIRED_TIMEOUT) {
                     log.warn(
-                        "SCAN: remove expired channel from ConsumerManager consumerTable. channel={}, consumerGroup={}",
+                        "SCAN: Remove expired channel from ConsumerManager consumerTable. channel={}, consumerGroup={}",
                         RemotingHelper.parseChannelRemoteAddr(clientChannelInfo.getChannel()), group);
                     RemotingUtil.closeChannel(clientChannelInfo.getChannel());
                     itChannel.remove();
@@ -166,7 +163,7 @@ public class ConsumerManager {
 
             if (channelInfoTable.isEmpty()) {
                 log.warn(
-                    "SCAN: remove expired channel from ConsumerManager consumerTable, all clear, consumerGroup={}",
+                    "SCAN: Remove expired channel from ConsumerManager consumerTable, all clear, consumerGroup={}",
                     group);
                 it.remove();
             }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java
index cb7c164..1f46c95 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java
@@ -43,7 +43,7 @@ public class DefaultConsumerIdsChangeListener implements ConsumerIdsChangeListen
                 List<Channel> channels = (List<Channel>) args[0];
                 if (channels != null && snodeController.getSnodeConfig().isNotifyConsumerIdsChangedEnable()) {
                     for (Channel chl : channels) {
-                        this.snodeController.getSnodeOuterService().notifyConsumerIdsChanged(chl, group);
+                        this.snodeController.getEnodeService().notifyConsumerIdsChanged(chl, group);
                     }
                 }
                 break;
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java
index b80c027..4513c7d 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java
@@ -36,11 +36,11 @@ public class ProducerManager {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
     private static final long LOCK_TIMEOUT_MILLIS = 3000;
     private static final long CHANNEL_EXPIRED_TIMEOUT = 1000 * 120;
-    private static final int GET_AVALIABLE_CHANNEL_RETRY_COUNT = 3;
     private final Lock groupChannelLock = new ReentrantLock();
     private final HashMap<String /* group name */, HashMap<Channel, ClientChannelInfo>> groupChannelTable =
-        new HashMap<String, HashMap<Channel, ClientChannelInfo>>();
+        new HashMap<>();
     private PositiveAtomicCounter positiveAtomicCounter = new PositiveAtomicCounter();
+
     public ProducerManager() {
 
     }
@@ -144,7 +144,7 @@ public class ProducerManager {
                     clientChannelInfoFound = channelTable.get(clientChannelInfo.getChannel());
                     if (null == clientChannelInfoFound) {
                         channelTable.put(clientChannelInfo.getChannel(), clientChannelInfo);
-                        log.info("new producer connected, group: {} channel: {}", group,
+                        log.info("New producer connected, group: {} channel: {}", group,
                             clientChannelInfo.toString());
                     }
                 } finally {
@@ -158,7 +158,7 @@ public class ProducerManager {
                 log.warn("ProducerManager registerProducer lock timeout");
             }
         } catch (InterruptedException e) {
-            log.error("", e);
+            log.error("Register Producer error: {}", e);
         }
     }
 
@@ -170,13 +170,13 @@ public class ProducerManager {
                     if (null != channelTable && !channelTable.isEmpty()) {
                         ClientChannelInfo old = channelTable.remove(clientChannelInfo.getChannel());
                         if (old != null) {
-                            log.info("unregister a producer[{}] from groupChannelTable {}", group,
+                            log.info("Unregister a producer[{}] from groupChannelTable {}", group,
                                 clientChannelInfo.toString());
                         }
 
                         if (channelTable.isEmpty()) {
                             this.groupChannelTable.remove(group);
-                            log.info("unregister a producer group[{}] from groupChannelTable", group);
+                            log.info("Unregister a producer group[{}] from groupChannelTable", group);
                         }
                     }
                 } finally {
@@ -190,35 +190,35 @@ public class ProducerManager {
         }
     }
 
-    public Channel getAvaliableChannel(String groupId) {
-        HashMap<Channel, ClientChannelInfo> channelClientChannelInfoHashMap = groupChannelTable.get(groupId);
-        List<Channel> channelList = new ArrayList<Channel>();
-        if (channelClientChannelInfoHashMap != null) {
-            for (Channel channel : channelClientChannelInfoHashMap.keySet()) {
-                channelList.add(channel);
-            }
-            int size = channelList.size();
-            if (0 == size) {
-                log.warn("Channel list is empty. groupId={}", groupId);
-                return null;
-            }
-
-            int index = positiveAtomicCounter.incrementAndGet() % size;
-            Channel channel = channelList.get(index);
-            int count = 0;
-            boolean isOk = channel.isActive() && channel.isWritable();
-            while (count++ < GET_AVALIABLE_CHANNEL_RETRY_COUNT) {
-                if (isOk) {
-                    return channel;
-                }
-                index = (++index) % size;
-                channel = channelList.get(index);
-                isOk = channel.isActive() && channel.isWritable();
-            }
-        } else {
-            log.warn("Check transaction failed, channel table is empty. groupId={}", groupId);
-            return null;
-        }
-        return null;
-    }
+//    public Channel getAvaliableChannel(String groupId) {
+//        HashMap<Channel, ClientChannelInfo> channelClientChannelInfoHashMap = groupChannelTable.get(groupId);
+//        List<Channel> channelList = new ArrayList<Channel>();
+//        if (channelClientChannelInfoHashMap != null) {
+//            for (Channel channel : channelClientChannelInfoHashMap.keySet()) {
+//                channelList.add(channel);
+//            }
+//            int size = channelList.size();
+//            if (0 == size) {
+//                log.warn("Channel list is empty. groupId={}", groupId);
+//                return null;
+//            }
+//
+//            int index = positiveAtomicCounter.incrementAndGet() % size;
+//            Channel channel = channelList.get(index);
+//            int count = 0;
+//            boolean isOk = channel.isActive() && channel.isWritable();
+//            while (count++ < GET_AVALIABLE_CHANNEL_RETRY_COUNT) {
+//                if (isOk) {
+//                    return channel;
+//                }
+//                index = (++index) % size;
+//                channel = channelList.get(index);
+//                isOk = channel.isActive() && channel.isWritable();
+//            }
+//        } else {
+//            log.warn("Check transaction failed, channel table is empty. groupId={}", groupId);
+//            return null;
+//        }
+//        return null;
+//    }
 }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/SubscriptionGroupManager.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/SubscriptionGroupManager.java
index 3c6799e..8d83d7a 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/SubscriptionGroupManager.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/SubscriptionGroupManager.java
@@ -38,12 +38,6 @@ public class SubscriptionGroupManager extends ConfigManager {
     private final DataVersion dataVersion = new DataVersion();
     private transient SnodeController snodeController;
 
-    public enum SUBSCRIPTION_EVENT {
-        CREATE,
-        UPDATE,
-        DELETE
-    }
-
     public SubscriptionGroupManager() {
         this.init();
     }
@@ -104,14 +98,14 @@ public class SubscriptionGroupManager extends ConfigManager {
     public void updateSubscriptionGroupConfig(final SubscriptionGroupConfig config) {
         SubscriptionGroupConfig old = this.subscriptionGroupTable.put(config.getGroupName(), config);
         if (old != null) {
-            log.info("update subscription group config, old: {} new: {}", old, config);
+            log.info("Update subscription group config, old: {} new: {}", old, config);
         } else {
-            log.info("create new subscription group, {}", config);
+            log.info("Create new subscription group, {}", config);
         }
 
         this.dataVersion.nextVersion();
 
-        this.persistToEnode(SUBSCRIPTION_EVENT.UPDATE, config);
+        this.persistToEnode(config);
     }
 
     public void disableConsume(final String groupName) {
@@ -133,7 +127,7 @@ public class SubscriptionGroupManager extends ConfigManager {
                     log.info("auto create a subscription group, {}", subscriptionGroupConfig.toString());
                 }
                 this.dataVersion.nextVersion();
-                this.persistToEnode(SUBSCRIPTION_EVENT.CREATE, subscriptionGroupConfig);
+                this.persistToEnode(subscriptionGroupConfig);
             }
         }
 
@@ -188,13 +182,13 @@ public class SubscriptionGroupManager extends ConfigManager {
         if (old != null) {
             log.info("delete subscription group OK, subscription group:{}", old);
             this.dataVersion.nextVersion();
-            this.persistToEnode(SUBSCRIPTION_EVENT.DELETE, old);
+            this.persistToEnode(old);
         } else {
             log.warn("delete subscription group failed, subscription groupName: {} not exist", groupName);
         }
     }
 
-    void persistToEnode(SUBSCRIPTION_EVENT event, SubscriptionGroupConfig config) {
-
+    void persistToEnode(SubscriptionGroupConfig config) {
+        this.snodeController.getEnodeService().persistSubscriptionGroupConfig(config);
     }
 }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java
index 725cf6a..6ef55b1 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java
@@ -21,6 +21,8 @@ import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 
+import static org.apache.rocketmq.client.ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY;
+
 public class SnodeConfig {
 
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.COMMON_LOGGER_NAME);
@@ -60,6 +62,8 @@ public class SnodeConfig {
 
     private int listenPort = 11911;
 
+    private boolean vipChannelEnabled = Boolean.parseBoolean(System.getProperty(SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY, "true"));
+
     public void setSnodeHeartBeatInterval(long snodeHeartBeatInterval) {
         this.snodeHeartBeatInterval = snodeHeartBeatInterval;
     }
@@ -220,4 +224,12 @@ public class SnodeConfig {
     public void setAutoCreateSubscriptionGroup(boolean autoCreateSubscriptionGroup) {
         this.autoCreateSubscriptionGroup = autoCreateSubscriptionGroup;
     }
+
+    public boolean isVipChannelEnabled() {
+        return vipChannelEnabled;
+    }
+
+    public void setVipChannelEnabled(boolean vipChannelEnabled) {
+        this.vipChannelEnabled = vipChannelEnabled;
+    }
 }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java
index 2ba91b2..1f5c7dd 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java
@@ -22,4 +22,6 @@ public class SnodeConstant {
 
     public static final long defaultTimeoutMills = 3000L;
 
+    public static final long CONSUMER_TIMEOUT_MILLIS_WHEN_SUSPEND = 1000 * 30;
+
 }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SendTransferService.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/exception/SnodeException.java
similarity index 50%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SendTransferService.java
rename to rocketmq-snode/src/main/java/org/apache/rocketmq/snode/exception/SnodeException.java
index 6dad57c..e9bd114 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SendTransferService.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/exception/SnodeException.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.service;/*
+package org.apache.rocketmq.snode.exception;/*
  * 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.
@@ -15,12 +15,27 @@ package org.apache.rocketmq.snode.service;/*
  * limitations under the License.
  */
 
-import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.common.UtilAll;
+import org.apache.rocketmq.common.help.FAQUrl;
 
-public interface SendTransferService {
-    RemotingCommand sendMessage(RemotingCommand request);
+public class SnodeException extends RuntimeException {
+    private static final long serialVersionUID = 5975020272601250368L;
 
-    boolean start();
+    private final int responseCode;
+    private final String errorMessage;
 
-    void shutdown();
-}
+    public SnodeException(int responseCode, String errorMessage) {
+        super(FAQUrl.attachDefaultURL("CODE: " + UtilAll.responseCode2String(responseCode) + "  DESC: "
+            + errorMessage));
+        this.responseCode = responseCode;
+        this.errorMessage = errorMessage;
+    }
+
+    public int getResponseCode() {
+        return responseCode;
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+}
\ No newline at end of file
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/offset/ConsumerOffsetManager.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/offset/ConsumerOffsetManager.java
new file mode 100644
index 0000000..c177ccf
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/offset/ConsumerOffsetManager.java
@@ -0,0 +1,243 @@
+/*
+ * 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.snode.offset;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.protocol.ResponseCode;
+import org.apache.rocketmq.common.protocol.header.GetMinOffsetResponseHeader;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.exception.RemotingCommandException;
+import org.apache.rocketmq.remoting.exception.RemotingConnectException;
+import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
+import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
+import org.apache.rocketmq.snode.SnodeController;
+import org.apache.rocketmq.snode.exception.SnodeException;
+
+public class ConsumerOffsetManager {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
+    private static final String TOPIC_GROUP_SEPARATOR = "@";
+
+    private ConcurrentMap<String/* topic@group */, ConcurrentMap<Integer, Long>> offsetTable =
+        new ConcurrentHashMap<String, ConcurrentMap<Integer, Long>>(512);
+
+    private transient SnodeController snodeController;
+
+    public ConsumerOffsetManager() {
+    }
+
+    public ConsumerOffsetManager(SnodeController brokerController) {
+        this.snodeController = brokerController;
+    }
+
+    public void scanUnsubscribedTopic(String enodeName) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException, RemotingCommandException {
+        Iterator<Entry<String, ConcurrentMap<Integer, Long>>> it = this.offsetTable.entrySet().iterator();
+        while (it.hasNext()) {
+            Entry<String, ConcurrentMap<Integer, Long>> next = it.next();
+            String topicAtGroup = next.getKey();
+            String[] arrays = topicAtGroup.split(TOPIC_GROUP_SEPARATOR);
+            if (arrays.length == 2) {
+                String topic = arrays[0];
+                String group = arrays[1];
+
+                if (null == snodeController.getConsumerManager().findSubscriptionData(group, topic)
+                    && this.offsetBehindMuchThanData(enodeName, topic, next.getValue())) {
+                    it.remove();
+                    log.warn("Remove topic offset, {}", topicAtGroup);
+                }
+            }
+        }
+    }
+
+    private String buildKey(final String enodeName, final String topic, final String consumerGroup) {
+        if (enodeName == null || topic == null || consumerGroup == null) {
+            log.warn("Build key parameter error enodeName: {}, topic: {} consumerGroup:{}",
+                enodeName, topic, consumerGroup);
+            throw new SnodeException(ResponseCode.PARAMETER_ERROR, "Build key parameter error!");
+        }
+        StringBuilder sb = new StringBuilder(50);
+        sb.append(enodeName).append(TOPIC_GROUP_SEPARATOR).append(topic).append(TOPIC_GROUP_SEPARATOR).append(consumerGroup);
+        return sb.toString();
+    }
+
+    private boolean offsetBehindMuchThanData(final String enodeName, final String topic,
+        ConcurrentMap<Integer, Long> table) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException, RemotingCommandException {
+        Iterator<Entry<Integer, Long>> it = table.entrySet().iterator();
+        boolean result = !table.isEmpty();
+
+        while (it.hasNext() && result) {
+            Entry<Integer, Long> next = it.next();
+            RemotingCommand remotingCommand = this.snodeController.getEnodeService().getMinOffsetInQueue(enodeName, topic, next.getKey());
+            long minOffsetInStore = 0;
+            if (remotingCommand != null) {
+                switch (remotingCommand.getCode()) {
+                    case ResponseCode.SUCCESS: {
+                        GetMinOffsetResponseHeader responseHeader =
+                            (GetMinOffsetResponseHeader) remotingCommand.decodeCommandCustomHeader(GetMinOffsetResponseHeader.class);
+                        minOffsetInStore = responseHeader.getOffset();
+                    }
+                    default:
+                        break;
+                }
+            } else {
+                throw new SnodeException(ResponseCode.QUERY_OFFSET_ERROR, "Query min offset error!");
+            }
+            long offsetInPersist = next.getValue();
+            result = offsetInPersist <= minOffsetInStore;
+        }
+        return result;
+    }
+
+    public Set<String> whichTopicByConsumer(final String group) {
+        Set<String> topics = new HashSet<String>();
+
+        Iterator<Entry<String, ConcurrentMap<Integer, Long>>> it = this.offsetTable.entrySet().iterator();
+        while (it.hasNext()) {
+            Entry<String, ConcurrentMap<Integer, Long>> next = it.next();
+            String topicAtGroup = next.getKey();
+            String[] arrays = topicAtGroup.split(TOPIC_GROUP_SEPARATOR);
+            if (arrays.length == 2) {
+                if (group.equals(arrays[1])) {
+                    topics.add(arrays[0]);
+                }
+            }
+        }
+
+        return topics;
+    }
+
+    public Set<String> whichGroupByTopic(final String topic) {
+        Set<String> groups = new HashSet<String>();
+        Iterator<Entry<String, ConcurrentMap<Integer, Long>>> it = this.offsetTable.entrySet().iterator();
+        while (it.hasNext()) {
+            Entry<String, ConcurrentMap<Integer, Long>> next = it.next();
+            String topicAtGroup = next.getKey();
+            String[] arrays = topicAtGroup.split(TOPIC_GROUP_SEPARATOR);
+            if (arrays.length == 2) {
+                if (topic.equals(arrays[0])) {
+                    groups.add(arrays[1]);
+                }
+            }
+        }
+
+        return groups;
+    }
+
+    public void commitOffset(final String enodeName, final String clientHost, final String group, final String topic,
+        final int queueId,
+        final long offset) {
+        // topic@group
+        String key = buildKey(enodeName, topic, group);
+        this.commitOffset(clientHost, key, queueId, offset);
+    }
+
+    private void commitOffset(final String clientHost, final String key, final int queueId, final long offset) {
+        ConcurrentMap<Integer, Long> map = this.offsetTable.get(key);
+        if (null == map) {
+            map = new ConcurrentHashMap<>(32);
+            map.put(queueId, offset);
+            this.offsetTable.put(key, map);
+        } else {
+            Long storeOffset = map.put(queueId, offset);
+            if (storeOffset != null && offset < storeOffset) {
+                log.warn("[NOTIFYME]update consumer offset less than store. clientHost={}, key={}, queueId={}, requestOffset={}, storeOffset={}", clientHost, key, queueId, offset, storeOffset);
+            }
+        }
+    }
+
+    public long queryOffset(final String enodeName, final String group, final String topic, final int queueId) {
+        String key = buildKey(enodeName, topic, group);
+        ConcurrentMap<Integer, Long> map = this.offsetTable.get(key);
+        if (null != map) {
+            Long offset = map.get(queueId);
+            if (offset != null)
+                return offset;
+        }
+
+        return -1;
+    }
+
+    public String encode() {
+        return this.encode(false);
+    }
+
+    public void decode(String jsonString) {
+        if (jsonString != null) {
+            ConsumerOffsetManager obj = RemotingSerializable.fromJson(jsonString, ConsumerOffsetManager.class);
+            if (obj != null) {
+                this.offsetTable = obj.offsetTable;
+            }
+        }
+    }
+
+    public String encode(final boolean prettyFormat) {
+        return RemotingSerializable.toJson(this, prettyFormat);
+    }
+
+    public ConcurrentMap<String, ConcurrentMap<Integer, Long>> getOffsetTable() {
+        return offsetTable;
+    }
+
+    public void setOffsetTable(ConcurrentHashMap<String, ConcurrentMap<Integer, Long>> offsetTable) {
+        this.offsetTable = offsetTable;
+    }
+
+
+    public Map<Integer, Long> queryOffset(final String enodeName, final String group, final String topic) {
+        // topic@group
+        String key = buildKey(enodeName, topic, group);
+        return this.offsetTable.get(key);
+    }
+
+    public void cloneOffset(final String srcGroup, final String destGroup, final String topic) {
+        ConcurrentMap<Integer, Long> offsets = this.offsetTable.get(topic + TOPIC_GROUP_SEPARATOR + srcGroup);
+        if (offsets != null) {
+            this.offsetTable.put(topic + TOPIC_GROUP_SEPARATOR + destGroup, new ConcurrentHashMap<Integer, Long>(offsets));
+        }
+    }
+
+    public void persist() {
+        for (Entry<String, ConcurrentMap<Integer, Long>> offSetEntry : this.offsetTable.entrySet()) {
+            ConcurrentHashMap<Integer, Long> map = (ConcurrentHashMap<Integer, Long>) offSetEntry.getValue();
+            String key = offSetEntry.getKey();
+            String[] keys = key.split(TOPIC_GROUP_SEPARATOR);
+            if (keys.length == 3) {
+                String enodeName = keys[0];
+                String topic = keys[1];
+                String consumerGroup = keys[2];
+                for (Entry<Integer, Long> queueEntry : map.entrySet()) {
+                    Integer queueId = queueEntry.getKey();
+                    Long offset = queueEntry.getValue();
+                    this.snodeController.getEnodeService().persistOffsetToEnode(enodeName, consumerGroup, topic, queueId, offset);
+                }
+            } else {
+                log.error("Persist offset split keys error:{}", key);
+            }
+        }
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
index aec6f04..3e53795 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
@@ -24,10 +24,20 @@ import org.apache.rocketmq.common.protocol.ResponseCode;
 import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupRequestHeader;
 import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupResponseBody;
 import org.apache.rocketmq.common.protocol.header.GetConsumerListByGroupResponseHeader;
+import org.apache.rocketmq.common.protocol.header.GetMaxOffsetRequestHeader;
+import org.apache.rocketmq.common.protocol.header.GetMinOffsetRequestHeader;
+import org.apache.rocketmq.common.protocol.header.QueryConsumerOffsetRequestHeader;
+import org.apache.rocketmq.common.protocol.header.QueryConsumerOffsetResponseHeader;
+import org.apache.rocketmq.common.protocol.header.SearchOffsetRequestHeader;
+import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader;
+import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetResponseHeader;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
+import org.apache.rocketmq.remoting.exception.RemotingConnectException;
+import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
+import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.snode.SnodeController;
@@ -38,16 +48,27 @@ public class ConsumerManageProcessor implements NettyRequestProcessor {
 
     private final SnodeController snodeController;
 
-    public ConsumerManageProcessor(final SnodeController snodeController) {
-        this.snodeController = snodeController;
+    public ConsumerManageProcessor(final SnodeController brokerController) {
+        this.snodeController = brokerController;
     }
 
     @Override
     public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request)
-        throws RemotingCommandException {
+        throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException, RemotingCommandException {
         switch (request.getCode()) {
             case RequestCode.GET_CONSUMER_LIST_BY_GROUP:
                 return this.getConsumerListByGroup(ctx, request);
+            case RequestCode.UPDATE_CONSUMER_OFFSET:
+                return this.updateConsumerOffset(ctx, request);
+            case RequestCode.QUERY_CONSUMER_OFFSET:
+                return this.queryConsumerOffset(ctx, request);
+            case RequestCode.SEARCH_OFFSET_BY_TIMESTAMP:
+                return searchOffsetByTimestamp(ctx, request);
+            case RequestCode.GET_MAX_OFFSET:
+                return getMaxOffset(ctx, request);
+            case RequestCode.GET_MIN_OFFSET:
+                return getMinOffset(ctx, request);
             default:
                 break;
         }
@@ -59,6 +80,45 @@ public class ConsumerManageProcessor implements NettyRequestProcessor {
         return false;
     }
 
+    public RemotingCommand searchOffsetByTimestamp(ChannelHandlerContext ctx,
+        RemotingCommand request) throws RemotingCommandException {
+        final SearchOffsetRequestHeader requestHeader =
+            (SearchOffsetRequestHeader) request
+                .decodeCommandCustomHeader(SearchOffsetRequestHeader.class);
+        try {
+            return this.snodeController.getEnodeService().getOffsetByTimestamp(requestHeader.getEnodeName(), request);
+        } catch (Exception ex) {
+            log.error("Search offset by timestamp error:{}", ex);
+        }
+        return null;
+    }
+
+    public RemotingCommand getMinOffset(ChannelHandlerContext ctx,
+        RemotingCommand request) throws RemotingCommandException {
+        final GetMinOffsetRequestHeader requestHeader =
+            (GetMinOffsetRequestHeader) request
+                .decodeCommandCustomHeader(GetMinOffsetRequestHeader.class);
+        try {
+            return this.snodeController.getEnodeService().getMinOffsetInQueue(requestHeader.getEnodeName(), requestHeader.getTopic(), requestHeader.getQueueId());
+        } catch (Exception ex) {
+            log.error("Get min offset error:{}", ex);
+        }
+        return null;
+    }
+
+    public RemotingCommand getMaxOffset(ChannelHandlerContext ctx,
+        RemotingCommand request) throws RemotingCommandException {
+        final GetMaxOffsetRequestHeader requestHeader =
+            (GetMaxOffsetRequestHeader) request
+                .decodeCommandCustomHeader(GetMaxOffsetRequestHeader.class);
+        try {
+            return this.snodeController.getEnodeService().getMaxOffsetInQueue(requestHeader.getEnodeName(), request);
+        } catch (Exception ex) {
+            log.error("Get min offset error:{}", ex);
+        }
+        return null;
+    }
+
     public RemotingCommand getConsumerListByGroup(ChannelHandlerContext ctx, RemotingCommand request)
         throws RemotingCommandException {
         final RemotingCommand response =
@@ -80,7 +140,7 @@ public class ConsumerManageProcessor implements NettyRequestProcessor {
                 response.setRemark(null);
                 return response;
             } else {
-                log.warn("Get all client failed, {} {}", requestHeader.getConsumerGroup(),
+                log.warn("GetAllClientId failed, {} {}", requestHeader.getConsumerGroup(),
                     RemotingHelper.parseChannelRemoteAddr(ctx.channel()));
             }
         } else {
@@ -89,8 +149,53 @@ public class ConsumerManageProcessor implements NettyRequestProcessor {
         }
 
         response.setCode(ResponseCode.SYSTEM_ERROR);
-        response.setRemark("no consumer for this group, " + requestHeader.getConsumerGroup());
+        response.setRemark("No consumer for this group, " + requestHeader.getConsumerGroup());
         return response;
     }
 
+    private RemotingCommand updateConsumerOffset(ChannelHandlerContext ctx, RemotingCommand request)
+        throws RemotingCommandException {
+        final RemotingCommand response =
+            RemotingCommand.createResponseCommand(UpdateConsumerOffsetResponseHeader.class);
+        final UpdateConsumerOffsetRequestHeader requestHeader =
+            (UpdateConsumerOffsetRequestHeader) request
+                .decodeCommandCustomHeader(UpdateConsumerOffsetRequestHeader.class);
+        this.snodeController.getConsumerOffsetManager().commitOffset(requestHeader.getEnodeName(), RemotingHelper.parseChannelRemoteAddr(ctx.channel()), requestHeader.getConsumerGroup(),
+            requestHeader.getTopic(), requestHeader.getQueueId(), requestHeader.getCommitOffset());
+        response.setCode(ResponseCode.SUCCESS);
+        response.setRemark(null);
+        return response;
+    }
+
+    private RemotingCommand queryConsumerOffset(ChannelHandlerContext ctx, RemotingCommand request)
+        throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException, RemotingCommandException {
+        final RemotingCommand response =
+            RemotingCommand.createResponseCommand(QueryConsumerOffsetResponseHeader.class);
+        final QueryConsumerOffsetResponseHeader responseHeader =
+            (QueryConsumerOffsetResponseHeader) response.readCustomHeader();
+        final QueryConsumerOffsetRequestHeader requestHeader =
+            (QueryConsumerOffsetRequestHeader) request
+                .decodeCommandCustomHeader(QueryConsumerOffsetRequestHeader.class);
+
+        long offset =
+            this.snodeController.getConsumerOffsetManager().queryOffset(requestHeader.getEnodeName(),
+                requestHeader.getConsumerGroup(), requestHeader.getTopic(), requestHeader.getQueueId());
+
+        if (offset < 0) {
+            log.info("Load offset from enode server, enodeName: {}, consumer group: {}, topic: {}, queueId: {}",
+                requestHeader.getEnodeName(),
+                requestHeader.getConsumerGroup(),
+                requestHeader.getTopic(),
+                requestHeader.getQueueId());
+            return this.snodeController.getEnodeService().loadOffset(requestHeader.getEnodeName(), requestHeader.getConsumerGroup(), requestHeader.getTopic(),
+                requestHeader.getQueueId());
+        } else {
+            responseHeader.setOffset(offset);
+            response.setCode(ResponseCode.SUCCESS);
+            response.setRemark(null);
+            return response;
+        }
+    }
 }
+
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
index c26ed7c..a0af26a 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
@@ -15,12 +15,20 @@
  * limitations under the License.
  */
 package org.apache.rocketmq.snode.processor;
+
 import io.netty.channel.ChannelHandlerContext;
+import org.apache.rocketmq.common.MixAll;
 import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.constant.PermName;
+import org.apache.rocketmq.common.protocol.RequestCode;
+import org.apache.rocketmq.common.protocol.ResponseCode;
+import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader;
+import org.apache.rocketmq.common.protocol.header.UnregisterClientResponseHeader;
 import org.apache.rocketmq.common.protocol.heartbeat.ConsumerData;
 import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData;
 import org.apache.rocketmq.common.protocol.heartbeat.ProducerData;
 import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.common.sysflag.TopicSysFlag;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
@@ -38,7 +46,19 @@ public class HearbeatProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) {
+    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) throws Exception {
+        switch (request.getCode()) {
+            case RequestCode.HEART_BEAT:
+                return heartbeat(ctx, request);
+            case RequestCode.UNREGISTER_CLIENT:
+                return unregister(ctx, request);
+            default:
+                break;
+        }
+        return null;
+    }
+
+    private RemotingCommand heartbeat(ChannelHandlerContext ctx, RemotingCommand request) {
         HeartbeatData heartbeatData = HeartbeatData.decode(request.getBody(), HeartbeatData.class);
         ClientChannelInfo clientChannelInfo = new ClientChannelInfo(
             ctx.channel(),
@@ -55,11 +75,15 @@ public class HearbeatProcessor implements NettyRequestProcessor {
         }
 
         if (heartbeatData.getConsumerDataSet() != null) {
+            log.info("ConsumerDataSet: {}", heartbeatData.getConsumerDataSet());
             for (ConsumerData data : heartbeatData.getConsumerDataSet()) {
                 SubscriptionGroupConfig subscriptionGroupConfig =
                     this.snodeController.getSubscriptionGroupManager().findSubscriptionGroupConfig(
                         data.getGroupName());
                 boolean isNotifyConsumerIdsChangedEnable = subscriptionGroupConfig.isNotifyConsumerIdsChangedEnable();
+                if (null != subscriptionGroupConfig) {
+                    isNotifyConsumerIdsChangedEnable = subscriptionGroupConfig.isNotifyConsumerIdsChangedEnable();
+                }
                 boolean changed = this.snodeController.getConsumerManager().registerConsumer(
                     data.getGroupName(),
                     clientChannelInfo,
@@ -79,6 +103,44 @@ public class HearbeatProcessor implements NettyRequestProcessor {
             }
         }
         RemotingCommand response = RemotingCommand.createResponseCommand(null);
+        response.setCode(ResponseCode.SUCCESS);
+        response.setRemark(null);
+        return response;
+    }
+
+    private RemotingCommand unregister(ChannelHandlerContext ctx, RemotingCommand request) throws Exception {
+        final RemotingCommand response =
+            RemotingCommand.createResponseCommand(UnregisterClientResponseHeader.class);
+        final UnregisterClientRequestHeader requestHeader =
+            (UnregisterClientRequestHeader) request.decodeCommandCustomHeader(UnregisterClientRequestHeader.class);
+
+        ClientChannelInfo clientChannelInfo = new ClientChannelInfo(
+            ctx.channel(),
+            requestHeader.getClientID(),
+            request.getLanguage(),
+            request.getVersion());
+        {
+            final String group = requestHeader.getProducerGroup();
+            if (group != null) {
+                this.snodeController.getProducerManager().unregisterProducer(group, clientChannelInfo);
+            }
+        }
+
+        {
+            final String group = requestHeader.getConsumerGroup();
+            if (group != null) {
+                SubscriptionGroupConfig subscriptionGroupConfig =
+                    this.snodeController.getSubscriptionGroupManager().findSubscriptionGroupConfig(group);
+                boolean isNotifyConsumerIdsChangedEnable = true;
+                if (null != subscriptionGroupConfig) {
+                    isNotifyConsumerIdsChangedEnable = subscriptionGroupConfig.isNotifyConsumerIdsChangedEnable();
+                }
+                this.snodeController.getConsumerManager().unregisterConsumer(group, clientChannelInfo, isNotifyConsumerIdsChangedEnable);
+            }
+        }
+
+        response.setCode(ResponseCode.SUCCESS);
+        response.setRemark(null);
         return response;
     }
 
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
index 6e474bc..a636f87 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
@@ -18,11 +18,19 @@ package org.apache.rocketmq.snode.processor;/*
 import io.netty.channel.ChannelHandlerContext;
 import java.util.concurrent.CompletableFuture;
 import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.help.FAQUrl;
+import org.apache.rocketmq.common.protocol.ResponseCode;
+import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader;
+import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader;
+import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.snode.SnodeController;
+import org.apache.rocketmq.snode.client.ConsumerGroupInfo;
 
 public class PullMessageProcessor implements NettyRequestProcessor {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
@@ -34,8 +42,52 @@ public class PullMessageProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) {
-        CompletableFuture<RemotingCommand> responseFuture = snodeController.getSnodeOuterService().pullMessage(ctx, request);
+    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) throws Exception {
+        RemotingCommand response = RemotingCommand.createResponseCommand(PullMessageResponseHeader.class);
+
+        final PullMessageRequestHeader requestHeader =
+            (PullMessageRequestHeader) request.decodeCommandCustomHeader(PullMessageRequestHeader.class);
+
+        ConsumerGroupInfo consumerGroupInfo = snodeController.getConsumerManager().getConsumerGroupInfo(requestHeader.getConsumerGroup());
+
+        SubscriptionGroupConfig subscriptionGroupConfig =
+            this.snodeController.getSubscriptionGroupManager().findSubscriptionGroupConfig(requestHeader.getConsumerGroup());
+        if (null == subscriptionGroupConfig) {
+            response.setCode(ResponseCode.SUBSCRIPTION_GROUP_NOT_EXIST);
+            response.setRemark(String.format("Subscription group [%s] does not exist, %s", requestHeader.getConsumerGroup(), FAQUrl.suggestTodo(FAQUrl.SUBSCRIPTION_GROUP_NOT_EXIST)));
+            return response;
+        }
+
+        if (!subscriptionGroupConfig.isConsumeEnable()) {
+            response.setCode(ResponseCode.NO_PERMISSION);
+            response.setRemark("Subscription group no permission, " + requestHeader.getConsumerGroup());
+            return response;
+        }
+
+        if (!subscriptionGroupConfig.isConsumeBroadcastEnable()
+            && consumerGroupInfo.getMessageModel() == MessageModel.BROADCASTING) {
+            response.setCode(ResponseCode.NO_PERMISSION);
+            response.setRemark("The consumer group[" + requestHeader.getConsumerGroup() + "] can not consume by broadcast way");
+            return response;
+        }
+
+        SubscriptionData subscriptionData = consumerGroupInfo.findSubscriptionData(requestHeader.getTopic());
+        if (null == subscriptionData) {
+            log.warn("The consumer's subscription not exist, group: {}, topic:{}", requestHeader.getConsumerGroup(), requestHeader.getTopic());
+            response.setCode(ResponseCode.SUBSCRIPTION_NOT_EXIST);
+            response.setRemark("The consumer's subscription not exist" + FAQUrl.suggestTodo(FAQUrl.SAME_GROUP_DIFFERENT_TOPIC));
+            return response;
+        }
+
+        if (subscriptionData.getSubVersion() < requestHeader.getSubVersion()) {
+            log.warn("The broker's subscription is not latest, group: {} {}", requestHeader.getConsumerGroup(),
+                subscriptionData.getSubString());
+            response.setCode(ResponseCode.SUBSCRIPTION_NOT_LATEST);
+            response.setRemark("The consumer's subscription not latest");
+            return response;
+        }
+
+        CompletableFuture<RemotingCommand> responseFuture = snodeController.getEnodeService().pullMessage(ctx, request);
         responseFuture.whenComplete((data, ex) -> {
             if (ex == null) {
                 this.snodeController.getSnodeServer().sendResponse(ctx, data);
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
index 3f52ed3..15e4294 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
@@ -35,7 +35,8 @@ public class SendMessageProcessor implements NettyRequestProcessor {
 
     @Override
     public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) {
-        CompletableFuture<RemotingCommand> responseFuture = snodeController.getSnodeOuterService().sendMessage(request);
+        log.info("-----Receive sendback request: {}", request);
+        CompletableFuture<RemotingCommand> responseFuture = snodeController.getEnodeService().sendMessage(request);
         responseFuture.whenComplete((data, ex) -> {
             if (ex == null) {
                 snodeController.getSnodeServer().sendResponse(ctx, data);
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SnodeOuterService.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java
similarity index 56%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SnodeOuterService.java
rename to rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java
index a1ffdd8..cf7c1e9 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SnodeOuterService.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java
@@ -17,17 +17,17 @@ package org.apache.rocketmq.snode.service;/*
 
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandlerContext;
-import io.netty.util.concurrent.CompleteFuture;
 import java.util.concurrent.CompletableFuture;
 import org.apache.rocketmq.client.exception.MQBrokerException;
 import org.apache.rocketmq.common.TopicConfig;
+import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
-import org.apache.rocketmq.snode.config.SnodeConfig;
 
-public interface SnodeOuterService {
+public interface EnodeService {
     void sendHearbeat(RemotingCommand remotingCommand);
 
     CompletableFuture<RemotingCommand> sendMessage(final RemotingCommand request);
@@ -35,22 +35,29 @@ public interface SnodeOuterService {
     CompletableFuture<RemotingCommand> pullMessage(final ChannelHandlerContext context,
         final RemotingCommand remotingCommand);
 
-    void saveSubscriptionData(RemotingCommand remotingCommand);
+    void notifyConsumerIdsChanged(final Channel channel, final String consumerGroup);
 
-    void start();
+    RemotingCommand creatTopic(String enodeName, TopicConfig topicConfig)throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException ;
 
-    void shutdown();
+    void updateEnodeAddr(String clusterName) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException, MQBrokerException;
 
-    void registerSnode(SnodeConfig snodeConfig);
+    boolean persistSubscriptionGroupConfig(SubscriptionGroupConfig subscriptionGroupConfig);
 
-    void updateNameServerAddressList(final String addrs);
+    void persistOffsetToEnode(String enodeName, String groupName, String topic, int queueId, long offset);
 
-    String fetchNameServerAddr();
+    RemotingCommand loadOffset(String enodeName, String consumerGroup, String topic,
+        int queueId) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException;
 
-    void updateEnodeAddr(String clusterName) throws InterruptedException, RemotingTimeoutException,
-        RemotingSendRequestException, RemotingConnectException, MQBrokerException;
+    RemotingCommand getMaxOffsetInQueue(String enodeName,
+        RemotingCommand request) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException, RemotingCommandException;
 
-    void notifyConsumerIdsChanged(final Channel channel, final String consumerGroup);
+    RemotingCommand getMinOffsetInQueue(String enodeName, String topic,
+        int queueId) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException, RemotingCommandException;
 
-    RemotingCommand creatTopic(TopicConfig topicConfig);
+    RemotingCommand getOffsetByTimestamp(String enodeName,
+        RemotingCommand request) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException;
 }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/NnodeService.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/NnodeService.java
new file mode 100644
index 0000000..21bc6ed
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/NnodeService.java
@@ -0,0 +1,47 @@
+package org.apache.rocketmq.snode.service;/*
+ * 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.
+ */
+
+import java.util.Set;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.common.protocol.body.ClusterInfo;
+import org.apache.rocketmq.common.protocol.route.TopicRouteData;
+import org.apache.rocketmq.remoting.exception.RemotingConnectException;
+import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
+import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.snode.config.SnodeConfig;
+
+public interface NnodeService {
+    void registerSnode(SnodeConfig snodeConfig);
+
+    void updateNnodeAddressList(final String addrs);
+
+    String fetchNnodeAdress();
+
+    void updateTopicRouteDataByTopic();
+
+    Set<String> getEnodeClusterInfo(String clusterName);
+
+    ClusterInfo updateEnodeClusterInfo() throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException;
+
+    String getAddressByEnodeName(String brokerName,
+        boolean isUseSlave) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException;
+
+    TopicRouteData getTopicRouteDataByTopic(String topic,
+        boolean allowTopicNotExist) throws MQClientException, InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException;
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
new file mode 100644
index 0000000..d647f47
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
@@ -0,0 +1,295 @@
+package org.apache.rocketmq.snode.service.impl;/*
+ * 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.
+ */
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.apache.rocketmq.client.exception.MQBrokerException;
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.TopicConfig;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.protocol.RequestCode;
+import org.apache.rocketmq.common.protocol.ResponseCode;
+import org.apache.rocketmq.common.protocol.body.ClusterInfo;
+import org.apache.rocketmq.common.protocol.header.ConsumerSendMsgBackRequestHeader;
+import org.apache.rocketmq.common.protocol.header.CreateTopicRequestHeader;
+import org.apache.rocketmq.common.protocol.header.GetMinOffsetRequestHeader;
+import org.apache.rocketmq.common.protocol.header.NotifyConsumerIdsChangedRequestHeader;
+import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader;
+import org.apache.rocketmq.common.protocol.header.QueryConsumerOffsetRequestHeader;
+import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeaderV2;
+import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHeader;
+import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.InvokeCallback;
+import org.apache.rocketmq.remoting.exception.RemotingCommandException;
+import org.apache.rocketmq.remoting.exception.RemotingConnectException;
+import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
+import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.remoting.netty.ResponseFuture;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
+import org.apache.rocketmq.snode.SnodeController;
+import org.apache.rocketmq.snode.constant.SnodeConstant;
+import org.apache.rocketmq.snode.service.EnodeService;
+
+public class EnodeServiceImpl implements EnodeService {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
+
+    private SnodeController snodeController;
+
+    private final ConcurrentMap<String/* Broker Name */, HashMap<Long/* brokerId */, String/* address */>> enodeTable =
+        new ConcurrentHashMap<>();
+
+    public EnodeServiceImpl(SnodeController snodeController) {
+        this.snodeController = snodeController;
+    }
+
+    @Override
+    public void sendHearbeat(RemotingCommand remotingCommand) {
+        for (Map.Entry<String, HashMap<Long, String>> entry : enodeTable.entrySet()) {
+            String enodeAddr = entry.getValue().get(MixAll.MASTER_ID);
+            if (enodeAddr != null) {
+                try {
+                    this.snodeController.getRemotingClient().invokeSync(enodeAddr, remotingCommand, SnodeConstant.defaultTimeoutMills);
+                } catch (Exception ex) {
+                    log.warn("Send heart beat faild:{} ,ex:{}", enodeAddr, ex);
+                }
+            }
+        }
+    }
+
+    @Override
+    public CompletableFuture<RemotingCommand> pullMessage(final ChannelHandlerContext context,
+        RemotingCommand request) {
+
+        CompletableFuture<RemotingCommand> future = new CompletableFuture<>();
+        try {
+            final PullMessageRequestHeader requestHeader =
+                (PullMessageRequestHeader) request.decodeCommandCustomHeader(PullMessageRequestHeader.class);
+            this.snodeController.getRemotingClient().invokeAsync(requestHeader.getEnodeAddr(), request, SnodeConstant.CONSUMER_TIMEOUT_MILLIS_WHEN_SUSPEND, new InvokeCallback() {
+                @Override
+                public void operationComplete(ResponseFuture responseFuture) {
+                    RemotingCommand response = responseFuture.getResponseCommand();
+                    if (response != null) {
+                        future.complete(response);
+                    } else {
+                        if (!responseFuture.isSendRequestOK()) {
+                            log.error("Pull message error in async callback: {}", responseFuture.getCause());
+                        } else if (responseFuture.isTimeout()) {
+                            log.warn("Pull message timeout!");
+                        } else {
+                            log.error("Unknown pull message error occurred: {}", responseFuture.getCause());
+                        }
+                    }
+                }
+            });
+        } catch (Exception ex) {
+            log.error("pull message async error:", ex);
+            future.completeExceptionally(ex);
+        }
+        return future;
+    }
+
+    @Override
+    public CompletableFuture<RemotingCommand> sendMessage(RemotingCommand request) {
+        CompletableFuture<RemotingCommand> future = new CompletableFuture<>();
+        try {
+            String enodeName = null;
+            if (request.getCode() == RequestCode.SEND_MESSAGE_V2) {
+                SendMessageRequestHeaderV2 sendMessageRequestHeaderV2 = (SendMessageRequestHeaderV2) request.decodeCommandCustomHeader(SendMessageRequestHeaderV2.class);
+                enodeName = sendMessageRequestHeaderV2.getN();
+            } else {
+                ConsumerSendMsgBackRequestHeader consumerSendMsgBackRequestHeader = (ConsumerSendMsgBackRequestHeader) request.decodeCommandCustomHeader(ConsumerSendMsgBackRequestHeader.class);
+                enodeName = consumerSendMsgBackRequestHeader.getEnodeName();
+            }
+            String enodeAddress = this.snodeController.getNnodeService().getAddressByEnodeName(enodeName, false);
+            log.info("Receive request: {}", request);
+            this.snodeController.getRemotingClient().invokeAsync(enodeAddress, request, SnodeConstant.defaultTimeoutMills, (responseFuture) -> {
+                future.complete(responseFuture.getResponseCommand());
+            });
+        } catch (Exception ex) {
+            log.error("Send message async error:{}", ex);
+            future.completeExceptionally(ex);
+        }
+        return future;
+    }
+
+    @Override
+    public void notifyConsumerIdsChanged(
+        final Channel channel,
+        final String consumerGroup) {
+        if (null == consumerGroup) {
+            log.error("NotifyConsumerIdsChanged consumerGroup is null");
+            return;
+        }
+
+        NotifyConsumerIdsChangedRequestHeader requestHeader = new NotifyConsumerIdsChangedRequestHeader();
+        requestHeader.setConsumerGroup(consumerGroup);
+        RemotingCommand request =
+            RemotingCommand.createRequestCommand(RequestCode.NOTIFY_CONSUMER_IDS_CHANGED, requestHeader);
+
+        try {
+            this.snodeController.getSnodeServer().invokeOneway(channel, request, SnodeConstant.oneWaytimeout);
+        } catch (Exception e) {
+            log.error("NotifyConsumerIdsChanged exception, " + consumerGroup, e.getMessage());
+        }
+    }
+
+    private ClusterInfo getBrokerClusterInfo(
+        final long timeoutMillis) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException, MQBrokerException {
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_BROKER_CLUSTER_INFO, null);
+        RemotingCommand response = this.snodeController.getRemotingClient().invokeSync(null, request, timeoutMillis);
+        switch (response.getCode()) {
+            case ResponseCode.SUCCESS: {
+                return ClusterInfo.decode(response.getBody(), ClusterInfo.class);
+            }
+            default:
+                break;
+        }
+        throw new MQBrokerException(response.getCode(), response.getRemark());
+    }
+
+    @Override
+    public void updateEnodeAddr(String clusterName) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException, MQBrokerException {
+        synchronized (this) {
+            ClusterInfo clusterInfo = getBrokerClusterInfo(SnodeConstant.defaultTimeoutMills);
+            if (clusterInfo != null) {
+                HashMap<String, Set<String>> enodeAddress = clusterInfo.getClusterAddrTable();
+                for (Map.Entry<String, Set<String>> entry : enodeAddress.entrySet()) {
+                    Set<String> enodeNames = entry.getValue();
+                    if (enodeNames != null) {
+                        for (String enodeName : enodeNames) {
+                            enodeTable.put(enodeName, clusterInfo.getBrokerAddrTable().get(enodeName).getBrokerAddrs());
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean persistSubscriptionGroupConfig(SubscriptionGroupConfig subscriptionGroupConfig) {
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UPDATE_AND_CREATE_SUBSCRIPTIONGROUP, null);
+        boolean persist = false;
+        for (Map.Entry<String, HashMap<Long, String>> entry : enodeTable.entrySet()) {
+            byte[] body = RemotingSerializable.encode(subscriptionGroupConfig);
+            request.setBody(body);
+            String enodeAddress = entry.getValue().get(MixAll.MASTER_ID);
+            try {
+                RemotingCommand response = this.snodeController.getRemotingClient().invokeSync(enodeAddress,
+                    request, SnodeConstant.defaultTimeoutMills);
+                if (response != null && response.getCode() == ResponseCode.SUCCESS) {
+                    persist = true;
+                } else {
+                    persist = false;
+                }
+                log.info("Persist to broker address: {} result: {}", enodeAddress, persist);
+            } catch (Exception ex) {
+                log.warn("Persist Subscription to Enode {} error", enodeAddress);
+                persist = false;
+            }
+        }
+        return persist;
+    }
+
+    @Override
+    public void persistOffsetToEnode(String enodeName, String groupName, String topic, int queueId, long offset) {
+        try {
+            String address = this.snodeController.getNnodeService().getAddressByEnodeName(enodeName, false);
+            UpdateConsumerOffsetRequestHeader requestHeader = new UpdateConsumerOffsetRequestHeader();
+            requestHeader.setTopic(topic);
+            requestHeader.setConsumerGroup(groupName);
+            requestHeader.setQueueId(queueId);
+            requestHeader.setCommitOffset(offset);
+            requestHeader.setEnodeName(enodeName);
+            RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UPDATE_CONSUMER_OFFSET, requestHeader);
+            this.snodeController.getRemotingClient().invokeOneway(address, request, SnodeConstant.defaultTimeoutMills);
+        } catch (Exception ex) {
+            log.error("Persist offset to Enode error!");
+        }
+    }
+
+    @Override
+    public RemotingCommand getMinOffsetInQueue(String enodeName, String topic,
+        int queueId) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException {
+        GetMinOffsetRequestHeader requestHeader = new GetMinOffsetRequestHeader();
+        requestHeader.setTopic(topic);
+        requestHeader.setQueueId(queueId);
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_MIN_OFFSET, requestHeader);
+        String addr = this.snodeController.getNnodeService().getAddressByEnodeName(enodeName, false);
+        return this.snodeController.getRemotingClient().invokeSync(MixAll.brokerVIPChannel(snodeController.getSnodeConfig().isVipChannelEnabled(), addr),
+            request, SnodeConstant.defaultTimeoutMills);
+    }
+
+    @Override
+    public RemotingCommand loadOffset(String enodeName, String consumerGroup, String topic,
+        int queueId) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException {
+        QueryConsumerOffsetRequestHeader requestHeader = new QueryConsumerOffsetRequestHeader();
+        requestHeader.setTopic(topic);
+        requestHeader.setConsumerGroup(consumerGroup);
+        requestHeader.setQueueId(queueId);
+
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.QUERY_CONSUMER_OFFSET, requestHeader);
+        String addr = this.snodeController.getNnodeService().getAddressByEnodeName(enodeName, false);
+        return this.snodeController.getRemotingClient().invokeSync(MixAll.brokerVIPChannel(this.snodeController.getSnodeConfig().isVipChannelEnabled(), addr),
+            request, SnodeConstant.defaultTimeoutMills);
+    }
+
+    @Override
+    public RemotingCommand getMaxOffsetInQueue(String enodeName,
+        RemotingCommand request) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, RemotingCommandException {
+        String addr = this.snodeController.getNnodeService().getAddressByEnodeName(enodeName, false);
+        return this.snodeController.getRemotingClient().invokeSync(MixAll.brokerVIPChannel(snodeController.getSnodeConfig().isVipChannelEnabled(), addr),
+            request, SnodeConstant.defaultTimeoutMills);
+    }
+
+    @Override
+    public RemotingCommand getOffsetByTimestamp(String enodeName,
+        RemotingCommand request) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException {
+        String addr = this.snodeController.getNnodeService().getAddressByEnodeName(enodeName, false);
+        return this.snodeController.getRemotingClient().invokeSync(MixAll.brokerVIPChannel(snodeController.getSnodeConfig().isVipChannelEnabled(), addr),
+            request, SnodeConstant.defaultTimeoutMills);
+    }
+
+    @Override
+    public RemotingCommand creatTopic(String enodeName,
+        TopicConfig topicConfig) throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException {
+        CreateTopicRequestHeader requestHeader = new CreateTopicRequestHeader();
+        requestHeader.setTopic(topicConfig.getTopicName());
+        requestHeader.setReadQueueNums(topicConfig.getReadQueueNums());
+        requestHeader.setWriteQueueNums(topicConfig.getWriteQueueNums());
+        requestHeader.setPerm(topicConfig.getPerm());
+        requestHeader.setTopicFilterType(topicConfig.getTopicFilterType().name());
+        requestHeader.setTopicSysFlag(topicConfig.getTopicSysFlag());
+        requestHeader.setOrder(topicConfig.isOrder());
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UPDATE_AND_CREATE_TOPIC, requestHeader);
+        String address = this.snodeController.getNnodeService().getAddressByEnodeName(enodeName, false);
+        return this.snodeController.getRemotingClient().invokeSync(address,
+            request, SnodeConstant.defaultTimeoutMills);
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java
new file mode 100644
index 0000000..fe28571
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java
@@ -0,0 +1,208 @@
+package org.apache.rocketmq.snode.service.impl;/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.rocketmq.client.ClientConfig;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.namesrv.TopAddressing;
+import org.apache.rocketmq.common.protocol.RequestCode;
+import org.apache.rocketmq.common.protocol.ResponseCode;
+import org.apache.rocketmq.common.protocol.body.ClusterInfo;
+import org.apache.rocketmq.common.protocol.header.namesrv.GetRouteInfoRequestHeader;
+import org.apache.rocketmq.common.protocol.header.namesrv.RegisterSnodeRequestHeader;
+import org.apache.rocketmq.common.protocol.route.TopicRouteData;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.exception.RemotingConnectException;
+import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
+import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.snode.SnodeController;
+import org.apache.rocketmq.snode.config.SnodeConfig;
+import org.apache.rocketmq.snode.constant.SnodeConstant;
+import org.apache.rocketmq.snode.exception.SnodeException;
+import org.apache.rocketmq.snode.service.NnodeService;
+
+public class NnodeServiceImpl implements NnodeService {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
+    private final TopAddressing topAddressing = new TopAddressing(MixAll.getWSAddr());
+    private String nameSrvAddr = null;
+    private SnodeController snodeController;
+    private ConcurrentHashMap<String /*Topic*/, TopicRouteData> topicRouteDataMap = new ConcurrentHashMap<>(1000);
+    private ClusterInfo clusterInfo;
+
+    public NnodeServiceImpl(SnodeController snodeController) {
+        this.snodeController = snodeController;
+    }
+
+    @Override
+    public void registerSnode(SnodeConfig snodeConfig) {
+        List<String> nnodeAddressList = this.snodeController.getRemotingClient().getNameServerAddressList();
+        RemotingCommand remotingCommand = new RemotingCommand();
+        RegisterSnodeRequestHeader requestHeader = new RegisterSnodeRequestHeader();
+        requestHeader.setSnodeAddr(snodeConfig.getSnodeAddr());
+        requestHeader.setSnodeName(snodeConfig.getSnodeName());
+        requestHeader.setClusterName(snodeConfig.getClusterName());
+        remotingCommand.setCustomHeader(requestHeader);
+        remotingCommand.setCode(RequestCode.REGISTER_SNODE);
+        if (nnodeAddressList != null && nnodeAddressList.size() > 0) {
+            for (String nodeAddress : nnodeAddressList) {
+                try {
+                    this.snodeController.getRemotingClient().invokeSync(nodeAddress, remotingCommand, SnodeConstant.heartbeatTimeout);
+                } catch (Exception ex) {
+                    log.warn("Register Snode to Nnode addr: {} error, ex:{} ", nodeAddress, ex);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void updateTopicRouteDataByTopic() {
+        Set<String> topSet = topicRouteDataMap.keySet();
+        for (String topic : topSet) {
+            try {
+                TopicRouteData topicRouteData = getTopicRouteDataByTopic(topic, false);
+                topicRouteDataMap.put(topic, topicRouteData);
+            } catch (Exception ex) {
+                log.error("Update topic {} error: {}", topic, ex);
+            }
+        }
+    }
+
+    private TopicRouteData getTopicRouteDataByTopicFromNnode(String topic,
+        boolean allowTopicNotExist) throws MQClientException, InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException {
+        GetRouteInfoRequestHeader requestHeader = new GetRouteInfoRequestHeader();
+        requestHeader.setTopic(topic);
+
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINTO_BY_TOPIC, requestHeader);
+        RemotingCommand response = this.snodeController.getRemotingClient().invokeSync(null, request, SnodeConstant.defaultTimeoutMills);
+        log.info("getTopicRouteInfoFromNameServer response: " + response);
+        assert response != null;
+        switch (response.getCode()) {
+            case ResponseCode.TOPIC_NOT_EXIST: {
+                if (allowTopicNotExist && !topic.equals(MixAll.AUTO_CREATE_TOPIC_KEY_TOPIC)) {
+                    log.warn("Topic [{}] RouteInfo is not exist value", topic);
+                }
+                break;
+            }
+            case ResponseCode.SUCCESS: {
+                byte[] body = response.getBody();
+                if (body != null) {
+                    return TopicRouteData.decode(body, TopicRouteData.class);
+                }
+            }
+            default:
+                break;
+        }
+
+        throw new MQClientException(response.getCode(), response.getRemark());
+    }
+
+    @Override
+    public TopicRouteData getTopicRouteDataByTopic(
+        String topic,
+        boolean allowTopicNotExist) throws MQClientException, InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException {
+        if (topic == null || "".equals(topic)) {
+            return null;
+        }
+
+        TopicRouteData topicRouteData = topicRouteDataMap.get(topic);
+        if (topicRouteData == null) {
+            topicRouteData = getTopicRouteDataByTopicFromNnode(topic, allowTopicNotExist);
+            if (topicRouteData != null) {
+                topicRouteDataMap.put(topic, topicRouteData);
+            }
+        }
+        return topicRouteData;
+    }
+
+    @Override
+    public void updateNnodeAddressList(final String addrs) {
+        List<String> list = new ArrayList<String>();
+        String[] addrArray = addrs.split(";");
+        for (String addr : addrArray) {
+            list.add(addr);
+        }
+        this.snodeController.getRemotingClient().updateNameServerAddressList(list);
+    }
+
+    @Override
+    public String fetchNnodeAdress() {
+        try {
+            String addrs = this.topAddressing.fetchNSAddr();
+            if (addrs != null) {
+                if (!addrs.equals(this.nameSrvAddr)) {
+                    log.info("Nnode server address changed, old: {} new: {}", this.nameSrvAddr, addrs);
+                    this.updateNnodeAddressList(addrs);
+                    this.nameSrvAddr = addrs;
+                    return nameSrvAddr;
+                }
+            }
+        } catch (Exception e) {
+            log.error("FetchNnodeServerAddr Exception", e);
+        }
+        return nameSrvAddr;
+    }
+
+    @Override
+    public ClusterInfo updateEnodeClusterInfo() throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException {
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_BROKER_CLUSTER_INFO, null);
+
+        RemotingCommand response = this.snodeController.getRemotingClient().invokeSync(null, request, SnodeConstant.defaultTimeoutMills);
+        switch (response.getCode()) {
+            case ResponseCode.SUCCESS: {
+                ClusterInfo clusterInfo = ClusterInfo.decode(response.getBody(), ClusterInfo.class);
+                this.clusterInfo = clusterInfo;
+                return clusterInfo;
+            }
+            default:
+                break;
+        }
+        log.error("Update Cluster info error: {}", response);
+        return clusterInfo;
+    }
+
+    public Set<String> getEnodeClusterInfo(String clusterName) {
+        if (this.clusterInfo == null) {
+            try {
+                updateEnodeClusterInfo();
+            } catch (Exception ex) {
+                log.error("Update Cluster info error:{}", ex);
+            }
+        }
+        return this.clusterInfo.getClusterAddrTable().get(clusterName);
+    }
+
+    @Override
+    public String getAddressByEnodeName(String enodeName,
+        boolean isUseSlave) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException {
+        if (this.clusterInfo == null) {
+            clusterInfo = this.updateEnodeClusterInfo();
+        }
+        if (this.clusterInfo != null) {
+            return this.clusterInfo.getBrokerAddrTable().get(enodeName).getBrokerAddrs().get(MixAll.MASTER_ID);
+        }
+        return null;
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java
index 23d8867..384a0c2 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java
@@ -26,21 +26,22 @@ import org.apache.rocketmq.common.protocol.heartbeat.SnodeData;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.snode.SnodeController;
 import org.apache.rocketmq.snode.config.SnodeConfig;
 import org.apache.rocketmq.snode.service.ScheduledService;
-import org.apache.rocketmq.snode.service.SnodeOuterService;
 
 public class ScheduledServiceImpl implements ScheduledService {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
 
-    private SnodeOuterService snodeOuterService;
+    private SnodeController snodeController;
+
     private SnodeConfig snodeConfig;
 
     private final RemotingCommand enodeHeartbeat;
 
-    public ScheduledServiceImpl(SnodeOuterService snodeOuterService, SnodeConfig snodeConfig) {
-        this.snodeOuterService = snodeOuterService;
-        this.snodeConfig = snodeConfig;
+    public ScheduledServiceImpl(SnodeController snodeController) {
+        this.snodeController = snodeController;
+        this.snodeConfig = snodeController.getSnodeConfig();
         enodeHeartbeat = RemotingCommand.createRequestCommand(RequestCode.HEART_BEAT, null);
         HeartbeatData heartbeatData = new HeartbeatData();
         heartbeatData.setClientID(snodeConfig.getSnodeName());
@@ -64,7 +65,7 @@ public class ScheduledServiceImpl implements ScheduledService {
             @Override
             public void run() {
                 try {
-                    snodeOuterService.sendHearbeat(enodeHeartbeat);
+                    snodeController.getEnodeService().sendHearbeat(enodeHeartbeat);
                 } catch (Exception e) {
                     log.error("ScheduledTask updateTopicRouteInfoFromNameServer exception", e);
                 }
@@ -76,7 +77,7 @@ public class ScheduledServiceImpl implements ScheduledService {
                 @Override
                 public void run() {
                     try {
-                        snodeOuterService.fetchNameServerAddr();
+                        snodeController.getNnodeService().fetchNnodeAdress();
                     } catch (Throwable e) {
                         log.error("ScheduledTask fetchNameServerAddr exception", e);
                     }
@@ -87,7 +88,18 @@ public class ScheduledServiceImpl implements ScheduledService {
         this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
             @Override
             public void run() {
-                snodeOuterService.registerSnode(snodeConfig);
+                snodeController.getNnodeService().registerSnode(snodeConfig);
+            }
+        }, 1000 * 10, Math.max(10000, Math.min(snodeConfig.getRegisterNameServerPeriod(), 60000)), TimeUnit.MILLISECONDS);
+
+        this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    snodeController.getEnodeService().updateEnodeAddr(snodeConfig.getClusterName());
+                } catch (Exception ex) {
+                    log.warn("Update broker addr error:{}", ex);
+                }
             }
         }, 1000 * 10, Math.max(10000, Math.min(snodeConfig.getRegisterNameServerPeriod(), 60000)), TimeUnit.MILLISECONDS);
 
@@ -95,13 +107,34 @@ public class ScheduledServiceImpl implements ScheduledService {
             @Override
             public void run() {
                 try {
-                    snodeOuterService.updateEnodeAddr(snodeConfig.getClusterName());
+                    snodeController.getNnodeService().updateTopicRouteDataByTopic();
                 } catch (Exception ex) {
                     log.warn("Update broker addr error:{}", ex);
                 }
             }
         }, 1000 * 10, Math.max(10000, Math.min(snodeConfig.getRegisterNameServerPeriod(), 60000)), TimeUnit.MILLISECONDS);
 
+        this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    snodeController.getNnodeService().updateEnodeClusterInfo();
+                } catch (Exception ex) {
+                    log.warn("Update broker addr error:{}", ex);
+                }
+            }
+        }, 1000 * 10, Math.max(10000, Math.min(snodeConfig.getRegisterNameServerPeriod(), 60000)), TimeUnit.MILLISECONDS);
+
+        this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    snodeController.getConsumerOffsetManager().persist();
+                } catch (Throwable e) {
+                    log.error("ScheduledTask fetchNameServerAddr exception", e);
+                }
+            }
+        }, 1000 * 10, 1000 * 60 * 2, TimeUnit.MILLISECONDS);
     }
 
     @Override
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SnodeOuterServiceImpl.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SnodeOuterServiceImpl.java
deleted file mode 100644
index 1863f6b..0000000
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SnodeOuterServiceImpl.java
+++ /dev/null
@@ -1,280 +0,0 @@
-package org.apache.rocketmq.snode.service.impl;/*
- * 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.
- */
-
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.util.concurrent.CompleteFuture;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import org.apache.rocketmq.client.exception.MQBrokerException;
-import org.apache.rocketmq.common.MixAll;
-import org.apache.rocketmq.common.TopicConfig;
-import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.common.namesrv.TopAddressing;
-import org.apache.rocketmq.common.protocol.RequestCode;
-import org.apache.rocketmq.common.protocol.ResponseCode;
-import org.apache.rocketmq.common.protocol.body.ClusterInfo;
-import org.apache.rocketmq.common.protocol.header.NotifyConsumerIdsChangedRequestHeader;
-import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader;
-import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeaderV2;
-import org.apache.rocketmq.common.protocol.header.namesrv.RegisterSnodeRequestHeader;
-import org.apache.rocketmq.logging.InternalLogger;
-import org.apache.rocketmq.logging.InternalLoggerFactory;
-import org.apache.rocketmq.remoting.InvokeCallback;
-import org.apache.rocketmq.remoting.RemotingClient;
-import org.apache.rocketmq.remoting.RemotingClientFactory;
-import org.apache.rocketmq.remoting.exception.RemotingConnectException;
-import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
-import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
-import org.apache.rocketmq.remoting.netty.ResponseFuture;
-import org.apache.rocketmq.remoting.protocol.RemotingCommand;
-import org.apache.rocketmq.snode.SnodeController;
-import org.apache.rocketmq.snode.config.SnodeConfig;
-import org.apache.rocketmq.snode.constant.SnodeConstant;
-import org.apache.rocketmq.snode.service.SnodeOuterService;
-
-public class SnodeOuterServiceImpl implements SnodeOuterService {
-    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
-    private final TopAddressing topAddressing = new TopAddressing(MixAll.getWSAddr());
-    private String nameSrvAddr = null;
-    private RemotingClient client;
-    private SnodeController snodeController;
-    private static SnodeOuterServiceImpl snodeOuterService;
-    private final ConcurrentMap<String/* Broker Name */, HashMap<Long/* brokerId */, String/* address */>> enodeTable =
-        new ConcurrentHashMap<>();
-
-    private SnodeOuterServiceImpl() {
-
-    }
-
-    public static SnodeOuterServiceImpl getInstance(SnodeController snodeController) {
-        if (snodeOuterService == null) {
-            synchronized (SnodeOuterServiceImpl.class) {
-                if (snodeOuterService == null) {
-                    snodeOuterService = new SnodeOuterServiceImpl(snodeController);
-                    return snodeOuterService;
-                }
-            }
-        }
-        return snodeOuterService;
-    }
-
-    private SnodeOuterServiceImpl(SnodeController snodeController) {
-        this.snodeController = snodeController;
-        this.client = RemotingClientFactory.createInstance().init(snodeController.getNettyClientConfig(), null);
-    }
-
-    @Override
-    public void start() {
-        this.client.start();
-    }
-
-    @Override
-    public void shutdown() {
-        this.client.shutdown();
-    }
-
-    @Override
-    public void sendHearbeat(RemotingCommand remotingCommand) {
-        for (Map.Entry<String, HashMap<Long, String>> entry : enodeTable.entrySet()) {
-            String enodeAddr = entry.getValue().get(MixAll.MASTER_ID);
-            if (enodeAddr != null) {
-                try {
-                    RemotingCommand response = this.client.invokeSync(enodeAddr, remotingCommand, SnodeConstant.defaultTimeoutMills);
-                } catch (Exception ex) {
-                    log.warn("Send heart beat faild:{} ,ex:{}", enodeAddr, ex);
-                }
-            }
-        }
-    }
-
-    @Override
-    public CompletableFuture<RemotingCommand> pullMessage(final ChannelHandlerContext context,
-        RemotingCommand request) {
-        try {
-            final PullMessageRequestHeader requestHeader =
-                (PullMessageRequestHeader) request.decodeCommandCustomHeader(PullMessageRequestHeader.class);
-            this.client.invokeAsync(requestHeader.getEnodeAddr(), request, SnodeConstant.defaultTimeoutMills, new InvokeCallback() {
-                @Override
-                public void operationComplete(ResponseFuture responseFuture) {
-                    RemotingCommand response = responseFuture.getResponseCommand();
-                    snodeController.getSnodeServer().sendResponse(context, response);
-                }
-            });
-            return null;
-        } catch (Exception ex) {
-            log.error("pull message async error:", ex);
-        }
-        return null;
-    }
-
-    @Override
-    public void saveSubscriptionData(RemotingCommand remotingCommand) {
-
-    }
-
-    @Override
-    public String fetchNameServerAddr() {
-        try {
-            String addrs = this.topAddressing.fetchNSAddr();
-            if (addrs != null) {
-                if (!addrs.equals(this.nameSrvAddr)) {
-                    log.info("name server address changed, old: {} new: {}", this.nameSrvAddr, addrs);
-                    this.updateNameServerAddressList(addrs);
-                    this.nameSrvAddr = addrs;
-                    return nameSrvAddr;
-                }
-            }
-        } catch (Exception e) {
-            log.error("fetchNameServerAddr Exception", e);
-        }
-        return nameSrvAddr;
-    }
-
-    private ClusterInfo getBrokerClusterInfo(
-        final long timeoutMillis) throws InterruptedException, RemotingTimeoutException,
-        RemotingSendRequestException, RemotingConnectException, MQBrokerException {
-        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_BROKER_CLUSTER_INFO, null);
-        RemotingCommand response = this.client.invokeSync(null, request, timeoutMillis);
-        assert response != null;
-        switch (response.getCode()) {
-            case ResponseCode.SUCCESS: {
-                return ClusterInfo.decode(response.getBody(), ClusterInfo.class);
-            }
-            default:
-                break;
-        }
-        throw new MQBrokerException(response.getCode(), response.getRemark());
-    }
-
-    @Override
-    public void updateEnodeAddr(String clusterName) throws InterruptedException, RemotingTimeoutException,
-        RemotingSendRequestException, RemotingConnectException, MQBrokerException {
-        synchronized (this) {
-            ClusterInfo clusterInfo = getBrokerClusterInfo(SnodeConstant.defaultTimeoutMills);
-            if (clusterInfo != null) {
-                HashMap<String, Set<String>> brokerAddrs = clusterInfo.getClusterAddrTable();
-                for (Map.Entry<String, Set<String>> entry : brokerAddrs.entrySet()) {
-                    Set<String> brokerNames = entry.getValue();
-                    if (brokerNames != null) {
-                        for (String brokerName : brokerNames) {
-                            enodeTable.put(brokerName, clusterInfo.getBrokerAddrTable().get(brokerName).getBrokerAddrs());
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    public void updateNameServerAddressList(final String addrs) {
-        List<String> list = new ArrayList<String>();
-        String[] addrArray = addrs.split(";");
-        for (String addr : addrArray) {
-            list.add(addr);
-        }
-        this.client.updateNameServerAddressList(list);
-    }
-
-    public void registerSnode(SnodeConfig snodeConfig) {
-        List<String> nameServerAddressList = this.client.getNameServerAddressList();
-        RemotingCommand remotingCommand = new RemotingCommand();
-        RegisterSnodeRequestHeader requestHeader = new RegisterSnodeRequestHeader();
-        requestHeader.setSnodeAddr(snodeConfig.getSnodeAddr());
-        requestHeader.setSnodeName(snodeConfig.getSnodeName());
-        requestHeader.setClusterName(snodeConfig.getClusterName());
-        remotingCommand.setCustomHeader(requestHeader);
-        remotingCommand.setCode(RequestCode.REGISTER_SNODE);
-        if (nameServerAddressList != null && nameServerAddressList.size() > 0) {
-            for (String nameServer : nameServerAddressList) {
-                try {
-                    this.client.invokeSync(nameSrvAddr, remotingCommand, SnodeConstant.heartbeatTimeout);
-                } catch (Exception ex) {
-                    log.warn("Register Snode to Nameserver addr: {} error, ex:{} ", nameServer, ex);
-                }
-            }
-        }
-    }
-
-    @Override
-    public CompletableFuture<RemotingCommand> sendMessage(RemotingCommand request) {
-        CompletableFuture<RemotingCommand> future = new CompletableFuture<>();
-        try {
-            SendMessageRequestHeaderV2 sendMessageRequestHeaderV2 = (SendMessageRequestHeaderV2) request.decodeCommandCustomHeader(SendMessageRequestHeaderV2.class);
-            this.client.invokeAsync(sendMessageRequestHeaderV2.getN(), request, SnodeConstant.defaultTimeoutMills, (responseFuture) -> {
-                future.complete(responseFuture.getResponseCommand());
-            });
-        } catch (Exception ex) {
-            log.error("Send message async error:{}", ex);
-            future.completeExceptionally(ex);
-        }
-        return future;
-    }
-
-    @Override
-    public void notifyConsumerIdsChanged(
-        final Channel channel,
-        final String consumerGroup) {
-        if (null == consumerGroup) {
-            log.error("notifyConsumerIdsChanged consumerGroup is null");
-            return;
-        }
-
-        NotifyConsumerIdsChangedRequestHeader requestHeader = new NotifyConsumerIdsChangedRequestHeader();
-        requestHeader.setConsumerGroup(consumerGroup);
-        RemotingCommand request =
-            RemotingCommand.createRequestCommand(RequestCode.NOTIFY_CONSUMER_IDS_CHANGED, requestHeader);
-
-        try {
-            this.snodeController.getSnodeServer().invokeOneway(channel, request, SnodeConstant.oneWaytimeout);
-        } catch (Exception e) {
-            log.error("notifyConsumerIdsChanged exception, " + consumerGroup, e.getMessage());
-        }
-    }
-
-    @Override
-    public RemotingCommand creatTopic(TopicConfig topicConfig) {
-//        CreateTopicRequestHeader requestHeader = new CreateTopicRequestHeader();
-//        requestHeader.setTopic(topicConfig.getTopicName());
-//        requestHeader.setDefaultTopic(defaultTopic);
-//        requestHeader.setReadQueueNums(topicConfig.getReadQueueNums());
-//        requestHeader.setWriteQueueNums(topicConfig.getWriteQueueNums());
-//        requestHeader.setPerm(topicConfig.getPerm());
-//        requestHeader.setTopicFilterType(topicConfig.getTopicFilterType().name());
-//        requestHeader.setTopicSysFlag(topicConfig.getTopicSysFlag());
-//        requestHeader.setOrder(topicConfig.isOrder());
-//
-//        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UPDATE_AND_CREATE_TOPIC, requestHeader);
-//
-//        RemotingCommand response = this.client.invokeSync(,
-//            request, defaultTimeoutMills);
-//        assert response != null;
-//        switch (response.getCode()) {
-//            case ResponseCode.SUCCESS: {
-//                return;
-//            }
-//            default:
-//                break;
-//        }
-        return null;
-    }
-}


[rocketmq] 06/14: Add async response interface and implementation

Posted by du...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a commit to branch snode
in repository https://gitbox.apache.org/repos/asf/rocketmq.git

commit 36cec93387beb331ee47343df5d28f6fdfb992b7
Author: duhenglucky <du...@gmail.com>
AuthorDate: Fri Dec 21 22:22:42 2018 +0800

    Add async response interface and implementation
---
 .../protocol/header/SendMessageRequestHeader.java  |  1 +
 pom.xml                                            |  4 +-
 .../apache/rocketmq/remoting/RemotingServer.java   |  2 +
 .../remoting/transport/http2/Http2ServerImpl.java  |  5 ++
 .../transport/rocketmq/NettyRemotingServer.java    | 22 ++++++++
 .../org/apache/rocketmq/snode/SnodeController.java |  4 +-
 .../SnodeConstant.java}                            | 25 ++-------
 .../snode/processor/ConsumerManageProcessor.java   |  4 +-
 .../snode/processor/HearbeatProcessor.java         |  7 +--
 .../snode/processor/PullMessageProcessor.java      | 23 +++++++--
 .../snode/processor/SendMessageProcessor.java      | 19 +++++--
 .../rocketmq/snode/service/SnodeOuterService.java  |  8 ++-
 .../service/impl/SendTransferServiceImpl.java      | 45 ----------------
 .../snode/service/impl/SnodeOuterServiceImpl.java  | 60 +++++++++++++---------
 14 files changed, 116 insertions(+), 113 deletions(-)

diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java
index 81e0cff..a032911 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/SendMessageRequestHeader.java
@@ -50,6 +50,7 @@ public class SendMessageRequestHeader implements CommandCustomHeader {
     private boolean unitMode = false;
     @CFNullable
     private boolean batch = false;
+
     private Integer maxReconsumeTimes;
 
     private String enodeAddr;
diff --git a/pom.xml b/pom.xml
index 47a7b68..08e438b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -100,8 +100,8 @@
         <maven.test.skip>false</maven.test.skip>
         <maven.javadoc.skip>true</maven.javadoc.skip>
         <!-- Compiler settings properties -->
-        <maven.compiler.source>1.7</maven.compiler.source>
-        <maven.compiler.target>1.7</maven.compiler.target>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
         <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
         <!-- Exclude all generated code -->
         <sonar.jacoco.itReportPath>${project.basedir}/../test/target/jacoco-it.exec</sonar.jacoco.itReportPath>
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java
index 0d5ff38..a939a3a 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java
@@ -17,6 +17,7 @@
 package org.apache.rocketmq.remoting;
 
 import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
 import java.util.concurrent.ExecutorService;
 import org.apache.rocketmq.remoting.common.Pair;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
@@ -53,4 +54,5 @@ public interface RemotingServer extends RemotingService {
 
     RemotingServer init(NettyServerConfig nettyServerConfig, ChannelEventListener channelEventListener);
 
+    void sendResponse(final ChannelHandlerContext channel, RemotingCommand remotingCommand);
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java
index 6ff3d90..bc6a5c1 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java
@@ -4,6 +4,7 @@ import io.netty.bootstrap.ServerBootstrap;
 import io.netty.buffer.PooledByteBufAllocator;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelOption;
 import io.netty.channel.ChannelPipeline;
@@ -240,4 +241,8 @@ public class Http2ServerImpl extends NettyRemotingServerAbstract implements Remo
         return this.channelEventListener;
     }
 
+    @Override
+    public void sendResponse(ChannelHandlerContext channel, RemotingCommand remotingCommand) {
+
+    }
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java
index d167b49..5387de4 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java
@@ -21,6 +21,7 @@ import io.netty.buffer.ByteBuf;
 import io.netty.buffer.PooledByteBufAllocator;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelOption;
@@ -344,4 +345,25 @@ public class NettyRemotingServer extends NettyRemotingServerAbstract implements
     public void push(String addr, String sessionId, RemotingCommand remotingCommand) {
 
     }
+
+    @Override
+    public void sendResponse(ChannelHandlerContext channel, RemotingCommand response) {
+        if (response != null) {
+            response.markResponseType();
+            try {
+                channel.writeAndFlush(response).addListener(new ChannelFutureListener() {
+                    @Override
+                    public void operationComplete(ChannelFuture future) throws Exception {
+                        if (!future.isSuccess()) {
+                            log.error("processRequestWrapper response to {} failed",
+                                future.channel().remoteAddress(), future.cause());
+                        }
+                    }
+                });
+            } catch (Throwable e) {
+                log.error("processRequestWrapper process request over, but response failed", e);
+                log.error(response.toString());
+            }
+        }
+    }
 }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
index cb19bc9..50337df 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
@@ -135,9 +135,9 @@ public class SnodeController {
     }
 
     public void registerProcessor() {
-        snodeServer.registerProcessor(RequestCode.SEND_MESSAGE_V2, new SendMessageProcessor(this.snodeOuterService), sendMessageExcutor);
+        snodeServer.registerProcessor(RequestCode.SEND_MESSAGE_V2, new SendMessageProcessor(this), sendMessageExcutor);
         snodeServer.registerProcessor(RequestCode.HEART_BEAT, new HearbeatProcessor(this), heartbeatExecutor);
-        snodeServer.registerProcessor(RequestCode.SNODE_PULL_MESSAGE, new PullMessageProcessor(this.snodeOuterService), pullMessageExcutor);
+        snodeServer.registerProcessor(RequestCode.SNODE_PULL_MESSAGE, new PullMessageProcessor(this), pullMessageExcutor);
         snodeServer.registerProcessor(RequestCode.GET_CONSUMER_LIST_BY_GROUP, new ConsumerManageProcessor(this), consumerManagerExcutor);
     }
 
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java
similarity index 50%
copy from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
copy to rocketmq-snode/src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java
index a165fd4..2ba91b2 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.processor;/*
+package org.apache.rocketmq.snode.constant;/*
  * 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.
@@ -15,26 +15,11 @@ package org.apache.rocketmq.snode.processor;/*
  * limitations under the License.
  */
 
-import io.netty.channel.ChannelHandlerContext;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
-import org.apache.rocketmq.remoting.protocol.RemotingCommand;
-import org.apache.rocketmq.snode.service.SnodeOuterService;
+public class SnodeConstant {
+    public static final long heartbeatTimeout = 3000;
 
-public class PullMessageProcessor implements NettyRequestProcessor {
+    public static final long oneWaytimeout = 10;
 
-    private final SnodeOuterService snodeOuterService;
+    public static final long defaultTimeoutMills = 3000L;
 
-    public PullMessageProcessor(SnodeOuterService snodeOuterService){
-        this.snodeOuterService = snodeOuterService;
-    }
-
-    @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) {
-        return snodeOuterService.pullMessage(request);
-    }
-
-    @Override
-    public boolean rejectRequest() {
-        return false;
-    }
 }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
index 8509546..aec6f04 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
@@ -80,11 +80,11 @@ public class ConsumerManageProcessor implements NettyRequestProcessor {
                 response.setRemark(null);
                 return response;
             } else {
-                log.warn("getAllClientId failed, {} {}", requestHeader.getConsumerGroup(),
+                log.warn("Get all client failed, {} {}", requestHeader.getConsumerGroup(),
                     RemotingHelper.parseChannelRemoteAddr(ctx.channel()));
             }
         } else {
-            log.warn("getConsumerGroupInfo failed, {} {}", requestHeader.getConsumerGroup(),
+            log.warn("GetConsumerGroupInfo failed, {} {}", requestHeader.getConsumerGroup(),
                 RemotingHelper.parseChannelRemoteAddr(ctx.channel()));
         }
 
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
index f06af79..c26ed7c 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
@@ -1,4 +1,4 @@
-package org.apache.rocketmq.snode.processor;/*
+/*
  * 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.
@@ -14,16 +14,13 @@ package org.apache.rocketmq.snode.processor;/*
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+package org.apache.rocketmq.snode.processor;
 import io.netty.channel.ChannelHandlerContext;
-import org.apache.rocketmq.common.MixAll;
 import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.common.constant.PermName;
 import org.apache.rocketmq.common.protocol.heartbeat.ConsumerData;
 import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData;
 import org.apache.rocketmq.common.protocol.heartbeat.ProducerData;
 import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
-import org.apache.rocketmq.common.sysflag.TopicSysFlag;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
index a165fd4..6e474bc 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
@@ -16,21 +16,34 @@ package org.apache.rocketmq.snode.processor;/*
  */
 
 import io.netty.channel.ChannelHandlerContext;
+import java.util.concurrent.CompletableFuture;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
-import org.apache.rocketmq.snode.service.SnodeOuterService;
+import org.apache.rocketmq.snode.SnodeController;
 
 public class PullMessageProcessor implements NettyRequestProcessor {
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
 
-    private final SnodeOuterService snodeOuterService;
+    private final SnodeController snodeController;
 
-    public PullMessageProcessor(SnodeOuterService snodeOuterService){
-        this.snodeOuterService = snodeOuterService;
+    public PullMessageProcessor(SnodeController snodeController) {
+        this.snodeController = snodeController;
     }
 
     @Override
     public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) {
-        return snodeOuterService.pullMessage(request);
+        CompletableFuture<RemotingCommand> responseFuture = snodeController.getSnodeOuterService().pullMessage(ctx, request);
+        responseFuture.whenComplete((data, ex) -> {
+            if (ex == null) {
+                this.snodeController.getSnodeServer().sendResponse(ctx, data);
+            } else {
+                log.error("Pull message error: {}", ex);
+            }
+        });
+        return null;
     }
 
     @Override
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
index e419475..3f52ed3 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
@@ -16,25 +16,34 @@ package org.apache.rocketmq.snode.processor;/*
  */
 
 import io.netty.channel.ChannelHandlerContext;
+import java.util.concurrent.CompletableFuture;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
-import org.apache.rocketmq.snode.service.SnodeOuterService;
+import org.apache.rocketmq.snode.SnodeController;
 
 public class SendMessageProcessor implements NettyRequestProcessor {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
 
-    private final SnodeOuterService snodeOuterService;
+    private final SnodeController snodeController;
 
-    public SendMessageProcessor(final SnodeOuterService snodeOuterService) {
-        this.snodeOuterService = snodeOuterService;
+    public SendMessageProcessor(final SnodeController snodeController) {
+        this.snodeController = snodeController;
     }
 
     @Override
     public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) {
-        return snodeOuterService.sendMessage(request);
+        CompletableFuture<RemotingCommand> responseFuture = snodeController.getSnodeOuterService().sendMessage(request);
+        responseFuture.whenComplete((data, ex) -> {
+            if (ex == null) {
+                snodeController.getSnodeServer().sendResponse(ctx, data);
+            } else {
+                log.error("Send Message error: {}", ex);
+            }
+        });
+        return null;
     }
 
     @Override
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SnodeOuterService.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SnodeOuterService.java
index 8764228..a1ffdd8 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SnodeOuterService.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/SnodeOuterService.java
@@ -16,6 +16,9 @@ package org.apache.rocketmq.snode.service;/*
  */
 
 import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.util.concurrent.CompleteFuture;
+import java.util.concurrent.CompletableFuture;
 import org.apache.rocketmq.client.exception.MQBrokerException;
 import org.apache.rocketmq.common.TopicConfig;
 import org.apache.rocketmq.remoting.exception.RemotingConnectException;
@@ -27,9 +30,10 @@ import org.apache.rocketmq.snode.config.SnodeConfig;
 public interface SnodeOuterService {
     void sendHearbeat(RemotingCommand remotingCommand);
 
-    RemotingCommand sendMessage(RemotingCommand remotingCommand);
+    CompletableFuture<RemotingCommand> sendMessage(final RemotingCommand request);
 
-    RemotingCommand pullMessage(RemotingCommand remotingCommand);
+    CompletableFuture<RemotingCommand> pullMessage(final ChannelHandlerContext context,
+        final RemotingCommand remotingCommand);
 
     void saveSubscriptionData(RemotingCommand remotingCommand);
 
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SendTransferServiceImpl.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SendTransferServiceImpl.java
deleted file mode 100644
index df589da..0000000
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SendTransferServiceImpl.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.apache.rocketmq.snode.service.impl;/*
- * 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.
- */
-
-import org.apache.rocketmq.common.ServiceState;
-import org.apache.rocketmq.remoting.protocol.RemotingCommand;
-import org.apache.rocketmq.snode.service.SendTransferService;
-import org.apache.rocketmq.snode.service.SnodeOuterService;
-
-public class SendTransferServiceImpl implements SendTransferService {
-    private ServiceState serviceState = ServiceState.CREATE_JUST;
-    private SnodeOuterService snodeOuterService;
-
-    public SendTransferServiceImpl(SnodeOuterService snodeOuterService) {
-        snodeOuterService = snodeOuterService;
-    }
-
-    @Override
-    public RemotingCommand sendMessage(RemotingCommand request) {
-        return snodeOuterService.sendMessage(request);
-    }
-
-    @Override
-    public boolean start() {
-        return false;
-    }
-
-    @Override
-    public void shutdown() {
-
-    }
-}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SnodeOuterServiceImpl.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SnodeOuterServiceImpl.java
index 14e577e..1863f6b 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SnodeOuterServiceImpl.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/SnodeOuterServiceImpl.java
@@ -16,11 +16,14 @@ package org.apache.rocketmq.snode.service.impl;/*
  */
 
 import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.util.concurrent.CompleteFuture;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import org.apache.rocketmq.client.exception.MQBrokerException;
@@ -31,22 +34,23 @@ import org.apache.rocketmq.common.namesrv.TopAddressing;
 import org.apache.rocketmq.common.protocol.RequestCode;
 import org.apache.rocketmq.common.protocol.ResponseCode;
 import org.apache.rocketmq.common.protocol.body.ClusterInfo;
-import org.apache.rocketmq.common.protocol.header.CreateTopicRequestHeader;
 import org.apache.rocketmq.common.protocol.header.NotifyConsumerIdsChangedRequestHeader;
 import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader;
-import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader;
 import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeaderV2;
 import org.apache.rocketmq.common.protocol.header.namesrv.RegisterSnodeRequestHeader;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.InvokeCallback;
 import org.apache.rocketmq.remoting.RemotingClient;
 import org.apache.rocketmq.remoting.RemotingClientFactory;
 import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.remoting.netty.ResponseFuture;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.snode.SnodeController;
 import org.apache.rocketmq.snode.config.SnodeConfig;
+import org.apache.rocketmq.snode.constant.SnodeConstant;
 import org.apache.rocketmq.snode.service.SnodeOuterService;
 
 public class SnodeOuterServiceImpl implements SnodeOuterService {
@@ -58,7 +62,6 @@ public class SnodeOuterServiceImpl implements SnodeOuterService {
     private static SnodeOuterServiceImpl snodeOuterService;
     private final ConcurrentMap<String/* Broker Name */, HashMap<Long/* brokerId */, String/* address */>> enodeTable =
         new ConcurrentHashMap<>();
-    private final long defaultTimeoutMills = 3000L;
 
     private SnodeOuterServiceImpl() {
 
@@ -97,7 +100,7 @@ public class SnodeOuterServiceImpl implements SnodeOuterService {
             String enodeAddr = entry.getValue().get(MixAll.MASTER_ID);
             if (enodeAddr != null) {
                 try {
-                    RemotingCommand response = this.client.invokeSync(enodeAddr, remotingCommand, defaultTimeoutMills);
+                    RemotingCommand response = this.client.invokeSync(enodeAddr, remotingCommand, SnodeConstant.defaultTimeoutMills);
                 } catch (Exception ex) {
                     log.warn("Send heart beat faild:{} ,ex:{}", enodeAddr, ex);
                 }
@@ -106,27 +109,19 @@ public class SnodeOuterServiceImpl implements SnodeOuterService {
     }
 
     @Override
-    public RemotingCommand sendMessage(RemotingCommand request) {
-        try {
-            SendMessageRequestHeaderV2 sendMessageRequestHeaderV2 = (SendMessageRequestHeaderV2) request.decodeCommandCustomHeader(SendMessageRequestHeaderV2.class);
-            RemotingCommand response =
-                this.client.invokeSync(sendMessageRequestHeaderV2.getN(), request, defaultTimeoutMills);
-            return response;
-        } catch (Exception ex) {
-            log.error("Send message async error:", ex);
-        }
-        return null;
-    }
-
-    @Override
-    public RemotingCommand pullMessage(RemotingCommand request) {
+    public CompletableFuture<RemotingCommand> pullMessage(final ChannelHandlerContext context,
+        RemotingCommand request) {
         try {
             final PullMessageRequestHeader requestHeader =
                 (PullMessageRequestHeader) request.decodeCommandCustomHeader(PullMessageRequestHeader.class);
-            RemotingCommand remotingCommand =  this.client.invokeSync(requestHeader.getEnodeAddr(), request, 20 * defaultTimeoutMills);
-            log.info("Pull message response:{}", remotingCommand);
-            log.info("Pull message response:{}", remotingCommand.getBody().length);
-            return remotingCommand;
+            this.client.invokeAsync(requestHeader.getEnodeAddr(), request, SnodeConstant.defaultTimeoutMills, new InvokeCallback() {
+                @Override
+                public void operationComplete(ResponseFuture responseFuture) {
+                    RemotingCommand response = responseFuture.getResponseCommand();
+                    snodeController.getSnodeServer().sendResponse(context, response);
+                }
+            });
+            return null;
         } catch (Exception ex) {
             log.error("pull message async error:", ex);
         }
@@ -176,7 +171,7 @@ public class SnodeOuterServiceImpl implements SnodeOuterService {
     public void updateEnodeAddr(String clusterName) throws InterruptedException, RemotingTimeoutException,
         RemotingSendRequestException, RemotingConnectException, MQBrokerException {
         synchronized (this) {
-            ClusterInfo clusterInfo = getBrokerClusterInfo(defaultTimeoutMills);
+            ClusterInfo clusterInfo = getBrokerClusterInfo(SnodeConstant.defaultTimeoutMills);
             if (clusterInfo != null) {
                 HashMap<String, Set<String>> brokerAddrs = clusterInfo.getClusterAddrTable();
                 for (Map.Entry<String, Set<String>> entry : brokerAddrs.entrySet()) {
@@ -212,7 +207,7 @@ public class SnodeOuterServiceImpl implements SnodeOuterService {
         if (nameServerAddressList != null && nameServerAddressList.size() > 0) {
             for (String nameServer : nameServerAddressList) {
                 try {
-                    this.client.invokeSync(nameSrvAddr, remotingCommand, 3000L);
+                    this.client.invokeSync(nameSrvAddr, remotingCommand, SnodeConstant.heartbeatTimeout);
                 } catch (Exception ex) {
                     log.warn("Register Snode to Nameserver addr: {} error, ex:{} ", nameServer, ex);
                 }
@@ -221,6 +216,21 @@ public class SnodeOuterServiceImpl implements SnodeOuterService {
     }
 
     @Override
+    public CompletableFuture<RemotingCommand> sendMessage(RemotingCommand request) {
+        CompletableFuture<RemotingCommand> future = new CompletableFuture<>();
+        try {
+            SendMessageRequestHeaderV2 sendMessageRequestHeaderV2 = (SendMessageRequestHeaderV2) request.decodeCommandCustomHeader(SendMessageRequestHeaderV2.class);
+            this.client.invokeAsync(sendMessageRequestHeaderV2.getN(), request, SnodeConstant.defaultTimeoutMills, (responseFuture) -> {
+                future.complete(responseFuture.getResponseCommand());
+            });
+        } catch (Exception ex) {
+            log.error("Send message async error:{}", ex);
+            future.completeExceptionally(ex);
+        }
+        return future;
+    }
+
+    @Override
     public void notifyConsumerIdsChanged(
         final Channel channel,
         final String consumerGroup) {
@@ -235,7 +245,7 @@ public class SnodeOuterServiceImpl implements SnodeOuterService {
             RemotingCommand.createRequestCommand(RequestCode.NOTIFY_CONSUMER_IDS_CHANGED, requestHeader);
 
         try {
-            this.snodeController.getSnodeServer().invokeOneway(channel, request, 10);
+            this.snodeController.getSnodeServer().invokeOneway(channel, request, SnodeConstant.oneWaytimeout);
         } catch (Exception e) {
             log.error("notifyConsumerIdsChanged exception, " + consumerGroup, e.getMessage());
         }


[rocketmq] 10/14: Remove netty dependency of RemotingClient and RemotingServer interface

Posted by du...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a commit to branch snode
in repository https://gitbox.apache.org/repos/asf/rocketmq.git

commit 6014a039c05272de1a18fb4c00716b6c92cc7f1c
Author: duhenglucky <du...@gmail.com>
AuthorDate: Wed Jan 2 10:42:31 2019 +0800

    Remove netty dependency of RemotingClient and RemotingServer interface
---
 .../client/impl/ClientRemotingProcessor.java       | 10 ++-
 .../rocketmq/client/impl/MQClientAPIImpl.java      |  9 +--
 .../client/impl/factory/MQClientInstance.java      | 15 ++--
 .../rocketmq/client/impl/MQClientAPIImplTest.java  |  5 +-
 .../apache/rocketmq/namesrv/NamesrvController.java |  8 +-
 .../apache/rocketmq/namesrv/NamesrvStartup.java    |  4 +-
 .../namesrv/processor/DefaultRequestProcessor.java | 12 ++-
 .../routeinfo/BrokerHousekeepingService.java       | 16 +++-
 .../rocketmq/namesrv/NameServerInstanceTest.java   |  4 +-
 .../processor/ClusterTestRequestProcessorTest.java |  4 +-
 .../processor/DefaultRequestProcessorTest.java     | 19 +++--
 .../routeinfo/BrokerHousekeepingServiceTest.java   |  4 +-
 .../rocketmq/remoting/ChannelEventListener.java    | 10 +--
 .../org/apache/rocketmq/remoting/ClientConfig.java |  6 +-
 .../apache/rocketmq/remoting/RemotingChannel.java  | 33 +++------
 .../apache/rocketmq/remoting/RemotingClient.java   |  6 +-
 .../apache/rocketmq/remoting/RemotingServer.java   | 20 ++---
 .../rocketmq/remoting/RemotingServerFactory.java   |  2 +-
 .../apache/rocketmq/remoting/RequestProcessor.java |  7 +-
 .../org/apache/rocketmq/remoting/ServerConfig.java |  8 +-
 .../rocketmq/remoting/common/RemotingHelper.java   |  4 +
 .../netty/NettyChannelHandlerContextImpl.java      | 85 +++++++++++++++++++++-
 .../rocketmq/remoting/netty/NettyChannelImpl.java  | 28 ++++---
 .../remoting/netty/NettyRemotingAbstract.java      | 36 ++++-----
 .../transport/NettyRemotingClientAbstract.java     |  4 -
 .../remoting/transport/http2/Http2ClientImpl.java  | 14 ++--
 .../remoting/transport/http2/Http2ServerImpl.java  | 41 ++++++-----
 .../transport/rocketmq/NettyRemotingClient.java    | 17 ++---
 .../transport/rocketmq/NettyRemotingServer.java    | 49 +++++++------
 .../rocketmq/remoting/RemotingServerTest.java      | 16 ++--
 .../java/org/apache/rocketmq/remoting/TlsTest.java |  5 +-
 .../remoting/netty/NettyRemotingAbstractTest.java  |  3 +-
 .../remoting/netty/NettyRemotingClientTest.java    |  4 +-
 .../org/apache/rocketmq/snode/SnodeController.java | 16 ++--
 .../org/apache/rocketmq/snode/SnodeStartup.java    |  8 +-
 .../rocketmq/snode/client/ClientChannelInfo.java   | 10 +--
 .../snode/client/ClientHousekeepingService.java    | 21 +++++-
 .../rocketmq/snode/client/ConsumerGroupInfo.java   | 17 +++--
 .../rocketmq/snode/client/ConsumerManager.java     | 11 +--
 .../client/DefaultConsumerIdsChangeListener.java   |  8 +-
 .../rocketmq/snode/client/ProducerManager.java     | 29 ++++----
 .../snode/processor/ConsumerManageProcessor.java   | 15 ++--
 .../snode/processor/HearbeatProcessor.java         | 21 +++---
 .../snode/processor/PullMessageProcessor.java      | 18 ++++-
 .../snode/processor/SendMessageProcessor.java      |  9 ++-
 .../rocketmq/snode/service/EnodeService.java       |  4 +-
 .../snode/service/impl/EnodeServiceImpl.java       |  3 +-
 .../rocketmq/test/base/IntegrationTestBase.java    | 10 +--
 48 files changed, 420 insertions(+), 288 deletions(-)

diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/ClientRemotingProcessor.java b/client/src/main/java/org/apache/rocketmq/client/impl/ClientRemotingProcessor.java
index fe0db96..74a6e33 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/ClientRemotingProcessor.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/ClientRemotingProcessor.java
@@ -41,13 +41,15 @@ import org.apache.rocketmq.common.protocol.header.GetConsumerRunningInfoRequestH
 import org.apache.rocketmq.common.protocol.header.GetConsumerStatusRequestHeader;
 import org.apache.rocketmq.common.protocol.header.NotifyConsumerIdsChangedRequestHeader;
 import org.apache.rocketmq.common.protocol.header.ResetOffsetRequestHeader;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
 
-public class ClientRemotingProcessor implements NettyRequestProcessor {
+public class ClientRemotingProcessor implements RequestProcessor {
     private final InternalLogger log = ClientLogger.getLog();
     private final MQClientInstance mqClientFactory;
 
@@ -56,8 +58,10 @@ public class ClientRemotingProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx,
+    public RemotingCommand processRequest(RemotingChannel remotingChannel,
         RemotingCommand request) throws RemotingCommandException {
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl)remotingChannel;
+        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
         switch (request.getCode()) {
             case RequestCode.CHECK_TRANSACTION_STATE:
                 return this.checkTransactionState(ctx, request);
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
index a7aead1..39f1b61 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
@@ -27,7 +27,6 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
-import org.apache.rocketmq.client.ClientConfig;
 import org.apache.rocketmq.client.consumer.PullCallback;
 import org.apache.rocketmq.client.consumer.PullResult;
 import org.apache.rocketmq.client.consumer.PullStatus;
@@ -145,7 +144,7 @@ import org.apache.rocketmq.remoting.exception.RemotingException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
+import org.apache.rocketmq.remoting.ClientConfig;
 import org.apache.rocketmq.remoting.netty.ResponseFuture;
 import org.apache.rocketmq.remoting.serialize.LanguageCode;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
@@ -166,11 +165,11 @@ public class MQClientAPIImpl {
     private final TopAddressing topAddressing;
     private final ClientRemotingProcessor clientRemotingProcessor;
     private String nameSrvAddr = null;
-    private ClientConfig clientConfig;
+    private org.apache.rocketmq.client.ClientConfig clientConfig;
 
-    public MQClientAPIImpl(final NettyClientConfig nettyClientConfig,
+    public MQClientAPIImpl(final ClientConfig nettyClientConfig,
         final ClientRemotingProcessor clientRemotingProcessor,
-        RPCHook rpcHook, final ClientConfig clientConfig) {
+        RPCHook rpcHook, final org.apache.rocketmq.client.ClientConfig clientConfig) {
         this.clientConfig = clientConfig;
         topAddressing = new TopAddressing(MixAll.getWSAddr(), clientConfig.getUnitName());
         this.remotingClient = new NettyRemotingClient(nettyClientConfig, null);
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
index 4e9d9ba..843d4da 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
@@ -36,7 +36,6 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
-import org.apache.rocketmq.client.ClientConfig;
 import org.apache.rocketmq.client.admin.MQAdminExtInner;
 import org.apache.rocketmq.client.exception.MQBrokerException;
 import org.apache.rocketmq.client.exception.MQClientException;
@@ -79,20 +78,20 @@ import org.apache.rocketmq.common.protocol.route.TopicRouteData;
 import org.apache.rocketmq.remoting.RPCHook;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.exception.RemotingException;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
+import org.apache.rocketmq.remoting.ClientConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
 public class MQClientInstance {
     private final static long LOCK_TIMEOUT_MILLIS = 3000;
     private final InternalLogger log = ClientLogger.getLog();
-    private final ClientConfig clientConfig;
+    private final org.apache.rocketmq.client.ClientConfig clientConfig;
     private final int instanceIndex;
     private final String clientId;
     private final long bootTimestamp = System.currentTimeMillis();
     private final ConcurrentMap<String/* group */, MQProducerInner> producerTable = new ConcurrentHashMap<String, MQProducerInner>();
     private final ConcurrentMap<String/* group */, MQConsumerInner> consumerTable = new ConcurrentHashMap<String, MQConsumerInner>();
     private final ConcurrentMap<String/* group */, MQAdminExtInner> adminExtTable = new ConcurrentHashMap<String, MQAdminExtInner>();
-    private final NettyClientConfig nettyClientConfig;
+    private final ClientConfig nettyClientConfig;
     private final MQClientAPIImpl mQClientAPIImpl;
     private final MQAdminImpl mQAdminImpl;
     private final ConcurrentMap<String/* Topic */, TopicRouteData> topicRouteTable = new ConcurrentHashMap<String, TopicRouteData>();
@@ -118,14 +117,14 @@ public class MQClientInstance {
     private DatagramSocket datagramSocket;
     private Random random = new Random();
 
-    public MQClientInstance(ClientConfig clientConfig, int instanceIndex, String clientId) {
+    public MQClientInstance(org.apache.rocketmq.client.ClientConfig clientConfig, int instanceIndex, String clientId) {
         this(clientConfig, instanceIndex, clientId, null);
     }
 
-    public MQClientInstance(ClientConfig clientConfig, int instanceIndex, String clientId, RPCHook rpcHook) {
+    public MQClientInstance(org.apache.rocketmq.client.ClientConfig clientConfig, int instanceIndex, String clientId, RPCHook rpcHook) {
         this.clientConfig = clientConfig;
         this.instanceIndex = instanceIndex;
-        this.nettyClientConfig = new NettyClientConfig();
+        this.nettyClientConfig = new ClientConfig();
         this.nettyClientConfig.setClientCallbackExecutorThreads(clientConfig.getClientCallbackExecutorThreads());
         this.nettyClientConfig.setUseTLS(clientConfig.isUseTLS());
         this.clientRemotingProcessor = new ClientRemotingProcessor(this);
@@ -1218,7 +1217,7 @@ public class MQClientInstance {
         return consumerStatsManager;
     }
 
-    public NettyClientConfig getNettyClientConfig() {
+    public ClientConfig getNettyClientConfig() {
         return nettyClientConfig;
     }
 }
diff --git a/client/src/test/java/org/apache/rocketmq/client/impl/MQClientAPIImplTest.java b/client/src/test/java/org/apache/rocketmq/client/impl/MQClientAPIImplTest.java
index c13e75c..1372a3e 100644
--- a/client/src/test/java/org/apache/rocketmq/client/impl/MQClientAPIImplTest.java
+++ b/client/src/test/java/org/apache/rocketmq/client/impl/MQClientAPIImplTest.java
@@ -17,7 +17,6 @@
 package org.apache.rocketmq.client.impl;
 
 import java.lang.reflect.Field;
-import org.apache.rocketmq.client.ClientConfig;
 import org.apache.rocketmq.client.exception.MQBrokerException;
 import org.apache.rocketmq.client.hook.SendMessageContext;
 import org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl;
@@ -34,7 +33,7 @@ import org.apache.rocketmq.remoting.InvokeCallback;
 import org.apache.rocketmq.remoting.RemotingClient;
 import org.apache.rocketmq.remoting.exception.RemotingException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
+import org.apache.rocketmq.remoting.ClientConfig;
 import org.apache.rocketmq.remoting.netty.ResponseFuture;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.junit.Before;
@@ -56,7 +55,7 @@ import static org.mockito.Mockito.doThrow;
 
 @RunWith(MockitoJUnitRunner.class)
 public class MQClientAPIImplTest {
-    private MQClientAPIImpl mqClientAPI = new MQClientAPIImpl(new NettyClientConfig(), null, null, new ClientConfig());
+    private MQClientAPIImpl mqClientAPI = new MQClientAPIImpl(new ClientConfig(), null, null, new org.apache.rocketmq.client.ClientConfig());
     @Mock
     private RemotingClient remotingClient;
     @Mock
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java
index a329e70..e833ae6 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java
@@ -34,7 +34,7 @@ import org.apache.rocketmq.namesrv.routeinfo.RouteInfoManager;
 import org.apache.rocketmq.remoting.RemotingServer;
 import org.apache.rocketmq.remoting.RemotingServerFactory;
 import org.apache.rocketmq.remoting.common.TlsMode;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.remoting.netty.TlsSystemConfig;
 import org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingServer;
 import org.apache.rocketmq.srvutil.FileWatchService;
@@ -44,7 +44,7 @@ public class NamesrvController {
 
     private final NamesrvConfig namesrvConfig;
 
-    private final NettyServerConfig nettyServerConfig;
+    private final ServerConfig nettyServerConfig;
 
     private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl(
         "NSScheduledThread"));
@@ -60,7 +60,7 @@ public class NamesrvController {
     private Configuration configuration;
     private FileWatchService fileWatchService;
 
-    public NamesrvController(NamesrvConfig namesrvConfig, NettyServerConfig nettyServerConfig) {
+    public NamesrvController(NamesrvConfig namesrvConfig, ServerConfig nettyServerConfig) {
         this.namesrvConfig = namesrvConfig;
         this.nettyServerConfig = nettyServerConfig;
         this.kvConfigManager = new KVConfigManager(this);
@@ -178,7 +178,7 @@ public class NamesrvController {
         return namesrvConfig;
     }
 
-    public NettyServerConfig getNettyServerConfig() {
+    public ServerConfig getNettyServerConfig() {
         return nettyServerConfig;
     }
 
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvStartup.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvStartup.java
index 9b49567..ac46b7d 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvStartup.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvStartup.java
@@ -35,7 +35,7 @@ import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.common.namesrv.NamesrvConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.srvutil.ServerUtil;
 import org.apache.rocketmq.srvutil.ShutdownHookThread;
@@ -80,7 +80,7 @@ public class NamesrvStartup {
         }
 
         final NamesrvConfig namesrvConfig = new NamesrvConfig();
-        final NettyServerConfig nettyServerConfig = new NettyServerConfig();
+        final ServerConfig nettyServerConfig = new ServerConfig();
         nettyServerConfig.setListenPort(9876);
         if (commandLine.hasOption('c')) {
             String file = commandLine.getOptionValue('c');
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
index 0af8c98..a7da99f 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java
@@ -53,12 +53,14 @@ import org.apache.rocketmq.common.protocol.header.namesrv.WipeWritePermOfBrokerR
 import org.apache.rocketmq.common.protocol.header.namesrv.WipeWritePermOfBrokerResponseHeader;
 import org.apache.rocketmq.common.protocol.route.TopicRouteData;
 import org.apache.rocketmq.namesrv.NamesrvController;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
-public class DefaultRequestProcessor implements NettyRequestProcessor {
+public class DefaultRequestProcessor implements RequestProcessor {
     private static InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME);
 
     protected final NamesrvController namesrvController;
@@ -68,9 +70,11 @@ public class DefaultRequestProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx,
+    public RemotingCommand processRequest(RemotingChannel remotingChannel,
         RemotingCommand request) throws RemotingCommandException {
-        log.info("receive remoting command: " + request);
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl) remotingChannel;
+        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
+
         if (ctx != null) {
             log.debug("receive request, {} {} {}",
                 request.getCode(),
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/BrokerHousekeepingService.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/BrokerHousekeepingService.java
index fedb4ae..e0cdd95 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/BrokerHousekeepingService.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/BrokerHousekeepingService.java
@@ -22,6 +22,8 @@ import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.namesrv.NamesrvController;
 import org.apache.rocketmq.remoting.ChannelEventListener;
+import org.apache.rocketmq.remoting.RemotingChannel;
+import org.apache.rocketmq.remoting.netty.NettyChannelImpl;
 
 public class BrokerHousekeepingService implements ChannelEventListener {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME);
@@ -32,21 +34,27 @@ public class BrokerHousekeepingService implements ChannelEventListener {
     }
 
     @Override
-    public void onChannelConnect(String remoteAddr, Channel channel) {
+    public void onChannelConnect(String remoteAddr, RemotingChannel channel) {
     }
 
     @Override
-    public void onChannelClose(String remoteAddr, Channel channel) {
+    public void onChannelClose(String remoteAddr, RemotingChannel remotingChannel) {
+        NettyChannelImpl nettyChannel = (NettyChannelImpl) remotingChannel;
+        Channel channel = nettyChannel.getChannel();
         this.namesrvController.getRouteInfoManager().onChannelDestroy(remoteAddr, channel);
     }
 
     @Override
-    public void onChannelException(String remoteAddr, Channel channel) {
+    public void onChannelException(String remoteAddr, RemotingChannel remotingChannel) {
+        NettyChannelImpl nettyChannel = (NettyChannelImpl) remotingChannel;
+        Channel channel = nettyChannel.getChannel();
         this.namesrvController.getRouteInfoManager().onChannelDestroy(remoteAddr, channel);
     }
 
     @Override
-    public void onChannelIdle(String remoteAddr, Channel channel) {
+    public void onChannelIdle(String remoteAddr, RemotingChannel remotingChannel) {
+        NettyChannelImpl nettyChannel = (NettyChannelImpl) remotingChannel;
+        Channel channel = nettyChannel.getChannel();
         this.namesrvController.getRouteInfoManager().onChannelDestroy(remoteAddr, channel);
     }
 }
diff --git a/namesrv/src/test/java/org/apache/rocketmq/namesrv/NameServerInstanceTest.java b/namesrv/src/test/java/org/apache/rocketmq/namesrv/NameServerInstanceTest.java
index 83ab103..f8aed00 100644
--- a/namesrv/src/test/java/org/apache/rocketmq/namesrv/NameServerInstanceTest.java
+++ b/namesrv/src/test/java/org/apache/rocketmq/namesrv/NameServerInstanceTest.java
@@ -17,7 +17,7 @@
 package org.apache.rocketmq.namesrv;
 
 import org.apache.rocketmq.common.namesrv.NamesrvConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.junit.After;
 import org.junit.Before;
 
@@ -25,7 +25,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 public class NameServerInstanceTest {
     protected NamesrvController nameSrvController = null;
-    protected NettyServerConfig nettyServerConfig = new NettyServerConfig();
+    protected ServerConfig nettyServerConfig = new ServerConfig();
     protected NamesrvConfig namesrvConfig = new NamesrvConfig();
 
     @Before
diff --git a/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/ClusterTestRequestProcessorTest.java b/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/ClusterTestRequestProcessorTest.java
index a0e8137..661deed 100644
--- a/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/ClusterTestRequestProcessorTest.java
+++ b/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/ClusterTestRequestProcessorTest.java
@@ -35,7 +35,7 @@ import org.apache.rocketmq.namesrv.NamesrvController;
 import org.apache.rocketmq.remoting.CommandCustomHeader;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 import org.apache.rocketmq.remoting.exception.RemotingException;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
 import org.apache.rocketmq.tools.admin.DefaultMQAdminExtImpl;
@@ -60,7 +60,7 @@ public class ClusterTestRequestProcessorTest {
     public void init() throws NoSuchFieldException, IllegalAccessException, RemotingException, MQClientException, InterruptedException {
         NamesrvController namesrvController = new NamesrvController(
             new NamesrvConfig(),
-            new NettyServerConfig()
+            new ServerConfig()
         );
 
         clusterTestProcessor = new ClusterTestRequestProcessor(namesrvController, "default-producer");
diff --git a/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessorTest.java b/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessorTest.java
index d4a2f66..8cd75f8 100644
--- a/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessorTest.java
+++ b/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessorTest.java
@@ -40,7 +40,8 @@ import org.apache.rocketmq.common.protocol.route.BrokerData;
 import org.apache.rocketmq.namesrv.NamesrvController;
 import org.apache.rocketmq.namesrv.routeinfo.RouteInfoManager;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.assertj.core.util.Maps;
 import org.junit.Before;
@@ -57,7 +58,7 @@ public class DefaultRequestProcessorTest {
 
     private NamesrvConfig namesrvConfig;
 
-    private NettyServerConfig nettyServerConfig;
+    private ServerConfig nettyServerConfig;
 
     private RouteInfoManager routeInfoManager;
 
@@ -66,7 +67,7 @@ public class DefaultRequestProcessorTest {
     @Before
     public void init() throws Exception {
         namesrvConfig = new NamesrvConfig();
-        nettyServerConfig = new NettyServerConfig();
+        nettyServerConfig = new ServerConfig();
         routeInfoManager = new RouteInfoManager();
 
         namesrvController = new NamesrvController(namesrvConfig, nettyServerConfig);
@@ -166,8 +167,8 @@ public class DefaultRequestProcessorTest {
 
         ChannelHandlerContext ctx = mock(ChannelHandlerContext.class);
         when(ctx.channel()).thenReturn(null);
-
-        RemotingCommand response = defaultRequestProcessor.processRequest(ctx, request);
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(ctx);
+        RemotingCommand response = defaultRequestProcessor.processRequest(nettyChannelHandlerContext, request);
 
         assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
         assertThat(response.getRemark()).isNull();
@@ -195,7 +196,8 @@ public class DefaultRequestProcessorTest {
         ChannelHandlerContext ctx = mock(ChannelHandlerContext.class);
         when(ctx.channel()).thenReturn(null);
 
-        RemotingCommand response = defaultRequestProcessor.processRequest(ctx, request);
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(ctx);
+        RemotingCommand response = defaultRequestProcessor.processRequest(nettyChannelHandlerContext, request);
 
         assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
         assertThat(response.getRemark()).isNull();
@@ -219,11 +221,12 @@ public class DefaultRequestProcessorTest {
 
         //Register broker
         RemotingCommand regRequest = genSampleRegisterCmd(true);
-        defaultRequestProcessor.processRequest(ctx, regRequest);
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = new NettyChannelHandlerContextImpl(ctx);
+        RemotingCommand response = defaultRequestProcessor.processRequest(nettyChannelHandlerContext, regRequest);
 
         //Unregister broker
         RemotingCommand unregRequest = genSampleRegisterCmd(false);
-        RemotingCommand unregResponse = defaultRequestProcessor.processRequest(ctx, unregRequest);
+        RemotingCommand unregResponse = defaultRequestProcessor.processRequest(nettyChannelHandlerContext, unregRequest);
 
         assertThat(unregResponse.getCode()).isEqualTo(ResponseCode.SUCCESS);
         assertThat(unregResponse.getRemark()).isNull();
diff --git a/namesrv/src/test/java/org/apache/rocketmq/namesrv/routeinfo/BrokerHousekeepingServiceTest.java b/namesrv/src/test/java/org/apache/rocketmq/namesrv/routeinfo/BrokerHousekeepingServiceTest.java
index ce6ce23..b3fee75 100644
--- a/namesrv/src/test/java/org/apache/rocketmq/namesrv/routeinfo/BrokerHousekeepingServiceTest.java
+++ b/namesrv/src/test/java/org/apache/rocketmq/namesrv/routeinfo/BrokerHousekeepingServiceTest.java
@@ -19,7 +19,7 @@ package org.apache.rocketmq.namesrv.routeinfo;
 
 import org.apache.rocketmq.common.namesrv.NamesrvConfig;
 import org.apache.rocketmq.namesrv.NamesrvController;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -31,7 +31,7 @@ public class BrokerHousekeepingServiceTest {
     public static void setup() {
         NamesrvController namesrvController = new NamesrvController(
             new NamesrvConfig(),
-            new NettyServerConfig()
+            new ServerConfig()
         );
         brokerHousekeepingService = new BrokerHousekeepingService(namesrvController);
     }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/ChannelEventListener.java b/remoting/src/main/java/org/apache/rocketmq/remoting/ChannelEventListener.java
index c99133b..1361fd1 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/ChannelEventListener.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/ChannelEventListener.java
@@ -16,14 +16,12 @@
  */
 package org.apache.rocketmq.remoting;
 
-import io.netty.channel.Channel;
-
 public interface ChannelEventListener {
-    void onChannelConnect(final String remoteAddr, final Channel channel);
+    void onChannelConnect(final String remoteAddr, final RemotingChannel channel);
 
-    void onChannelClose(final String remoteAddr, final Channel channel);
+    void onChannelClose(final String remoteAddr, final RemotingChannel channel);
 
-    void onChannelException(final String remoteAddr, final Channel channel);
+    void onChannelException(final String remoteAddr, final RemotingChannel channel);
 
-    void onChannelIdle(final String remoteAddr, final Channel channel);
+    void onChannelIdle(final String remoteAddr, final RemotingChannel channel);
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/ClientConfig.java b/remoting/src/main/java/org/apache/rocketmq/remoting/ClientConfig.java
index fbc071b..04f2143 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/ClientConfig.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/ClientConfig.java
@@ -14,9 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.rocketmq.remoting.netty;
+package org.apache.rocketmq.remoting;
 
-public class NettyClientConfig {
+import org.apache.rocketmq.remoting.netty.NettySystemConfig;
+
+public class ClientConfig {
     /**
      * Worker thread number
      */
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingChannel.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingChannel.java
index c8f00f7..89dbdc0 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingChannel.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingChannel.java
@@ -19,36 +19,31 @@ package org.apache.rocketmq.remoting;
 
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
-import org.apache.rocketmq.remoting.api.command.RemotingCommand;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
 public interface RemotingChannel {
     /**
-     * Returns the local address where this {@code RemotingChannel} is bound to.  The returned
-     * {@link SocketAddress} is supposed to be down-cast into more concrete
-     * type such as {@link InetSocketAddress} to retrieve the detailed
+     * Returns the local address where this {@code RemotingChannel} is bound to.  The returned {@link SocketAddress} is
+     * supposed to be down-cast into more concrete type such as {@link InetSocketAddress} to retrieve the detailed
      * information.
      *
-     * @return the local address of this channel.
-     * {@code null} if this channel is not bound.
+     * @return the local address of this channel. {@code null} if this channel is not bound.
      */
     SocketAddress localAddress();
 
     /**
-     * Returns the remote address where this {@code RemotingChannel} is connected to.  The
-     * returned {@link SocketAddress} is supposed to be down-cast into more
-     * concrete type such as {@link InetSocketAddress} to retrieve the detailed
-     * information.
+     * Returns the remote address where this {@code RemotingChannel} is connected to.  The returned {@link
+     * SocketAddress} is supposed to be down-cast into more concrete type such as {@link InetSocketAddress} to retrieve
+     * the detailed information.
      *
-     * @return the remote address of this channel.
-     * {@code null} if this channel is not connected.
+     * @return the remote address of this channel. {@code null} if this channel is not connected.
      */
     SocketAddress remoteAddress();
 
     /**
-     * Returns {@code true} if and only if the I/O thread will perform the
-     * requested write operation immediately.  Any write requests made when
-     * this method returns {@code false} are queued until the I/O thread is
-     * ready to process the queued write requests.
+     * Returns {@code true} if and only if the I/O thread will perform the requested write operation immediately.  Any
+     * write requests made when this method returns {@code false} are queued until the I/O thread is ready to process
+     * the queued write requests.
      */
     boolean isWritable();
 
@@ -69,10 +64,4 @@ public interface RemotingChannel {
      */
     void reply(RemotingCommand command);
 
-    /**
-     * Writes a response {@code ChunkRegion} to remote.
-     *
-     * @param fileRegion the response chunk file region
-     */
-    void reply(ChunkRegion fileRegion);
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java
index 88bca57..c706eed 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java
@@ -22,8 +22,6 @@ import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
 public interface RemotingClient extends RemotingService {
@@ -44,7 +42,7 @@ public interface RemotingClient extends RemotingService {
         throws InterruptedException, RemotingConnectException, RemotingTooMuchRequestException,
         RemotingTimeoutException, RemotingSendRequestException;
 
-    void registerProcessor(final int requestCode, final NettyRequestProcessor processor,
+    void registerProcessor(final int requestCode, final RequestProcessor processor,
         final ExecutorService executor);
 
     void setCallbackExecutor(final ExecutorService callbackExecutor);
@@ -53,5 +51,5 @@ public interface RemotingClient extends RemotingService {
 
     boolean isChannelWritable(final String addr);
 
-    RemotingClient init(NettyClientConfig nettyClientConfig, ChannelEventListener channelEventListener);
+    RemotingClient init(ClientConfig nettyClientConfig, ChannelEventListener channelEventListener);
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java
index a939a3a..c773e5a 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java
@@ -16,43 +16,39 @@
  */
 package org.apache.rocketmq.remoting;
 
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelHandlerContext;
 import java.util.concurrent.ExecutorService;
 import org.apache.rocketmq.remoting.common.Pair;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
 public interface RemotingServer extends RemotingService {
 
-    void registerProcessor(final int requestCode, final NettyRequestProcessor processor,
+    void registerProcessor(final int requestCode, final RequestProcessor processor,
         final ExecutorService executor);
 
-    void registerDefaultProcessor(final NettyRequestProcessor processor, final ExecutorService executor);
+    void registerDefaultProcessor(final RequestProcessor processor, final ExecutorService executor);
 
     int localListenPort();
 
-    Pair<NettyRequestProcessor, ExecutorService> getProcessorPair(final int requestCode);
+    Pair<RequestProcessor, ExecutorService> getProcessorPair(final int requestCode);
 
     void push(final String addr, final String sessionId, RemotingCommand remotingCommand);
 
-    RemotingCommand invokeSync(final Channel channel, final RemotingCommand request,
+    RemotingCommand invokeSync(final RemotingChannel remotingChannel, final RemotingCommand request,
         final long timeoutMillis) throws InterruptedException, RemotingSendRequestException,
         RemotingTimeoutException;
 
-    void invokeAsync(final Channel channel, final RemotingCommand request, final long timeoutMillis,
+    void invokeAsync(final RemotingChannel remotingChannel, final RemotingCommand request, final long timeoutMillis,
         final InvokeCallback invokeCallback) throws InterruptedException,
         RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException;
 
-    void invokeOneway(final Channel channel, final RemotingCommand request, final long timeoutMillis)
+    void invokeOneway(final RemotingChannel remotingChannel, final RemotingCommand request, final long timeoutMillis)
         throws InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException,
         RemotingSendRequestException;
 
-    RemotingServer init(NettyServerConfig nettyServerConfig, ChannelEventListener channelEventListener);
+    RemotingServer init(ServerConfig nettyServerConfig, ChannelEventListener channelEventListener);
 
-    void sendResponse(final ChannelHandlerContext channel, RemotingCommand remotingCommand);
+    void sendResponse(final RemotingChannel remotingChannel, RemotingCommand remotingCommand);
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java
index e530d7a..a2cdf2b 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java
@@ -22,10 +22,10 @@ public class RemotingServerFactory {
         protocolPathMap = ServiceProvider.loadPath(SERVER_LOCATION);
     }
 
-
     public static RemotingServer createInstance(String protocol) {
         return ServiceProvider.createInstance(protocolPathMap.get(protocol), RemotingClient.class);
     }
+
     public static RemotingServer createInstance() {
         return ServiceProvider.createInstance(protocolPathMap.get(RemotingUtil.DEFAULT_PROTOCOL), RemotingServer.class);
     }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RequestProcessor.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RequestProcessor.java
index 040f768..208c194 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RequestProcessor.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RequestProcessor.java
@@ -14,16 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.rocketmq.remoting.netty;
+package org.apache.rocketmq.remoting;
 
-import io.netty.channel.ChannelHandlerContext;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
 /**
  * Common remoting command processor
  */
-public interface NettyRequestProcessor {
-    RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request)
+public interface RequestProcessor {
+    RemotingCommand processRequest(RemotingChannel remotingChannel, RemotingCommand request)
         throws Exception;
 
     boolean rejectRequest();
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/ServerConfig.java b/remoting/src/main/java/org/apache/rocketmq/remoting/ServerConfig.java
index b3f55cd..dda2528 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/ServerConfig.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/ServerConfig.java
@@ -14,9 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.rocketmq.remoting.netty;
+package org.apache.rocketmq.remoting;
 
-public class NettyServerConfig implements Cloneable {
+import org.apache.rocketmq.remoting.netty.NettySystemConfig;
+
+public class ServerConfig implements Cloneable {
     private int listenPort = 8888;
     private int serverWorkerThreads = 8;
     private int serverCallbackExecutorThreads = 8;
@@ -155,6 +157,6 @@ public class NettyServerConfig implements Cloneable {
 
     @Override
     public Object clone() throws CloneNotSupportedException {
-        return (NettyServerConfig) super.clone();
+        return (ServerConfig) super.clone();
     }
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingHelper.java b/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingHelper.java
index 0414996..fd8aa1e 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingHelper.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingHelper.java
@@ -63,6 +63,10 @@ public class RemotingHelper {
             return "";
         }
         SocketAddress remote = channel.remoteAddress();
+        return parseChannelRemoteAddr(remote);
+    }
+
+    public static String parseChannelRemoteAddr(final SocketAddress remote) {
         final String addr = remote != null ? remote.toString() : "";
 
         if (addr.length() > 0) {
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelHandlerContextImpl.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelHandlerContextImpl.java
index 9eb489a..673c12a 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelHandlerContextImpl.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelHandlerContextImpl.java
@@ -15,5 +15,88 @@ package org.apache.rocketmq.remoting.netty;/*
  * limitations under the License.
  */
 
-public class NettyChannelHandlerContextImpl {
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import java.net.SocketAddress;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingChannel;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+
+public class NettyChannelHandlerContextImpl implements RemotingChannel {
+    public static final String ROCKETMQ_REMOTING = "RocketmqRemoting";
+
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(ROCKETMQ_REMOTING);
+
+    private final ChannelHandlerContext channelHandlerContext;
+
+    public NettyChannelHandlerContextImpl(ChannelHandlerContext channelHandlerContext) {
+        this.channelHandlerContext = channelHandlerContext;
+    }
+
+    @Override
+    public SocketAddress localAddress() {
+        return channelHandlerContext.channel().localAddress();
+    }
+
+    @Override
+    public SocketAddress remoteAddress() {
+        return channelHandlerContext.channel().remoteAddress();
+    }
+
+    @Override
+    public boolean isWritable() {
+        return channelHandlerContext.channel().isWritable();
+    }
+
+    @Override
+    public boolean isActive() {
+        return channelHandlerContext.channel().isActive();
+    }
+
+    @Override
+    public void close() {
+        final String addrRemote = RemotingHelper.parseChannelRemoteAddr(channelHandlerContext.channel());
+        channelHandlerContext.close().addListener(new ChannelFutureListener() {
+            @Override
+            public void operationComplete(ChannelFuture future) throws Exception {
+                log.info("CloseChannel: close the connection to remote address[{}] result: {}", addrRemote,
+                    future.isSuccess());
+            }
+        });
+    }
+
+    @Override
+    public void reply(final RemotingCommand command) {
+        channelHandlerContext.writeAndFlush(command);
+    }
+
+    public ChannelHandlerContext getChannelHandlerContext() {
+        return channelHandlerContext;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        final NettyChannelHandlerContextImpl that = (NettyChannelHandlerContextImpl) o;
+
+        return channelHandlerContext != null ? channelHandlerContext.equals(that.channelHandlerContext) : that.channelHandlerContext == null;
+
+    }
+
+    @Override
+    public int hashCode() {
+        return channelHandlerContext != null ? channelHandlerContext.hashCode() : 0;
+    }
+
+    @Override
+    public String toString() {
+        return "NettyChannelHandlerContextImpl [channel=" + channelHandlerContext + "]";
+    }
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelImpl.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelImpl.java
index e4be7ca..86436c1 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelImpl.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyChannelImpl.java
@@ -18,12 +18,20 @@
 package org.apache.rocketmq.remoting.netty;
 
 import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
 import java.net.SocketAddress;
-import org.apache.rocketmq.remoting.api.channel.ChunkRegion;
-import org.apache.rocketmq.remoting.api.channel.RemotingChannel;
-import org.apache.rocketmq.remoting.api.command.RemotingCommand;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingChannel;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
 public class NettyChannelImpl implements RemotingChannel {
+    public static final String ROCKETMQ_REMOTING = "RocketmqRemoting";
+
+    private static final InternalLogger log = InternalLoggerFactory.getLogger(ROCKETMQ_REMOTING);
+
     private final io.netty.channel.Channel channel;
 
     public NettyChannelImpl(Channel channel) {
@@ -52,7 +60,14 @@ public class NettyChannelImpl implements RemotingChannel {
 
     @Override
     public void close() {
-        channel.close();
+        final String addrRemote = RemotingHelper.parseChannelRemoteAddr(channel);
+        channel.close().addListener(new ChannelFutureListener() {
+            @Override
+            public void operationComplete(ChannelFuture future) throws Exception {
+                log.info("CloseChannel: close the connection to remote address[{}] result: {}", addrRemote,
+                    future.isSuccess());
+            }
+        });
     }
 
     @Override
@@ -60,11 +75,6 @@ public class NettyChannelImpl implements RemotingChannel {
         channel.writeAndFlush(command);
     }
 
-    @Override
-    public void reply(final ChunkRegion fileRegion) {
-        channel.writeAndFlush(fileRegion);
-    }
-
     public io.netty.channel.Channel getChannel() {
         return channel;
     }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
index 8d3f54b..1e0235d 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
@@ -17,15 +17,12 @@
 package org.apache.rocketmq.remoting.netty;
 
 import io.netty.channel.Channel;
-import io.netty.channel.ChannelDuplexHandler;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.SimpleChannelInboundHandler;
 import io.netty.handler.ssl.SslContext;
 import io.netty.handler.ssl.SslHandler;
-import io.netty.handler.timeout.IdleState;
-import io.netty.handler.timeout.IdleStateEvent;
 import java.net.SocketAddress;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -42,11 +39,11 @@ import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import org.apache.rocketmq.remoting.ChannelEventListener;
 import org.apache.rocketmq.remoting.InvokeCallback;
+import org.apache.rocketmq.remoting.RemotingChannel;
+import org.apache.rocketmq.remoting.RequestProcessor;
 import org.apache.rocketmq.remoting.RPCHook;
-import org.apache.rocketmq.remoting.RemotingServer;
 import org.apache.rocketmq.remoting.common.Pair;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
-import org.apache.rocketmq.remoting.common.RemotingUtil;
 import org.apache.rocketmq.remoting.common.SemaphoreReleaseOnlyOnce;
 import org.apache.rocketmq.remoting.common.ServiceThread;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
@@ -85,8 +82,8 @@ public abstract class NettyRemotingAbstract {
      * This container holds all processors per request code, aka, for each incoming request, we may look up the
      * responding processor in this map to handle the request.
      */
-    protected final HashMap<Integer/* request code */, Pair<NettyRequestProcessor, ExecutorService>> processorTable =
-        new HashMap<Integer, Pair<NettyRequestProcessor, ExecutorService>>(64);
+    protected final HashMap<Integer/* request code */, Pair<RequestProcessor, ExecutorService>> processorTable =
+        new HashMap<Integer, Pair<RequestProcessor, ExecutorService>>(64);
 
     /**
      * Executor to feed netty events to user defined {@link ChannelEventListener}.
@@ -97,7 +94,7 @@ public abstract class NettyRemotingAbstract {
      * The default request processor to use in case there is no exact match in {@link #processorTable} per request
      * code.
      */
-    protected Pair<NettyRequestProcessor, ExecutorService> defaultRequestProcessor;
+    protected Pair<RequestProcessor, ExecutorService> defaultRequestProcessor;
 
     /**
      * Used for async execute task for aysncInvokeMethod
@@ -170,10 +167,11 @@ public abstract class NettyRemotingAbstract {
      */
     public void processMessageReceived(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception {
         final RemotingCommand cmd = msg;
+        final RemotingChannel remotingChannel = new NettyChannelHandlerContextImpl(ctx);
         if (cmd != null) {
             switch (cmd.getType()) {
                 case REQUEST_COMMAND:
-                    processRequestCommand(ctx, cmd);
+                    processRequestCommand(remotingChannel, cmd);
                     break;
                 case RESPONSE_COMMAND:
                     processResponseCommand(ctx, cmd);
@@ -187,12 +185,14 @@ public abstract class NettyRemotingAbstract {
     /**
      * Process incoming request command issued by remote peer.
      *
-     * @param ctx channel handler context.
+     * @param remotingChannel channel handler context.
      * @param cmd request command.
      */
-    public void processRequestCommand(final ChannelHandlerContext ctx, final RemotingCommand cmd) {
-        final Pair<NettyRequestProcessor, ExecutorService> matched = this.processorTable.get(cmd.getCode());
-        final Pair<NettyRequestProcessor, ExecutorService> pair = null == matched ? this.defaultRequestProcessor : matched;
+    public void processRequestCommand(final RemotingChannel remotingChannel, final RemotingCommand cmd) {
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl) remotingChannel;
+        final ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
+        final Pair<RequestProcessor, ExecutorService> matched = this.processorTable.get(cmd.getCode());
+        final Pair<RequestProcessor, ExecutorService> pair = null == matched ? this.defaultRequestProcessor : matched;
         final int opaque = cmd.getOpaque();
 
         if (pair != null) {
@@ -205,7 +205,7 @@ public abstract class NettyRemotingAbstract {
                             rpcHook.doBeforeRequest(RemotingHelper.parseChannelRemoteAddr(ctx.channel()), cmd);
                         }
 
-                        final RemotingCommand response = pair.getObject1().processRequest(ctx, cmd);
+                        final RemotingCommand response = pair.getObject1().processRequest(remotingChannel, cmd);
                         if (rpcHook != null) {
                             rpcHook.doAfterResponse(RemotingHelper.parseChannelRemoteAddr(ctx.channel()), cmd, response);
                         }
@@ -620,16 +620,16 @@ public abstract class NettyRemotingAbstract {
                     if (event != null && listener != null) {
                         switch (event.getType()) {
                             case IDLE:
-                                listener.onChannelIdle(event.getRemoteAddr(), event.getChannel());
+                                listener.onChannelIdle(event.getRemoteAddr(), new NettyChannelImpl(event.getChannel()));
                                 break;
                             case CLOSE:
-                                listener.onChannelClose(event.getRemoteAddr(), event.getChannel());
+                                listener.onChannelClose(event.getRemoteAddr(), new NettyChannelImpl(event.getChannel()));
                                 break;
                             case CONNECT:
-                                listener.onChannelConnect(event.getRemoteAddr(), event.getChannel());
+                                listener.onChannelConnect(event.getRemoteAddr(), new NettyChannelImpl(event.getChannel()));
                                 break;
                             case EXCEPTION:
-                                listener.onChannelException(event.getRemoteAddr(), event.getChannel());
+                                listener.onChannelException(event.getRemoteAddr(), new NettyChannelImpl(event.getChannel()));
                                 break;
                             default:
                                 break;
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingClientAbstract.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingClientAbstract.java
index d53d40b..957b053 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingClientAbstract.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingClientAbstract.java
@@ -60,10 +60,6 @@ public abstract class NettyRemotingClientAbstract extends NettyRemotingAbstract
     private final AtomicReference<String> namesrvAddrChoosed = new AtomicReference<String>();
     private final AtomicInteger namesrvIndex = new AtomicInteger(initValueIndex());
     private final Lock lockNamesrvChannel = new ReentrantLock();
-    /**
-     * Used for async execute task for aysncInvokeMethod
-     */
-    private ExecutorService asyncExecuteService = ThreadUtils.newFixedThreadPool(5, 10000, "asyncExecute", false);
 
     private final Lock lockChannelTables = new ReentrantLock();
     private static final long LOCK_TIMEOUT_MILLIS = 3000;
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java
index 65504d1..e37f354 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java
@@ -34,17 +34,17 @@ import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
+import org.apache.rocketmq.remoting.ClientConfig;
 import org.apache.rocketmq.remoting.transport.rocketmq.NettyDecoder;
 import org.apache.rocketmq.remoting.transport.rocketmq.NettyEncoder;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.RequestProcessor;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.remoting.transport.NettyRemotingClientAbstract;
 import org.apache.rocketmq.remoting.util.ThreadUtils;
 
 public class Http2ClientImpl extends NettyRemotingClientAbstract implements RemotingClient {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
-    private NettyClientConfig nettyClientConfig;
+    private ClientConfig nettyClientConfig;
     private final Bootstrap bootstrap = new Bootstrap();
     private EventLoopGroup ioGroup;
     private ExecutorService publicExecutor;
@@ -53,7 +53,7 @@ public class Http2ClientImpl extends NettyRemotingClientAbstract implements Remo
     private DefaultEventExecutorGroup defaultEventExecutorGroup;
     private RPCHook rpcHook;
 
-    public Http2ClientImpl(final NettyClientConfig clientConfig,
+    public Http2ClientImpl(final ClientConfig clientConfig,
         final ChannelEventListener channelEventListener) {
         super(clientConfig.getClientOnewaySemaphoreValue(), clientConfig.getClientAsyncSemaphoreValue());
         init(clientConfig, channelEventListener);
@@ -64,7 +64,7 @@ public class Http2ClientImpl extends NettyRemotingClientAbstract implements Remo
     }
 
     @Override
-    public RemotingClient init(NettyClientConfig clientConfig, ChannelEventListener channelEventListener) {
+    public RemotingClient init(ClientConfig clientConfig, ChannelEventListener channelEventListener) {
         this.nettyClientConfig = clientConfig;
         this.channelEventListener = channelEventListener;
         this.ioGroup = new NioEventLoopGroup(clientConfig.getClientWorkerThreads(), ThreadUtils.newGenericThreadFactory("NettyClientEpollIoThreads",
@@ -240,13 +240,13 @@ public class Http2ClientImpl extends NettyRemotingClientAbstract implements Remo
     }
 
     @Override
-    public void registerProcessor(int requestCode, NettyRequestProcessor processor, ExecutorService executor) {
+    public void registerProcessor(int requestCode, RequestProcessor processor, ExecutorService executor) {
         ExecutorService executorThis = executor;
         if (null == executor) {
             executorThis = this.publicExecutor;
         }
 
-        Pair<NettyRequestProcessor, ExecutorService> pair = new Pair<NettyRequestProcessor, ExecutorService>(processor, executorThis);
+        Pair<RequestProcessor, ExecutorService> pair = new Pair<RequestProcessor, ExecutorService>(processor, executorThis);
         this.processorTable.put(requestCode, pair);
     }
 
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java
index bc6a5c1..8e5e4c7 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java
@@ -2,9 +2,7 @@ package org.apache.rocketmq.remoting.transport.http2;
 
 import io.netty.bootstrap.ServerBootstrap;
 import io.netty.buffer.PooledByteBufAllocator;
-import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelOption;
 import io.netty.channel.ChannelPipeline;
@@ -35,6 +33,7 @@ import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.ChannelEventListener;
 import org.apache.rocketmq.remoting.InvokeCallback;
 import org.apache.rocketmq.remoting.RPCHook;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.RemotingServer;
 import org.apache.rocketmq.remoting.common.Pair;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
@@ -42,10 +41,11 @@ import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
 import org.apache.rocketmq.remoting.netty.ChannelStatisticsHandler;
+import org.apache.rocketmq.remoting.netty.NettyChannelImpl;
 import org.apache.rocketmq.remoting.transport.rocketmq.NettyDecoder;
 import org.apache.rocketmq.remoting.transport.rocketmq.NettyEncoder;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.remoting.transport.NettyRemotingServerAbstract;
 import org.apache.rocketmq.remoting.util.JvmUtils;
@@ -59,13 +59,13 @@ public class Http2ServerImpl extends NettyRemotingServerAbstract implements Remo
     private EventLoopGroup ioGroup;
     private EventExecutorGroup workerGroup;
     private Class<? extends ServerSocketChannel> socketChannelClass;
-    private NettyServerConfig serverConfig;
+    private ServerConfig serverConfig;
     private ChannelEventListener channelEventListener;
     private ExecutorService publicExecutor;
     private int port;
     private RPCHook rpcHook;
 
-    public Http2ServerImpl(NettyServerConfig nettyServerConfig, ChannelEventListener channelEventListener) {
+    public Http2ServerImpl(ServerConfig nettyServerConfig, ChannelEventListener channelEventListener) {
         super(nettyServerConfig.getServerOnewaySemaphoreValue(), nettyServerConfig.getServerAsyncSemaphoreValue());
         init(nettyServerConfig, channelEventListener);
     }
@@ -75,7 +75,7 @@ public class Http2ServerImpl extends NettyRemotingServerAbstract implements Remo
     }
 
     @Override
-    public RemotingServer init(NettyServerConfig nettyServerConfig, ChannelEventListener channelEventListener) {
+    public RemotingServer init(ServerConfig nettyServerConfig, ChannelEventListener channelEventListener) {
         super.init(nettyServerConfig.getServerOnewaySemaphoreValue(), nettyServerConfig.getServerAsyncSemaphoreValue());
         this.serverBootstrap = new ServerBootstrap();
         this.serverConfig = nettyServerConfig;
@@ -120,18 +120,18 @@ public class Http2ServerImpl extends NettyRemotingServerAbstract implements Remo
     }
 
     @Override
-    public void registerProcessor(int requestCode, NettyRequestProcessor processor, ExecutorService executor) {
+    public void registerProcessor(int requestCode, RequestProcessor processor, ExecutorService executor) {
         ExecutorService executorThis = executor;
         if (null == executor) {
             executorThis = this.publicExecutor;
         }
-        Pair<NettyRequestProcessor, ExecutorService> pair = new Pair<NettyRequestProcessor, ExecutorService>(processor, executorThis);
+        Pair<RequestProcessor, ExecutorService> pair = new Pair<RequestProcessor, ExecutorService>(processor, executorThis);
         this.processorTable.put(requestCode, pair);
     }
 
     @Override
-    public void registerDefaultProcessor(NettyRequestProcessor processor, ExecutorService executor) {
-        this.defaultRequestProcessor = new Pair<NettyRequestProcessor, ExecutorService>(processor, executor);
+    public void registerDefaultProcessor(RequestProcessor processor, ExecutorService executor) {
+        this.defaultRequestProcessor = new Pair<RequestProcessor, ExecutorService>(processor, executor);
     }
 
     @Override
@@ -140,7 +140,7 @@ public class Http2ServerImpl extends NettyRemotingServerAbstract implements Remo
     }
 
     @Override
-    public Pair<NettyRequestProcessor, ExecutorService> getProcessorPair(int requestCode) {
+    public Pair<RequestProcessor, ExecutorService> getProcessorPair(int requestCode) {
         return processorTable.get(requestCode);
     }
 
@@ -150,21 +150,24 @@ public class Http2ServerImpl extends NettyRemotingServerAbstract implements Remo
     }
 
     @Override
-    public RemotingCommand invokeSync(final Channel channel, final RemotingCommand request, final long timeoutMillis)
+    public RemotingCommand invokeSync(final RemotingChannel remotingChannel, final RemotingCommand request,
+        final long timeoutMillis)
         throws InterruptedException, RemotingSendRequestException, RemotingTimeoutException {
-        return this.invokeSyncImpl(channel, request, timeoutMillis);
+        return this.invokeSyncImpl(((NettyChannelImpl) remotingChannel).getChannel(), request, timeoutMillis);
     }
 
     @Override
-    public void invokeAsync(Channel channel, RemotingCommand request, long timeoutMillis, InvokeCallback invokeCallback)
+    public void invokeAsync(RemotingChannel remotingChannel, RemotingCommand request, long timeoutMillis,
+        InvokeCallback invokeCallback)
         throws InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
-        this.invokeAsyncImpl(channel, request, timeoutMillis, invokeCallback);
+        this.invokeAsyncImpl(((NettyChannelImpl) remotingChannel).getChannel(), request, timeoutMillis, invokeCallback);
     }
 
     @Override
-    public void invokeOneway(Channel channel, RemotingCommand request, long timeoutMillis) throws InterruptedException,
+    public void invokeOneway(RemotingChannel remotingChannel, RemotingCommand request,
+        long timeoutMillis) throws InterruptedException,
         RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
-        this.invokeOnewayImpl(channel, request, timeoutMillis);
+        this.invokeOnewayImpl(((NettyChannelImpl) remotingChannel).getChannel(), request, timeoutMillis);
     }
 
     private void applyOptions(ServerBootstrap bootstrap) {
@@ -242,7 +245,7 @@ public class Http2ServerImpl extends NettyRemotingServerAbstract implements Remo
     }
 
     @Override
-    public void sendResponse(ChannelHandlerContext channel, RemotingCommand remotingCommand) {
+    public void sendResponse(RemotingChannel channel, RemotingCommand remotingCommand) {
 
     }
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java
index 55a1d3d..686bb01 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java
@@ -33,7 +33,6 @@ import java.io.IOException;
 import java.security.cert.CertificateException;
 import java.util.List;
 import java.util.concurrent.ExecutorService;
-import javax.xml.ws.AsyncHandler;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.ChannelEventListener;
@@ -46,8 +45,8 @@ import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.ClientConfig;
+import org.apache.rocketmq.remoting.RequestProcessor;
 import org.apache.rocketmq.remoting.netty.TlsHelper;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.remoting.transport.NettyRemotingClientAbstract;
@@ -56,7 +55,7 @@ import org.apache.rocketmq.remoting.util.ThreadUtils;
 public class NettyRemotingClient extends NettyRemotingClientAbstract implements RemotingClient {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
 
-    private NettyClientConfig nettyClientConfig;
+    private ClientConfig nettyClientConfig;
     private Bootstrap bootstrap = new Bootstrap();
     private EventLoopGroup eventLoopGroupWorker;
 
@@ -75,18 +74,18 @@ public class NettyRemotingClient extends NettyRemotingClientAbstract implements
         super();
     }
 
-    public NettyRemotingClient(final NettyClientConfig nettyClientConfig) {
+    public NettyRemotingClient(final ClientConfig nettyClientConfig) {
         this(nettyClientConfig, null);
     }
 
-    public NettyRemotingClient(final NettyClientConfig nettyClientConfig,
+    public NettyRemotingClient(final ClientConfig nettyClientConfig,
         final ChannelEventListener channelEventListener) {
         super(nettyClientConfig.getClientOnewaySemaphoreValue(), nettyClientConfig.getClientAsyncSemaphoreValue());
         init(nettyClientConfig, channelEventListener);
     }
 
     @Override
-    public RemotingClient init(NettyClientConfig nettyClientConfig, ChannelEventListener channelEventListener) {
+    public RemotingClient init(ClientConfig nettyClientConfig, ChannelEventListener channelEventListener) {
         this.nettyClientConfig = nettyClientConfig;
         this.channelEventListener = channelEventListener;
         this.eventLoopGroupWorker = new NioEventLoopGroup(nettyClientConfig.getClientWorkerThreads(), ThreadUtils.newGenericThreadFactory("NettyClientEpollIoThreads",
@@ -263,13 +262,13 @@ public class NettyRemotingClient extends NettyRemotingClientAbstract implements
     }
 
     @Override
-    public void registerProcessor(int requestCode, NettyRequestProcessor processor, ExecutorService executor) {
+    public void registerProcessor(int requestCode, RequestProcessor processor, ExecutorService executor) {
         ExecutorService executorThis = executor;
         if (null == executor) {
             executorThis = this.publicExecutor;
         }
 
-        Pair<NettyRequestProcessor, ExecutorService> pair = new Pair<NettyRequestProcessor, ExecutorService>(processor, executorThis);
+        Pair<RequestProcessor, ExecutorService> pair = new Pair<RequestProcessor, ExecutorService>(processor, executorThis);
         this.processorTable.put(requestCode, pair);
     }
 
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java
index 5387de4..2bd397c 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java
@@ -19,7 +19,6 @@ package org.apache.rocketmq.remoting.transport.rocketmq;
 import io.netty.bootstrap.ServerBootstrap;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.PooledByteBufAllocator;
-import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandlerContext;
@@ -45,6 +44,7 @@ import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.ChannelEventListener;
 import org.apache.rocketmq.remoting.InvokeCallback;
 import org.apache.rocketmq.remoting.RPCHook;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.RemotingServer;
 import org.apache.rocketmq.remoting.common.Pair;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
@@ -53,8 +53,10 @@ import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
 import org.apache.rocketmq.remoting.netty.FileRegionEncoder;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
+import org.apache.rocketmq.remoting.netty.NettyChannelImpl;
+import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.remoting.netty.TlsHelper;
 import org.apache.rocketmq.remoting.netty.TlsSystemConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
@@ -67,7 +69,7 @@ public class NettyRemotingServer extends NettyRemotingServerAbstract implements
     private ServerBootstrap serverBootstrap;
     private EventLoopGroup eventLoopGroupSelector;
     private EventLoopGroup eventLoopGroupBoss;
-    private NettyServerConfig nettyServerConfig;
+    private ServerConfig nettyServerConfig;
 
     private ExecutorService publicExecutor;
     private ChannelEventListener channelEventListener;
@@ -86,17 +88,17 @@ public class NettyRemotingServer extends NettyRemotingServerAbstract implements
         super();
     }
 
-    public NettyRemotingServer(final NettyServerConfig nettyServerConfig) {
+    public NettyRemotingServer(final ServerConfig nettyServerConfig) {
         this(nettyServerConfig, null);
     }
 
-    public NettyRemotingServer(final NettyServerConfig nettyServerConfig,
+    public NettyRemotingServer(final ServerConfig nettyServerConfig,
         final ChannelEventListener channelEventListener) {
         init(nettyServerConfig, channelEventListener);
     }
 
     @Override
-    public RemotingServer init(NettyServerConfig serverConfig, ChannelEventListener channelEventListener) {
+    public RemotingServer init(ServerConfig serverConfig, ChannelEventListener channelEventListener) {
         this.nettyServerConfig = serverConfig;
         super.init(nettyServerConfig.getServerOnewaySemaphoreValue(), nettyServerConfig.getServerAsyncSemaphoreValue());
         this.serverBootstrap = new ServerBootstrap();
@@ -221,19 +223,19 @@ public class NettyRemotingServer extends NettyRemotingServerAbstract implements
     }
 
     @Override
-    public void registerProcessor(int requestCode, NettyRequestProcessor processor, ExecutorService executor) {
+    public void registerProcessor(int requestCode, RequestProcessor processor, ExecutorService executor) {
         ExecutorService executorThis = executor;
         if (null == executor) {
             executorThis = this.publicExecutor;
         }
 
-        Pair<NettyRequestProcessor, ExecutorService> pair = new Pair<NettyRequestProcessor, ExecutorService>(processor, executorThis);
+        Pair<RequestProcessor, ExecutorService> pair = new Pair<RequestProcessor, ExecutorService>(processor, executorThis);
         this.processorTable.put(requestCode, pair);
     }
 
     @Override
-    public void registerDefaultProcessor(NettyRequestProcessor processor, ExecutorService executor) {
-        this.defaultRequestProcessor = new Pair<NettyRequestProcessor, ExecutorService>(processor, executor);
+    public void registerDefaultProcessor(RequestProcessor processor, ExecutorService executor) {
+        this.defaultRequestProcessor = new Pair<RequestProcessor, ExecutorService>(processor, executor);
     }
 
     @Override
@@ -242,31 +244,34 @@ public class NettyRemotingServer extends NettyRemotingServerAbstract implements
     }
 
     @Override
-    public Pair<NettyRequestProcessor, ExecutorService> getProcessorPair(int requestCode) {
+    public Pair<RequestProcessor, ExecutorService> getProcessorPair(int requestCode) {
         return processorTable.get(requestCode);
     }
 
     @Override
-    public RemotingCommand invokeSync(final Channel channel, final RemotingCommand request, final long timeoutMillis)
+    public RemotingCommand invokeSync(final RemotingChannel remotingChannel, final RemotingCommand request,
+        final long timeoutMillis)
         throws InterruptedException, RemotingSendRequestException, RemotingTimeoutException {
-        return this.invokeSyncImpl(channel, request, timeoutMillis);
+        return this.invokeSyncImpl(((NettyChannelImpl) remotingChannel).getChannel(), request, timeoutMillis);
     }
 
     @Override
-    public void invokeAsync(Channel channel, RemotingCommand request, long timeoutMillis, InvokeCallback invokeCallback)
+    public void invokeAsync(RemotingChannel remotingChannel, RemotingCommand request, long timeoutMillis,
+        InvokeCallback invokeCallback)
         throws InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
-        this.invokeAsyncImpl(channel, request, timeoutMillis, invokeCallback);
+        this.invokeAsyncImpl(((NettyChannelImpl) remotingChannel).getChannel(), request, timeoutMillis, invokeCallback);
     }
 
     @Override
-    public void invokeOneway(Channel channel, RemotingCommand request, long timeoutMillis) throws InterruptedException,
+    public void invokeOneway(RemotingChannel remotingChannel, RemotingCommand request,
+        long timeoutMillis) throws InterruptedException,
         RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
-        this.invokeOnewayImpl(channel, request, timeoutMillis);
+        this.invokeOnewayImpl(((NettyChannelImpl) remotingChannel).getChannel(), request, timeoutMillis);
     }
 
     @Override
     public ChannelEventListener getChannelEventListener() {
-        return channelEventListener;
+        return this.channelEventListener;
     }
 
     @Override
@@ -347,11 +352,13 @@ public class NettyRemotingServer extends NettyRemotingServerAbstract implements
     }
 
     @Override
-    public void sendResponse(ChannelHandlerContext channel, RemotingCommand response) {
+    public void sendResponse(RemotingChannel remotingChannel, RemotingCommand response) {
+        NettyChannelHandlerContextImpl channelHandlerContext = (NettyChannelHandlerContextImpl) remotingChannel;
+        ChannelHandlerContext ctx = channelHandlerContext.getChannelHandlerContext();
         if (response != null) {
             response.markResponseType();
             try {
-                channel.writeAndFlush(response).addListener(new ChannelFutureListener() {
+                ctx.writeAndFlush(response).addListener(new ChannelFutureListener() {
                     @Override
                     public void operationComplete(ChannelFuture future) throws Exception {
                         if (!future.isSuccess()) {
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/RemotingServerTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/RemotingServerTest.java
index b41dc37..f3384a2 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/RemotingServerTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/RemotingServerTest.java
@@ -17,7 +17,6 @@
 
 package org.apache.rocketmq.remoting;
 
-import io.netty.channel.ChannelHandlerContext;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executors;
 import org.apache.rocketmq.remoting.annotation.CFNullable;
@@ -26,9 +25,6 @@ import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
 import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
 import org.apache.rocketmq.remoting.netty.ResponseFuture;
 import org.apache.rocketmq.remoting.serialize.LanguageCode;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
@@ -46,12 +42,12 @@ public class RemotingServerTest {
     private static RemotingClient remotingClient;
 
     public static RemotingServer createRemotingServer() throws InterruptedException {
-        NettyServerConfig config = new NettyServerConfig();
+        ServerConfig config = new ServerConfig();
         RemotingServer remotingServer = new NettyRemotingServer(config);
-        remotingServer.registerProcessor(0, new NettyRequestProcessor() {
+        remotingServer.registerProcessor(0, new RequestProcessor() {
             @Override
-            public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) {
-                request.setRemark("Hi " + ctx.channel().remoteAddress());
+            public RemotingCommand processRequest(RemotingChannel ctx, RemotingCommand request) {
+                request.setRemark("Hi " + ctx.remoteAddress());
                 return request;
             }
 
@@ -67,10 +63,10 @@ public class RemotingServerTest {
     }
 
     public static RemotingClient createRemotingClient() {
-        return createRemotingClient(new NettyClientConfig());
+        return createRemotingClient(new ClientConfig());
     }
 
-    public static RemotingClient createRemotingClient(NettyClientConfig nettyClientConfig) {
+    public static RemotingClient createRemotingClient(ClientConfig nettyClientConfig) {
         RemotingClient client = new NettyRemotingClient(nettyClientConfig);
         client.start();
         return client;
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/TlsTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/TlsTest.java
index 50409f2..91bc63a 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/TlsTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/TlsTest.java
@@ -24,7 +24,6 @@ import java.io.IOException;
 import java.io.PrintWriter;
 import org.apache.rocketmq.remoting.common.TlsMode;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
 import org.apache.rocketmq.remoting.netty.TlsHelper;
 import org.apache.rocketmq.remoting.serialize.LanguageCode;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
@@ -94,7 +93,7 @@ public class TlsTest {
         tlsClientKeyPassword = "1234";
         tlsServerKeyPassword = "";
 
-        NettyClientConfig clientConfig = new NettyClientConfig();
+        ClientConfig clientConfig = new ClientConfig();
         clientConfig.setUseTLS(true);
 
         if ("serverRejectsUntrustedClientCert".equals(name.getMethodName())) {
@@ -174,7 +173,7 @@ public class TlsTest {
         requestThenAssertResponse();
 
         //Start another client
-        NettyClientConfig clientConfig = new NettyClientConfig();
+        ClientConfig clientConfig = new ClientConfig();
         clientConfig.setUseTLS(true);
         RemotingClient remotingClient = RemotingServerTest.createRemotingClient(clientConfig);
         requestThenAssertResponse(remotingClient);
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstractTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstractTest.java
index 2b96abd..2fd36b7 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstractTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstractTest.java
@@ -17,6 +17,7 @@
 package org.apache.rocketmq.remoting.netty;
 
 import java.util.concurrent.Semaphore;
+import org.apache.rocketmq.remoting.ClientConfig;
 import org.apache.rocketmq.remoting.InvokeCallback;
 import org.apache.rocketmq.remoting.common.SemaphoreReleaseOnlyOnce;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
@@ -32,7 +33,7 @@ import static org.mockito.Mockito.when;
 @RunWith(MockitoJUnitRunner.class)
 public class NettyRemotingAbstractTest {
     @Spy
-    private NettyRemotingAbstract remotingAbstract = new NettyRemotingClient(new NettyClientConfig());
+    private NettyRemotingAbstract remotingAbstract = new NettyRemotingClient(new ClientConfig());
 
     @Test
     public void testProcessResponseCommand() throws InterruptedException {
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingClientTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingClientTest.java
index d0a7ed7..13bccca 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingClientTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/netty/NettyRemotingClientTest.java
@@ -16,9 +16,9 @@
  */
 package org.apache.rocketmq.remoting.netty;
 
-import java.lang.reflect.Field;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import org.apache.rocketmq.remoting.ClientConfig;
 import org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingClient;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -28,7 +28,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 @RunWith(MockitoJUnitRunner.class)
 public class NettyRemotingClientTest {
-    private NettyRemotingClient remotingClient = new NettyRemotingClient(new NettyClientConfig());
+    private NettyRemotingClient remotingClient = new NettyRemotingClient(new ClientConfig());
 
     @Test
     public void testSetCallbackExecutor() throws NoSuchFieldException, IllegalAccessException {        
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
index cb8d662..c1ccb4a 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
@@ -30,8 +30,8 @@ import org.apache.rocketmq.remoting.RemotingClient;
 import org.apache.rocketmq.remoting.RemotingClientFactory;
 import org.apache.rocketmq.remoting.RemotingServer;
 import org.apache.rocketmq.remoting.RemotingServerFactory;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.ClientConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.snode.client.ClientHousekeepingService;
 import org.apache.rocketmq.snode.client.ConsumerIdsChangeListener;
 import org.apache.rocketmq.snode.client.ConsumerManager;
@@ -55,8 +55,8 @@ public class SnodeController {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
 
     private final SnodeConfig snodeConfig;
-    private final NettyServerConfig nettyServerConfig;
-    private final NettyClientConfig nettyClientConfig;
+    private final ServerConfig nettyServerConfig;
+    private final ClientConfig nettyClientConfig;
     private RemotingClient remotingClient;
     private RemotingServer snodeServer;
     private ExecutorService sendMessageExecutor;
@@ -80,8 +80,8 @@ public class SnodeController {
     private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl(
         "SnodeControllerScheduledThread"));
 
-    public SnodeController(NettyServerConfig nettyServerConfig,
-        NettyClientConfig nettyClientConfig,
+    public SnodeController(ServerConfig nettyServerConfig,
+        ClientConfig nettyClientConfig,
         SnodeConfig snodeConfig) {
         this.nettyClientConfig = nettyClientConfig;
         this.nettyServerConfig = nettyServerConfig;
@@ -159,7 +159,7 @@ public class SnodeController {
     }
 
     public boolean initialize() {
-        this.snodeServer = RemotingServerFactory.createInstance().init(this.nettyServerConfig, null);
+        this.snodeServer = RemotingServerFactory.createInstance().init(this.nettyServerConfig, this.clientHousekeepingService);
         this.registerProcessor();
         return true;
     }
@@ -229,7 +229,7 @@ public class SnodeController {
         this.subscriptionGroupManager = subscriptionGroupManager;
     }
 
-    public NettyClientConfig getNettyClientConfig() {
+    public ClientConfig getNettyClientConfig() {
         return nettyClientConfig;
     }
 
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java
index ddbeef8..8ccb34e 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java
@@ -32,8 +32,8 @@ import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.common.TlsMode;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.ClientConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.remoting.netty.TlsSystemConfig;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.snode.config.SnodeConfig;
@@ -81,8 +81,8 @@ public class SnodeStartup {
         }
 
         final SnodeConfig snodeConfig = new SnodeConfig();
-        final NettyServerConfig nettyServerConfig = new NettyServerConfig();
-        final NettyClientConfig nettyClientConfig = new NettyClientConfig();
+        final ServerConfig nettyServerConfig = new ServerConfig();
+        final ClientConfig nettyClientConfig = new ClientConfig();
 
         nettyServerConfig.setListenPort(snodeConfig.getListenPort());
 
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientChannelInfo.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientChannelInfo.java
index 16d8cde..a0d28e5 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientChannelInfo.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientChannelInfo.java
@@ -16,28 +16,28 @@
  */
 package org.apache.rocketmq.snode.client;
 
-import io.netty.channel.Channel;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.serialize.LanguageCode;
 
 public class ClientChannelInfo {
-    private final Channel channel;
+    private final RemotingChannel channel;
     private final String clientId;
     private final LanguageCode language;
     private final int version;
     private volatile long lastUpdateTimestamp = System.currentTimeMillis();
 
-    public ClientChannelInfo(Channel channel) {
+    public ClientChannelInfo(RemotingChannel channel) {
         this(channel, null, null, 0);
     }
 
-    public ClientChannelInfo(Channel channel, String clientId, LanguageCode language, int version) {
+    public ClientChannelInfo(RemotingChannel channel, String clientId, LanguageCode language, int version) {
         this.channel = channel;
         this.clientId = clientId;
         this.language = language;
         this.version = version;
     }
 
-    public Channel getChannel() {
+    public RemotingChannel getChannel() {
         return channel;
     }
 
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java
index 02598b9..3a86a88 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java
@@ -25,6 +25,9 @@ import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.ChannelEventListener;
+import org.apache.rocketmq.remoting.RemotingChannel;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+import org.apache.rocketmq.remoting.netty.NettyChannelImpl;
 
 public class ClientHousekeepingService implements ChannelEventListener {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
@@ -62,24 +65,34 @@ public class ClientHousekeepingService implements ChannelEventListener {
     }
 
     @Override
-    public void onChannelConnect(String remoteAddr, Channel channel) {
+    public void onChannelConnect(String remoteAddr, RemotingChannel channel) {
+        log.info("Remoting channel connected: {}", RemotingHelper.parseChannelRemoteAddr(channel.remoteAddress()));
 
     }
 
     @Override
-    public void onChannelClose(String remoteAddr, Channel channel) {
+    public void onChannelClose(String remoteAddr, RemotingChannel remotingChannel) {
+        NettyChannelImpl nettyChannel = (NettyChannelImpl) remotingChannel;
+        Channel channel = nettyChannel.getChannel();
+        log.info("Remoting channel closed: {}", RemotingHelper.parseChannelRemoteAddr(channel.remoteAddress()));
         this.producerManager.doChannelCloseEvent(remoteAddr, channel);
         this.producerManager.doChannelCloseEvent(remoteAddr, channel);
     }
 
     @Override
-    public void onChannelException(String remoteAddr, Channel channel) {
+    public void onChannelException(String remoteAddr, RemotingChannel remotingChannel) {
+        NettyChannelImpl nettyChannel = (NettyChannelImpl) remotingChannel;
+        Channel channel = nettyChannel.getChannel();
+        log.info("Remoting channel exception: {}", RemotingHelper.parseChannelRemoteAddr(channel.remoteAddress()));
         this.producerManager.doChannelCloseEvent(remoteAddr, channel);
         this.consumerManager.doChannelCloseEvent(remoteAddr, channel);
     }
 
     @Override
-    public void onChannelIdle(String remoteAddr, Channel channel) {
+    public void onChannelIdle(String remoteAddr, RemotingChannel remotingChannel) {
+        NettyChannelImpl nettyChannel = (NettyChannelImpl) remotingChannel;
+        Channel channel = nettyChannel.getChannel();
+        log.info("Remoting channel idle: {}", RemotingHelper.parseChannelRemoteAddr(channel.remoteAddress()));
         this.producerManager.doChannelCloseEvent(remoteAddr, channel);
         this.consumerManager.doChannelCloseEvent(remoteAddr, channel);
     }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java
index 89b02fd..5298945 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java
@@ -31,13 +31,14 @@ import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
 import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingChannel;
 
 public class ConsumerGroupInfo {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
     private final String groupName;
     private final ConcurrentMap<String/* Topic */, SubscriptionData> subscriptionTable =
         new ConcurrentHashMap<>();
-    private final ConcurrentMap<Channel, ClientChannelInfo> channelInfoTable =
+    private final ConcurrentMap<RemotingChannel, ClientChannelInfo> channelInfoTable =
         new ConcurrentHashMap<>(16);
     private volatile ConsumeType consumeType;
     private volatile MessageModel messageModel;
@@ -53,9 +54,9 @@ public class ConsumerGroupInfo {
     }
 
     public ClientChannelInfo findChannel(final String clientId) {
-        Iterator<Entry<Channel, ClientChannelInfo>> it = this.channelInfoTable.entrySet().iterator();
+        Iterator<Entry<RemotingChannel, ClientChannelInfo>> it = this.channelInfoTable.entrySet().iterator();
         while (it.hasNext()) {
-            Entry<Channel, ClientChannelInfo> next = it.next();
+            Entry<RemotingChannel, ClientChannelInfo> next = it.next();
             if (next.getValue().getClientId().equals(clientId)) {
                 return next.getValue();
             }
@@ -68,12 +69,12 @@ public class ConsumerGroupInfo {
         return subscriptionTable;
     }
 
-    public ConcurrentMap<Channel, ClientChannelInfo> getChannelInfoTable() {
+    public ConcurrentMap<RemotingChannel, ClientChannelInfo> getChannelInfoTable() {
         return channelInfoTable;
     }
 
-    public List<Channel> getAllChannel() {
-        List<Channel> result = new ArrayList<>();
+    public List<RemotingChannel> getAllChannel() {
+        List<RemotingChannel> result = new ArrayList<>();
 
         result.addAll(this.channelInfoTable.keySet());
 
@@ -83,10 +84,10 @@ public class ConsumerGroupInfo {
     public List<String> getAllClientId() {
         List<String> result = new ArrayList<>();
 
-        Iterator<Entry<Channel, ClientChannelInfo>> it = this.channelInfoTable.entrySet().iterator();
+        Iterator<Entry<RemotingChannel, ClientChannelInfo>> it = this.channelInfoTable.entrySet().iterator();
 
         while (it.hasNext()) {
-            Entry<Channel, ClientChannelInfo> entry = it.next();
+            Entry<RemotingChannel, ClientChannelInfo> entry = it.next();
             ClientChannelInfo clientChannelInfo = entry.getValue();
             result.add(clientChannelInfo.getClientId());
         }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java
index a0bab83..939dcc0 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java
@@ -30,6 +30,7 @@ import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
 import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.common.RemotingUtil;
 
@@ -144,19 +145,19 @@ public class ConsumerManager {
             Entry<String, ConsumerGroupInfo> next = it.next();
             String group = next.getKey();
             ConsumerGroupInfo consumerGroupInfo = next.getValue();
-            ConcurrentMap<Channel, ClientChannelInfo> channelInfoTable =
+            ConcurrentMap<RemotingChannel, ClientChannelInfo> channelInfoTable =
                 consumerGroupInfo.getChannelInfoTable();
 
-            Iterator<Entry<Channel, ClientChannelInfo>> itChannel = channelInfoTable.entrySet().iterator();
+            Iterator<Entry<RemotingChannel, ClientChannelInfo>> itChannel = channelInfoTable.entrySet().iterator();
             while (itChannel.hasNext()) {
-                Entry<Channel, ClientChannelInfo> nextChannel = itChannel.next();
+                Entry<RemotingChannel, ClientChannelInfo> nextChannel = itChannel.next();
                 ClientChannelInfo clientChannelInfo = nextChannel.getValue();
                 long diff = System.currentTimeMillis() - clientChannelInfo.getLastUpdateTimestamp();
                 if (diff > CHANNEL_EXPIRED_TIMEOUT) {
                     log.warn(
                         "SCAN: Remove expired channel from ConsumerManager consumerTable. channel={}, consumerGroup={}",
-                        RemotingHelper.parseChannelRemoteAddr(clientChannelInfo.getChannel()), group);
-                    RemotingUtil.closeChannel(clientChannelInfo.getChannel());
+                        RemotingHelper.parseChannelRemoteAddr(clientChannelInfo.getChannel().remoteAddress()), group);
+                    clientChannelInfo.getChannel().close();
                     itChannel.remove();
                 }
             }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java
index 1f46c95..df74e93 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java
@@ -16,10 +16,8 @@
  */
 package org.apache.rocketmq.snode.client;
 
-import io.netty.channel.Channel;
-import java.util.Collection;
 import java.util.List;
-import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.snode.SnodeController;
 
 //TODO Filter implementation
@@ -40,9 +38,9 @@ public class DefaultConsumerIdsChangeListener implements ConsumerIdsChangeListen
                 if (args == null || args.length < 1) {
                     return;
                 }
-                List<Channel> channels = (List<Channel>) args[0];
+                List<RemotingChannel> channels = (List<RemotingChannel>) args[0];
                 if (channels != null && snodeController.getSnodeConfig().isNotifyConsumerIdsChangedEnable()) {
-                    for (Channel chl : channels) {
+                    for (RemotingChannel chl : channels) {
                         this.snodeController.getEnodeService().notifyConsumerIdsChanged(chl, group);
                     }
                 }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java
index 4513c7d..b8ec6ef 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java
@@ -29,6 +29,7 @@ import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.common.utils.PositiveAtomicCounter;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.common.RemotingUtil;
 
@@ -37,7 +38,7 @@ public class ProducerManager {
     private static final long LOCK_TIMEOUT_MILLIS = 3000;
     private static final long CHANNEL_EXPIRED_TIMEOUT = 1000 * 120;
     private final Lock groupChannelLock = new ReentrantLock();
-    private final HashMap<String /* group name */, HashMap<Channel, ClientChannelInfo>> groupChannelTable =
+    private final HashMap<String /* group name */, HashMap<RemotingChannel, ClientChannelInfo>> groupChannelTable =
         new HashMap<>();
     private PositiveAtomicCounter positiveAtomicCounter = new PositiveAtomicCounter();
 
@@ -45,9 +46,9 @@ public class ProducerManager {
 
     }
 
-    public HashMap<String, HashMap<Channel, ClientChannelInfo>> getGroupChannelTable() {
-        HashMap<String /* group name */, HashMap<Channel, ClientChannelInfo>> newGroupChannelTable =
-            new HashMap<String, HashMap<Channel, ClientChannelInfo>>();
+    public HashMap<String, HashMap<RemotingChannel, ClientChannelInfo>> getGroupChannelTable() {
+        HashMap<String /* group name */, HashMap<RemotingChannel, ClientChannelInfo>> newGroupChannelTable =
+            new HashMap<>();
         try {
             if (this.groupChannelLock.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
                 try {
@@ -66,14 +67,14 @@ public class ProducerManager {
         try {
             if (this.groupChannelLock.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
                 try {
-                    for (final Entry<String, HashMap<Channel, ClientChannelInfo>> entry : this.groupChannelTable
+                    for (final Entry<String, HashMap<RemotingChannel, ClientChannelInfo>> entry : this.groupChannelTable
                         .entrySet()) {
                         final String group = entry.getKey();
-                        final HashMap<Channel, ClientChannelInfo> chlMap = entry.getValue();
+                        final HashMap<RemotingChannel, ClientChannelInfo> chlMap = entry.getValue();
 
-                        Iterator<Entry<Channel, ClientChannelInfo>> it = chlMap.entrySet().iterator();
+                        Iterator<Entry<RemotingChannel, ClientChannelInfo>> it = chlMap.entrySet().iterator();
                         while (it.hasNext()) {
-                            Entry<Channel, ClientChannelInfo> item = it.next();
+                            Entry<RemotingChannel, ClientChannelInfo> item = it.next();
                             // final Integer id = item.getKey();
                             final ClientChannelInfo info = item.getValue();
 
@@ -82,8 +83,8 @@ public class ProducerManager {
                                 it.remove();
                                 log.warn(
                                     "SCAN: remove expired channel[{}] from ProducerManager groupChannelTable, producer group name: {}",
-                                    RemotingHelper.parseChannelRemoteAddr(info.getChannel()), group);
-                                RemotingUtil.closeChannel(info.getChannel());
+                                    RemotingHelper.parseChannelRemoteAddr(info.getChannel().remoteAddress()), group);
+                                info.getChannel().close();
                             }
                         }
                     }
@@ -103,10 +104,10 @@ public class ProducerManager {
             try {
                 if (this.groupChannelLock.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
                     try {
-                        for (final Entry<String, HashMap<Channel, ClientChannelInfo>> entry : this.groupChannelTable
+                        for (final Entry<String, HashMap<RemotingChannel, ClientChannelInfo>> entry : this.groupChannelTable
                             .entrySet()) {
                             final String group = entry.getKey();
-                            final HashMap<Channel, ClientChannelInfo> clientChannelInfoTable =
+                            final HashMap<RemotingChannel, ClientChannelInfo> clientChannelInfoTable =
                                 entry.getValue();
                             final ClientChannelInfo clientChannelInfo =
                                 clientChannelInfoTable.remove(channel);
@@ -135,7 +136,7 @@ public class ProducerManager {
 
             if (this.groupChannelLock.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
                 try {
-                    HashMap<Channel, ClientChannelInfo> channelTable = this.groupChannelTable.get(group);
+                    HashMap<RemotingChannel, ClientChannelInfo> channelTable = this.groupChannelTable.get(group);
                     if (null == channelTable) {
                         channelTable = new HashMap<>();
                         this.groupChannelTable.put(group, channelTable);
@@ -166,7 +167,7 @@ public class ProducerManager {
         try {
             if (this.groupChannelLock.tryLock(LOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
                 try {
-                    HashMap<Channel, ClientChannelInfo> channelTable = this.groupChannelTable.get(group);
+                    HashMap<RemotingChannel, ClientChannelInfo> channelTable = this.groupChannelTable.get(group);
                     if (null != channelTable && !channelTable.isEmpty()) {
                         ClientChannelInfo old = channelTable.remove(clientChannelInfo.getChannel());
                         if (old != null) {
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
index 3e53795..bc58a5c 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
@@ -33,17 +33,19 @@ import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetRequestHea
 import org.apache.rocketmq.common.protocol.header.UpdateConsumerOffsetResponseHeader;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.snode.SnodeController;
 import org.apache.rocketmq.snode.client.ConsumerGroupInfo;
 
-public class ConsumerManageProcessor implements NettyRequestProcessor {
+public class ConsumerManageProcessor implements RequestProcessor {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
 
     private final SnodeController snodeController;
@@ -53,9 +55,12 @@ public class ConsumerManageProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request)
-        throws InterruptedException, RemotingTimeoutException,
-        RemotingSendRequestException, RemotingConnectException, RemotingCommandException {
+    public RemotingCommand processRequest(RemotingChannel remotingChannel,
+        RemotingCommand request) throws InterruptedException, RemotingTimeoutException,
+        RemotingSendRequestException, RemotingConnectException, RemotingCommandException  {
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl)remotingChannel;
+        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
+
         switch (request.getCode()) {
             case RequestCode.GET_CONSUMER_LIST_BY_GROUP:
                 return this.getConsumerListByGroup(ctx, request);
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
index a0af26a..c69ba5d 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
@@ -17,9 +17,7 @@
 package org.apache.rocketmq.snode.processor;
 
 import io.netty.channel.ChannelHandlerContext;
-import org.apache.rocketmq.common.MixAll;
 import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.common.constant.PermName;
 import org.apache.rocketmq.common.protocol.RequestCode;
 import org.apache.rocketmq.common.protocol.ResponseCode;
 import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader;
@@ -28,16 +26,19 @@ import org.apache.rocketmq.common.protocol.heartbeat.ConsumerData;
 import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData;
 import org.apache.rocketmq.common.protocol.heartbeat.ProducerData;
 import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
-import org.apache.rocketmq.common.sysflag.TopicSysFlag;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
+import org.apache.rocketmq.remoting.netty.NettyChannelImpl;
+import org.apache.rocketmq.remoting.RequestProcessor;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.snode.SnodeController;
 import org.apache.rocketmq.snode.client.ClientChannelInfo;
 
-public class HearbeatProcessor implements NettyRequestProcessor {
+public class HearbeatProcessor implements RequestProcessor {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
     private final SnodeController snodeController;
 
@@ -46,7 +47,10 @@ public class HearbeatProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) throws Exception {
+    public RemotingCommand processRequest(RemotingChannel remotingChannel,
+        RemotingCommand request) throws Exception {
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl)remotingChannel;
+        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
         switch (request.getCode()) {
             case RequestCode.HEART_BEAT:
                 return heartbeat(ctx, request);
@@ -61,7 +65,7 @@ public class HearbeatProcessor implements NettyRequestProcessor {
     private RemotingCommand heartbeat(ChannelHandlerContext ctx, RemotingCommand request) {
         HeartbeatData heartbeatData = HeartbeatData.decode(request.getBody(), HeartbeatData.class);
         ClientChannelInfo clientChannelInfo = new ClientChannelInfo(
-            ctx.channel(),
+            new NettyChannelImpl(ctx.channel()),
             heartbeatData.getClientID(),
             request.getLanguage(),
             request.getVersion()
@@ -75,7 +79,6 @@ public class HearbeatProcessor implements NettyRequestProcessor {
         }
 
         if (heartbeatData.getConsumerDataSet() != null) {
-            log.info("ConsumerDataSet: {}", heartbeatData.getConsumerDataSet());
             for (ConsumerData data : heartbeatData.getConsumerDataSet()) {
                 SubscriptionGroupConfig subscriptionGroupConfig =
                     this.snodeController.getSubscriptionGroupManager().findSubscriptionGroupConfig(
@@ -115,7 +118,7 @@ public class HearbeatProcessor implements NettyRequestProcessor {
             (UnregisterClientRequestHeader) request.decodeCommandCustomHeader(UnregisterClientRequestHeader.class);
 
         ClientChannelInfo clientChannelInfo = new ClientChannelInfo(
-            ctx.channel(),
+            new NettyChannelImpl(ctx.channel()),
             requestHeader.getClientID(),
             request.getLanguage(),
             request.getVersion());
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
index a636f87..951d175 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
@@ -27,12 +27,18 @@ import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
 import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.RemotingChannel;
+import org.apache.rocketmq.remoting.RequestProcessor;
+import org.apache.rocketmq.remoting.exception.RemotingCommandException;
+import org.apache.rocketmq.remoting.exception.RemotingConnectException;
+import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
+import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.remoting.netty.NettyChannelHandlerContextImpl;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.snode.SnodeController;
 import org.apache.rocketmq.snode.client.ConsumerGroupInfo;
 
-public class PullMessageProcessor implements NettyRequestProcessor {
+public class PullMessageProcessor implements RequestProcessor {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
 
     private final SnodeController snodeController;
@@ -42,7 +48,11 @@ public class PullMessageProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) throws Exception {
+    public RemotingCommand processRequest(RemotingChannel remotingChannel,
+        RemotingCommand request) throws RemotingCommandException {
+        NettyChannelHandlerContextImpl nettyChannelHandlerContext = (NettyChannelHandlerContextImpl) remotingChannel;
+        ChannelHandlerContext ctx = nettyChannelHandlerContext.getChannelHandlerContext();
+
         RemotingCommand response = RemotingCommand.createResponseCommand(PullMessageResponseHeader.class);
 
         final PullMessageRequestHeader requestHeader =
@@ -90,7 +100,7 @@ public class PullMessageProcessor implements NettyRequestProcessor {
         CompletableFuture<RemotingCommand> responseFuture = snodeController.getEnodeService().pullMessage(ctx, request);
         responseFuture.whenComplete((data, ex) -> {
             if (ex == null) {
-                this.snodeController.getSnodeServer().sendResponse(ctx, data);
+                this.snodeController.getSnodeServer().sendResponse(remotingChannel, data);
             } else {
                 log.error("Pull message error: {}", ex);
             }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
index 81bdcf0..6641b2a 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
@@ -20,11 +20,12 @@ import java.util.concurrent.CompletableFuture;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
-import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
+import org.apache.rocketmq.remoting.RemotingChannel;
+import org.apache.rocketmq.remoting.RequestProcessor;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.snode.SnodeController;
 
-public class SendMessageProcessor implements NettyRequestProcessor {
+public class SendMessageProcessor implements RequestProcessor {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
 
     private final SnodeController snodeController;
@@ -34,11 +35,11 @@ public class SendMessageProcessor implements NettyRequestProcessor {
     }
 
     @Override
-    public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) {
+    public RemotingCommand processRequest(RemotingChannel remotingChannel, RemotingCommand request) {
         CompletableFuture<RemotingCommand> responseFuture = snodeController.getEnodeService().sendMessage(request);
         responseFuture.whenComplete((data, ex) -> {
             if (ex == null) {
-                snodeController.getSnodeServer().sendResponse(ctx, data);
+                snodeController.getSnodeServer().sendResponse(remotingChannel, data);
             } else {
                 log.error("Send Message error: {}", ex);
             }
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java
index cf7c1e9..add1cde 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java
@@ -15,12 +15,12 @@ package org.apache.rocketmq.snode.service;/*
  * limitations under the License.
  */
 
-import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandlerContext;
 import java.util.concurrent.CompletableFuture;
 import org.apache.rocketmq.client.exception.MQBrokerException;
 import org.apache.rocketmq.common.TopicConfig;
 import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
@@ -35,7 +35,7 @@ public interface EnodeService {
     CompletableFuture<RemotingCommand> pullMessage(final ChannelHandlerContext context,
         final RemotingCommand remotingCommand);
 
-    void notifyConsumerIdsChanged(final Channel channel, final String consumerGroup);
+    void notifyConsumerIdsChanged(final RemotingChannel channel, final String consumerGroup);
 
     RemotingCommand creatTopic(String enodeName, TopicConfig topicConfig)throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException ;
 
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
index 3729cc4..cd4a519 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
@@ -42,6 +42,7 @@ import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.InvokeCallback;
+import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
@@ -136,7 +137,7 @@ public class EnodeServiceImpl implements EnodeService {
 
     @Override
     public void notifyConsumerIdsChanged(
-        final Channel channel,
+        final RemotingChannel channel,
         final String consumerGroup) {
         if (null == consumerGroup) {
             log.error("NotifyConsumerIdsChanged consumerGroup is null");
diff --git a/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java
index 9dcb2d8..edbd971 100644
--- a/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java
+++ b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java
@@ -30,8 +30,8 @@ import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.common.namesrv.NamesrvConfig;
 import org.apache.rocketmq.namesrv.NamesrvController;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.ClientConfig;
+import org.apache.rocketmq.remoting.ServerConfig;
 import org.apache.rocketmq.store.config.MessageStoreConfig;
 import org.apache.rocketmq.test.util.MQAdmin;
 import org.apache.rocketmq.test.util.TestUtils;
@@ -101,7 +101,7 @@ public class IntegrationTestBase {
     public static NamesrvController createAndStartNamesrv() {
         String baseDir = createBaseDir();
         NamesrvConfig namesrvConfig = new NamesrvConfig();
-        NettyServerConfig nameServerNettyServerConfig = new NettyServerConfig();
+        ServerConfig nameServerNettyServerConfig = new ServerConfig();
         namesrvConfig.setKvConfigPath(baseDir + SEP + "namesrv" + SEP + "kvConfig.json");
         namesrvConfig.setConfigStorePath(baseDir + SEP + "namesrv" + SEP + "namesrv.properties");
 
@@ -123,8 +123,8 @@ public class IntegrationTestBase {
     public static BrokerController createAndStartBroker(String nsAddr) {
         String baseDir = createBaseDir();
         BrokerConfig brokerConfig = new BrokerConfig();
-        NettyServerConfig nettyServerConfig = new NettyServerConfig();
-        NettyClientConfig nettyClientConfig = new NettyClientConfig();
+        ServerConfig nettyServerConfig = new ServerConfig();
+        ClientConfig nettyClientConfig = new ClientConfig();
         MessageStoreConfig storeConfig = new MessageStoreConfig();
         brokerConfig.setBrokerName(BROKER_NAME_PREFIX + BROKER_INDEX.getAndIncrement());
         brokerConfig.setBrokerIP1("127.0.0.1");


[rocketmq] 03/14: Modify Serviceloader implementation

Posted by du...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a commit to branch snode
in repository https://gitbox.apache.org/repos/asf/rocketmq.git

commit c668abb8cff8da1f040a89fd0043893a81b6aece
Author: duhengforever <du...@gmail.com>
AuthorDate: Wed Dec 12 20:55:42 2018 +0800

    Modify Serviceloader implementation
---
 .../apache/rocketmq/broker/BrokerController.java   |  8 +--
 .../apache/rocketmq/broker/out/BrokerOuterAPI.java |  4 +-
 .../rocketmq/broker/util/ServiceProviderTest.java  |  1 +
 .../apache/rocketmq/namesrv/NamesrvController.java |  2 +-
 .../apache/rocketmq/remoting/RemotingClient.java   |  2 +-
 .../rocketmq/remoting/RemotingClientFactory.java   | 16 +++---
 .../apache/rocketmq/remoting/RemotingServer.java   |  2 +-
 .../rocketmq/remoting/RemotingServerFactory.java   | 24 ++++-----
 .../rocketmq/remoting/common/RemotingUtil.java     |  2 +
 .../remoting/transport/http2/Http2ClientImpl.java  |  3 +-
 .../remoting/transport/http2/Http2ServerImpl.java  |  3 +-
 .../transport/rocketmq/NettyRemotingClient.java    |  3 +-
 .../transport/rocketmq/NettyRemotingServer.java    |  3 +-
 .../rocketmq/remoting/util/RemotingUtil.java       |  6 ---
 .../rocketmq/remoting/util/ServiceProvider.java    | 58 +++++++++++++---------
 15 files changed, 70 insertions(+), 67 deletions(-)

diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
index 024ce67..1cbd39c 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
@@ -246,14 +246,14 @@ public class BrokerController {
         result = result && this.messageStore.load();
 
         if (result) {
-            this.remotingServer = RemotingServerFactory.getRemotingServer();
+            this.remotingServer = RemotingServerFactory.createInstance();
             this.remotingServer.init(this.nettyServerConfig, this.clientHousekeepingService);
 //            this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.clientHousekeepingService);
             NettyServerConfig fastConfig = (NettyServerConfig) this.nettyServerConfig.clone();
             fastConfig.setListenPort(nettyServerConfig.getListenPort() - 2);
-            this.fastRemotingServer = new NettyRemotingServer(fastConfig, this.clientHousekeepingService);
-//            this.fastRemotingServer = RemotingServerFactory.getRemotingServer();
-//            this.fastRemotingServer.init(this.nettyServerConfig, this.clientHousekeepingService);
+//            this.fastRemotingServer = new NettyRemotingServer(fastConfig, this.clientHousekeepingService);
+            this.fastRemotingServer = RemotingServerFactory.createInstance();
+            this.fastRemotingServer.init(fastConfig, this.clientHousekeepingService);
 
             this.sendMessageExecutor = new BrokerFixedThreadPoolExecutor(
                 this.brokerConfig.getSendMessageThreadPoolNums(),
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java b/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
index d157021..9edfcb8 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
@@ -71,9 +71,7 @@ public class BrokerOuterAPI {
     }
 
     public BrokerOuterAPI(final NettyClientConfig nettyClientConfig, RPCHook rpcHook) {
-        this.remotingClient = RemotingClientFactory.getClient();
-        this.remotingClient.init(nettyClientConfig, null);
-//        this.remotingClient = new NettyRemotingClient(nettyClientConfig);
+        this.remotingClient = RemotingClientFactory.createInstance().init(nettyClientConfig, null);
         this.remotingClient.registerRPCHook(rpcHook);
     }
 
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/util/ServiceProviderTest.java b/broker/src/test/java/org/apache/rocketmq/broker/util/ServiceProviderTest.java
index 22228a6..1437ffc 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/util/ServiceProviderTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/util/ServiceProviderTest.java
@@ -19,6 +19,7 @@ package org.apache.rocketmq.broker.util;
 
 import org.apache.rocketmq.broker.transaction.AbstractTransactionalMessageCheckListener;
 import org.apache.rocketmq.broker.transaction.TransactionalMessageService;
+import org.apache.rocketmq.remoting.util.ServiceProvider;
 import org.junit.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java
index 6faccf7..a329e70 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvController.java
@@ -77,7 +77,7 @@ public class NamesrvController {
 
         this.kvConfigManager.load();
 
-        this.remotingServer = RemotingServerFactory.getRemotingServer();
+        this.remotingServer = RemotingServerFactory.createInstance();
         this.remotingServer.init(this.nettyServerConfig, this.brokerHousekeepingService);
 //        this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.brokerHousekeepingService);
 
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java
index ab4e914..88bca57 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java
@@ -53,5 +53,5 @@ public interface RemotingClient extends RemotingService {
 
     boolean isChannelWritable(final String addr);
 
-    void init(NettyClientConfig nettyClientConfig, ChannelEventListener channelEventListener);
+    RemotingClient init(NettyClientConfig nettyClientConfig, ChannelEventListener channelEventListener);
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClientFactory.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClientFactory.java
index 5e87ec9..a766625 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClientFactory.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClientFactory.java
@@ -4,7 +4,7 @@ import java.util.Map;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
-import org.apache.rocketmq.remoting.util.RemotingUtil;
+import org.apache.rocketmq.remoting.common.RemotingUtil;
 import org.apache.rocketmq.remoting.util.ServiceProvider;
 
 public class RemotingClientFactory {
@@ -13,21 +13,21 @@ public class RemotingClientFactory {
     private RemotingClientFactory() {
     }
 
-    private static Map<String, RemotingClient> clients;
+    private static Map<String, String> paths;
 
     private static final String CLIENT_LOCATION = "META-INF/service/org.apache.rocketmq.remoting.RemotingClient";
 
     static {
         log.info("begin load client");
-        clients = ServiceProvider.load(CLIENT_LOCATION, RemotingClient.class);
-        log.info("end load client, size:{}", clients.size());
+        paths = ServiceProvider.loadPath(CLIENT_LOCATION);
+        log.info("end load client, size:{}", paths.size());
     }
 
-    public static RemotingClient getClient(String protocolType) {
-        return clients.get(protocolType);
+    public static RemotingClient createInstance(String protocol) {
+        return ServiceProvider.createInstance(paths.get(protocol), RemotingClient.class);
     }
 
-    public static RemotingClient getClient() {
-        return clients.get(RemotingUtil.DEFAULT_PROTOCOL);
+    public static RemotingClient createInstance() {
+        return ServiceProvider.createInstance(paths.get(RemotingUtil.DEFAULT_PROTOCOL), RemotingClient.class);
     }
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java
index 6a5fb91..0d5ff38 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServer.java
@@ -51,6 +51,6 @@ public interface RemotingServer extends RemotingService {
         throws InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException,
         RemotingSendRequestException;
 
-    void init(NettyServerConfig nettyServerConfig, ChannelEventListener channelEventListener);
+    RemotingServer init(NettyServerConfig nettyServerConfig, ChannelEventListener channelEventListener);
 
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java
index e7a7700..125d4e0 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java
@@ -4,7 +4,7 @@ import java.util.Map;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
-import org.apache.rocketmq.remoting.util.RemotingUtil;
+import org.apache.rocketmq.remoting.common.RemotingUtil;
 import org.apache.rocketmq.remoting.util.ServiceProvider;
 
 public class RemotingServerFactory {
@@ -14,27 +14,21 @@ public class RemotingServerFactory {
     private RemotingServerFactory() {
     }
 
-    private static Map<String, RemotingServer> servers;
-
-//    private static Map<String/*protocolType*/, String/*path*/ >
+    private static Map<String, String> protocolPathMap;
 
     private static final String SERVER_LOCATION = "META-INF/service/org.apache.rocketmq.remoting.RemotingServer";
 
     static {
         log.info("begin load server");
-        servers = ServiceProvider.load(SERVER_LOCATION, RemotingClient.class);
-        log.info("end load server, size:{}", servers.size());
+        protocolPathMap = ServiceProvider.loadPath(SERVER_LOCATION);
+        log.info("end load server, size:{}", protocolPathMap.size());
     }
 
-    public static RemotingServer getRemotingServer() {
-        return getRemotingServer(RemotingUtil.DEFAULT_PROTOCOL);
-    }
 
-    public static RemotingServer getRemotingServer(String protocolType) {
-        return servers.get(protocolType);
+    public static RemotingServer createInstance(String protocol) {
+        return ServiceProvider.createInstance(protocolPathMap.get(protocol), RemotingClient.class);
+    }
+    public static RemotingServer createInstance() {
+        return ServiceProvider.createInstance(protocolPathMap.get(RemotingUtil.DEFAULT_PROTOCOL), RemotingServer.class);
     }
-
-//    public static RemotingServer createNewInstance(String protocolType){
-//        return ServiceProvider.load()
-//    }
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingUtil.java b/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingUtil.java
index 3da3a18..88008ab 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingUtil.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingUtil.java
@@ -41,6 +41,8 @@ public class RemotingUtil {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
     private static boolean isLinuxPlatform = false;
     private static boolean isWindowsPlatform = false;
+    public static final String DEFAULT_PROTOCOL = "http2";
+    public static final String REMOTING_CHARSET = "UTF-8";
 
     static {
         if (OS_NAME != null && OS_NAME.toLowerCase().contains("linux")) {
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java
index b294958..65504d1 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java
@@ -64,7 +64,7 @@ public class Http2ClientImpl extends NettyRemotingClientAbstract implements Remo
     }
 
     @Override
-    public void init(NettyClientConfig clientConfig, ChannelEventListener channelEventListener) {
+    public RemotingClient init(NettyClientConfig clientConfig, ChannelEventListener channelEventListener) {
         this.nettyClientConfig = clientConfig;
         this.channelEventListener = channelEventListener;
         this.ioGroup = new NioEventLoopGroup(clientConfig.getClientWorkerThreads(), ThreadUtils.newGenericThreadFactory("NettyClientEpollIoThreads",
@@ -75,6 +75,7 @@ public class Http2ClientImpl extends NettyRemotingClientAbstract implements Remo
         this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(clientConfig.getClientWorkerThreads(),
             ThreadUtils.newGenericThreadFactory("NettyClientWorkerThreads", clientConfig.getClientWorkerThreads()));
         buildSslContext();
+        return this;
     }
 
     private void buildSslContext() {
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java
index 02c4fb6..6ff3d90 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ServerImpl.java
@@ -74,7 +74,7 @@ public class Http2ServerImpl extends NettyRemotingServerAbstract implements Remo
     }
 
     @Override
-    public void init(NettyServerConfig nettyServerConfig, ChannelEventListener channelEventListener) {
+    public RemotingServer init(NettyServerConfig nettyServerConfig, ChannelEventListener channelEventListener) {
         super.init(nettyServerConfig.getServerOnewaySemaphoreValue(), nettyServerConfig.getServerAsyncSemaphoreValue());
         this.serverBootstrap = new ServerBootstrap();
         this.serverConfig = nettyServerConfig;
@@ -100,6 +100,7 @@ public class Http2ServerImpl extends NettyRemotingServerAbstract implements Remo
             ThreadUtils.newGenericThreadFactory("NettyWorkerThreads", serverConfig.getServerWorkerThreads()));
         this.port = nettyServerConfig.getListenPort();
         buildHttp2SslContext();
+        return this;
     }
 
     private void buildHttp2SslContext() {
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java
index 14666d2..4e691f1 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java
@@ -86,7 +86,7 @@ public class NettyRemotingClient extends NettyRemotingClientAbstract implements
     }
 
     @Override
-    public void init(NettyClientConfig nettyClientConfig, ChannelEventListener channelEventListener) {
+    public RemotingClient init(NettyClientConfig nettyClientConfig, ChannelEventListener channelEventListener) {
         this.nettyClientConfig = nettyClientConfig;
         this.channelEventListener = channelEventListener;
         this.eventLoopGroupWorker = new NioEventLoopGroup(nettyClientConfig.getClientWorkerThreads(), ThreadUtils.newGenericThreadFactory("NettyClientEpollIoThreads",
@@ -107,6 +107,7 @@ public class NettyRemotingClient extends NettyRemotingClientAbstract implements
                 throw new RuntimeException("Failed to create SSLContext", e);
             }
         }
+        return this;
     }
 
     @Override
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java
index 9e7d419..d167b49 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingServer.java
@@ -95,7 +95,7 @@ public class NettyRemotingServer extends NettyRemotingServerAbstract implements
     }
 
     @Override
-    public void init(NettyServerConfig serverConfig, ChannelEventListener channelEventListener) {
+    public RemotingServer init(NettyServerConfig serverConfig, ChannelEventListener channelEventListener) {
         this.nettyServerConfig = serverConfig;
         super.init(nettyServerConfig.getServerOnewaySemaphoreValue(), nettyServerConfig.getServerAsyncSemaphoreValue());
         this.serverBootstrap = new ServerBootstrap();
@@ -126,6 +126,7 @@ public class NettyRemotingServer extends NettyRemotingServerAbstract implements
         this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(serverConfig.getServerWorkerThreads(),
             ThreadUtils.newGenericThreadFactory("NettyWorkerThreads", serverConfig.getServerWorkerThreads()));
         loadSslContext();
+        return this;
     }
 
     public void loadSslContext() {
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/util/RemotingUtil.java b/remoting/src/main/java/org/apache/rocketmq/remoting/util/RemotingUtil.java
deleted file mode 100644
index ccd037f..0000000
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/util/RemotingUtil.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.apache.rocketmq.remoting.util;
-
-public class RemotingUtil {
-    public static final String REMOTING_CHARSET = "UTF-8";
-    public static final String DEFAULT_PROTOCOL = "rocketmq";
-}
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/util/ServiceProvider.java b/remoting/src/main/java/org/apache/rocketmq/remoting/util/ServiceProvider.java
index 24fa721..33c8312 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/util/ServiceProvider.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/util/ServiceProvider.java
@@ -15,6 +15,7 @@ package org.apache.rocketmq.remoting.util;
 import java.io.BufferedReader;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import org.apache.rocketmq.logging.InternalLogger;
@@ -91,11 +92,10 @@ public class ServiceProvider {
         }
     }
 
-    public static <T> Map<String, T> load(String path, Class<?> clazz) {
-        LOG.info("Looking for a resource file of name [{}] ...", path);
-        Map<String, T> services = new ConcurrentHashMap<String, T>();
+    public static Map<String, String> loadPath(String path) {
+        LOG.info("Load path looking for a resource file of name [{}] ...", path);
+        Map<String, String> pathMap = new HashMap<String, String>();
         try {
-
             final InputStream is = getResourceAsStream(getContextClassLoader(), path);
             if (is != null) {
                 BufferedReader reader;
@@ -106,29 +106,35 @@ public class ServiceProvider {
                 }
                 String serviceName = reader.readLine();
                 while (serviceName != null && !"".equals(serviceName)) {
-                    LOG.info(
-                        "Creating an instance as specified by file {} which was present in the path of the context classloader.",
-                        path);
                     String[] service = serviceName.split("=");
-                    if (service.length != 2) {
-                        continue;
-                    } else {
-                        if (services.containsKey(service[0])) {
+                    if (service.length == 2) {
+                        if (pathMap.containsKey(service[0])) {
                             continue;
                         } else {
-                            LOG.info("Begin to load protocol: " + service[0]);
-                            services.put(service[0], (T) initService(getContextClassLoader(), service[1], clazz));
+                            pathMap.put(service[0], service[1]);
                         }
+                    } else {
+                        continue;
                     }
                     serviceName = reader.readLine();
                 }
                 reader.close();
-            } else {
-                // is == null
-                LOG.warn("No resource file with name [{}] found.", path);
             }
-        } catch (Exception e) {
-            LOG.error("Error occured when looking for resource file " + path, e);
+        } catch (Exception ex) {
+            LOG.error("Error occured when looking for resource file " + path, ex);
+        }
+        return pathMap;
+    }
+
+    public static <T> Map<String, T> load(String path, Class<?> clazz) {
+        LOG.info("Load map is looking for a resource file of name [{}] ...", path);
+        Map<String, T> services = new HashMap<String, T>();
+        Map<String, String> pathMaps = loadPath(path);
+        for (Map.Entry<String, String> entry : pathMaps.entrySet()) {
+            T instance = (T) createInstance(entry.getValue(), clazz);
+            if (instance != null && !services.containsKey(entry.getKey())) {
+                services.put(entry.getKey(), instance);
+            }
         }
         return services;
     }
@@ -145,12 +151,7 @@ public class ServiceProvider {
                 }
                 String serviceName = reader.readLine();
                 reader.close();
-                if (serviceName != null && !"".equals(serviceName)) {
-                    return initService(getContextClassLoader(), serviceName, clazz);
-                } else {
-                    LOG.warn("ServiceName is empty!");
-                    return null;
-                }
+                return createInstance(serviceName, clazz);
             } catch (Exception e) {
                 LOG.warn("Error occurred when looking for resource file " + name, e);
             }
@@ -158,6 +159,15 @@ public class ServiceProvider {
         return null;
     }
 
+    public static <T> T createInstance(String serviceName, Class<?> clazz) {
+        if (serviceName != null && !"".equals(serviceName)) {
+            return initService(getContextClassLoader(), serviceName, clazz);
+        } else {
+            LOG.warn("ServiceName is empty!");
+            return null;
+        }
+    }
+
     protected static <T> T initService(ClassLoader classLoader, String serviceName, Class<?> clazz) {
         Class<?> serviceClazz = null;
         try {


[rocketmq] 11/14: Rename rocket-snode directory name

Posted by du...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a commit to branch snode
in repository https://gitbox.apache.org/repos/asf/rocketmq.git

commit fe63f3adc4002310382fdd2af0772d4b15c2a111
Author: duhenglucky <du...@gmail.com>
AuthorDate: Wed Jan 2 10:55:12 2019 +0800

    Rename rocket-snode directory name
---
 {rocketmq-snode => snode}/pom.xml                                         | 0
 .../src/main/java/org/apache/rocketmq/snode/SnodeController.java          | 0
 .../src/main/java/org/apache/rocketmq/snode/SnodeStartup.java             | 0
 .../src/main/java/org/apache/rocketmq/snode/client/ClientChannelInfo.java | 0
 .../java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java  | 0
 .../main/java/org/apache/rocketmq/snode/client/ConsumerGroupEvent.java    | 0
 .../src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java | 0
 .../java/org/apache/rocketmq/snode/client/ConsumerIdsChangeListener.java  | 0
 .../src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java   | 0
 .../apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java    | 0
 .../src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java   | 0
 .../src/main/java/org/apache/rocketmq/snode/client/PushSession.java       | 0
 .../main/java/org/apache/rocketmq/snode/client/PushSessionManager.java    | 0
 .../java/org/apache/rocketmq/snode/client/SubscriptionGroupManager.java   | 0
 .../src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java       | 0
 .../src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java   | 0
 .../src/main/java/org/apache/rocketmq/snode/exception/SnodeException.java | 0
 .../main/java/org/apache/rocketmq/snode/offset/ConsumerOffsetManager.java | 0
 .../java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java | 0
 .../main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java  | 0
 .../java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java    | 0
 .../java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java    | 0
 .../src/main/java/org/apache/rocketmq/snode/service/EnodeService.java     | 0
 .../src/main/java/org/apache/rocketmq/snode/service/NnodeService.java     | 0
 .../src/main/java/org/apache/rocketmq/snode/service/PushService.java      | 0
 .../src/main/java/org/apache/rocketmq/snode/service/ScheduledService.java | 0
 .../java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java     | 0
 .../java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java     | 0
 .../java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java | 0
 .../src/main/java/org/apache/rocketmq/snode/topic/TopicConfigManager.java | 0
 30 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/rocketmq-snode/pom.xml b/snode/pom.xml
similarity index 100%
rename from rocketmq-snode/pom.xml
rename to snode/pom.xml
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java b/snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
rename to snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java b/snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java
rename to snode/src/main/java/org/apache/rocketmq/snode/SnodeStartup.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientChannelInfo.java b/snode/src/main/java/org/apache/rocketmq/snode/client/ClientChannelInfo.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientChannelInfo.java
rename to snode/src/main/java/org/apache/rocketmq/snode/client/ClientChannelInfo.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java b/snode/src/main/java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java
rename to snode/src/main/java/org/apache/rocketmq/snode/client/ClientHousekeepingService.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupEvent.java b/snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupEvent.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupEvent.java
rename to snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupEvent.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java b/snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java
rename to snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerGroupInfo.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerIdsChangeListener.java b/snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerIdsChangeListener.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerIdsChangeListener.java
rename to snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerIdsChangeListener.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java b/snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java
rename to snode/src/main/java/org/apache/rocketmq/snode/client/ConsumerManager.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java b/snode/src/main/java/org/apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java
rename to snode/src/main/java/org/apache/rocketmq/snode/client/DefaultConsumerIdsChangeListener.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java b/snode/src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java
rename to snode/src/main/java/org/apache/rocketmq/snode/client/ProducerManager.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/PushSession.java b/snode/src/main/java/org/apache/rocketmq/snode/client/PushSession.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/PushSession.java
rename to snode/src/main/java/org/apache/rocketmq/snode/client/PushSession.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/PushSessionManager.java b/snode/src/main/java/org/apache/rocketmq/snode/client/PushSessionManager.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/PushSessionManager.java
rename to snode/src/main/java/org/apache/rocketmq/snode/client/PushSessionManager.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/SubscriptionGroupManager.java b/snode/src/main/java/org/apache/rocketmq/snode/client/SubscriptionGroupManager.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/SubscriptionGroupManager.java
rename to snode/src/main/java/org/apache/rocketmq/snode/client/SubscriptionGroupManager.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java b/snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java
rename to snode/src/main/java/org/apache/rocketmq/snode/config/SnodeConfig.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java b/snode/src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java
rename to snode/src/main/java/org/apache/rocketmq/snode/constant/SnodeConstant.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/exception/SnodeException.java b/snode/src/main/java/org/apache/rocketmq/snode/exception/SnodeException.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/exception/SnodeException.java
rename to snode/src/main/java/org/apache/rocketmq/snode/exception/SnodeException.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/offset/ConsumerOffsetManager.java b/snode/src/main/java/org/apache/rocketmq/snode/offset/ConsumerOffsetManager.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/offset/ConsumerOffsetManager.java
rename to snode/src/main/java/org/apache/rocketmq/snode/offset/ConsumerOffsetManager.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java b/snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
rename to snode/src/main/java/org/apache/rocketmq/snode/processor/ConsumerManageProcessor.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java b/snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
rename to snode/src/main/java/org/apache/rocketmq/snode/processor/HearbeatProcessor.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java b/snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
rename to snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java b/snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
rename to snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java b/snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java
rename to snode/src/main/java/org/apache/rocketmq/snode/service/EnodeService.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/NnodeService.java b/snode/src/main/java/org/apache/rocketmq/snode/service/NnodeService.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/NnodeService.java
rename to snode/src/main/java/org/apache/rocketmq/snode/service/NnodeService.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/PushService.java b/snode/src/main/java/org/apache/rocketmq/snode/service/PushService.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/PushService.java
rename to snode/src/main/java/org/apache/rocketmq/snode/service/PushService.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/ScheduledService.java b/snode/src/main/java/org/apache/rocketmq/snode/service/ScheduledService.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/ScheduledService.java
rename to snode/src/main/java/org/apache/rocketmq/snode/service/ScheduledService.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
rename to snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java
rename to snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java
rename to snode/src/main/java/org/apache/rocketmq/snode/service/impl/ScheduledServiceImpl.java
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/topic/TopicConfigManager.java b/snode/src/main/java/org/apache/rocketmq/snode/topic/TopicConfigManager.java
similarity index 100%
rename from rocketmq-snode/src/main/java/org/apache/rocketmq/snode/topic/TopicConfigManager.java
rename to snode/src/main/java/org/apache/rocketmq/snode/topic/TopicConfigManager.java


[rocketmq] 04/14: Polish async invoke implementation, prevent the block occurred during create channel

Posted by du...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a commit to branch snode
in repository https://gitbox.apache.org/repos/asf/rocketmq.git

commit e42970b090d37cce820f747d2f3dd77787f35130
Author: duhengforever <du...@gmail.com>
AuthorDate: Thu Dec 13 17:25:13 2018 +0800

    Polish async invoke implementation, prevent the block occurred during create channel
---
 .../rocketmq/remoting/RemotingClientFactory.java   |  2 -
 .../rocketmq/remoting/RemotingServerFactory.java   |  2 -
 .../rocketmq/remoting/common/RemotingUtil.java     |  2 +-
 .../rocketmq/remoting/netty/CodecHelper.java       |  1 -
 .../remoting/netty/NettyRemotingAbstract.java      | 84 +++++++++++++++-------
 .../rocketmq/remoting/netty/ResponseFuture.java    |  6 +-
 .../transport/NettyRemotingClientAbstract.java     | 12 ++++
 .../transport/NettyRemotingServerAbstract.java     |  5 ++
 .../org.apache.rocketmq.remoting.RemotingServer    |  2 +-
 9 files changed, 82 insertions(+), 34 deletions(-)

diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClientFactory.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClientFactory.java
index a766625..825d96b 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClientFactory.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClientFactory.java
@@ -18,9 +18,7 @@ public class RemotingClientFactory {
     private static final String CLIENT_LOCATION = "META-INF/service/org.apache.rocketmq.remoting.RemotingClient";
 
     static {
-        log.info("begin load client");
         paths = ServiceProvider.loadPath(CLIENT_LOCATION);
-        log.info("end load client, size:{}", paths.size());
     }
 
     public static RemotingClient createInstance(String protocol) {
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java
index 125d4e0..e530d7a 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingServerFactory.java
@@ -19,9 +19,7 @@ public class RemotingServerFactory {
     private static final String SERVER_LOCATION = "META-INF/service/org.apache.rocketmq.remoting.RemotingServer";
 
     static {
-        log.info("begin load server");
         protocolPathMap = ServiceProvider.loadPath(SERVER_LOCATION);
-        log.info("end load server, size:{}", protocolPathMap.size());
     }
 
 
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingUtil.java b/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingUtil.java
index 88008ab..7cc8915 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingUtil.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/common/RemotingUtil.java
@@ -41,7 +41,7 @@ public class RemotingUtil {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
     private static boolean isLinuxPlatform = false;
     private static boolean isWindowsPlatform = false;
-    public static final String DEFAULT_PROTOCOL = "http2";
+    public static final String DEFAULT_PROTOCOL = "rocketmq";
     public static final String REMOTING_CHARSET = "UTF-8";
 
     static {
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/CodecHelper.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/CodecHelper.java
index d0e3632..193cd39 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/CodecHelper.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/CodecHelper.java
@@ -45,7 +45,6 @@ public class CodecHelper {
         byte[] headerData = new byte[headerLength];
         byteBuffer.get(headerData);
         RemotingCommand cmd = headerDecode(headerData, getProtocolType(oriHeaderLen));
-        System.out.println("cmd: " + cmd);
         int bodyLength = length - 4 - headerLength;
         byte[] bodyData = null;
         if (bodyLength > 0) {
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
index 17053ff..cae2bf4 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
@@ -100,6 +100,11 @@ public abstract class NettyRemotingAbstract {
     protected Pair<NettyRequestProcessor, ExecutorService> defaultRequestProcessor;
 
     /**
+     * Used for async execute task for aysncInvokeMethod
+     */
+    private ExecutorService asyncExecuteService = ThreadUtils.newFixedThreadPool(5, 10000, "asyncExecute", false);
+
+    /**
      * SSL context via which to create {@link SslHandler}.
      */
     protected volatile SslContext sslContext;
@@ -445,38 +450,66 @@ public abstract class NettyRemotingAbstract {
         }
     }
 
-    public void invokeAsyncImpl(final Channel channel, final RemotingCommand request, final long timeoutMillis,
+    abstract protected Channel getAndCreateChannel(final String addr, long timeout) throws InterruptedException;
+
+    public void invokeAsyncImpl(final Channel channel, final RemotingCommand request,
+        final long timeoutMillis,
         final InvokeCallback invokeCallback)
         throws InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
-        long beginStartTime = System.currentTimeMillis();
-        final int opaque = request.getOpaque();
-        boolean acquired = this.semaphoreAsync.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS);
+        invokeAsyncImpl(null, channel, request, timeoutMillis, invokeCallback);
+    }
+
+    public void invokeAsyncImpl(final String addr, final RemotingCommand request,
+        final long timeoutMillis,
+        final InvokeCallback invokeCallback)
+        throws InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
+        invokeAsyncImpl(addr, null, request, timeoutMillis, invokeCallback);
+    }
+
+    public void invokeAsyncImpl(final String addr, final Channel currentChannel, final RemotingCommand request,
+        final long timeoutMillis,
+        final InvokeCallback invokeCallback)
+        throws InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
+        final long beginStartTime = System.currentTimeMillis();
+        boolean acquired = semaphoreAsync.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS);
         if (acquired) {
-            final SemaphoreReleaseOnlyOnce once = new SemaphoreReleaseOnlyOnce(this.semaphoreAsync);
+            SemaphoreReleaseOnlyOnce once = new SemaphoreReleaseOnlyOnce(semaphoreAsync);
             long costTime = System.currentTimeMillis() - beginStartTime;
             if (timeoutMillis < costTime) {
-                throw new RemotingTimeoutException("invokeAsyncImpl call timeout");
+                once.release();
+                throw new RemotingTimeoutException("InvokeAsyncImpl call timeout");
             }
-
-            final ResponseFuture responseFuture = new ResponseFuture(channel, opaque, timeoutMillis - costTime, invokeCallback, once);
-            this.responseTable.put(opaque, responseFuture);
-            try {
-                channel.writeAndFlush(request).addListener(new ChannelFutureListener() {
-                    @Override
-                    public void operationComplete(ChannelFuture f) throws Exception {
-                        if (f.isSuccess()) {
-                            responseFuture.setSendRequestOK(true);
-                            return;
+            final int opaque = request.getOpaque();
+            final ResponseFuture responseFuture = new ResponseFuture(currentChannel, opaque, timeoutMillis, invokeCallback, once);
+            responseTable.put(opaque, responseFuture);
+            asyncExecuteService.submit(new Runnable() {
+                @Override
+                public void run() {
+                    Channel channel = currentChannel;
+                    final String remotingAddr = RemotingHelper.parseChannelRemoteAddr(channel);
+                    try {
+                        if (channel == null) {
+                            channel = getAndCreateChannel(addr, timeoutMillis);
+                            responseFuture.setProcessChannel(channel);
                         }
+                        channel.writeAndFlush(request).addListener(new ChannelFutureListener() {
+                            @Override
+                            public void operationComplete(ChannelFuture f) throws Exception {
+                                if (f.isSuccess()) {
+                                    responseFuture.setSendRequestOK(true);
+                                    return;
+                                }
+                                requestFail(opaque);
+                                log.warn("send a request command to channel <{}> failed.", remotingAddr);
+                            }
+                        });
+                    } catch (Exception ex) {
+                        responseFuture.release();
                         requestFail(opaque);
-                        log.warn("send a request command to channel <{}> failed.", RemotingHelper.parseChannelRemoteAddr(channel));
+                        log.warn("send a request command to channel <" + RemotingHelper.parseChannelRemoteAddr(channel) + "> Exception", ex);
                     }
-                });
-            } catch (Exception e) {
-                responseFuture.release();
-                log.warn("send a request command to channel <" + RemotingHelper.parseChannelRemoteAddr(channel) + "> Exception", e);
-                throw new RemotingSendRequestException(RemotingHelper.parseChannelRemoteAddr(channel), e);
-            }
+                }
+            });
         } else {
             if (timeoutMillis <= 0) {
                 throw new RemotingTooMuchRequestException("invokeAsyncImpl invoke too fast");
@@ -527,7 +560,8 @@ public abstract class NettyRemotingAbstract {
     }
 
     public void invokeOnewayImpl(final Channel channel, final RemotingCommand request, final long timeoutMillis)
-        throws InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
+        throws
+        InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
         request.markOnewayRPC();
         boolean acquired = this.semaphoreOneway.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS);
         if (acquired) {
@@ -625,6 +659,4 @@ public abstract class NettyRemotingAbstract {
         }
     }
 
-
-
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/ResponseFuture.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/ResponseFuture.java
index 5f4c8c6..bffe602 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/ResponseFuture.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/ResponseFuture.java
@@ -26,7 +26,7 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
 public class ResponseFuture {
     private final int opaque;
-    private final Channel processChannel;
+    private Channel processChannel;
     private final long timeoutMillis;
     private final InvokeCallback invokeCallback;
     private final long beginTimestamp = System.currentTimeMillis();
@@ -121,6 +121,10 @@ public class ResponseFuture {
         return processChannel;
     }
 
+    public void setProcessChannel(Channel processChannel) {
+        this.processChannel = processChannel;
+    }
+
     @Override
     public String toString() {
         return "ResponseFuture [responseCommand=" + responseCommand
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingClientAbstract.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingClientAbstract.java
index 6dab218..d53d40b 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingClientAbstract.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingClientAbstract.java
@@ -32,6 +32,7 @@ import java.util.Random;
 import java.util.Timer;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutorService;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
@@ -39,11 +40,17 @@ import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 import org.apache.rocketmq.logging.InternalLogger;
 import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.apache.rocketmq.remoting.InvokeCallback;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 import org.apache.rocketmq.remoting.common.RemotingUtil;
+import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
+import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
 import org.apache.rocketmq.remoting.netty.NettyEvent;
 import org.apache.rocketmq.remoting.netty.NettyEventType;
 import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.util.ThreadUtils;
 
 public abstract class NettyRemotingClientAbstract extends NettyRemotingAbstract {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
@@ -53,6 +60,10 @@ public abstract class NettyRemotingClientAbstract extends NettyRemotingAbstract
     private final AtomicReference<String> namesrvAddrChoosed = new AtomicReference<String>();
     private final AtomicInteger namesrvIndex = new AtomicInteger(initValueIndex());
     private final Lock lockNamesrvChannel = new ReentrantLock();
+    /**
+     * Used for async execute task for aysncInvokeMethod
+     */
+    private ExecutorService asyncExecuteService = ThreadUtils.newFixedThreadPool(5, 10000, "asyncExecute", false);
 
     private final Lock lockChannelTables = new ReentrantLock();
     private static final long LOCK_TIMEOUT_MILLIS = 3000;
@@ -169,6 +180,7 @@ public abstract class NettyRemotingClientAbstract extends NettyRemotingAbstract
         }
     }
 
+    @Override
     protected Channel getAndCreateChannel(final String addr, long timeout) throws InterruptedException {
         if (null == addr) {
             return getAndCreateNameserverChannel(timeout);
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingServerAbstract.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingServerAbstract.java
index e8d8471..cec0086 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingServerAbstract.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/NettyRemotingServerAbstract.java
@@ -1,5 +1,6 @@
 package org.apache.rocketmq.remoting.transport;
 
+import io.netty.channel.Channel;
 import io.netty.channel.ChannelDuplexHandler;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.timeout.IdleState;
@@ -90,4 +91,8 @@ public abstract class NettyRemotingServerAbstract extends NettyRemotingAbstract
             RemotingUtil.closeChannel(ctx.channel());
         }
     }
+
+    @Override protected Channel getAndCreateChannel(String addr, long timeout) throws InterruptedException {
+        return null;
+    }
 }
diff --git a/remoting/src/main/resources/META-INF/service/org.apache.rocketmq.remoting.RemotingServer b/remoting/src/main/resources/META-INF/service/org.apache.rocketmq.remoting.RemotingServer
index 5079c88..9f70dce 100644
--- a/remoting/src/main/resources/META-INF/service/org.apache.rocketmq.remoting.RemotingServer
+++ b/remoting/src/main/resources/META-INF/service/org.apache.rocketmq.remoting.RemotingServer
@@ -1,2 +1,2 @@
 rocketmq=org.apache.rocketmq.remoting.transport.rocketmq.NettyRemotingServer
-http2=org.apache.rocketmq.remoting.transport.http2.Http2ServerImpl
\ No newline at end of file
+http2=org.apache.rocketmq.remoting.transport.http2.Http2ServerImpl


[rocketmq] 13/14: Add snode interceptor

Posted by du...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a commit to branch snode
in repository https://gitbox.apache.org/repos/asf/rocketmq.git

commit 6a49f0cbdfd5e598149f517681eca14d75c02064
Author: duhenglucky <du...@gmail.com>
AuthorDate: Wed Jan 2 23:39:05 2019 +0800

    Add snode interceptor
---
 .../rocketmq/broker/mqtrace/SendMessageHook.java   |  6 +--
 .../apache/rocketmq/remoting/RemotingClient.java   |  2 -
 .../remoting/transport/http2/Http2ClientImpl.java  |  9 ----
 .../transport/rocketmq/NettyRemotingClient.java    |  9 ----
 .../rocketmq/remoting/util/ServiceProvider.java    | 37 ++++++++++++-
 .../org/apache/rocketmq/snode/SnodeController.java | 60 +++++++++++-----------
 .../snode/interceptor/ExceptionContext.java        | 47 +++++++++++++++++
 .../rocketmq/snode/interceptor/Interceptor.java    | 11 ++--
 .../snode/interceptor/InterceptorFactory.java      | 46 +++++++++++++++++
 .../snode/interceptor/InterceptorGroup.java        | 47 +++++++++++++++++
 .../rocketmq/snode/interceptor/RequestContext.java | 45 ++++++++++++++++
 .../snode/interceptor/ResponseContext.java         | 23 ++++++---
 .../snode/offset/ConsumerOffsetManager.java        |  3 +-
 .../snode/processor/PullMessageProcessor.java      | 31 +++++++++--
 .../snode/processor/SendMessageProcessor.java      | 15 ++++++
 .../snode/service/impl/EnodeServiceImpl.java       |  3 --
 .../snode/service/impl/NnodeServiceImpl.java       |  2 +-
 ...tmq.snode.interceptor.ConsumeMessageInterceptor |  0
 ...cketmq.snode.interceptor.SendMessageInterceptor |  0
 19 files changed, 320 insertions(+), 76 deletions(-)

diff --git a/broker/src/main/java/org/apache/rocketmq/broker/mqtrace/SendMessageHook.java b/broker/src/main/java/org/apache/rocketmq/broker/mqtrace/SendMessageHook.java
index a74b6d6..a89bace 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/mqtrace/SendMessageHook.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/mqtrace/SendMessageHook.java
@@ -17,9 +17,9 @@
 package org.apache.rocketmq.broker.mqtrace;
 
 public interface SendMessageHook {
-    public String hookName();
+    String hookName();
 
-    public void sendMessageBefore(final SendMessageContext context);
+    void sendMessageBefore(final SendMessageContext context);
 
-    public void sendMessageAfter(final SendMessageContext context);
+    void sendMessageAfter(final SendMessageContext context);
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java
index c706eed..84d4241 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingClient.java
@@ -49,7 +49,5 @@ public interface RemotingClient extends RemotingService {
 
     ExecutorService getCallbackExecutor();
 
-    boolean isChannelWritable(final String addr);
-
     RemotingClient init(ClientConfig nettyClientConfig, ChannelEventListener channelEventListener);
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java
index 71bee1e..fb9e3f8 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/http2/Http2ClientImpl.java
@@ -267,15 +267,6 @@ public class Http2ClientImpl extends NettyRemotingClientAbstract implements Remo
     }
 
     @Override
-    public boolean isChannelWritable(String addr) {
-        ChannelWrapper cw = this.channelTables.get(addr);
-        if (cw != null && cw.isOK()) {
-            return cw.isWritable();
-        }
-        return true;
-    }
-
-    @Override
     public List<String> getNameServerAddressList() {
         return this.namesrvAddrList.get();
     }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java
index 686bb01..a5790df 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/transport/rocketmq/NettyRemotingClient.java
@@ -273,15 +273,6 @@ public class NettyRemotingClient extends NettyRemotingClientAbstract implements
     }
 
     @Override
-    public boolean isChannelWritable(String addr) {
-        ChannelWrapper cw = this.channelTables.get(addr);
-        if (cw != null && cw.isOK()) {
-            return cw.isWritable();
-        }
-        return true;
-    }
-
-    @Override
     public List<String> getNameServerAddressList() {
         return this.namesrvAddrList.get();
     }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/util/ServiceProvider.java b/remoting/src/main/java/org/apache/rocketmq/remoting/util/ServiceProvider.java
index 33c8312..586a846 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/util/ServiceProvider.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/util/ServiceProvider.java
@@ -15,7 +15,9 @@ package org.apache.rocketmq.remoting.util;
 import java.io.BufferedReader;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import org.apache.rocketmq.logging.InternalLogger;
@@ -92,6 +94,39 @@ public class ServiceProvider {
         }
     }
 
+    public static <T> List<T> loadServiceList(String name, Class<?> clazz) {
+        LOG.info("Looking for a resource file of name [{}] ...", name);
+        List<T> services = new ArrayList<T>();
+        try {
+            ArrayList<String> names = new ArrayList<String>();
+            final InputStream is = getResourceAsStream(getContextClassLoader(), name);
+            if (is != null) {
+                BufferedReader reader;
+                try {
+                    reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+                } catch (java.io.UnsupportedEncodingException e) {
+                    reader = new BufferedReader(new InputStreamReader(is));
+                }
+                String serviceName = reader.readLine();
+                while (serviceName != null && !"".equals(serviceName)) {
+                    if (!names.contains(serviceName)) {
+                        T instance = createInstance(serviceName, clazz);
+                        services.add(instance);
+                    }
+                    names.add(serviceName);
+                    serviceName = reader.readLine();
+                }
+                reader.close();
+            } else {
+                // is == null
+                LOG.warn("No resource file with name [{}] found.", name);
+            }
+        } catch (Exception e) {
+            LOG.error("Error occured when looking for resource file " + name, e);
+        }
+        return services;
+    }
+
     public static Map<String, String> loadPath(String path) {
         LOG.info("Load path looking for a resource file of name [{}] ...", path);
         Map<String, String> pathMap = new HashMap<String, String>();
@@ -121,7 +156,7 @@ public class ServiceProvider {
                 reader.close();
             }
         } catch (Exception ex) {
-            LOG.error("Error occured when looking for resource file " + path, ex);
+            LOG.error("Error occurred when looking for resource file " + path, ex);
         }
         return pathMap;
     }
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java b/snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
index c1ccb4a..66d792d 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/SnodeController.java
@@ -15,6 +15,7 @@ package org.apache.rocketmq.snode;/*
  * limitations under the License.
  */
 
+import java.util.List;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -39,6 +40,9 @@ import org.apache.rocketmq.snode.client.DefaultConsumerIdsChangeListener;
 import org.apache.rocketmq.snode.client.ProducerManager;
 import org.apache.rocketmq.snode.client.SubscriptionGroupManager;
 import org.apache.rocketmq.snode.config.SnodeConfig;
+import org.apache.rocketmq.snode.interceptor.InterceptorFactory;
+import org.apache.rocketmq.snode.interceptor.InterceptorGroup;
+import org.apache.rocketmq.snode.interceptor.Interceptor;
 import org.apache.rocketmq.snode.offset.ConsumerOffsetManager;
 import org.apache.rocketmq.snode.processor.ConsumerManageProcessor;
 import org.apache.rocketmq.snode.processor.HearbeatProcessor;
@@ -76,6 +80,8 @@ public class SnodeController {
     private SendMessageProcessor sendMessageProcessor;
     private PullMessageProcessor pullMessageProcessor;
     private HearbeatProcessor hearbeatProcessor;
+    private InterceptorGroup consumeMessageInterceptorGroup;
+    private InterceptorGroup sendMessageInterceptorGroup;
 
     private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl(
         "SnodeControllerScheduledThread"));
@@ -161,9 +167,27 @@ public class SnodeController {
     public boolean initialize() {
         this.snodeServer = RemotingServerFactory.createInstance().init(this.nettyServerConfig, this.clientHousekeepingService);
         this.registerProcessor();
+        initInterceptorGroup();
         return true;
     }
 
+    private void initInterceptorGroup() {
+        List<Interceptor> consumeMessageInterceptors = InterceptorFactory.getInstance().loadConsumeMessageInterceptors();
+        if (consumeMessageInterceptors != null) {
+            this.consumeMessageInterceptorGroup = new InterceptorGroup();
+            for (Interceptor interceptor : consumeMessageInterceptors) {
+                this.consumeMessageInterceptorGroup.registerInterceptor(interceptor);
+            }
+        }
+        List<Interceptor> sendMessageInterceptors = InterceptorFactory.getInstance().loadSendMessageInterceptors();
+        if (sendMessageInterceptors != null) {
+            this.sendMessageInterceptorGroup = new InterceptorGroup();
+            for (Interceptor interceptor : sendMessageInterceptors) {
+                this.sendMessageInterceptorGroup.registerInterceptor(interceptor);
+            }
+        }
+    }
+
     public void registerProcessor() {
         this.snodeServer.registerProcessor(RequestCode.SEND_MESSAGE_V2, sendMessageProcessor, this.sendMessageExecutor);
         this.snodeServer.registerProcessor(RequestCode.CONSUMER_SEND_MSG_BACK, sendMessageProcessor, this.sendMessageExecutor);
@@ -201,34 +225,18 @@ public class SnodeController {
         return producerManager;
     }
 
-    public void setProducerManager(ProducerManager producerManager) {
-        this.producerManager = producerManager;
-    }
-
     public RemotingServer getSnodeServer() {
         return snodeServer;
     }
 
-    public void setSnodeServer(RemotingServer snodeServer) {
-        this.snodeServer = snodeServer;
-    }
-
     public ConsumerManager getConsumerManager() {
         return consumerManager;
     }
 
-    public void setConsumerManager(ConsumerManager consumerManager) {
-        this.consumerManager = consumerManager;
-    }
-
     public SubscriptionGroupManager getSubscriptionGroupManager() {
         return subscriptionGroupManager;
     }
 
-    public void setSubscriptionGroupManager(SubscriptionGroupManager subscriptionGroupManager) {
-        this.subscriptionGroupManager = subscriptionGroupManager;
-    }
-
     public ClientConfig getNettyClientConfig() {
         return nettyClientConfig;
     }
@@ -237,31 +245,23 @@ public class SnodeController {
         return enodeService;
     }
 
-    public void setEnodeService(EnodeService enodeService) {
-        this.enodeService = enodeService;
-    }
-
     public NnodeService getNnodeService() {
         return nnodeService;
     }
 
-    public void setNnodeService(NnodeService nnodeService) {
-        this.nnodeService = nnodeService;
-    }
-
     public RemotingClient getRemotingClient() {
         return remotingClient;
     }
 
-    public void setRemotingClient(RemotingClient remotingClient) {
-        this.remotingClient = remotingClient;
-    }
-
     public ConsumerOffsetManager getConsumerOffsetManager() {
         return consumerOffsetManager;
     }
 
-    public void setConsumerOffsetManager(ConsumerOffsetManager consumerOffsetManager) {
-        this.consumerOffsetManager = consumerOffsetManager;
+    public InterceptorGroup getConsumeMessageInterceptorGroup() {
+        return consumeMessageInterceptorGroup;
+    }
+
+    public InterceptorGroup getSendMessageInterceptorGroup() {
+        return sendMessageInterceptorGroup;
     }
 }
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/interceptor/ExceptionContext.java b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/ExceptionContext.java
new file mode 100644
index 0000000..569633d
--- /dev/null
+++ b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/ExceptionContext.java
@@ -0,0 +1,47 @@
+package org.apache.rocketmq.snode.interceptor;/*
+ * 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.
+ */
+
+import org.apache.rocketmq.remoting.RemotingChannel;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+
+public class ExceptionContext extends RequestContext {
+    private Throwable throwable;
+    private String remark;
+
+    public ExceptionContext(RemotingCommand request, RemotingChannel remotingChannel, Throwable throwable,
+        String remark) {
+        super(request, remotingChannel);
+        this.throwable = throwable;
+        this.remark = remark;
+    }
+
+    public Throwable getThrowable() {
+        return throwable;
+    }
+
+    public void setThrowable(Throwable throwable) {
+        this.throwable = throwable;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+}
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/mqtrace/SendMessageHook.java b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/Interceptor.java
similarity index 76%
copy from broker/src/main/java/org/apache/rocketmq/broker/mqtrace/SendMessageHook.java
copy to snode/src/main/java/org/apache/rocketmq/snode/interceptor/Interceptor.java
index a74b6d6..18cf6b3 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/mqtrace/SendMessageHook.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/Interceptor.java
@@ -14,12 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.rocketmq.broker.mqtrace;
+package org.apache.rocketmq.snode.interceptor;
+public interface Interceptor {
+    void beforeSendMessage(RequestContext requestContext);
 
-public interface SendMessageHook {
-    public String hookName();
+    void afterSendMessage(ResponseContext responseContext);
 
-    public void sendMessageBefore(final SendMessageContext context);
-
-    public void sendMessageAfter(final SendMessageContext context);
+    void onException(ExceptionContext exceptionContext);
 }
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/interceptor/InterceptorFactory.java b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/InterceptorFactory.java
new file mode 100644
index 0000000..e2b4332
--- /dev/null
+++ b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/InterceptorFactory.java
@@ -0,0 +1,46 @@
+/*
+ * 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.snode.interceptor;
+
+import java.util.List;
+import org.apache.rocketmq.remoting.util.ServiceProvider;
+
+public class InterceptorFactory {
+    private static InterceptorFactory ourInstance = new InterceptorFactory();
+
+    public static InterceptorFactory getInstance() {
+        return ourInstance;
+    }
+
+    private final String SEND_MESSAGE_INTERCEPTOR = "META-INF/service/org.apache.rocketmq.snode.interceptor.SendMessageInterceptor";
+
+    private final String CONSUME_MESSAGE_INTERCEPTOR = "META-INF/service/org.apache.rocketmq.snode.interceptor.ConsumeMessageInterceptor";
+
+    private InterceptorFactory() {
+    }
+
+    public List loadConsumeMessageInterceptors() {
+        List<Interceptor> consumeMessageInterceptors = ServiceProvider.loadServiceList(CONSUME_MESSAGE_INTERCEPTOR, Interceptor.class);
+        return consumeMessageInterceptors;
+    }
+
+    public List loadSendMessageInterceptors() {
+        List<Interceptor> sendMessageInterceptors = ServiceProvider.loadServiceList(SEND_MESSAGE_INTERCEPTOR, Interceptor.class);
+        return sendMessageInterceptors;
+    }
+
+}
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/interceptor/InterceptorGroup.java b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/InterceptorGroup.java
new file mode 100644
index 0000000..4582894
--- /dev/null
+++ b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/InterceptorGroup.java
@@ -0,0 +1,47 @@
+package org.apache.rocketmq.snode.interceptor;/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class InterceptorGroup {
+    private List<Interceptor> interceptors = new ArrayList<>();
+
+    public void registerInterceptor(Interceptor sendMessageInterceptor) {
+        if (sendMessageInterceptor != null) {
+            interceptors.add(sendMessageInterceptor);
+        }
+    }
+
+    public void beforeRequest(RequestContext requestContext) {
+        for (Interceptor interceptor : interceptors) {
+            interceptor.beforeSendMessage(requestContext);
+        }
+    }
+
+    public void afterRequest(ResponseContext responseContext) {
+        for (Interceptor interceptor : interceptors) {
+            interceptor.afterSendMessage(responseContext);
+        }
+    }
+
+    public void onException(ExceptionContext exceptionContext) {
+        for (Interceptor interceptor : interceptors) {
+            interceptor.onException(exceptionContext);
+        }
+    }
+}
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/interceptor/RequestContext.java b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/RequestContext.java
new file mode 100644
index 0000000..796358b
--- /dev/null
+++ b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/RequestContext.java
@@ -0,0 +1,45 @@
+package org.apache.rocketmq.snode.interceptor;/*
+ * 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.
+ */
+
+import org.apache.rocketmq.remoting.RemotingChannel;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+
+public class RequestContext {
+    protected RemotingCommand request;
+    protected RemotingChannel remotingChannel;
+
+    public RequestContext(RemotingCommand request, RemotingChannel remotingChannel) {
+        this.remotingChannel = remotingChannel;
+        this.request = request;
+    }
+
+    public RemotingCommand getRequest() {
+        return request;
+    }
+
+    public void setRequest(RemotingCommand request) {
+        this.request = request;
+    }
+
+    public RemotingChannel getRemotingChannel() {
+        return remotingChannel;
+    }
+
+    public void setRemotingChannel(RemotingChannel remotingChannel) {
+        this.remotingChannel = remotingChannel;
+    }
+}
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/mqtrace/SendMessageHook.java b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/ResponseContext.java
similarity index 56%
copy from broker/src/main/java/org/apache/rocketmq/broker/mqtrace/SendMessageHook.java
copy to snode/src/main/java/org/apache/rocketmq/snode/interceptor/ResponseContext.java
index a74b6d6..2634426 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/mqtrace/SendMessageHook.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/interceptor/ResponseContext.java
@@ -1,4 +1,4 @@
-/*
+package org.apache.rocketmq.snode.interceptor;/*
  * 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.
@@ -14,12 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.rocketmq.broker.mqtrace;
 
-public interface SendMessageHook {
-    public String hookName();
+import org.apache.rocketmq.remoting.RemotingChannel;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 
-    public void sendMessageBefore(final SendMessageContext context);
+public class ResponseContext extends RequestContext {
+    private RemotingCommand response;
 
-    public void sendMessageAfter(final SendMessageContext context);
+    public ResponseContext(RemotingCommand request, RemotingChannel remotingChannel, RemotingCommand response) {
+        super(request, remotingChannel);
+        this.response = response;
+    }
+
+    public RemotingCommand getResponse() {
+        return response;
+    }
+
+    public void setResponse(RemotingCommand response) {
+        this.response = response;
+    }
 }
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/offset/ConsumerOffsetManager.java b/snode/src/main/java/org/apache/rocketmq/snode/offset/ConsumerOffsetManager.java
index c177ccf..065c017 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/offset/ConsumerOffsetManager.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/offset/ConsumerOffsetManager.java
@@ -42,7 +42,7 @@ public class ConsumerOffsetManager {
     private static final String TOPIC_GROUP_SEPARATOR = "@";
 
     private ConcurrentMap<String/* topic@group */, ConcurrentMap<Integer, Long>> offsetTable =
-        new ConcurrentHashMap<String, ConcurrentMap<Integer, Long>>(512);
+        new ConcurrentHashMap<>(512);
 
     private transient SnodeController snodeController;
 
@@ -207,7 +207,6 @@ public class ConsumerOffsetManager {
         this.offsetTable = offsetTable;
     }
 
-
     public Map<Integer, Long> queryOffset(final String enodeName, final String group, final String topic) {
         // topic@group
         String key = buildKey(enodeName, topic, group);
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java b/snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
index 645d7fc..f5d080f 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/processor/PullMessageProcessor.java
@@ -32,6 +32,9 @@ import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.snode.SnodeController;
 import org.apache.rocketmq.snode.client.ConsumerGroupInfo;
+import org.apache.rocketmq.snode.interceptor.ExceptionContext;
+import org.apache.rocketmq.snode.interceptor.RequestContext;
+import org.apache.rocketmq.snode.interceptor.ResponseContext;
 
 public class PullMessageProcessor implements RequestProcessor {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
@@ -45,8 +48,21 @@ public class PullMessageProcessor implements RequestProcessor {
     @Override
     public RemotingCommand processRequest(RemotingChannel remotingChannel,
         RemotingCommand request) throws RemotingCommandException {
-        RemotingCommand response = RemotingCommand.createResponseCommand(PullMessageResponseHeader.class);
+        if (this.snodeController.getConsumeMessageInterceptorGroup() != null) {
+            RequestContext requestContext = new RequestContext(request, remotingChannel);
+            this.snodeController.getConsumeMessageInterceptorGroup().beforeRequest(requestContext);
+        }
+        RemotingCommand response = pullMessage(remotingChannel, request);
+        if (this.snodeController.getConsumeMessageInterceptorGroup() != null && response != null) {
+            ResponseContext responseContext = new ResponseContext(request, remotingChannel, response);
+            this.snodeController.getSendMessageInterceptorGroup().afterRequest(responseContext);
+        }
+        return response;
+    }
 
+    private RemotingCommand pullMessage(RemotingChannel remotingChannel,
+        RemotingCommand request) throws RemotingCommandException {
+        RemotingCommand response = RemotingCommand.createResponseCommand(PullMessageResponseHeader.class);
         final PullMessageRequestHeader requestHeader =
             (PullMessageRequestHeader) request.decodeCommandCustomHeader(PullMessageRequestHeader.class);
 
@@ -72,14 +88,13 @@ public class PullMessageProcessor implements RequestProcessor {
             response.setRemark("The consumer group[" + requestHeader.getConsumerGroup() + "] can not consume by broadcast way");
             return response;
         }
-
-        SubscriptionData subscriptionData = consumerGroupInfo.findSubscriptionData(requestHeader.getTopic());
-        if (null == subscriptionData) {
+        if ((consumerGroupInfo == null) || (consumerGroupInfo.findSubscriptionData(requestHeader.getTopic()) == null)) {
             log.warn("The consumer's subscription not exist, group: {}, topic:{}", requestHeader.getConsumerGroup(), requestHeader.getTopic());
             response.setCode(ResponseCode.SUBSCRIPTION_NOT_EXIST);
             response.setRemark("The consumer's subscription not exist" + FAQUrl.suggestTodo(FAQUrl.SAME_GROUP_DIFFERENT_TOPIC));
             return response;
         }
+        SubscriptionData subscriptionData = consumerGroupInfo.findSubscriptionData(requestHeader.getTopic());
 
         if (subscriptionData.getSubVersion() < requestHeader.getSubVersion()) {
             log.warn("The broker's subscription is not latest, group: {} {}", requestHeader.getConsumerGroup(),
@@ -92,8 +107,16 @@ public class PullMessageProcessor implements RequestProcessor {
         CompletableFuture<RemotingCommand> responseFuture = snodeController.getEnodeService().pullMessage(request);
         responseFuture.whenComplete((data, ex) -> {
             if (ex == null) {
+                if (this.snodeController.getConsumeMessageInterceptorGroup() != null) {
+                    ResponseContext responseContext = new ResponseContext(request, remotingChannel, data);
+                    this.snodeController.getSendMessageInterceptorGroup().afterRequest(responseContext);
+                }
                 remotingChannel.reply(data);
             } else {
+                if (this.snodeController.getConsumeMessageInterceptorGroup() != null) {
+                    ExceptionContext exceptionContext = new ExceptionContext(request, remotingChannel, ex, null);
+                    this.snodeController.getConsumeMessageInterceptorGroup().onException(exceptionContext);
+                }
                 log.error("Pull message error: {}", ex);
             }
         });
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java b/snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
index bd18339..2c45bb7 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
@@ -23,6 +23,9 @@ import org.apache.rocketmq.remoting.RemotingChannel;
 import org.apache.rocketmq.remoting.RequestProcessor;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.snode.SnodeController;
+import org.apache.rocketmq.snode.interceptor.ExceptionContext;
+import org.apache.rocketmq.snode.interceptor.RequestContext;
+import org.apache.rocketmq.snode.interceptor.ResponseContext;
 
 public class SendMessageProcessor implements RequestProcessor {
     private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.SNODE_LOGGER_NAME);
@@ -35,11 +38,23 @@ public class SendMessageProcessor implements RequestProcessor {
 
     @Override
     public RemotingCommand processRequest(RemotingChannel remotingChannel, RemotingCommand request) {
+        if (this.snodeController.getSendMessageInterceptorGroup() != null) {
+            RequestContext requestContext = new RequestContext(request, remotingChannel);
+            this.snodeController.getSendMessageInterceptorGroup().beforeRequest(requestContext);
+        }
         CompletableFuture<RemotingCommand> responseFuture = snodeController.getEnodeService().sendMessage(request);
         responseFuture.whenComplete((data, ex) -> {
             if (ex == null) {
+                if (this.snodeController.getSendMessageInterceptorGroup() != null) {
+                    ResponseContext responseContext = new ResponseContext(request, remotingChannel, data);
+                    this.snodeController.getSendMessageInterceptorGroup().afterRequest(responseContext);
+                }
                 remotingChannel.reply(data);
             } else {
+                if (this.snodeController.getSendMessageInterceptorGroup() != null) {
+                    ExceptionContext exceptionContext = new ExceptionContext(request, remotingChannel, ex, null);
+                    this.snodeController.getSendMessageInterceptorGroup().onException(exceptionContext);
+                }
                 log.error("Send Message error: {}", ex);
             }
         });
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
index 20a4d2f..5e28ebe 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
@@ -15,8 +15,6 @@ package org.apache.rocketmq.snode.service.impl;/*
  * limitations under the License.
  */
 
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelHandlerContext;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
@@ -47,7 +45,6 @@ import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 import org.apache.rocketmq.remoting.exception.RemotingConnectException;
 import org.apache.rocketmq.remoting.exception.RemotingSendRequestException;
 import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
-import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
 import org.apache.rocketmq.remoting.netty.ResponseFuture;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
 import org.apache.rocketmq.remoting.serialize.RemotingSerializable;
diff --git a/snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java
index b272c31..78fd624 100644
--- a/snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java
+++ b/snode/src/main/java/org/apache/rocketmq/snode/service/impl/NnodeServiceImpl.java
@@ -93,7 +93,7 @@ public class NnodeServiceImpl implements NnodeService {
 
         RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINTO_BY_TOPIC, requestHeader);
         RemotingCommand response = this.snodeController.getRemotingClient().invokeSync(null, request, SnodeConstant.defaultTimeoutMills);
-        log.info("getTopicRouteInfoFromNameServer response: " + response);
+        log.info("GetTopicRouteInfoFromNameServer response: " + response);
         assert response != null;
         switch (response.getCode()) {
             case ResponseCode.TOPIC_NOT_EXIST: {
diff --git a/snode/src/main/resources/META-INF/service/org.apache.rocketmq.snode.interceptor.ConsumeMessageInterceptor b/snode/src/main/resources/META-INF/service/org.apache.rocketmq.snode.interceptor.ConsumeMessageInterceptor
new file mode 100644
index 0000000..e69de29
diff --git a/snode/src/main/resources/META-INF/service/org.apache.rocketmq.snode.interceptor.SendMessageInterceptor b/snode/src/main/resources/META-INF/service/org.apache.rocketmq.snode.interceptor.SendMessageInterceptor
new file mode 100644
index 0000000..e69de29


[rocketmq] 08/14: Add push and push session interface

Posted by du...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

duhengforever pushed a commit to branch snode
in repository https://gitbox.apache.org/repos/asf/rocketmq.git

commit e836fc33c06f6883a4c9d85e077544aa3e5460c3
Author: duhenglucky <du...@gmail.com>
AuthorDate: Sat Dec 29 19:59:59 2018 +0800

    Add push and push session interface
---
 .../apache/rocketmq/snode/client/PushSession.java  | 51 ++++++++++++++++++++++
 .../rocketmq/snode/client/PushSessionManager.java  | 23 ++++++++++
 .../snode/processor/SendMessageProcessor.java      |  1 -
 .../apache/rocketmq/snode/service/PushService.java | 26 +++++++++++
 .../snode/service/impl/EnodeServiceImpl.java       |  3 +-
 5 files changed, 101 insertions(+), 3 deletions(-)

diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/PushSession.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/PushSession.java
new file mode 100644
index 0000000..c08bab5
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/PushSession.java
@@ -0,0 +1,51 @@
+package org.apache.rocketmq.snode.client;/*
+ * 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.
+ */
+
+import io.netty.channel.Channel;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+
+public class PushSession {
+    private SubscriptionData subscriptionData;
+
+    private Channel channel;
+
+    private String consumerGroup;
+
+    public SubscriptionData getSubscriptionData() {
+        return subscriptionData;
+    }
+
+    public void setSubscriptionData(SubscriptionData subscriptionData) {
+        this.subscriptionData = subscriptionData;
+    }
+
+    public Channel getChannel() {
+        return channel;
+    }
+
+    public void setChannel(Channel channel) {
+        this.channel = channel;
+    }
+
+    public String getConsumerGroup() {
+        return consumerGroup;
+    }
+
+    public void setConsumerGroup(String consumerGroup) {
+        this.consumerGroup = consumerGroup;
+    }
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/PushSessionManager.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/PushSessionManager.java
new file mode 100644
index 0000000..083ee0d
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/client/PushSessionManager.java
@@ -0,0 +1,23 @@
+package org.apache.rocketmq.snode.client;/*
+ * 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.
+ */
+
+import java.util.concurrent.ConcurrentHashMap;
+
+public class PushSessionManager {
+    private ConcurrentHashMap<String/*topic*/, PushSession> topicPushSessionMap = new ConcurrentHashMap<>(1024);
+    
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
index 15e4294..81bdcf0 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/processor/SendMessageProcessor.java
@@ -35,7 +35,6 @@ public class SendMessageProcessor implements NettyRequestProcessor {
 
     @Override
     public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) {
-        log.info("-----Receive sendback request: {}", request);
         CompletableFuture<RemotingCommand> responseFuture = snodeController.getEnodeService().sendMessage(request);
         responseFuture.whenComplete((data, ex) -> {
             if (ex == null) {
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/PushService.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/PushService.java
new file mode 100644
index 0000000..e9bfe2b
--- /dev/null
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/PushService.java
@@ -0,0 +1,26 @@
+package org.apache.rocketmq.snode.service;/*
+ * 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.
+ */
+
+import org.apache.rocketmq.common.message.Message;
+
+public interface PushService {
+    boolean registerPushSession(String consumerGroup);
+
+    void unregisterPushSession(String consumerGroup);
+
+    void pushMessage(Message message);
+}
diff --git a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
index d647f47..3729cc4 100644
--- a/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
+++ b/rocketmq-snode/src/main/java/org/apache/rocketmq/snode/service/impl/EnodeServiceImpl.java
@@ -115,7 +115,7 @@ public class EnodeServiceImpl implements EnodeService {
     public CompletableFuture<RemotingCommand> sendMessage(RemotingCommand request) {
         CompletableFuture<RemotingCommand> future = new CompletableFuture<>();
         try {
-            String enodeName = null;
+            String enodeName;
             if (request.getCode() == RequestCode.SEND_MESSAGE_V2) {
                 SendMessageRequestHeaderV2 sendMessageRequestHeaderV2 = (SendMessageRequestHeaderV2) request.decodeCommandCustomHeader(SendMessageRequestHeaderV2.class);
                 enodeName = sendMessageRequestHeaderV2.getN();
@@ -124,7 +124,6 @@ public class EnodeServiceImpl implements EnodeService {
                 enodeName = consumerSendMsgBackRequestHeader.getEnodeName();
             }
             String enodeAddress = this.snodeController.getNnodeService().getAddressByEnodeName(enodeName, false);
-            log.info("Receive request: {}", request);
             this.snodeController.getRemotingClient().invokeAsync(enodeAddress, request, SnodeConstant.defaultTimeoutMills, (responseFuture) -> {
                 future.complete(responseFuture.getResponseCommand());
             });