private void returnResponse(
      final String group,
      final String topic,
      ChannelHandlerContext ctx,
      final RemotingCommand response,
      final List<MessageExt> msgList) {
    if (null != msgList) {
      ByteBuffer[] msgBufferList = new ByteBuffer[msgList.size()];
      int bodyTotalSize = 0;
      for (int i = 0; i < msgList.size(); i++) {
        try {
          msgBufferList[i] = messageToByteBuffer(msgList.get(i));
          bodyTotalSize += msgBufferList[i].capacity();
        } catch (Exception e) {
          log.error("messageToByteBuffer UnsupportedEncodingException", e);
        }
      }

      ByteBuffer body = ByteBuffer.allocate(bodyTotalSize);
      for (ByteBuffer bb : msgBufferList) {
        bb.flip();
        body.put(bb);
      }

      response.setBody(body.array());

      // 统计
      this.filtersrvController
          .getFilterServerStatsManager()
          .incGroupGetNums(group, topic, msgList.size());

      this.filtersrvController
          .getFilterServerStatsManager()
          .incGroupGetSize(group, topic, bodyTotalSize);
    }

    try {
      ctx.writeAndFlush(response)
          .addListener(
              new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                  if (!future.isSuccess()) {
                    log.error(
                        "FilterServer response to " + future.channel().remoteAddress() + " failed",
                        future.cause());
                    log.error(response.toString());
                  }
                }
              });
    } catch (Throwable e) {
      log.error("FilterServer process request over, but response failed", e);
      log.error(response.toString());
    }
  }
  public void processResponseCommand(ChannelHandlerContext ctx, RemotingCommand cmd) {
    final ResponseFuture responseFuture = responseTable.get(cmd.getOpaque());
    if (responseFuture != null) {
      responseFuture.setResponseCommand(cmd);

      responseFuture.release();

      // 异步调用
      if (responseFuture.getInvokeCallback() != null) {
        boolean runInThisThread = false;
        ExecutorService executor = this.getCallbackExecutor();
        if (executor != null) {
          try {
            executor.submit(
                new Runnable() {
                  @Override
                  public void run() {
                    try {
                      responseFuture.executeInvokeCallback();
                    } catch (Throwable e) {
                      plog.warn("excute callback in executor exception, and callback throw", e);
                    }
                  }
                });
          } catch (Exception e) {
            runInThisThread = true;
            plog.warn("excute callback in executor exception, maybe executor busy", e);
          }
        } else {
          runInThisThread = true;
        }

        if (runInThisThread) {
          try {
            responseFuture.executeInvokeCallback();
          } catch (Throwable e) {
            plog.warn("executeInvokeCallback Exception", e);
          }
        }
      }
      // 同步调用
      else {
        responseFuture.putResponse(cmd);
      }
    } else {
      plog.warn(
          "receive response, but not matched any request, "
              + RemotingHelper.parseChannelRemoteAddr(ctx.channel()));
      plog.warn(cmd.toString());
    }

    responseTable.remove(cmd.getOpaque());
  }
 public void invokeOnewayImpl(
     final Channel channel, final RemotingCommand request, final long timeoutMillis)
     throws InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException,
         RemotingSendRequestException {
   request.markOnewayRPC();
   boolean acquired = this.semaphoreOneway.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS);
   if (acquired) {
     final SemaphoreReleaseOnlyOnce once = new SemaphoreReleaseOnlyOnce(this.semaphoreOneway);
     try {
       channel
           .writeAndFlush(request)
           .addListener(
               new ChannelFutureListener() {
                 @Override
                 public void operationComplete(ChannelFuture f) throws Exception {
                   once.release();
                   if (!f.isSuccess()) {
                     plog.warn(
                         "send a request command to channel <"
                             + channel.remoteAddress()
                             + "> failed.");
                     plog.warn(request.toString());
                   }
                 }
               });
     } catch (Exception e) {
       once.release();
       plog.warn(
           "write send a request command to channel <" + channel.remoteAddress() + "> failed.");
       throw new RemotingSendRequestException(RemotingHelper.parseChannelRemoteAddr(channel), e);
     }
   } else {
     if (timeoutMillis <= 0) {
       throw new RemotingTooMuchRequestException("invokeOnewayImpl invoke too fast");
     } else {
       String info =
           String.format(
               "invokeOnewayImpl tryAcquire semaphore timeout, %dms, waiting thread nums: %d semaphoreAsyncValue: %d", //
               timeoutMillis, //
               this.semaphoreAsync.getQueueLength(), //
               this.semaphoreAsync.availablePermits() //
               );
       plog.warn(info);
       plog.warn(request.toString());
       throw new RemotingTimeoutException(info);
     }
   }
 }
  public void invokeAsyncImpl(
      final Channel channel,
      final RemotingCommand request,
      final long timeoutMillis,
      final InvokeCallback invokeCallback)
      throws InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException,
          RemotingSendRequestException {
    boolean acquired = this.semaphoreAsync.tryAcquire(timeoutMillis, TimeUnit.MILLISECONDS);
    if (acquired) {
      final SemaphoreReleaseOnlyOnce once = new SemaphoreReleaseOnlyOnce(this.semaphoreAsync);

      final ResponseFuture responseFuture =
          new ResponseFuture(request.getOpaque(), timeoutMillis, invokeCallback, once);
      this.responseTable.put(request.getOpaque(), responseFuture);
      try {
        channel
            .writeAndFlush(request)
            .addListener(
                new ChannelFutureListener() {
                  @Override
                  public void operationComplete(ChannelFuture f) throws Exception {
                    if (f.isSuccess()) {
                      responseFuture.setSendRequestOK(true);
                      return;
                    } else {
                      responseFuture.setSendRequestOK(false);
                    }

                    responseFuture.putResponse(null);
                    responseTable.remove(request.getOpaque());
                    try {
                      responseFuture.executeInvokeCallback();
                    } catch (Throwable e) {
                      plog.warn(
                          "excute callback in writeAndFlush addListener, and callback throw", e);
                    } finally {
                      responseFuture.release();
                    }

                    plog.warn(
                        "send a request command to channel <{}> failed.",
                        RemotingHelper.parseChannelRemoteAddr(channel));
                    plog.warn(request.toString());
                  }
                });
      } catch (Exception e) {
        responseFuture.release();
        plog.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");
      } else {
        String info =
            String.format(
                "invokeAsyncImpl tryAcquire semaphore timeout, %dms, waiting thread nums: %d semaphoreAsyncValue: %d", //
                timeoutMillis, //
                this.semaphoreAsync.getQueueLength(), //
                this.semaphoreAsync.availablePermits() //
                );
        plog.warn(info);
        plog.warn(request.toString());
        throw new RemotingTimeoutException(info);
      }
    }
  }