You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rocketmq.apache.org by ji...@apache.org on 2025/12/04 11:09:13 UTC

(rocketmq) branch develop updated: [ISSUE #9396] Use fastjson2 in all modules (#9397)

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

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


The following commit(s) were added to refs/heads/develop by this push:
     new d7e27d6d69 [ISSUE #9396] Use fastjson2 in all modules (#9397)
d7e27d6d69 is described below

commit d7e27d6d6988a0cd98100097c9207ec0f5a9f83c
Author: yx9o <ya...@163.com>
AuthorDate: Thu Dec 4 19:09:08 2025 +0800

    [ISSUE #9396] Use fastjson2 in all modules (#9397)
    
    * Use fastjson2 in all modules
    
    * Update test
    
    * Update test
    
    * Update test
    
    * Add serialization compatibility test tool class
    
    * Update RemotingSerializableCompatTest.java
    
    * Update RemotingSerializableCompatTest.java
    
    * Update RemotingSerializableCompatTest.java
    
    * Update BitSet problem
    
    * Update
    
    * Update
    
    * Update test
    
    * Update test
    
    * Update BUILD.bazel
    
    * Update BUILD.bazel
    
    * Update test
    
    * Update BitSet problem
    
    * Add test
    
    * Add compat test
    
    * merge develop
    
    * Update test
    
    * merge develop
---
 broker/BUILD.bazel                                 |   2 -
 broker/pom.xml                                     |   4 -
 .../broker/config/v1/RocksDBConfigManager.java     |   9 +-
 .../config/v1/RocksDBConsumerOffsetManager.java    |  15 +-
 .../config/v1/RocksDBSubscriptionGroupManager.java |  25 +-
 .../config/v1/RocksDBTopicConfigManager.java       |  15 +-
 .../rocketmq/broker/pop/PopConsumerRecord.java     |   8 +-
 .../rocketmq/broker/pop/PopConsumerService.java    |  35 +-
 .../pop/orderly/QueueLevelConsumerManager.java     |   2 +-
 .../broker/processor/AckMessageProcessor.java      |   2 +-
 .../broker/processor/AdminBrokerProcessor.java     |   7 +-
 .../processor/ChangeInvisibleTimeProcessor.java    |   2 +-
 .../broker/processor/PopBufferMergeService.java    |  19 +-
 .../broker/processor/PopMessageProcessor.java      |  29 +-
 .../broker/processor/PopReviveService.java         |  23 +-
 .../broker/topic/TopicQueueMappingManager.java     |   8 +-
 .../broker/transaction/TransactionMetrics.java     |  27 +-
 .../rocketmq/broker/RocksDBConfigManagerTest.java  |  67 ++
 .../broker/client/ConsumerManagerTest.java         |   4 +
 .../v1/RocksDBSubscriptionGroupManagerTest.java    | 120 +++
 .../config/v1/RocksDBTopicConfigManagerTest.java   |  97 +++
 .../broker/pagecache/QueryMessageTransferTest.java | 139 ++++
 .../broker/processor/AdminBrokerProcessorTest.java |  84 ++-
 .../ChangeInvisibleTimeProcessorTest.java          |  83 ++-
 .../processor/PopBufferMergeServiceTest.java       | 192 ++++-
 .../broker/processor/PopMessageProcessorTest.java  |  50 +-
 .../broker/processor/PopReviveServiceTest.java     | 105 ++-
 .../subscription/SubscriptionGroupManagerTest.java |   8 +-
 .../broker/topic/TopicQueueMappingManagerTest.java |  68 +-
 .../transaction/queue/TransactionMetricsTest.java  |  59 +-
 client/BUILD.bazel                                 |   1 -
 .../rocketmq/client/impl/MQClientAPIImpl.java      |   2 +-
 .../client/impl/factory/MQClientInstance.java      |  39 +-
 .../rocketmq/client/producer/SendResult.java       |   2 +-
 .../consumer/DefaultLitePullConsumerTest.java      |  25 +-
 .../rocketmq/client/impl/MQClientAPIImplTest.java  |  18 +
 .../client/impl/admin/MqClientAdminImplTest.java   |   4 +-
 .../client/impl/consumer/PopProcessQueueTest.java  |  56 ++
 .../client/impl/consumer/ProcessQueueTest.java     |  12 +-
 .../rocketmq/client/producer/SendResultTest.java   |  59 ++
 common/BUILD.bazel                                 |   2 -
 .../org/apache/rocketmq/common/TopicConfig.java    |  11 +-
 .../fastjson/GenericMapSuperclassDeserializer.java |  41 +-
 .../rocketmq/common/utils/FastJsonSerializer.java  |  16 +-
 .../GenericMapSuperclassDeserializerTest.java      | 104 +++
 container/BUILD.bazel                              |   2 -
 controller/BUILD.bazel                             |   4 +-
 .../impl/heartbeat/RaftBrokerHeartBeatManager.java |   4 +-
 .../impl/manager/RaftReplicasInfoManager.java      |   2 +-
 .../impl/RaftBrokerHeartBeatManagerTest.java       |  11 +-
 .../controller/impl/event/EventSerializerTest.java | 122 +++
 .../impl/event/ListEventSerializerTest.java        |  93 +++
 .../heartbeat/RaftBrokerHeartBeatManagerTest.java  | 352 +++++++++
 .../impl/manager/RaftReplicasInfoManagerTest.java  | 243 ++++++
 filter/BUILD.bazel                                 |   1 -
 namesrv/BUILD.bazel                                |   4 +-
 .../namesrv/processor/ClientRequestProcessor.java  |  12 +-
 .../processor/ClientRequestProcessorTest.java      | 195 +++++
 proxy/BUILD.bazel                                  |   2 -
 .../rocketmq/proxy/config/Configuration.java       |   2 +-
 .../proxy/config/ConfigurationManager.java         |   6 +-
 .../processor/channel/RemoteChannelSerializer.java |   9 +-
 .../remoting/activity/GetTopicRouteActivity.java   |  17 +-
 .../proxy/remoting/channel/RemotingChannel.java    |  15 +-
 .../sysmessage/AbstractSystemMessageSyncer.java    |  11 +-
 .../proxy/service/sysmessage/HeartbeatSyncer.java  |  19 +-
 .../proxy/config/ConfigurationManagerTest.java     |  10 +
 ...tionManagerTest.java => ConfigurationTest.java} |  35 +-
 .../activity/GetTopicRouteActivityTest.java        | 171 +++++
 remoting/BUILD.bazel                               |   4 +-
 .../remoting/netty/NettyRemotingClient.java        |  47 +-
 .../protocol/BitSetSerializerDeserializer.java     |  47 +-
 .../remoting/protocol/RemotingCommand.java         |  22 +-
 .../remoting/protocol/RemotingSerializable.java    |  12 +-
 .../rocketmq/remoting/protocol/body/BatchAck.java  |   2 +-
 .../remoting/protocol/body/RegisterBrokerBody.java |  21 +-
 .../remoting/protocol/heartbeat/HeartbeatData.java |  10 +-
 .../protocol/heartbeat/SubscriptionData.java       |   5 +-
 .../protocol/subscription/GroupRetryPolicy.java    |   2 +-
 .../protocol/RemotingSerializableCompatTest.java   | 425 +++++++++++
 .../protocol/RemotingSerializableTest.java         |   5 +-
 .../remoting/protocol/body/BatchAckTest.java       |   2 +-
 .../statictopic/TopicQueueMappingTest.java         |  14 +-
 srvutil/BUILD.bazel                                |   1 -
 store/BUILD.bazel                                  |   3 +-
 .../java/org/apache/rocketmq/store/pop/AckMsg.java |   2 +-
 .../org/apache/rocketmq/store/pop/BatchAckMsg.java |   3 +-
 .../apache/rocketmq/store/pop/PopCheckPoint.java   |   6 +-
 .../store/queue/CombineConsumeQueueStore.java      |   2 +-
 .../apache/rocketmq/store/timer/TimerMetrics.java  |  34 +-
 .../org/apache/rocketmq/store/pop/AckMsgTest.java  |   2 +-
 .../apache/rocketmq/store/pop/BatchAckMsgTest.java |   2 +-
 test/BUILD.bazel                                   |   1 -
 tieredstore/BUILD.bazel                            |   4 +-
 .../rocketmq/tieredstore/file/FlatMessageFile.java |   2 +-
 .../tieredstore/metadata/DefaultMetadataStore.java |  28 +-
 .../metadata/entity/FileSegmentMetadata.java       |   2 +-
 .../tieredstore/metadata/entity/QueueMetadata.java |   2 +-
 .../tieredstore/metadata/entity/TopicMetadata.java |   2 +-
 tools/BUILD.bazel                                  |   1 -
 tools/pom.xml                                      |   4 -
 .../tools/admin/DefaultMQAdminExtImpl.java         |   2 +-
 .../broker/GetColdDataFlowCtrInfoSubCommand.java   |  18 +-
 .../command/consumer/UpdateSubGroupSubCommand.java |   7 +-
 .../tools/command/export/ExportConfigsCommand.java |  20 +-
 .../command/export/ExportMetadataCommand.java      |  16 +-
 .../export/ExportMetadataInRocksDBCommand.java     |  17 +-
 .../tools/command/export/ExportMetricsCommand.java |  16 +-
 .../metadata/RocksDBConfigToJsonCommand.java       |  38 +-
 .../command/queue/QueryConsumeQueueCommand.java    |   5 +-
 .../tools/admin/DefaultMQAdminExtImplTest.java     | 825 +++++++++++++++++++++
 .../ConsumerConnectionSubCommandTest.java          |   5 +-
 .../ProducerConnectionSubCommandTest.java          |   5 +-
 .../consumer/ConsumerStatusSubCommandTest.java     |   5 +-
 .../consumer/GetConsumerConfigSubCommandTest.java  |   9 +-
 .../command/producer/ProducerSubCommandTest.java   |  36 +-
 116 files changed, 4176 insertions(+), 609 deletions(-)

diff --git a/broker/BUILD.bazel b/broker/BUILD.bazel
index fdf549d3e5..ffd2bea14c 100644
--- a/broker/BUILD.bazel
+++ b/broker/BUILD.bazel
@@ -31,7 +31,6 @@ java_library(
         "//tieredstore",
         "@maven//:org_slf4j_slf4j_api",
         "@maven//:ch_qos_logback_logback_classic",
-        "@maven//:com_alibaba_fastjson",
         "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:com_github_luben_zstd_jni",
         "@maven//:com_google_guava_guava",
@@ -83,7 +82,6 @@ java_library(
         "//remoting",
         "//store",
         "//tieredstore",
-        "@maven//:com_alibaba_fastjson",
         "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:org_slf4j_slf4j_api",
         "@maven//:com_google_guava_guava",
diff --git a/broker/pom.xml b/broker/pom.xml
index 1751852631..b94e596cc5 100644
--- a/broker/pom.xml
+++ b/broker/pom.xml
@@ -66,10 +66,6 @@
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
         </dependency>
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>fastjson</artifactId>
-        </dependency>
         <dependency>
             <groupId>org.javassist</groupId>
             <artifactId>javassist</artifactId>
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConfigManager.java b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConfigManager.java
index e4827e2baf..e68cd20a9d 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConfigManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConfigManager.java
@@ -16,10 +16,7 @@
  */
 package org.apache.rocketmq.broker.config.v1;
 
-import com.alibaba.fastjson.JSON;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.function.BiConsumer;
+import com.alibaba.fastjson2.JSON;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.rocketmq.common.config.ConfigRocksDBStorage;
 import org.apache.rocketmq.common.constant.LoggerName;
@@ -33,6 +30,10 @@ import org.rocksdb.RocksDBException;
 import org.rocksdb.Statistics;
 import org.rocksdb.WriteBatch;
 
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.function.BiConsumer;
+
 public class RocksDBConfigManager {
     protected static final Logger BROKER_LOG = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
 
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConsumerOffsetManager.java b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConsumerOffsetManager.java
index 6536f90a8d..45e1a2ab23 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConsumerOffsetManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBConsumerOffsetManager.java
@@ -16,12 +16,8 @@
  */
 package org.apache.rocketmq.broker.config.v1;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentMap;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.rocketmq.broker.BrokerController;
 import org.apache.rocketmq.broker.BrokerPathConfigHelper;
@@ -35,6 +31,11 @@ import org.apache.rocketmq.remoting.protocol.DataVersion;
 import org.rocksdb.CompressionType;
 import org.rocksdb.WriteBatch;
 
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentMap;
+
 public class RocksDBConsumerOffsetManager extends ConsumerOffsetManager {
 
     protected static final Logger log = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
@@ -184,7 +185,7 @@ public class RocksDBConsumerOffsetManager extends ConsumerOffsetManager {
         byte[] keyBytes = topicGroupName.getBytes(DataConverter.CHARSET_UTF8);
         RocksDBOffsetSerializeWrapper wrapper = new RocksDBOffsetSerializeWrapper();
         wrapper.setOffsetTable(offsetMap);
-        byte[] valueBytes = JSON.toJSONBytes(wrapper, SerializerFeature.BrowserCompatible);
+        byte[] valueBytes = JSON.toJSONBytes(wrapper, JSONWriter.Feature.BrowserCompatible);
         rocksDBConfigManager.writeBatchPutOperation(writeBatch, keyBytes, valueBytes);
     }
 
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBSubscriptionGroupManager.java b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBSubscriptionGroupManager.java
index f6ae3a3e59..b4392212a6 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBSubscriptionGroupManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBSubscriptionGroupManager.java
@@ -16,16 +16,9 @@
  */
 package org.apache.rocketmq.broker.config.v1;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.alibaba.fastjson.serializer.SerializerFeature;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.function.BiConsumer;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.JSONWriter;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.rocketmq.broker.BrokerController;
 import org.apache.rocketmq.broker.BrokerPathConfigHelper;
@@ -35,6 +28,14 @@ import org.apache.rocketmq.remoting.protocol.DataVersion;
 import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
 import org.rocksdb.CompressionType;
 
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.BiConsumer;
+
 public class RocksDBSubscriptionGroupManager extends SubscriptionGroupManager {
 
     protected transient RocksDBConfigManager rocksDBConfigManager;
@@ -162,7 +163,7 @@ public class RocksDBSubscriptionGroupManager extends SubscriptionGroupManager {
 
         try {
             byte[] keyBytes = groupName.getBytes(RocksDBConfigManager.CHARSET);
-            byte[] valueBytes = JSON.toJSONBytes(subscriptionGroupConfig, SerializerFeature.BrowserCompatible);
+            byte[] valueBytes = JSON.toJSONBytes(subscriptionGroupConfig, JSONWriter.Feature.BrowserCompatible);
             this.rocksDBConfigManager.put(keyBytes, valueBytes);
         } catch (Exception e) {
             log.error("kv put sub Failed, {}", subscriptionGroupConfig.toString());
@@ -177,7 +178,7 @@ public class RocksDBSubscriptionGroupManager extends SubscriptionGroupManager {
         if (oldConfig == null) {
             try {
                 byte[] keyBytes = groupName.getBytes(RocksDBConfigManager.CHARSET);
-                byte[] valueBytes = JSON.toJSONBytes(subscriptionGroupConfig, SerializerFeature.BrowserCompatible);
+                byte[] valueBytes = JSON.toJSONBytes(subscriptionGroupConfig, JSONWriter.Feature.BrowserCompatible);
                 this.rocksDBConfigManager.put(keyBytes, valueBytes);
             } catch (Exception e) {
                 log.error("kv put sub Failed, {}", subscriptionGroupConfig.toString());
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBTopicConfigManager.java b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBTopicConfigManager.java
index 4a8d124e9b..96f12e6681 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBTopicConfigManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/config/v1/RocksDBTopicConfigManager.java
@@ -16,12 +16,8 @@
  */
 package org.apache.rocketmq.broker.config.v1;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Map;
-import java.util.concurrent.ConcurrentMap;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.rocketmq.broker.BrokerController;
 import org.apache.rocketmq.broker.BrokerPathConfigHelper;
@@ -32,6 +28,11 @@ import org.apache.rocketmq.common.utils.DataConverter;
 import org.apache.rocketmq.remoting.protocol.DataVersion;
 import org.rocksdb.CompressionType;
 
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
 public class RocksDBTopicConfigManager extends TopicConfigManager {
     private static final String VERSION_COLUMN_FAMILY = "topicVersion";
     private static final String TOPIC_COLUMN_FAMILY = "topic";
@@ -142,7 +143,7 @@ public class RocksDBTopicConfigManager extends TopicConfigManager {
         TopicConfig oldTopicConfig = this.topicConfigTable.put(topicName, topicConfig);
         try {
             byte[] keyBytes = topicName.getBytes(DataConverter.CHARSET_UTF8);
-            byte[] valueBytes = JSON.toJSONBytes(topicConfig, SerializerFeature.BrowserCompatible);
+            byte[] valueBytes = JSON.toJSONBytes(topicConfig, JSONWriter.Feature.BrowserCompatible);
             this.rocksDBConfigManager.put(keyBytes, valueBytes);
         } catch (Exception e) {
             log.error("kv put topic Failed, {}", topicConfig.toString(), e);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerRecord.java b/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerRecord.java
index 1ee01fea1c..661ace9bcb 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerRecord.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerRecord.java
@@ -16,9 +16,9 @@
  */
 package org.apache.rocketmq.broker.pop;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.annotation.JSONField;
+
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 
@@ -119,7 +119,7 @@ public class PopConsumerRecord {
     }
 
     public static PopConsumerRecord decode(byte[] body) {
-        return JSONObject.parseObject(body, PopConsumerRecord.class);
+        return JSON.parseObject(body, PopConsumerRecord.class);
     }
 
     public long getPopTime() {
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerService.java b/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerService.java
index 7678daa1d3..839c96e390 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/pop/PopConsumerService.java
@@ -16,25 +16,9 @@
  */
 package org.apache.rocketmq.broker.pop;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Stopwatch;
-import java.nio.ByteBuffer;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Objects;
-import java.util.Queue;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionException;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Triple;
 import org.apache.rocketmq.broker.BrokerController;
@@ -65,6 +49,23 @@ import org.apache.rocketmq.store.pop.PopCheckPoint;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.nio.ByteBuffer;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
 public class PopConsumerService extends ServiceThread {
 
     private static final Logger log = LoggerFactory.getLogger(LoggerName.ROCKETMQ_POP_LOGGER_NAME);
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/pop/orderly/QueueLevelConsumerManager.java b/broker/src/main/java/org/apache/rocketmq/broker/pop/orderly/QueueLevelConsumerManager.java
index 79bd59fb78..8a5ed6b150 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/pop/orderly/QueueLevelConsumerManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/pop/orderly/QueueLevelConsumerManager.java
@@ -16,7 +16,7 @@
  */
 package org.apache.rocketmq.broker.pop.orderly;
 
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.MoreObjects;
 import java.util.ArrayList;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/AckMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/AckMessageProcessor.java
index 864f40d296..1334693352 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/AckMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/AckMessageProcessor.java
@@ -16,7 +16,7 @@
  */
 package org.apache.rocketmq.broker.processor;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandlerContext;
 import java.nio.charset.StandardCharsets;
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 298e239086..e7333ab91a 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
@@ -16,8 +16,9 @@
  */
 package org.apache.rocketmq.broker.processor;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.JSONWriter;
 import com.google.common.collect.Sets;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandlerContext;
@@ -2785,7 +2786,7 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
             } else {
                 ConsumerFilterData filterData = this.brokerController.getConsumerFilterManager()
                     .get(requestHeader.getTopic(), requestHeader.getConsumerGroup());
-                body.setFilterData(JSON.toJSONString(filterData, true));
+                body.setFilterData(JSON.toJSONString(filterData, JSONWriter.Feature.PrettyFormat));
 
                 messageFilter = new ExpressionMessageFilter(subscriptionData, filterData,
                     this.brokerController.getConsumerFilterManager());
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessor.java
index f104e76a52..332930cd78 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessor.java
@@ -16,7 +16,7 @@
  */
 package org.apache.rocketmq.broker.processor;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandlerContext;
 import java.nio.charset.StandardCharsets;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopBufferMergeService.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopBufferMergeService.java
index 657adaa34d..06d89e047d 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopBufferMergeService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopBufferMergeService.java
@@ -16,15 +16,7 @@
  */
 package org.apache.rocketmq.broker.processor;
 
-import com.alibaba.fastjson.JSON;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.LinkedBlockingDeque;
-import java.util.concurrent.atomic.AtomicInteger;
+import com.alibaba.fastjson2.JSON;
 import org.apache.rocketmq.broker.BrokerController;
 import org.apache.rocketmq.common.KeyBuilder;
 import org.apache.rocketmq.common.PopAckConstants;
@@ -43,6 +35,15 @@ import org.apache.rocketmq.store.pop.AckMsg;
 import org.apache.rocketmq.store.pop.BatchAckMsg;
 import org.apache.rocketmq.store.pop.PopCheckPoint;
 
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.atomic.AtomicInteger;
+
 public class PopBufferMergeService extends ServiceThread {
     private static final Logger POP_LOGGER = LoggerFactory.getLogger(LoggerName.ROCKETMQ_POP_LOGGER_NAME);
     ConcurrentHashMap<String/*mergeKey*/, PopCheckPointWrapper>
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopMessageProcessor.java
index 9967955656..3144eb973a 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopMessageProcessor.java
@@ -16,26 +16,13 @@
  */
 package org.apache.rocketmq.broker.processor;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import com.github.benmanes.caffeine.cache.Cache;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.FileRegion;
 import io.opentelemetry.api.common.Attributes;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Random;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentSkipListSet;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
 import org.apache.rocketmq.broker.BrokerController;
 import org.apache.rocketmq.broker.filter.ConsumerFilterData;
 import org.apache.rocketmq.broker.filter.ConsumerFilterManager;
@@ -89,6 +76,20 @@ import org.apache.rocketmq.store.pop.AckMsg;
 import org.apache.rocketmq.store.pop.BatchAckMsg;
 import org.apache.rocketmq.store.pop.PopCheckPoint;
 
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Random;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
 import static org.apache.rocketmq.broker.metrics.BrokerMetricsConstant.LABEL_CONSUMER_GROUP;
 import static org.apache.rocketmq.broker.metrics.BrokerMetricsConstant.LABEL_IS_RETRY;
 import static org.apache.rocketmq.broker.metrics.BrokerMetricsConstant.LABEL_IS_SYSTEM;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopReviveService.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopReviveService.java
index aa7d87505e..434812883e 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/PopReviveService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/PopReviveService.java
@@ -16,18 +16,8 @@
  */
 package org.apache.rocketmq.broker.processor;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import io.opentelemetry.api.common.Attributes;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.NavigableMap;
-import java.util.TreeMap;
-import java.util.concurrent.CompletableFuture;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Triple;
 import org.apache.rocketmq.broker.BrokerController;
@@ -59,6 +49,17 @@ import org.apache.rocketmq.store.pop.AckMsg;
 import org.apache.rocketmq.store.pop.BatchAckMsg;
 import org.apache.rocketmq.store.pop.PopCheckPoint;
 
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.TreeMap;
+import java.util.concurrent.CompletableFuture;
+
 import static org.apache.rocketmq.broker.metrics.BrokerMetricsConstant.LABEL_CONSUMER_GROUP;
 import static org.apache.rocketmq.broker.metrics.BrokerMetricsConstant.LABEL_IS_SYSTEM;
 import static org.apache.rocketmq.broker.metrics.BrokerMetricsConstant.LABEL_TOPIC;
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManager.java b/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManager.java
index 4b0714decb..9e20ecd9b6 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManager.java
@@ -16,7 +16,8 @@
  */
 package org.apache.rocketmq.broker.topic;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
 import com.google.common.collect.Maps;
 import java.util.List;
 import java.util.Map;
@@ -156,7 +157,10 @@ public class TopicQueueMappingManager extends ConfigManager {
         TopicQueueMappingSerializeWrapper wrapper = new TopicQueueMappingSerializeWrapper();
         wrapper.setTopicQueueMappingInfoMap(topicQueueMappingTable);
         wrapper.setDataVersion(this.dataVersion);
-        return JSON.toJSONString(wrapper, pretty);
+        if (pretty) {
+            return JSON.toJSONString(wrapper, JSONWriter.Feature.PrettyFormat);
+        }
+        return JSON.toJSONString(wrapper);
     }
 
     @Override
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionMetrics.java b/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionMetrics.java
index 8a18218f53..17b0ac6774 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionMetrics.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/transaction/TransactionMetrics.java
@@ -16,9 +16,19 @@
  */
 package org.apache.rocketmq.broker.transaction;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
+import org.apache.rocketmq.common.ConfigManager;
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.topic.TopicValidator;
+import org.apache.rocketmq.logging.org.slf4j.Logger;
+import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
+import org.apache.rocketmq.remoting.protocol.DataVersion;
+import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+
 import java.io.File;
+import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.io.StringWriter;
 import java.io.Writer;
@@ -32,14 +42,7 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicLong;
-import org.apache.rocketmq.common.ConfigManager;
-import org.apache.rocketmq.common.MixAll;
-import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.common.topic.TopicValidator;
-import org.apache.rocketmq.logging.org.slf4j.Logger;
-import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
-import org.apache.rocketmq.remoting.protocol.DataVersion;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+
 
 public class TransactionMetrics extends ConfigManager {
     private static final Logger log = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
@@ -90,11 +93,11 @@ public class TransactionMetrics extends ConfigManager {
         this.transactionCounts = transactionCounts;
     }
 
-    protected void write0(Writer writer) {
+    protected void write0(Writer writer) throws IOException {
         TransactionMetricsSerializeWrapper wrapper = new TransactionMetricsSerializeWrapper();
         wrapper.setTransactionCount(transactionCounts);
         wrapper.setDataVersion(dataVersion);
-        JSON.writeJSONString(writer, wrapper, SerializerFeature.BrowserCompatible);
+        writer.write(JSON.toJSONString(wrapper, JSONWriter.Feature.BrowserCompatible));
     }
 
     @Override
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/RocksDBConfigManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/RocksDBConfigManagerTest.java
new file mode 100644
index 0000000000..1832902a76
--- /dev/null
+++ b/broker/src/test/java/org/apache/rocketmq/broker/RocksDBConfigManagerTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import org.apache.rocketmq.broker.config.v1.RocksDBConfigManager;
+import org.apache.rocketmq.common.config.ConfigRocksDBStorage;
+import org.apache.rocketmq.remoting.protocol.DataVersion;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.powermock.api.mockito.PowerMockito.mock;
+
+public class RocksDBConfigManagerTest {
+
+    private ConfigRocksDBStorage configRocksDBStorage;
+
+    private RocksDBConfigManager rocksDBConfigManager;
+
+    @Before
+    public void setUp() throws IllegalAccessException {
+        configRocksDBStorage = mock(ConfigRocksDBStorage.class);
+        rocksDBConfigManager = spy(new RocksDBConfigManager("testPath", 1000L, null));
+        rocksDBConfigManager.configRocksDBStorage = configRocksDBStorage;
+    }
+
+    @Test
+    public void testLoadDataVersion() throws Exception {
+        DataVersion expected = new DataVersion();
+        expected.nextVersion();
+
+        when(rocksDBConfigManager.getKvDataVersion()).thenReturn(expected);
+
+        boolean result = rocksDBConfigManager.loadDataVersion();
+
+        assertTrue(result);
+        assertEquals(expected.getCounter().get(), rocksDBConfigManager.getKvDataVersion().getCounter().get());
+        assertEquals(expected.getTimestamp(), rocksDBConfigManager.getKvDataVersion().getTimestamp());
+    }
+
+    @Test
+    public void testUpdateKvDataVersion() throws Exception {
+        rocksDBConfigManager.updateKvDataVersion();
+
+        verify(rocksDBConfigManager, times(1)).updateKvDataVersion();
+    }
+}
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java
index 1b8293159d..5f2e96015d 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/client/ConsumerManagerTest.java
@@ -20,6 +20,7 @@ package org.apache.rocketmq.broker.client;
 import com.google.common.collect.ImmutableSet;
 import io.netty.channel.Channel;
 import org.apache.rocketmq.broker.BrokerController;
+import org.apache.rocketmq.broker.client.net.Broker2Client;
 import org.apache.rocketmq.broker.filter.ConsumerFilterManager;
 import org.apache.rocketmq.common.BrokerConfig;
 import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
@@ -214,6 +215,9 @@ public class ConsumerManagerTest {
     
     @Test
     public void testRegisterConsumerWithoutSub() {
+        when(brokerController.getBrokerConfig()).thenReturn(brokerConfig);
+        Broker2Client broker2Client = mock(Broker2Client.class);
+        when(brokerController.getBroker2Client()).thenReturn(broker2Client);
         ConsumerGroupInfo groupInfo = new ConsumerGroupInfo(GROUP, CONSUME_PASSIVELY,
                 MessageModel.CLUSTERING, ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
         SubscriptionData subscriptionData = new SubscriptionData(TOPIC, "*");
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/config/v1/RocksDBSubscriptionGroupManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/config/v1/RocksDBSubscriptionGroupManagerTest.java
new file mode 100644
index 0000000000..98d0e34219
--- /dev/null
+++ b/broker/src/test/java/org/apache/rocketmq/broker/config/v1/RocksDBSubscriptionGroupManagerTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.config.v1;
+
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.rocketmq.broker.BrokerController;
+import org.apache.rocketmq.common.BrokerConfig;
+import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.store.config.MessageStoreConfig;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.ConcurrentMap;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RocksDBSubscriptionGroupManagerTest {
+
+    @Mock
+    private BrokerController brokerController;
+
+    @Mock
+    private RocksDBConfigManager rocksDBConfigManager;
+
+    private RocksDBSubscriptionGroupManager rocksDBSubscriptionGroupManager;
+
+    @Mock
+    private MessageStoreConfig messageStoreConfig;
+
+    @Before
+    public void init() throws IllegalAccessException {
+        when(brokerController.getMessageStoreConfig()).thenReturn(messageStoreConfig);
+        when(messageStoreConfig.getMemTableFlushIntervalMs()).thenReturn(1000L);
+        when(messageStoreConfig.getRocksdbCompressionType()).thenReturn("LZ4_COMPRESSION");
+        when(messageStoreConfig.getStorePathRootDir()).thenReturn("/");
+        BrokerConfig brokerConfig = mock(BrokerConfig.class);
+        when(brokerConfig.isUseSingleRocksDBForAllConfigs()).thenReturn(true);
+        when(brokerController.getBrokerConfig()).thenReturn(brokerConfig);
+        rocksDBSubscriptionGroupManager = new RocksDBSubscriptionGroupManager(brokerController);
+        FieldUtils.writeDeclaredField(rocksDBSubscriptionGroupManager, "rocksDBConfigManager", rocksDBConfigManager, true);
+    }
+
+    @Test
+    public void testPutSubscriptionGroupConfig() {
+        SubscriptionGroupConfig newConfig = new SubscriptionGroupConfig();
+        newConfig.setGroupName("group");
+        SubscriptionGroupConfig oldConfig = new SubscriptionGroupConfig();
+        oldConfig.setGroupName("group");
+        rocksDBSubscriptionGroupManager.getSubscriptionGroupTable().put("group", oldConfig);
+
+        assertEquals(oldConfig, rocksDBSubscriptionGroupManager.putSubscriptionGroupConfig(newConfig));
+        assertEquals(newConfig, rocksDBSubscriptionGroupManager.getSubscriptionGroupTable().get("group"));
+    }
+
+    @Test
+    public void testPutSubscriptionGroupConfigIfAbsent() {
+        SubscriptionGroupConfig newConfig = new SubscriptionGroupConfig();
+        newConfig.setGroupName("group");
+        SubscriptionGroupConfig oldConfig = new SubscriptionGroupConfig();
+        oldConfig.setGroupName("group");
+
+        assertNull(rocksDBSubscriptionGroupManager.putSubscriptionGroupConfigIfAbsent(newConfig));
+        assertEquals(newConfig, rocksDBSubscriptionGroupManager.getSubscriptionGroupTable().get("group"));
+    }
+
+    @Test
+    public void testDecodeForbidden() {
+        String forbiddenGroupName = "group";
+        String bodyJson = "{\"topic1\":1,\"topic2\":2}";
+        byte[] key = forbiddenGroupName.getBytes(StandardCharsets.UTF_8);
+        byte[] body = bodyJson.getBytes(StandardCharsets.UTF_8);
+
+        rocksDBSubscriptionGroupManager.decodeForbidden(key, body);
+        ConcurrentMap<String, ConcurrentMap<String, Integer>> forbiddenTable = rocksDBSubscriptionGroupManager.getForbiddenTable();
+        assertTrue(forbiddenTable.containsKey(forbiddenGroupName));
+
+        ConcurrentMap<String, Integer> forbiddenGroup = forbiddenTable.get(forbiddenGroupName);
+        assertEquals(2, forbiddenGroup.size());
+        assertEquals(Integer.valueOf(1), forbiddenGroup.get("topic1"));
+        assertEquals(Integer.valueOf(2), forbiddenGroup.get("topic2"));
+    }
+
+    @Test
+    public void testDecodeSubscriptionGroup() {
+        String groupName = "group";
+        String bodyJson = "{\"groupName\":\"group\",\"consumeEnable\":true}";
+        byte[] key = groupName.getBytes(StandardCharsets.UTF_8);
+        byte[] body = bodyJson.getBytes(StandardCharsets.UTF_8);
+
+        rocksDBSubscriptionGroupManager.decodeSubscriptionGroup(key, body);
+        ConcurrentMap<String, SubscriptionGroupConfig> subscriptionGroupTable = rocksDBSubscriptionGroupManager.getSubscriptionGroupTable();
+        assertEquals(1, subscriptionGroupTable.size());
+        SubscriptionGroupConfig config = subscriptionGroupTable.get(groupName);
+        assertEquals(groupName, config.getGroupName());
+        assertTrue(config.isConsumeEnable());
+    }
+}
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/config/v1/RocksDBTopicConfigManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/config/v1/RocksDBTopicConfigManagerTest.java
new file mode 100644
index 0000000000..b2b742fb2f
--- /dev/null
+++ b/broker/src/test/java/org/apache/rocketmq/broker/config/v1/RocksDBTopicConfigManagerTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.config.v1;
+
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.rocketmq.broker.BrokerController;
+import org.apache.rocketmq.common.BrokerConfig;
+import org.apache.rocketmq.common.TopicConfig;
+import org.apache.rocketmq.store.config.MessageStoreConfig;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.ConcurrentMap;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RocksDBTopicConfigManagerTest {
+
+    @Mock
+    private BrokerController brokerController;
+
+    @Mock
+    private MessageStoreConfig messageStoreConfig;
+
+    @Mock
+    private RocksDBConfigManager rocksDBConfigManager;
+
+    private RocksDBTopicConfigManager rocksDBTopicConfigManager;
+
+    @Before
+    public void init() throws Exception {
+        when(brokerController.getMessageStoreConfig()).thenReturn(messageStoreConfig);
+        when(messageStoreConfig.getMemTableFlushIntervalMs()).thenReturn(1000L);
+        when(messageStoreConfig.getRocksdbCompressionType()).thenReturn("LZ4_COMPRESSION");
+        when(messageStoreConfig.getStorePathRootDir()).thenReturn("/");
+        BrokerConfig brokerConfig = mock(BrokerConfig.class);
+        when(brokerConfig.isUseSingleRocksDBForAllConfigs()).thenReturn(true);
+        when(brokerController.getBrokerConfig()).thenReturn(brokerConfig);
+        rocksDBTopicConfigManager = new RocksDBTopicConfigManager(brokerController);
+        FieldUtils.writeDeclaredField(rocksDBTopicConfigManager, "rocksDBConfigManager", rocksDBConfigManager, true);
+    }
+
+    @Test
+    public void testDecodeTopicConfig() {
+        String topicName = "testTopic";
+        String topicConfigJson = "{\"topicName\":\"testTopic\",\"readQueueNums\":10,\"writeQueueNums\":10}";
+        byte[] key = topicName.getBytes(StandardCharsets.UTF_8);
+        byte[] body = topicConfigJson.getBytes(StandardCharsets.UTF_8);
+
+        rocksDBTopicConfigManager.decodeTopicConfig(key, body);
+
+        ConcurrentMap<String, TopicConfig> topicConfigTable = rocksDBTopicConfigManager.getTopicConfigTable();
+        assertNotNull(topicConfigTable);
+        assertEquals(1, topicConfigTable.size());
+        TopicConfig topicConfig = topicConfigTable.get(topicName);
+        assertNotNull(topicConfig);
+        assertEquals(topicName, topicConfig.getTopicName());
+        assertEquals(10, topicConfig.getReadQueueNums());
+        assertEquals(10, topicConfig.getWriteQueueNums());
+    }
+
+    @Test
+    public void testPutTopicConfig() throws Exception {
+        TopicConfig newTopicConfig = new TopicConfig("newTopic");
+        newTopicConfig.setReadQueueNums(10);
+        newTopicConfig.setWriteQueueNums(10);
+
+        assertNull(rocksDBTopicConfigManager.putTopicConfig(newTopicConfig));
+        verify(rocksDBConfigManager, times(1)).put(any(byte[].class), any(byte[].class));
+    }
+}
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/pagecache/QueryMessageTransferTest.java b/broker/src/test/java/org/apache/rocketmq/broker/pagecache/QueryMessageTransferTest.java
new file mode 100644
index 0000000000..a10dd4efca
--- /dev/null
+++ b/broker/src/test/java/org/apache/rocketmq/broker/pagecache/QueryMessageTransferTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.pagecache;
+
+import org.apache.rocketmq.store.QueryMessageResult;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class QueryMessageTransferTest {
+
+    @Mock
+    private WritableByteChannel writableByteChannel;
+
+    @Mock
+    private QueryMessageResult queryMessageResult;
+
+    private QueryMessageTransfer queryMessageTransfer;
+
+    private ByteBuffer byteBufferHeader;
+
+    private ByteBuffer bb1;
+
+    private ByteBuffer bb2;
+
+    @Before
+    public void init() {
+        byteBufferHeader = ByteBuffer.allocate(4);
+        byteBufferHeader.putInt(1);
+        byteBufferHeader.flip();
+
+        bb1 = ByteBuffer.allocate(4);
+        bb1.putInt(2);
+        bb1.flip();
+
+        bb2 = ByteBuffer.allocate(4);
+        bb2.putInt(3);
+        bb2.flip();
+
+        when(queryMessageResult.getMessageBufferList()).thenReturn(Arrays.asList(bb1, bb2));
+
+        queryMessageTransfer = new QueryMessageTransfer(byteBufferHeader, queryMessageResult);
+    }
+
+    @Test
+    public void testPosition_WithHeaderAndMessageBuffers() {
+        byteBufferHeader.position(2);
+        bb1.position(1);
+        bb2.position(3);
+
+        long actual = queryMessageTransfer.position();
+
+        long expected = byteBufferHeader.position() + bb1.position() + bb2.position();
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testPosition_WithHeaderOnly() {
+        byteBufferHeader.position(2);
+
+        when(queryMessageResult.getMessageBufferList()).thenReturn(new ArrayList<>());
+
+        long actual = queryMessageTransfer.position();
+
+        long expected = byteBufferHeader.position();
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testPosition_WithMessageBuffersOnly() {
+        byteBufferHeader.clear();
+        byteBufferHeader.flip();
+
+        bb1.position(1);
+        bb2.position(3);
+
+        long actual = queryMessageTransfer.position();
+
+        long expected = bb1.position() + bb2.position();
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testTransferTo_OnlyHeaderData() throws Exception {
+        bb1.clear();
+        bb2.clear();
+
+        when(writableByteChannel.write(byteBufferHeader)).thenReturn(4);
+
+        long actual = queryMessageTransfer.transferTo(writableByteChannel, 0);
+
+        assertEquals(4, actual);
+        verify(writableByteChannel, times(1)).write(byteBufferHeader);
+        verify(writableByteChannel, never()).write(bb1);
+        verify(writableByteChannel, never()).write(bb2);
+    }
+
+    @Test
+    public void testTransferTo_OnlyMessageBuffersData() throws Exception {
+        byteBufferHeader.clear();
+        byteBufferHeader.flip();
+
+        when(writableByteChannel.write(bb1)).thenReturn(4);
+
+        long actual = queryMessageTransfer.transferTo(writableByteChannel, 0);
+
+        assertEquals(4, actual);
+        verify(writableByteChannel, never()).write(byteBufferHeader);
+        verify(writableByteChannel, times(1)).write(bb1);
+    }
+}
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessorTest.java
index 1bf99eadfb..572be63e3f 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessorTest.java
@@ -16,7 +16,8 @@
  */
 package org.apache.rocketmq.broker.processor;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
@@ -37,11 +38,11 @@ import org.apache.rocketmq.broker.client.ClientChannelInfo;
 import org.apache.rocketmq.broker.client.ConsumerGroupInfo;
 import org.apache.rocketmq.broker.client.ConsumerManager;
 import org.apache.rocketmq.broker.client.net.Broker2Client;
+import org.apache.rocketmq.broker.config.v1.RocksDBSubscriptionGroupManager;
+import org.apache.rocketmq.broker.config.v1.RocksDBTopicConfigManager;
 import org.apache.rocketmq.broker.metrics.BrokerMetricsManager;
 import org.apache.rocketmq.broker.offset.ConsumerOffsetManager;
 import org.apache.rocketmq.broker.schedule.ScheduleMessageService;
-import org.apache.rocketmq.broker.config.v1.RocksDBSubscriptionGroupManager;
-import org.apache.rocketmq.broker.config.v1.RocksDBTopicConfigManager;
 import org.apache.rocketmq.broker.topic.TopicConfigManager;
 import org.apache.rocketmq.common.BoundaryType;
 import org.apache.rocketmq.common.BrokerConfig;
@@ -80,6 +81,7 @@ import org.apache.rocketmq.remoting.protocol.body.SubscriptionGroupWrapper;
 import org.apache.rocketmq.remoting.protocol.body.TopicConfigSerializeWrapper;
 import org.apache.rocketmq.remoting.protocol.body.UnlockBatchRequestBody;
 import org.apache.rocketmq.remoting.protocol.body.UserInfo;
+import org.apache.rocketmq.remoting.protocol.header.CheckRocksdbCqWriteProgressRequestHeader;
 import org.apache.rocketmq.remoting.protocol.header.CreateAclRequestHeader;
 import org.apache.rocketmq.remoting.protocol.header.CreateTopicRequestHeader;
 import org.apache.rocketmq.remoting.protocol.header.CreateUserRequestHeader;
@@ -97,11 +99,13 @@ import org.apache.rocketmq.remoting.protocol.header.GetConsumerStatusRequestHead
 import org.apache.rocketmq.remoting.protocol.header.GetEarliestMsgStoretimeRequestHeader;
 import org.apache.rocketmq.remoting.protocol.header.GetMaxOffsetRequestHeader;
 import org.apache.rocketmq.remoting.protocol.header.GetMinOffsetRequestHeader;
+import org.apache.rocketmq.remoting.protocol.header.GetSubscriptionGroupConfigRequestHeader;
 import org.apache.rocketmq.remoting.protocol.header.GetTopicConfigRequestHeader;
 import org.apache.rocketmq.remoting.protocol.header.GetUserRequestHeader;
 import org.apache.rocketmq.remoting.protocol.header.ListAclsRequestHeader;
 import org.apache.rocketmq.remoting.protocol.header.ListUsersRequestHeader;
 import org.apache.rocketmq.remoting.protocol.header.NotifyMinBrokerIdChangeRequestHeader;
+import org.apache.rocketmq.remoting.protocol.header.QueryConsumeQueueRequestHeader;
 import org.apache.rocketmq.remoting.protocol.header.QueryCorrectionOffsetHeader;
 import org.apache.rocketmq.remoting.protocol.header.QuerySubscriptionByConsumerRequestHeader;
 import org.apache.rocketmq.remoting.protocol.header.QueryTopicConsumeByWhoRequestHeader;
@@ -114,6 +118,8 @@ import org.apache.rocketmq.remoting.protocol.header.UpdateAclRequestHeader;
 import org.apache.rocketmq.remoting.protocol.header.UpdateUserRequestHeader;
 import org.apache.rocketmq.remoting.protocol.heartbeat.ConsumeType;
 import org.apache.rocketmq.remoting.protocol.heartbeat.MessageModel;
+import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.remoting.protocol.statictopic.TopicConfigAndQueueMapping;
 import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
 import org.apache.rocketmq.store.CommitLog;
 import org.apache.rocketmq.store.DefaultMessageStore;
@@ -121,6 +127,7 @@ import org.apache.rocketmq.store.MessageStore;
 import org.apache.rocketmq.store.SelectMappedBufferResult;
 import org.apache.rocketmq.store.config.MessageStoreConfig;
 import org.apache.rocketmq.store.logfile.DefaultMappedFile;
+import org.apache.rocketmq.store.queue.ConsumeQueueInterface;
 import org.apache.rocketmq.store.stats.BrokerStats;
 import org.apache.rocketmq.store.timer.TimerCheckpoint;
 import org.apache.rocketmq.store.timer.TimerMessageStore;
@@ -159,6 +166,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.LongAdder;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -889,7 +898,7 @@ public class AdminBrokerProcessorTest {
         consumerOffsetManager = mock(ConsumerOffsetManager.class);
         when(brokerController.getConsumerOffsetManager()).thenReturn(consumerOffsetManager);
         ConsumerOffsetManager consumerOffset = new ConsumerOffsetManager();
-        when(consumerOffsetManager.encode()).thenReturn(JSON.toJSONString(consumerOffset, false));
+        when(consumerOffsetManager.encode()).thenReturn(JSON.toJSONString(consumerOffset));
         RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ALL_CONSUMER_OFFSET, null);
         RemotingCommand response = adminBrokerProcessor.processRequest(handlerContext, request);
         assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
@@ -1500,6 +1509,73 @@ public class AdminBrokerProcessorTest {
         assertThat(response.getCode()).isEqualTo(ResponseCode.SUCCESS);
     }
 
+    @Test
+    public void testGetSubscriptionGroup() throws RemotingCommandException {
+        brokerController.getSubscriptionGroupManager().getSubscriptionGroupTable().put("group", new SubscriptionGroupConfig());
+        GetSubscriptionGroupConfigRequestHeader requestHeader = new GetSubscriptionGroupConfigRequestHeader();
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_SUBSCRIPTIONGROUP_CONFIG, requestHeader);
+        requestHeader.setGroup("group");
+        request.makeCustomHeaderToNet();
+        RemotingCommand response = adminBrokerProcessor.processRequest(handlerContext, request);
+        assertEquals(ResponseCode.SUCCESS, response.getCode());
+    }
+
+    @Test
+    public void testCheckRocksdbCqWriteProgress() throws RemotingCommandException {
+        CheckRocksdbCqWriteProgressRequestHeader requestHeader = new CheckRocksdbCqWriteProgressRequestHeader();
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.CHECK_ROCKSDB_CQ_WRITE_PROGRESS, requestHeader);
+        requestHeader.setTopic("topic");
+        request.makeCustomHeaderToNet();
+        RemotingCommand response = adminBrokerProcessor.processRequest(handlerContext, request);
+        assertEquals(ResponseCode.SUCCESS, response.getCode());
+    }
+
+    @Test
+    public void testQueryConsumeQueue() throws RemotingCommandException {
+        messageStore = mock(MessageStore.class);
+        ConsumeQueueInterface consumeQueue = mock(ConsumeQueueInterface.class);
+        when(consumeQueue.getMinOffsetInQueue()).thenReturn(0L);
+        when(consumeQueue.getMaxOffsetInQueue()).thenReturn(1L);
+        when(messageStore.getConsumeQueue(anyString(), anyInt())).thenReturn(consumeQueue);
+        when(brokerController.getMessageStore()).thenReturn(messageStore);
+        QueryConsumeQueueRequestHeader requestHeader = new QueryConsumeQueueRequestHeader();
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.QUERY_CONSUME_QUEUE, requestHeader);
+        requestHeader.setTopic("topic");
+        requestHeader.setQueueId(0);
+        requestHeader.setConsumerGroup("testGroup");
+        request.makeCustomHeaderToNet();
+        SubscriptionData subscriptionData = mock(SubscriptionData.class);
+        when(brokerController.getConsumerManager()).thenReturn(consumerManager);
+        when(consumerManager.findSubscriptionData(any(), any())).thenReturn(subscriptionData);
+        RemotingCommand response = adminBrokerProcessor.processRequest(handlerContext, request);
+        assertEquals(ResponseCode.SUCCESS, response.getCode());
+    }
+
+    @Test
+    public void testProcessRequest_GetTopicConfig() throws Exception {
+        GetTopicConfigRequestHeader requestHeader = new GetTopicConfigRequestHeader();
+        requestHeader.setTopic("testTopic");
+
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_TOPIC_CONFIG, requestHeader);
+        request.makeCustomHeaderToNet();
+
+        TopicConfig topicConfig = new TopicConfig();
+        topicConfig.setTopicName("testTopic");
+        TopicConfigManager topicConfigManager = mock(TopicConfigManager.class);
+        when(brokerController.getTopicConfigManager()).thenReturn(topicConfigManager);
+        when(topicConfigManager.selectTopicConfig("testTopic"))
+                .thenReturn(topicConfig);
+
+        RemotingCommand response = adminBrokerProcessor.processRequest(handlerContext, request);
+
+        assertNotNull(response);
+        assertEquals(ResponseCode.SUCCESS, response.getCode());
+
+        String responseBody = new String(response.getBody(), StandardCharsets.UTF_8);
+        TopicConfigAndQueueMapping result = JSONObject.parseObject(responseBody, TopicConfigAndQueueMapping.class);
+        assertEquals("testTopic", result.getTopicName());
+    }
+
     private ResetOffsetRequestHeader createRequestHeader(String topic,String group,long timestamp,boolean force,long offset,int queueId) {
         ResetOffsetRequestHeader requestHeader = new ResetOffsetRequestHeader();
         requestHeader.setTopic(topic);
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessorTest.java
index ca2529e319..7afd338dca 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessorTest.java
@@ -18,18 +18,15 @@ package org.apache.rocketmq.broker.processor;
 
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandlerContext;
-import java.lang.reflect.Field;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
 import org.apache.rocketmq.broker.BrokerController;
 import org.apache.rocketmq.broker.client.ClientChannelInfo;
 import org.apache.rocketmq.broker.client.net.Broker2Client;
 import org.apache.rocketmq.broker.failover.EscapeBridge;
 import org.apache.rocketmq.broker.metrics.BrokerMetricsManager;
-import org.apache.rocketmq.store.stats.BrokerStatsManager;
+import org.apache.rocketmq.broker.metrics.PopMetricsManager;
+import org.apache.rocketmq.broker.topic.TopicConfigManager;
 import org.apache.rocketmq.common.BrokerConfig;
 import org.apache.rocketmq.common.TopicConfig;
-import org.apache.rocketmq.broker.topic.TopicConfigManager;
 import org.apache.rocketmq.common.message.MessageConst;
 import org.apache.rocketmq.common.message.MessageExtBrokerInner;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
@@ -41,13 +38,16 @@ import org.apache.rocketmq.remoting.protocol.RequestCode;
 import org.apache.rocketmq.remoting.protocol.ResponseCode;
 import org.apache.rocketmq.remoting.protocol.header.ChangeInvisibleTimeRequestHeader;
 import org.apache.rocketmq.remoting.protocol.header.ExtraInfoUtil;
+import org.apache.rocketmq.remoting.protocol.heartbeat.ConsumerData;
 import org.apache.rocketmq.store.AppendMessageResult;
 import org.apache.rocketmq.store.AppendMessageStatus;
 import org.apache.rocketmq.store.DefaultMessageStore;
+import org.apache.rocketmq.store.MessageStore;
 import org.apache.rocketmq.store.PutMessageResult;
 import org.apache.rocketmq.store.PutMessageStatus;
 import org.apache.rocketmq.store.config.MessageStoreConfig;
 import org.apache.rocketmq.store.exception.ConsumeQueueException;
+import org.apache.rocketmq.store.stats.BrokerStatsManager;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -55,10 +55,18 @@ import org.mockito.Mock;
 import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.lang.reflect.Field;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.apache.rocketmq.broker.processor.PullMessageProcessorTest.createConsumerData;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -118,6 +126,17 @@ public class ChangeInvisibleTimeProcessorTest {
         PopBufferMergeService popBufferMergeService = mock(PopBufferMergeService.class);
         when(brokerController.getPopMessageProcessor()).thenReturn(popMessageProcessor);
         when(popMessageProcessor.getPopBufferMergeService()).thenReturn(popBufferMergeService);
+
+        ConsumerData consumerData = createConsumerData(group, topic);
+        clientInfo = new ClientChannelInfo(channel, "127.0.0.1", LanguageCode.JAVA, 0);
+        brokerController.getConsumerManager().registerConsumer(
+                consumerData.getGroupName(),
+                clientInfo,
+                consumerData.getConsumeType(),
+                consumerData.getMessageModel(),
+                consumerData.getConsumeFromWhere(),
+                consumerData.getSubscriptionDataSet(),
+                false);
         
         clientInfo = new ClientChannelInfo(channel, "127.0.0.1", LanguageCode.JAVA, 0);
         changeInvisibleTimeProcessor = new ChangeInvisibleTimeProcessor(brokerController);
@@ -177,4 +196,58 @@ public class ChangeInvisibleTimeProcessorTest {
         assertThat(responseToReturn.getCode()).isEqualTo(ResponseCode.NO_MESSAGE);
         assertThat(responseToReturn.getOpaque()).isEqualTo(request.getOpaque());
     }
+
+    @Test
+    public void testProcessRequestAsync_JsonParsing() throws Exception {
+        Channel mockChannel = mock(Channel.class);
+        RemotingCommand mockRequest = mock(RemotingCommand.class);
+        BrokerController mockBrokerController = mock(BrokerController.class);
+        TopicConfigManager mockTopicConfigManager = mock(TopicConfigManager.class);
+        MessageStore mockMessageStore = mock(MessageStore.class);
+        BrokerConfig mockBrokerConfig = mock(BrokerConfig.class);
+        BrokerStatsManager mockBrokerStatsManager = mock(BrokerStatsManager.class);
+        PopMessageProcessor mockPopMessageProcessor = mock(PopMessageProcessor.class);
+        PopBufferMergeService mockPopBufferMergeService = mock(PopBufferMergeService.class);
+        BrokerMetricsManager brokerMetricsManager = mock(BrokerMetricsManager.class);
+        PopMetricsManager popMetricsManager = mock(PopMetricsManager.class);
+
+        when(brokerMetricsManager.getPopMetricsManager()).thenReturn(popMetricsManager);
+        when(mockBrokerController.getBrokerMetricsManager()).thenReturn(brokerMetricsManager);
+        doNothing().when(popMetricsManager).incPopReviveCkPutCount(any(), any());
+        when(brokerMetricsManager.getPopMetricsManager()).thenReturn(popMetricsManager);
+        when(mockBrokerController.getTopicConfigManager()).thenReturn(mockTopicConfigManager);
+        when(mockBrokerController.getMessageStore()).thenReturn(mockMessageStore);
+        when(mockBrokerController.getBrokerConfig()).thenReturn(mockBrokerConfig);
+        when(mockBrokerController.getBrokerStatsManager()).thenReturn(mockBrokerStatsManager);
+        when(mockBrokerController.getPopMessageProcessor()).thenReturn(mockPopMessageProcessor);
+        when(mockPopMessageProcessor.getPopBufferMergeService()).thenReturn(mockPopBufferMergeService);
+        when(mockPopBufferMergeService.addAk(anyInt(), any())).thenReturn(false);
+        when(mockBrokerController.getEscapeBridge()).thenReturn(escapeBridge);
+        PutMessageResult mockPutMessageResult = new PutMessageResult(PutMessageStatus.PUT_OK, null, true);
+        when(mockBrokerController.getEscapeBridge().asyncPutMessageToSpecificQueue(any()))
+                .thenReturn(CompletableFuture.completedFuture(mockPutMessageResult));
+
+        TopicConfig topicConfig = new TopicConfig();
+        topicConfig.setReadQueueNums(4);
+        when(mockTopicConfigManager.selectTopicConfig(anyString())).thenReturn(topicConfig);
+        when(mockMessageStore.getMinOffsetInQueue(anyString(), anyInt())).thenReturn(0L);
+        when(mockMessageStore.getMaxOffsetInQueue(anyString(), anyInt())).thenReturn(10L);
+        when(mockBrokerConfig.isPopConsumerKVServiceEnable()).thenReturn(false);
+
+        ChangeInvisibleTimeRequestHeader requestHeader = new ChangeInvisibleTimeRequestHeader();
+        requestHeader.setTopic("TestTopic");
+        requestHeader.setQueueId(1);
+        requestHeader.setOffset(5L);
+        requestHeader.setConsumerGroup("TestGroup");
+        requestHeader.setExtraInfo("0 10000 10000 0 TestBroker 1");
+        requestHeader.setInvisibleTime(60000L);
+        when(mockRequest.decodeCommandCustomHeader(ChangeInvisibleTimeRequestHeader.class)).thenReturn(requestHeader);
+
+        ChangeInvisibleTimeProcessor processor = new ChangeInvisibleTimeProcessor(mockBrokerController);
+        CompletableFuture<RemotingCommand> futureResponse = processor.processRequestAsync(mockChannel, mockRequest, true);
+
+        RemotingCommand response = futureResponse.get();
+        assertNotNull(response);
+        assertEquals(ResponseCode.SUCCESS, response.getCode());
+    }
 }
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopBufferMergeServiceTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopBufferMergeServiceTest.java
index acc7a3da74..6cbbd9cfd9 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopBufferMergeServiceTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopBufferMergeServiceTest.java
@@ -16,19 +16,22 @@
  */
 package org.apache.rocketmq.broker.processor;
 
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelHandlerContext;
+import com.alibaba.fastjson2.JSON;
 import org.apache.commons.lang3.reflect.FieldUtils;
 import org.apache.rocketmq.broker.BrokerController;
-import org.apache.rocketmq.broker.client.ClientChannelInfo;
+import org.apache.rocketmq.broker.client.ConsumerManager;
+import org.apache.rocketmq.broker.failover.EscapeBridge;
+import org.apache.rocketmq.broker.metrics.BrokerMetricsManager;
+import org.apache.rocketmq.broker.metrics.PopMetricsManager;
 import org.apache.rocketmq.broker.schedule.ScheduleMessageService;
+import org.apache.rocketmq.broker.topic.TopicConfigManager;
 import org.apache.rocketmq.common.BrokerConfig;
 import org.apache.rocketmq.common.MixAll;
 import org.apache.rocketmq.common.TopicConfig;
-import org.apache.rocketmq.remoting.netty.NettyClientConfig;
-import org.apache.rocketmq.remoting.netty.NettyServerConfig;
-import org.apache.rocketmq.remoting.protocol.heartbeat.ConsumerData;
+import org.apache.rocketmq.common.message.MessageExtBrokerInner;
 import org.apache.rocketmq.store.DefaultMessageStore;
+import org.apache.rocketmq.store.PutMessageResult;
+import org.apache.rocketmq.store.PutMessageStatus;
 import org.apache.rocketmq.store.config.MessageStoreConfig;
 import org.apache.rocketmq.store.pop.AckMsg;
 import org.apache.rocketmq.store.pop.PopCheckPoint;
@@ -37,56 +40,83 @@ import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnitRunner;
 
-import static org.apache.rocketmq.broker.processor.PullMessageProcessorTest.createConsumerData;
+import java.lang.reflect.Method;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.Silent.class)
 public class PopBufferMergeServiceTest {
-    @Spy
-    private BrokerController brokerController = new BrokerController(new BrokerConfig(), new NettyServerConfig(), new NettyClientConfig(), new MessageStoreConfig());
+
     @Mock
+    private BrokerController brokerController;
+
     private PopMessageProcessor popMessageProcessor;
+
+    @Mock
+    private ScheduleMessageService scheduleMessageService;
+
     @Mock
-    private ChannelHandlerContext handlerContext;
+    private TopicConfigManager topicConfigManager;
+
+    @Mock
+    private ConsumerManager consumerManager;
+
     @Mock
     private DefaultMessageStore messageStore;
-    private ScheduleMessageService scheduleMessageService;
-    private ClientChannelInfo clientChannelInfo;
-    private String group = "FooBarGroup";
-    private String topic = "FooBar";
+
+    @Mock
+    private MessageStoreConfig messageStoreConfig;
+
+    private String defaultGroup = "defaultGroup";
+
+    private String defaultTopic = "defaultTopic";
+
+    private PopBufferMergeService popBufferMergeService;
+
+    @Mock
+    private BrokerConfig brokerConfig;
+
+    @Mock
+    private EscapeBridge escapeBridge;
 
     @Before
     public void init() throws Exception {
-        FieldUtils.writeField(brokerController.getBrokerConfig(), "enablePopBufferMerge", true, true);
-        brokerController.setMessageStore(messageStore);
+        when(brokerConfig.getBrokerIP1()).thenReturn("127.0.0.1");
+        when(brokerConfig.isEnablePopBufferMerge()).thenReturn(true);
+        when(brokerConfig.getPopCkStayBufferTime()).thenReturn(10 * 1000);
+        when(brokerController.getBrokerConfig()).thenReturn(brokerConfig);
+        when(brokerController.getEscapeBridge()).thenReturn(escapeBridge);
+        when(brokerController.getMessageStore()).thenReturn(messageStore);
+        when(brokerController.getTopicConfigManager()).thenReturn(topicConfigManager);
+        when(brokerController.getScheduleMessageService()).thenReturn(scheduleMessageService);
+        when(brokerController.getConsumerManager()).thenReturn(consumerManager);
+        when(brokerController.getMessageStoreConfig()).thenReturn(messageStoreConfig);
         popMessageProcessor = new PopMessageProcessor(brokerController);
-        scheduleMessageService = new ScheduleMessageService(brokerController);
-        scheduleMessageService.parseDelayLevel();
-        Channel mockChannel = mock(Channel.class);
-        brokerController.getTopicConfigManager().getTopicConfigTable().put(topic, new TopicConfig());
-        clientChannelInfo = new ClientChannelInfo(mockChannel);
-        ConsumerData consumerData = createConsumerData(group, topic);
-        brokerController.getConsumerManager().registerConsumer(
-            consumerData.getGroupName(),
-            clientChannelInfo,
-            consumerData.getConsumeType(),
-            consumerData.getMessageModel(),
-            consumerData.getConsumeFromWhere(),
-            consumerData.getSubscriptionDataSet(),
-            false);
+        popBufferMergeService = new PopBufferMergeService(brokerController, popMessageProcessor);
+        FieldUtils.writeDeclaredField(popBufferMergeService, "brokerController", brokerController, true);
+        ConcurrentMap<String, TopicConfig> topicConfigTable = new ConcurrentHashMap<>();
+        topicConfigTable.put(defaultTopic, new TopicConfig());
+        when(topicConfigManager.getTopicConfigTable()).thenReturn(topicConfigTable);
     }
 
-    @Test(timeout = 10_000)
+    @Test(timeout = 15_000)
     public void testBasic() throws Exception {
         // This test case fails on Windows in CI pipeline
         // Disable it for later fix
         Assume.assumeFalse(MixAll.isWindows());
-        PopBufferMergeService popBufferMergeService = new PopBufferMergeService(brokerController, popMessageProcessor);
-        popBufferMergeService.start();
         PopCheckPoint ck = new PopCheckPoint();
         ck.setBitMap(0);
         int msgCnt = 1;
@@ -97,8 +127,8 @@ public class PopBufferMergeServiceTest {
         ck.setInvisibleTime(invisibleTime);
         int offset = 100;
         ck.setStartOffset(offset);
-        ck.setCId(group);
-        ck.setTopic(topic);
+        ck.setCId(defaultGroup);
+        ck.setTopic(defaultTopic);
         int queueId = 0;
         ck.setQueueId(queueId);
 
@@ -108,18 +138,100 @@ public class PopBufferMergeServiceTest {
         AckMsg ackMsg = new AckMsg();
         ackMsg.setAckOffset(ackOffset);
         ackMsg.setStartOffset(offset);
-        ackMsg.setConsumerGroup(group);
-        ackMsg.setTopic(topic);
+        ackMsg.setConsumerGroup(defaultGroup);
+        ackMsg.setTopic(defaultTopic);
         ackMsg.setQueueId(queueId);
         ackMsg.setPopTime(popTime);
         try {
             assertThat(popBufferMergeService.addCk(ck, reviveQid, ackOffset, nextBeginOffset)).isTrue();
-            assertThat(popBufferMergeService.getLatestOffset(topic, group, queueId)).isEqualTo(nextBeginOffset);
+            assertThat(popBufferMergeService.getLatestOffset(defaultTopic, defaultGroup, queueId)).isEqualTo(nextBeginOffset);
             Thread.sleep(1000); // wait background threads of PopBufferMergeService run for some time
             assertThat(popBufferMergeService.addAk(reviveQid, ackMsg)).isTrue();
-            assertThat(popBufferMergeService.getLatestOffset(topic, group, queueId)).isEqualTo(nextBeginOffset);
+            assertThat(popBufferMergeService.getLatestOffset(defaultTopic, defaultGroup, queueId)).isEqualTo(nextBeginOffset);
         } finally {
             popBufferMergeService.shutdown(true);
         }
     }
+
+    @Test
+    public void testAddCkJustOffset_MergeKeyConflict() {
+        PopCheckPoint point = mock(PopCheckPoint.class);
+        String mergeKey = "testMergeKey";
+        when(point.getTopic()).thenReturn(mergeKey);
+        when(point.getCId()).thenReturn("");
+        when(point.getQueueId()).thenReturn(0);
+        when(point.getStartOffset()).thenReturn(0L);
+        when(point.getPopTime()).thenReturn(0L);
+        when(point.getBrokerName()).thenReturn("");
+        popBufferMergeService.buffer.put(mergeKey + "000", mock(PopBufferMergeService.PopCheckPointWrapper.class));
+
+        assertFalse(popBufferMergeService.addCkJustOffset(point, 0, 0, 0));
+    }
+
+    @Test
+    public void testAddCkMock() {
+        int queueId = 0;
+        long startOffset = 100L;
+        long invisibleTime = 30_000L;
+        long popTime = System.currentTimeMillis();
+        int reviveQueueId = 0;
+        long nextBeginOffset = 101L;
+        String brokerName = "brokerName";
+        popBufferMergeService.addCkMock(defaultGroup, defaultTopic, queueId, startOffset, invisibleTime, popTime, reviveQueueId, nextBeginOffset, brokerName);
+        verify(brokerConfig, times(1)).isEnablePopLog();
+    }
+
+    @Test
+    public void testPutAckToStore() throws Exception {
+        PopCheckPoint point = new PopCheckPoint();
+        point.setStartOffset(100L);
+        point.setCId("testGroup");
+        point.setTopic("testTopic");
+        point.setQueueId(1);
+        point.setPopTime(System.currentTimeMillis());
+        point.setBrokerName("testBroker");
+
+        PopBufferMergeService.PopCheckPointWrapper pointWrapper = mock(PopBufferMergeService.PopCheckPointWrapper.class);
+        when(pointWrapper.getCk()).thenReturn(point);
+        when(pointWrapper.getReviveQueueId()).thenReturn(0);
+
+        AtomicInteger toStoreBits = new AtomicInteger(0);
+        when(pointWrapper.getToStoreBits()).thenReturn(toStoreBits);
+
+        byte msgIndex = 0;
+        AtomicInteger count = new AtomicInteger(0);
+
+        EscapeBridge escapeBridge = mock(EscapeBridge.class);
+        when(brokerController.getEscapeBridge()).thenReturn(escapeBridge);
+        when(brokerController.getBrokerConfig().isAppendAckAsync()).thenReturn(false);
+        BrokerMetricsManager brokerMetricsManager = mock(BrokerMetricsManager.class);
+        PopMetricsManager popMetricsManager = mock(PopMetricsManager.class);
+
+        when(brokerMetricsManager.getPopMetricsManager()).thenReturn(popMetricsManager);
+        when(brokerController.getBrokerMetricsManager()).thenReturn(brokerMetricsManager);
+        doNothing().when(popMetricsManager).incPopReviveCkPutCount(any(), any());
+        when(brokerMetricsManager.getPopMetricsManager()).thenReturn(popMetricsManager);
+
+        when(escapeBridge.putMessageToSpecificQueue(any())).thenAnswer(invocation -> {
+            MessageExtBrokerInner capturedMessage = invocation.getArgument(0);
+            AckMsg ackMsg = JSON.parseObject(capturedMessage.getBody(), AckMsg.class);
+
+            assertEquals(point.ackOffsetByIndex(msgIndex), ackMsg.getAckOffset());
+            assertEquals(point.getStartOffset(), ackMsg.getStartOffset());
+            assertEquals(point.getCId(), ackMsg.getConsumerGroup());
+            assertEquals(point.getTopic(), ackMsg.getTopic());
+            assertEquals(point.getQueueId(), ackMsg.getQueueId());
+            assertEquals(point.getPopTime(), ackMsg.getPopTime());
+            assertEquals(point.getBrokerName(), ackMsg.getBrokerName());
+
+            PutMessageResult result = mock(PutMessageResult.class);
+            when(result.getPutMessageStatus()).thenReturn(PutMessageStatus.PUT_OK);
+            return result;
+        });
+
+        Method method = PopBufferMergeService.class.getDeclaredMethod("putAckToStore", PopBufferMergeService.PopCheckPointWrapper.class, byte.class, AtomicInteger.class);
+        method.setAccessible(true);
+        method.invoke(popBufferMergeService, pointWrapper, msgIndex, count);
+        verify(escapeBridge, times(1)).putMessageToSpecificQueue(any(MessageExtBrokerInner.class));
+    }
 }
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopMessageProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopMessageProcessorTest.java
index 59559d3cfd..5d7b97f229 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopMessageProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopMessageProcessorTest.java
@@ -16,10 +16,9 @@
  */
 package org.apache.rocketmq.broker.processor;
 
+import com.alibaba.fastjson2.JSON;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.embedded.EmbeddedChannel;
-import java.nio.ByteBuffer;
-import java.util.concurrent.CompletableFuture;
 import org.apache.rocketmq.broker.BrokerController;
 import org.apache.rocketmq.broker.client.ClientChannelInfo;
 import org.apache.rocketmq.broker.metrics.BrokerMetricsManager;
@@ -28,6 +27,7 @@ import org.apache.rocketmq.common.KeyBuilder;
 import org.apache.rocketmq.common.TopicConfig;
 import org.apache.rocketmq.common.constant.ConsumeInitMode;
 import org.apache.rocketmq.common.message.MessageDecoder;
+import org.apache.rocketmq.common.message.MessageExtBrokerInner;
 import org.apache.rocketmq.remoting.exception.RemotingCommandException;
 import org.apache.rocketmq.remoting.netty.NettyClientConfig;
 import org.apache.rocketmq.remoting.netty.NettyServerConfig;
@@ -43,7 +43,7 @@ import org.apache.rocketmq.store.SelectMappedBufferResult;
 import org.apache.rocketmq.store.config.MessageStoreConfig;
 import org.apache.rocketmq.store.exception.ConsumeQueueException;
 import org.apache.rocketmq.store.logfile.DefaultMappedFile;
-import org.junit.Assert;
+import org.apache.rocketmq.store.pop.PopCheckPoint;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -51,8 +51,13 @@ import org.mockito.Mock;
 import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.CompletableFuture;
+
 import static org.apache.rocketmq.broker.processor.PullMessageProcessorTest.createConsumerData;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -171,17 +176,17 @@ public class PopMessageProcessorTest {
                 .thenReturn(CompletableFuture.completedFuture(getMessageResult));
 
         long offset = brokerController.getConsumerOffsetManager().queryOffset(newGroup, retryTopic, 0);
-        Assert.assertEquals(-1, offset);
+        assertEquals(-1, offset);
 
         RemotingCommand request = createPopMsgCommand(newGroup, topic, 0, ConsumeInitMode.MAX);
         popMessageProcessor.processRequest(handlerContext, request);
         offset = brokerController.getConsumerOffsetManager().queryOffset(newGroup, retryTopic, 0);
-        Assert.assertEquals(minOffset, offset);
+        assertEquals(minOffset, offset);
 
         when(messageStore.getMinOffsetInQueue(retryTopic, 0)).thenReturn(minOffset * 2);
         popMessageProcessor.processRequest(handlerContext, request);
         offset = brokerController.getConsumerOffsetManager().queryOffset(newGroup, retryTopic, 0);
-        Assert.assertEquals(minOffset, offset); // will not entry getInitOffset() again
+        assertEquals(minOffset, offset); // will not entry getInitOffset() again
         messageStore.getMinOffsetInQueue(retryTopic, 0); // prevent UnnecessaryStubbingException
     }
 
@@ -196,20 +201,47 @@ public class PopMessageProcessorTest {
                 .thenReturn(CompletableFuture.completedFuture(getMessageResult));
 
         long offset = brokerController.getConsumerOffsetManager().queryOffset(newGroup, topic, 0);
-        Assert.assertEquals(-1, offset);
+        assertEquals(-1, offset);
 
         RemotingCommand request = createPopMsgCommand(newGroup, topic, 0, ConsumeInitMode.MAX);
         popMessageProcessor.processRequest(handlerContext, request);
         offset = brokerController.getConsumerOffsetManager().queryOffset(newGroup, topic, 0);
-        Assert.assertEquals(maxOffset - 1, offset); // checkInMem return false
+        assertEquals(maxOffset - 1, offset); // checkInMem return false
 
         when(messageStore.getMaxOffsetInQueue(topic, 0)).thenReturn(maxOffset * 2);
         popMessageProcessor.processRequest(handlerContext, request);
         offset = brokerController.getConsumerOffsetManager().queryOffset(newGroup, topic, 0);
-        Assert.assertEquals(maxOffset - 1, offset); // will not entry getInitOffset() again
+        assertEquals(maxOffset - 1, offset); // will not entry getInitOffset() again
         messageStore.getMaxOffsetInQueue(topic, 0); // prevent UnnecessaryStubbingException
     }
 
+    @Test
+    public void testBuildCkMsgJsonParsing() {
+        PopCheckPoint ck = new PopCheckPoint();
+        ck.setTopic("TestTopic");
+        ck.setQueueId(1);
+        ck.setStartOffset(100L);
+        ck.setCId("TestConsumer");
+        ck.setPopTime(System.currentTimeMillis());
+        ck.setBrokerName("TestBroker");
+
+        int reviveQid = 0;
+        PopMessageProcessor processor = new PopMessageProcessor(brokerController);
+
+        MessageExtBrokerInner result = processor.buildCkMsg(ck, reviveQid);
+
+        String jsonBody = new String(result.getBody(), StandardCharsets.UTF_8);
+        PopCheckPoint actual = JSON.parseObject(jsonBody, PopCheckPoint.class);
+
+        assertEquals(ck.getTopic(), actual.getTopic());
+        assertEquals(ck.getQueueId(), actual.getQueueId());
+        assertEquals(ck.getStartOffset(), actual.getStartOffset());
+        assertEquals(ck.getCId(), actual.getCId());
+        assertEquals(ck.getPopTime(), actual.getPopTime());
+        assertEquals(ck.getBrokerName(), actual.getBrokerName());
+        assertEquals(ck.getReviveTime(), actual.getReviveTime());
+    }
+
     private RemotingCommand createPopMsgCommand() {
         return createPopMsgCommand(group, topic, -1, ConsumeInitMode.MAX);
     }
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopReviveServiceTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopReviveServiceTest.java
index 6e77e7c557..fa7e9982e1 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/PopReviveServiceTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/PopReviveServiceTest.java
@@ -16,13 +16,7 @@
  */
 package org.apache.rocketmq.broker.processor;
 
-import com.alibaba.fastjson.JSON;
-import java.net.SocketAddress;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
+import com.alibaba.fastjson2.JSON;
 import org.apache.commons.lang3.tuple.Triple;
 import org.apache.rocketmq.broker.BrokerController;
 import org.apache.rocketmq.broker.failover.EscapeBridge;
@@ -42,12 +36,13 @@ import org.apache.rocketmq.common.message.MessageExtBrokerInner;
 import org.apache.rocketmq.common.utils.DataConverter;
 import org.apache.rocketmq.common.utils.NetworkUtil;
 import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.store.AppendMessageResult;
+import org.apache.rocketmq.store.AppendMessageStatus;
 import org.apache.rocketmq.store.MessageStore;
 import org.apache.rocketmq.store.PutMessageResult;
 import org.apache.rocketmq.store.PutMessageStatus;
-import org.apache.rocketmq.store.AppendMessageResult;
-import org.apache.rocketmq.store.AppendMessageStatus;
 import org.apache.rocketmq.store.pop.AckMsg;
+import org.apache.rocketmq.store.pop.BatchAckMsg;
 import org.apache.rocketmq.store.pop.PopCheckPoint;
 import org.apache.rocketmq.store.timer.TimerMessageStore;
 import org.junit.Assert;
@@ -58,18 +53,27 @@ import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.Silent.class)
 public class PopReviveServiceTest {
@@ -139,7 +143,7 @@ public class PopReviveServiceTest {
         long maxReviveOffset = 4;
 
         when(consumerOffsetManager.queryOffset(PopAckConstants.REVIVE_GROUP, REVIVE_TOPIC, REVIVE_QUEUE_ID))
-            .thenReturn(0L);
+                .thenReturn(0L);
         List<MessageExt> reviveMessageExtList = new ArrayList<>();
         long basePopTime = System.currentTimeMillis();
         {
@@ -176,7 +180,7 @@ public class PopReviveServiceTest {
         long maxReviveOffset = 4;
 
         when(consumerOffsetManager.queryOffset(PopAckConstants.REVIVE_GROUP, REVIVE_TOPIC, REVIVE_QUEUE_ID))
-            .thenReturn(0L);
+                .thenReturn(0L);
         List<MessageExt> reviveMessageExtList = new ArrayList<>();
         long basePopTime = System.currentTimeMillis() - brokerConfig.getReviveAckWaitMs() * 2;
         {
@@ -213,7 +217,7 @@ public class PopReviveServiceTest {
         long maxReviveOffset = 4;
 
         when(consumerOffsetManager.queryOffset(PopAckConstants.REVIVE_GROUP, REVIVE_TOPIC, REVIVE_QUEUE_ID))
-            .thenReturn(0L);
+                .thenReturn(0L);
         List<MessageExt> reviveMessageExtList = new ArrayList<>();
         long basePopTime = System.currentTimeMillis() - brokerConfig.getReviveAckWaitMs() * 2;
         {
@@ -419,6 +423,59 @@ public class PopReviveServiceTest {
         verify(messageStore, times(1)).putMessage(any(MessageExtBrokerInner.class)); // rewrite CK
     }
 
+    @Test
+    public void testReviveMsgFromBatchAck() throws Throwable {
+        brokerConfig.setEnableSkipLongAwaitingAck(true);
+        when(consumerOffsetManager.queryOffset(PopAckConstants.REVIVE_GROUP, REVIVE_TOPIC, REVIVE_QUEUE_ID)).thenReturn(0L);
+        List<MessageExt> reviveMessageExtList = new ArrayList<>();
+        long basePopTime = System.currentTimeMillis();
+        reviveMessageExtList.add(buildBatchAckMsg(buildBatchAckMsg(Arrays.asList(1L, 2L, 3L), basePopTime), 1, 1, basePopTime));
+        doReturn(reviveMessageExtList, new ArrayList<>()).when(popReviveService).getReviveMessage(anyLong(), anyInt());
+
+        PopReviveService.ConsumeReviveObj consumeReviveObj = new PopReviveService.ConsumeReviveObj();
+        popReviveService.consumeReviveMessage(consumeReviveObj);
+        assertEquals(1, consumeReviveObj.map.size());
+
+        ArgumentCaptor<Long> commitOffsetCaptor = ArgumentCaptor.forClass(Long.class);
+        doNothing().when(consumerOffsetManager).commitOffset(anyString(), anyString(), anyString(), anyInt(), commitOffsetCaptor.capture());
+        popReviveService.mergeAndRevive(consumeReviveObj);
+        assertEquals(1, commitOffsetCaptor.getValue().longValue());
+    }
+
+    public static MessageExtBrokerInner buildBatchAckMsg(BatchAckMsg batchAckMsg, long deliverMs, long reviveOffset, long deliverTime) {
+        MessageExtBrokerInner result = buildBatchAckInnerMessage(REVIVE_TOPIC, batchAckMsg, REVIVE_QUEUE_ID, STORE_HOST, deliverMs, PopMessageProcessor.genAckUniqueId(batchAckMsg));
+        result.setQueueOffset(reviveOffset);
+        result.setDeliverTimeMs(deliverMs);
+        result.setStoreTimestamp(deliverTime);
+        return result;
+    }
+
+    public static BatchAckMsg buildBatchAckMsg(Collection<Long> offsets, long popTime) {
+        BatchAckMsg result = new BatchAckMsg();
+        result.setConsumerGroup(GROUP);
+        result.setTopic(TOPIC);
+        result.setQueueId(0);
+        result.setPopTime(popTime);
+        result.setBrokerName("broker-a");
+        result.getAckOffsetList().addAll(offsets);
+        return result;
+    }
+
+    public static MessageExtBrokerInner buildBatchAckInnerMessage(String reviveTopic, AckMsg ackMsg, int reviveQid, SocketAddress host, long deliverMs, String ackUniqueId) {
+        MessageExtBrokerInner result = new MessageExtBrokerInner();
+        result.setTopic(reviveTopic);
+        result.setBody(JSON.toJSONString(ackMsg).getBytes(DataConverter.CHARSET_UTF8));
+        result.setQueueId(reviveQid);
+        result.setTags(PopAckConstants.BATCH_ACK_TAG);
+        result.setBornTimestamp(System.currentTimeMillis());
+        result.setBornHost(host);
+        result.setStoreHost(host);
+        result.setDeliverTimeMs(deliverMs);
+        result.getProperties().put(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, ackUniqueId);
+        result.setPropertiesString(MessageDecoder.messageProperties2String(result.getProperties()));
+        return result;
+    }
+
     public static PopCheckPoint buildPopCheckPoint(long startOffset, long popTime, long reviveOffset) {
         PopCheckPoint ck = new PopCheckPoint();
         ck.setStartOffset(startOffset);
@@ -467,14 +524,14 @@ public class PopReviveServiceTest {
     }
 
     public static MessageExtBrokerInner buildAckMsg(AckMsg ackMsg, long deliverMs, long reviveOffset,
-        long deliverTime) {
+                                                    long deliverTime) {
         MessageExtBrokerInner messageExtBrokerInner = buildAckInnerMessage(
-            REVIVE_TOPIC,
-            ackMsg,
-            REVIVE_QUEUE_ID,
-            STORE_HOST,
-            deliverMs,
-            PopMessageProcessor.genAckUniqueId(ackMsg)
+                REVIVE_TOPIC,
+                ackMsg,
+                REVIVE_QUEUE_ID,
+                STORE_HOST,
+                deliverMs,
+                PopMessageProcessor.genAckUniqueId(ackMsg)
         );
         messageExtBrokerInner.setQueueOffset(reviveOffset);
         messageExtBrokerInner.setDeliverTimeMs(deliverMs);
@@ -483,7 +540,7 @@ public class PopReviveServiceTest {
     }
 
     public static MessageExtBrokerInner buildAckInnerMessage(String reviveTopic, AckMsg ackMsg, int reviveQid,
-        SocketAddress host, long deliverMs, String ackUniqueId) {
+                                                             SocketAddress host, long deliverMs, String ackUniqueId) {
         MessageExtBrokerInner msgInner = new MessageExtBrokerInner();
         msgInner.setTopic(reviveTopic);
         msgInner.setBody(JSON.toJSONString(ackMsg).getBytes(DataConverter.CHARSET_UTF8));
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManagerTest.java
index 3c975a599b..bc34e26bf5 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManagerTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManagerTest.java
@@ -47,7 +47,6 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 @RunWith(MockitoJUnitRunner.class)
@@ -101,13 +100,13 @@ public class SubscriptionGroupManagerTest {
         subscriptionGroupConfig.setGroupName(group);
         Map<String, String> attr = ImmutableMap.of("+test", "true");
         subscriptionGroupConfig.setAttributes(attr);
+        SubscriptionGroupManager subscriptionGroupManager = new SubscriptionGroupManager(brokerControllerMock);
         subscriptionGroupManager.updateSubscriptionGroupConfig(subscriptionGroupConfig);
         SubscriptionGroupConfig result = subscriptionGroupManager.getSubscriptionGroupTable().get(group);
         assertThat(result).isNotNull();
         assertThat(result.getGroupName()).isEqualTo(group);
         assertThat(result.getAttributes().get("test")).isEqualTo("true");
 
-
         SubscriptionGroupConfig subscriptionGroupConfig1 = new SubscriptionGroupConfig();
         subscriptionGroupConfig1.setGroupName(group);
         Map<String, String> attrRemove = ImmutableMap.of("-test", "");
@@ -157,14 +156,11 @@ public class SubscriptionGroupManagerTest {
             groupNames.add(groupName);
         }
 
+        SubscriptionGroupManager subscriptionGroupManager = new SubscriptionGroupManager(brokerControllerMock);
         subscriptionGroupManager.updateSubscriptionGroupConfigList(configList);
 
-        // Verifying that persist() is called once
-        verify(subscriptionGroupManager, times(1)).persist();
-
         groupNames.forEach(groupName ->
             assertThat(subscriptionGroupManager.getSubscriptionGroupTable().get(groupName)).isNotNull());
-
     }
 
     @Test
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManagerTest.java
index b74e57ab93..9b25e0134c 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManagerTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManagerTest.java
@@ -17,15 +17,11 @@
 
 package org.apache.rocketmq.broker.topic;
 
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
 import org.apache.rocketmq.broker.BrokerController;
 import org.apache.rocketmq.common.BrokerConfig;
+import org.apache.rocketmq.remoting.protocol.body.TopicQueueMappingSerializeWrapper;
 import org.apache.rocketmq.remoting.protocol.statictopic.TopicQueueMappingDetail;
 import org.apache.rocketmq.remoting.protocol.statictopic.TopicQueueMappingUtils;
 import org.apache.rocketmq.remoting.protocol.statictopic.TopicRemappingDetailWrapper;
@@ -37,6 +33,16 @@ import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
@@ -79,9 +85,9 @@ public class TopicQueueMappingManagerTest {
                 String topic = UUID.randomUUID().toString();
                 int queueNum = 10;
                 TopicRemappingDetailWrapper topicRemappingDetailWrapper  = TopicQueueMappingUtils.createTopicConfigMapping(topic, queueNum, brokers, new HashMap<>());
-                Assert.assertEquals(1, topicRemappingDetailWrapper.getBrokerConfigMap().size());
+                assertEquals(1, topicRemappingDetailWrapper.getBrokerConfigMap().size());
                 TopicQueueMappingDetail topicQueueMappingDetail  = topicRemappingDetailWrapper.getBrokerConfigMap().values().iterator().next().getMappingDetail();
-                Assert.assertEquals(queueNum, topicQueueMappingDetail.getHostedQueues().size());
+                assertEquals(queueNum, topicQueueMappingDetail.getHostedQueues().size());
                 mappingDetailMap.put(topic, topicQueueMappingDetail);
             }
         }
@@ -89,7 +95,7 @@ public class TopicQueueMappingManagerTest {
         {
             topicQueueMappingManager = new TopicQueueMappingManager(brokerController);
             Assert.assertTrue(topicQueueMappingManager.load());
-            Assert.assertEquals(0, topicQueueMappingManager.getTopicQueueMappingTable().size());
+            assertEquals(0, topicQueueMappingManager.getTopicQueueMappingTable().size());
             for (TopicQueueMappingDetail mappingDetail : mappingDetailMap.values()) {
                 for (int i = 0; i < 10; i++) {
                     topicQueueMappingManager.updateTopicQueueMapping(mappingDetail, false, false, true);
@@ -101,11 +107,49 @@ public class TopicQueueMappingManagerTest {
         {
             topicQueueMappingManager = new TopicQueueMappingManager(brokerController);
             Assert.assertTrue(topicQueueMappingManager.load());
-            Assert.assertEquals(mappingDetailMap.size(), topicQueueMappingManager.getTopicQueueMappingTable().size());
+            assertEquals(mappingDetailMap.size(), topicQueueMappingManager.getTopicQueueMappingTable().size());
             for (TopicQueueMappingDetail topicQueueMappingDetail: topicQueueMappingManager.getTopicQueueMappingTable().values()) {
-                Assert.assertEquals(topicQueueMappingDetail, mappingDetailMap.get(topicQueueMappingDetail.getTopic()));
+                assertEquals(topicQueueMappingDetail, mappingDetailMap.get(topicQueueMappingDetail.getTopic()));
             }
         }
         delete(topicQueueMappingManager);
     }
+
+    @Test
+    public void testEncodePretty() {
+        TopicQueueMappingManager topicQueueMappingManager = new TopicQueueMappingManager(null);
+        TopicQueueMappingDetail detail = new TopicQueueMappingDetail();
+        detail.setTopic("testTopic");
+        detail.setBname("testBroker");
+
+        topicQueueMappingManager.getTopicQueueMappingTable().put("testTopic", detail);
+        topicQueueMappingManager.getDataVersion().nextVersion();
+
+        String actual = topicQueueMappingManager.encode(true);
+        TopicQueueMappingSerializeWrapper expectedWrapper = new TopicQueueMappingSerializeWrapper();
+        expectedWrapper.setTopicQueueMappingInfoMap(new ConcurrentHashMap<>(topicQueueMappingManager.getTopicQueueMappingTable()));
+        expectedWrapper.setDataVersion(topicQueueMappingManager.getDataVersion());
+        String expected = JSON.toJSONString(expectedWrapper, JSONWriter.Feature.PrettyFormat);
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testEncodeNonPretty() {
+        TopicQueueMappingManager topicQueueMappingManager = new TopicQueueMappingManager(null);
+        TopicQueueMappingDetail detail = new TopicQueueMappingDetail();
+        detail.setTopic("testTopic");
+        detail.setBname("testBroker");
+
+        topicQueueMappingManager.getTopicQueueMappingTable().put("testTopic", detail);
+        topicQueueMappingManager.getDataVersion().nextVersion();
+
+        String actual = topicQueueMappingManager.encode(false);
+        TopicQueueMappingSerializeWrapper expectedWrapper = new TopicQueueMappingSerializeWrapper();
+        expectedWrapper.setTopicQueueMappingInfoMap(new ConcurrentHashMap<>(topicQueueMappingManager.getTopicQueueMappingTable()));
+        expectedWrapper.setDataVersion(topicQueueMappingManager.getDataVersion());
+        String expected = JSON.toJSONString(expectedWrapper);
+
+        assertEquals(expected, actual);
+    }
 }
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionMetricsTest.java b/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionMetricsTest.java
index 690b4eabb5..62a6ad8b5b 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionMetricsTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/transaction/queue/TransactionMetricsTest.java
@@ -19,23 +19,40 @@ package org.apache.rocketmq.broker.transaction.queue;
 
 import org.apache.rocketmq.broker.transaction.TransactionMetrics;
 import org.apache.rocketmq.broker.transaction.TransactionMetrics.Metric;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Collections;
+import java.util.UUID;
 
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 
 @RunWith(MockitoJUnitRunner.class)
 public class TransactionMetricsTest {
     private TransactionMetrics transactionMetrics;
     private String configPath;
+    private Path path;
 
     @Before
-    public void setUp() throws Exception {
-        configPath = "configPath";
-        transactionMetrics = new TransactionMetrics(configPath);
+    public void before() throws Exception {
+        configPath = createBaseDir();
+        path = Paths.get(configPath);
+        transactionMetrics = spy(new TransactionMetrics(configPath));
+    }
+
+    @After
+    public void after() throws Exception {
+        deleteFile(configPath);
+        assertFalse(path.toFile().exists());
     }
 
     /**
@@ -80,4 +97,40 @@ public class TransactionMetricsTest {
         transactionMetrics.cleanMetrics(Collections.singleton(topic));
         assert transactionMetrics.getTransactionCount(topic) == 0;
     }
+
+    @Test
+    public void testPersist() {
+        assertFalse(path.toFile().exists());
+        transactionMetrics.persist();
+        assertTrue(path.toFile().exists());
+        verify(transactionMetrics).persist();
+    }
+
+    private String createBaseDir() {
+        String baseDir = System.getProperty("java.io.tmpdir") + File.separator + "unitteststore-" + UUID.randomUUID();
+        final File file = new File(baseDir);
+        if (file.exists()) {
+            System.exit(1);
+        }
+        return baseDir;
+    }
+
+    private void deleteFile(String fileName) {
+        deleteFile(new File(fileName));
+    }
+
+    private void deleteFile(File file) {
+        if (!file.exists()) {
+            return;
+        }
+        if (file.isFile()) {
+            file.delete();
+        } else if (file.isDirectory()) {
+            File[] files = file.listFiles();
+            for (File file1 : files) {
+                deleteFile(file1);
+            }
+            file.delete();
+        }
+    }
 }
diff --git a/client/BUILD.bazel b/client/BUILD.bazel
index 31681f1029..3bd84606a2 100644
--- a/client/BUILD.bazel
+++ b/client/BUILD.bazel
@@ -27,7 +27,6 @@ java_library(
         "@maven//:commons_validator_commons_validator",
         "@maven//:com_github_luben_zstd_jni",
         "@maven//:org_lz4_lz4_java",
-        "@maven//:com_alibaba_fastjson",
         "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:io_netty_netty_all",
         "@maven//:io_opentracing_opentracing_api",
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 95bb0e8a96..11af6ecd4b 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
@@ -16,7 +16,7 @@
  */
 package org.apache.rocketmq.client.impl;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.rocketmq.client.ClientConfig;
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 3055f2cdee..bb838a6265 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
@@ -16,26 +16,8 @@
  */
 package org.apache.rocketmq.client.impl.factory;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import io.netty.channel.Channel;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Random;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ThreadFactory;
-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.commons.lang3.StringUtils;
 import org.apache.rocketmq.client.ClientConfig;
 import org.apache.rocketmq.client.admin.MQAdminExtInner;
@@ -86,6 +68,25 @@ import org.apache.rocketmq.remoting.protocol.route.BrokerData;
 import org.apache.rocketmq.remoting.protocol.route.QueueData;
 import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
 
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
 import static org.apache.rocketmq.remoting.rpc.ClientMetadata.topicRouteData2EndpointsForStaticTopic;
 
 public class MQClientInstance {
diff --git a/client/src/main/java/org/apache/rocketmq/client/producer/SendResult.java b/client/src/main/java/org/apache/rocketmq/client/producer/SendResult.java
index d160eb4eae..5405275398 100644
--- a/client/src/main/java/org/apache/rocketmq/client/producer/SendResult.java
+++ b/client/src/main/java/org/apache/rocketmq/client/producer/SendResult.java
@@ -16,7 +16,7 @@
  */
 package org.apache.rocketmq.client.producer;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import org.apache.rocketmq.common.message.MessageQueue;
 
 public class SendResult {
diff --git a/client/src/test/java/org/apache/rocketmq/client/consumer/DefaultLitePullConsumerTest.java b/client/src/test/java/org/apache/rocketmq/client/consumer/DefaultLitePullConsumerTest.java
index 592c247057..f57b3f80fe 100644
--- a/client/src/test/java/org/apache/rocketmq/client/consumer/DefaultLitePullConsumerTest.java
+++ b/client/src/test/java/org/apache/rocketmq/client/consumer/DefaultLitePullConsumerTest.java
@@ -17,17 +17,6 @@
 
 package org.apache.rocketmq.client.consumer;
 
-import java.io.ByteArrayOutputStream;
-import java.lang.reflect.Field;
-import java.net.InetSocketAddress;
-import java.time.Duration;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentMap;
 import org.apache.commons.lang3.reflect.FieldUtils;
 import org.apache.rocketmq.client.ClientConfig;
 import org.apache.rocketmq.client.consumer.store.OffsetStore;
@@ -65,6 +54,18 @@ import org.mockito.invocation.InvocationOnMock;
 import org.mockito.junit.MockitoJUnitRunner;
 import org.mockito.stubbing.Answer;
 
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.Field;
+import java.net.InetSocketAddress;
+import java.time.Duration;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Fail.failBecauseExceptionWasNotThrown;
 import static org.awaitility.Awaitility.await;
@@ -75,6 +76,7 @@ import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
@@ -898,5 +900,6 @@ public class DefaultLitePullConsumerTest {
         ConcurrentMap<String, MQClientInstance> factoryTable = (ConcurrentMap<String, MQClientInstance>) FieldUtils.readDeclaredField(MQClientManager.getInstance(), "factoryTable", true);
         factoryTable.put(litePullConsumer.buildMQClientId(), mQClientFactory);
         doReturn(false).when(mQClientFactory).updateTopicRouteInfoFromNameServer(anyString());
+        doNothing().when(mQClientFactory).updateTopicRouteInfoFromNameServer();
     }
 }
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 c12b23cb0d..c8d23274bd 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
@@ -16,6 +16,7 @@
  */
 package org.apache.rocketmq.client.impl;
 
+import com.alibaba.fastjson2.JSON;
 import org.apache.rocketmq.client.ClientConfig;
 import org.apache.rocketmq.client.consumer.AckCallback;
 import org.apache.rocketmq.client.consumer.AckResult;
@@ -34,6 +35,7 @@ import org.apache.rocketmq.client.producer.DefaultMQProducer;
 import org.apache.rocketmq.client.producer.SendCallback;
 import org.apache.rocketmq.client.producer.SendResult;
 import org.apache.rocketmq.client.producer.SendStatus;
+import org.apache.rocketmq.common.CheckRocksdbCqWriteResult;
 import org.apache.rocketmq.common.MixAll;
 import org.apache.rocketmq.common.ObjectCreator;
 import org.apache.rocketmq.common.Pair;
@@ -2031,6 +2033,22 @@ public class MQClientAPIImplTest {
         }
     }
 
+    @Test
+    public void testCheckRocksdbCqWriteProgress() throws Exception {
+        RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success");
+        CheckRocksdbCqWriteResult expectedResult = new CheckRocksdbCqWriteResult();
+        expectedResult.setCheckStatus(CheckRocksdbCqWriteResult.CheckStatus.CHECK_OK.getValue());
+        response.setBody(JSON.toJSONString(expectedResult).getBytes());
+
+        when(remotingClient.invokeSync(any(String.class), any(RemotingCommand.class), any(Long.class)))
+                .thenReturn(response);
+
+        CheckRocksdbCqWriteResult result = mqClientAPI.checkRocksdbCqWriteProgress(
+                "brokerAddr", "testTopic", 12345L, 3000L);
+
+        assertEquals(CheckRocksdbCqWriteResult.CheckStatus.CHECK_OK.getValue(), result.getCheckStatus());
+    }
+
     private Properties createProperties() {
         Properties result = new Properties();
         result.put("key", "value");
diff --git a/client/src/test/java/org/apache/rocketmq/client/impl/admin/MqClientAdminImplTest.java b/client/src/test/java/org/apache/rocketmq/client/impl/admin/MqClientAdminImplTest.java
index 71682fb52c..520f4da5f2 100644
--- a/client/src/test/java/org/apache/rocketmq/client/impl/admin/MqClientAdminImplTest.java
+++ b/client/src/test/java/org/apache/rocketmq/client/impl/admin/MqClientAdminImplTest.java
@@ -206,7 +206,7 @@ public class MqClientAdminImplTest {
     @Test
     public void assertUpdateOrCreateSubscriptionGroupWithSuccess() throws Exception {
         setResponseSuccess(null);
-        SubscriptionGroupConfig config = mock(SubscriptionGroupConfig.class);
+        SubscriptionGroupConfig config = new SubscriptionGroupConfig();
         CompletableFuture<Void> actual = mqClientAdminImpl.updateOrCreateSubscriptionGroup(defaultBrokerAddr, config, defaultTimeout);
         assertNull(actual.get());
     }
@@ -214,7 +214,7 @@ public class MqClientAdminImplTest {
     @Test
     public void assertUpdateOrCreateSubscriptionGroupWithError() {
         setResponseError();
-        SubscriptionGroupConfig config = mock(SubscriptionGroupConfig.class);
+        SubscriptionGroupConfig config = new SubscriptionGroupConfig();
         CompletableFuture<Void> actual = mqClientAdminImpl.updateOrCreateSubscriptionGroup(defaultBrokerAddr, config, defaultTimeout);
         Throwable thrown = assertThrows(ExecutionException.class, actual::get);
         assertTrue(thrown.getCause() instanceof MQClientException);
diff --git a/client/src/test/java/org/apache/rocketmq/client/impl/consumer/PopProcessQueueTest.java b/client/src/test/java/org/apache/rocketmq/client/impl/consumer/PopProcessQueueTest.java
new file mode 100644
index 0000000000..0633342c59
--- /dev/null
+++ b/client/src/test/java/org/apache/rocketmq/client/impl/consumer/PopProcessQueueTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.client.impl.consumer;
+
+import org.apache.rocketmq.remoting.protocol.body.PopProcessQueueInfo;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(MockitoJUnitRunner.class)
+public class PopProcessQueueTest {
+
+    private final PopProcessQueueInfo popProcessQueueInfo = new PopProcessQueueInfo();
+
+    @Test
+    public void testPopProcessQueue() {
+        long currentTime = System.currentTimeMillis();
+        PopProcessQueue popRequest1 = createPopProcessQueue(currentTime);
+        PopProcessQueue popRequest2 = createPopProcessQueue(currentTime);
+        assertEquals(popRequest1.getLastPopTimestamp(), popRequest2.getLastPopTimestamp());
+        assertEquals(popRequest1.toString(), popRequest2.toString());
+        assertEquals(popRequest1.getWaiAckMsgCount(), popRequest2.getWaiAckMsgCount());
+        assertEquals(popRequest1.ack(), popRequest2.ack());
+        assertEquals(popRequest1.isPullExpired(), popRequest2.isPullExpired());
+        assertEquals(popProcessQueueInfo.getLastPopTimestamp(), popRequest1.getLastPopTimestamp());
+        assertEquals(popProcessQueueInfo.isDroped(), popRequest1.isDropped());
+        assertEquals(popProcessQueueInfo.getWaitAckCount(), popRequest1.getWaiAckMsgCount() + popRequest2.getWaiAckMsgCount());
+    }
+
+    private PopProcessQueue createPopProcessQueue(final long currentTime) {
+        PopProcessQueue result = new PopProcessQueue();
+        long curTime = System.currentTimeMillis();
+        result.setLastPopTimestamp(curTime);
+        result.incFoundMsg(1);
+        result.decFoundMsg(1);
+        result.setLastPopTimestamp(currentTime);
+        result.fillPopProcessQueueInfo(popProcessQueueInfo);
+        return result;
+    }
+}
diff --git a/client/src/test/java/org/apache/rocketmq/client/impl/consumer/ProcessQueueTest.java b/client/src/test/java/org/apache/rocketmq/client/impl/consumer/ProcessQueueTest.java
index dd7ffa757f..a12633be1b 100644
--- a/client/src/test/java/org/apache/rocketmq/client/impl/consumer/ProcessQueueTest.java
+++ b/client/src/test/java/org/apache/rocketmq/client/impl/consumer/ProcessQueueTest.java
@@ -16,11 +16,6 @@
  */
 package org.apache.rocketmq.client.impl.consumer;
 
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.TreeMap;
 import org.apache.commons.lang3.reflect.FieldUtils;
 import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
 import org.apache.rocketmq.client.exception.MQBrokerException;
@@ -34,6 +29,12 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.TreeMap;
+
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -164,6 +165,7 @@ public class ProcessQueueTest {
         ProcessQueue result = new ProcessQueue();
         result.setMsgAccCnt(1);
         result.incTryUnlockTimes();
+        result.setLastPullTimestamp(10000L);
         return result;
     }
 
diff --git a/client/src/test/java/org/apache/rocketmq/client/producer/SendResultTest.java b/client/src/test/java/org/apache/rocketmq/client/producer/SendResultTest.java
new file mode 100644
index 0000000000..1ae8371a96
--- /dev/null
+++ b/client/src/test/java/org/apache/rocketmq/client/producer/SendResultTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.client.producer;
+
+import com.alibaba.fastjson2.JSON;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class SendResultTest {
+
+    @Test
+    public void testEncoderSendResultToJson() {
+        SendResult sendResult = new SendResult();
+        sendResult.setSendStatus(SendStatus.SEND_OK);
+        sendResult.setMsgId("12345");
+        sendResult.setQueueOffset(100L);
+        MessageQueue messageQueue = new MessageQueue("TestTopic", "BrokerA", 1);
+        sendResult.setMessageQueue(messageQueue);
+
+        String json = SendResult.encoderSendResultToJson(sendResult);
+
+        SendResult decodedResult = JSON.parseObject(json, SendResult.class);
+        assertEquals(sendResult.getSendStatus(), decodedResult.getSendStatus());
+        assertEquals(sendResult.getMsgId(), decodedResult.getMsgId());
+        assertEquals(sendResult.getQueueOffset(), decodedResult.getQueueOffset());
+        assertEquals(sendResult.getMessageQueue(), decodedResult.getMessageQueue());
+    }
+
+    @Test
+    public void testDecoderSendResultFromJson() {
+        String json = "{\"sendStatus\":\"SEND_OK\",\"msgId\":\"12345\",\"queueOffset\":100,\"messageQueue\":{\"topic\":\"TestTopic\",\"brokerName\":\"BrokerA\",\"queueId\":1}}";
+
+        SendResult sendResult = SendResult.decoderSendResultFromJson(json);
+
+        assertEquals(SendStatus.SEND_OK, sendResult.getSendStatus());
+        assertEquals("12345", sendResult.getMsgId());
+        assertEquals(100L, sendResult.getQueueOffset());
+        assertEquals("TestTopic", sendResult.getMessageQueue().getTopic());
+        assertEquals("BrokerA", sendResult.getMessageQueue().getBrokerName());
+        assertEquals(1, sendResult.getMessageQueue().getQueueId());
+    }
+}
diff --git a/common/BUILD.bazel b/common/BUILD.bazel
index 10c5d19fbe..8aeeb2f24f 100644
--- a/common/BUILD.bazel
+++ b/common/BUILD.bazel
@@ -21,7 +21,6 @@ java_library(
     srcs = glob(["src/main/java/**/*.java"]),
     visibility = ["//visibility:public"],
     deps = [
-        "@maven//:com_alibaba_fastjson",
         "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:com_github_luben_zstd_jni",
         "@maven//:com_google_guava_guava",
@@ -55,7 +54,6 @@ java_library(
         ":common",
         "//:test_deps",
         "@maven//:com_google_guava_guava",
-        "@maven//:com_alibaba_fastjson",
         "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:commons_codec_commons_codec",
         "@maven//:io_netty_netty_all",
diff --git a/common/src/main/java/org/apache/rocketmq/common/TopicConfig.java b/common/src/main/java/org/apache/rocketmq/common/TopicConfig.java
index 0bf64905a0..ebb009c567 100644
--- a/common/src/main/java/org/apache/rocketmq/common/TopicConfig.java
+++ b/common/src/main/java/org/apache/rocketmq/common/TopicConfig.java
@@ -16,14 +16,15 @@
  */
 package org.apache.rocketmq.common;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.TypeReference;
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.TypeReference;
+import com.alibaba.fastjson2.annotation.JSONField;
+import org.apache.rocketmq.common.attribute.TopicMessageType;
+import org.apache.rocketmq.common.constant.PermName;
+
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
-import org.apache.rocketmq.common.attribute.TopicMessageType;
-import org.apache.rocketmq.common.constant.PermName;
 
 import static org.apache.rocketmq.common.TopicAttributes.TOPIC_MESSAGE_TYPE_ATTRIBUTE;
 
diff --git a/common/src/main/java/org/apache/rocketmq/common/fastjson/GenericMapSuperclassDeserializer.java b/common/src/main/java/org/apache/rocketmq/common/fastjson/GenericMapSuperclassDeserializer.java
index 80a1554d12..f2639b51c1 100644
--- a/common/src/main/java/org/apache/rocketmq/common/fastjson/GenericMapSuperclassDeserializer.java
+++ b/common/src/main/java/org/apache/rocketmq/common/fastjson/GenericMapSuperclassDeserializer.java
@@ -17,11 +17,10 @@
 
 package org.apache.rocketmq.common.fastjson;
 
-import com.alibaba.fastjson.JSONException;
-import com.alibaba.fastjson.parser.DefaultJSONParser;
-import com.alibaba.fastjson.parser.JSONToken;
-import com.alibaba.fastjson.parser.deserializer.MapDeserializer;
-import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
+import com.alibaba.fastjson2.JSONException;
+import com.alibaba.fastjson2.JSONReader;
+import com.alibaba.fastjson2.reader.ObjectReader;
+
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.util.Map;
@@ -29,32 +28,40 @@ import java.util.Map;
 /**
  * workaround https://github.com/alibaba/fastjson/issues/3730
  */
-public class GenericMapSuperclassDeserializer implements ObjectDeserializer {
+public class GenericMapSuperclassDeserializer implements ObjectReader<Object> {
     public static final GenericMapSuperclassDeserializer INSTANCE = new GenericMapSuperclassDeserializer();
-
     @SuppressWarnings({"unchecked", "rawtypes"})
     @Override
-    public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
+    public Object readObject(JSONReader reader, Type type, Object fieldName, long features) {
         Class<?> clz = (Class<?>) type;
         Type genericSuperclass = clz.getGenericSuperclass();
         Map map;
         try {
-            map = (Map) clz.newInstance();
+            map = (Map) clz.getDeclaredConstructor().newInstance();
         } catch (Exception e) {
             throw new JSONException("unsupport type " + type, e);
         }
         ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
         Type keyType = parameterizedType.getActualTypeArguments()[0];
         Type valueType = parameterizedType.getActualTypeArguments()[1];
-        if (String.class == keyType) {
-            return (T) MapDeserializer.parseMap(parser, (Map<String, Object>) map, valueType, fieldName);
-        } else {
-            return (T) MapDeserializer.parseMap(parser, map, keyType, valueType, fieldName);
+
+        if (!reader.nextIfObjectStart()) {
+            throw new JSONException(reader.info("expect '{', but " + reader.current()));
         }
-    }
 
-    @Override
-    public int getFastMatchToken() {
-        return JSONToken.LBRACE;
+        while (!reader.nextIfObjectEnd()) {
+            Object key;
+            if (keyType == String.class) {
+                key = reader.readFieldName();
+            } else {
+                key = reader.getContext().getProvider().getObjectReader(keyType).readObject(reader, keyType, fieldName, features);
+                reader.nextIfMatch(':');
+            }
+
+            Object value = reader.getContext().getProvider().getObjectReader(valueType).readObject(reader, valueType, fieldName, features);
+            map.put(key, value);
+            reader.nextIfComma();
+        }
+        return map;
     }
 }
diff --git a/common/src/main/java/org/apache/rocketmq/common/utils/FastJsonSerializer.java b/common/src/main/java/org/apache/rocketmq/common/utils/FastJsonSerializer.java
index 600054b40b..943e823566 100644
--- a/common/src/main/java/org/apache/rocketmq/common/utils/FastJsonSerializer.java
+++ b/common/src/main/java/org/apache/rocketmq/common/utils/FastJsonSerializer.java
@@ -16,23 +16,13 @@
  */
 package org.apache.rocketmq.common.utils;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.support.config.FastJsonConfig;
+import com.alibaba.fastjson2.JSON;
 import org.apache.commons.lang3.SerializationException;
 
 /**
  * The object serializer based on fastJson
  */
 public class FastJsonSerializer implements Serializer {
-    private FastJsonConfig fastJsonConfig = new FastJsonConfig();
-
-    public FastJsonConfig getFastJsonConfig() {
-        return this.fastJsonConfig;
-    }
-
-    public void setFastJsonConfig(FastJsonConfig fastJsonConfig) {
-        this.fastJsonConfig = fastJsonConfig;
-    }
 
     @Override
     public <T> byte[] serialize(T t) throws SerializationException {
@@ -40,7 +30,7 @@ public class FastJsonSerializer implements Serializer {
             return new byte[0];
         } else {
             try {
-                return JSON.toJSONBytes(this.fastJsonConfig.getCharset(), t, this.fastJsonConfig.getSerializeConfig(), this.fastJsonConfig.getSerializeFilters(), this.fastJsonConfig.getDateFormat(), JSON.DEFAULT_GENERATE_FEATURE, this.fastJsonConfig.getSerializerFeatures());
+                return JSON.toJSONBytes(t);
             } catch (Exception var3) {
                 throw new SerializationException("Could not serialize: " + var3.getMessage(), var3);
             }
@@ -51,7 +41,7 @@ public class FastJsonSerializer implements Serializer {
     public <T> T deserialize(byte[] bytes, Class<T> type) throws SerializationException {
         if (bytes != null && bytes.length != 0) {
             try {
-                return JSON.parseObject(bytes, this.fastJsonConfig.getCharset(), type, this.fastJsonConfig.getParserConfig(), this.fastJsonConfig.getParseProcess(), JSON.DEFAULT_PARSER_FEATURE, this.fastJsonConfig.getFeatures());
+                return JSON.parseObject(bytes, type);
             } catch (Exception var3) {
                 throw new SerializationException("Could not deserialize: " + var3.getMessage(), var3);
             }
diff --git a/common/src/test/java/org/apache/rocketmq/common/fastjson/GenericMapSuperclassDeserializerTest.java b/common/src/test/java/org/apache/rocketmq/common/fastjson/GenericMapSuperclassDeserializerTest.java
new file mode 100644
index 0000000000..36c633f699
--- /dev/null
+++ b/common/src/test/java/org/apache/rocketmq/common/fastjson/GenericMapSuperclassDeserializerTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.fastjson;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONException;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class GenericMapSuperclassDeserializerTest {
+
+    public static class CustomMap extends HashMap<String, Object> {
+        private static final long serialVersionUID = 1L;
+    }
+
+    public static class IntKeyMap extends HashMap<Integer, String> {
+        private static final long serialVersionUID = 1L;
+    }
+
+    @Test
+    public void testBasicDeserialization() {
+        JSON.registerIfAbsent(CustomMap.class, GenericMapSuperclassDeserializer.INSTANCE);
+        String json = "{\"key1\":\"value1\",\"key2\":42,\"key3\":true}";
+        CustomMap map = JSON.parseObject(json, CustomMap.class);
+
+        assertNotNull(map);
+        assertEquals(3, map.size());
+        assertEquals("value1", map.get("key1"));
+        assertEquals(42, map.get("key2"));
+        assertEquals(true, map.get("key3"));
+    }
+
+    @Test
+    public void testNestedObjects() {
+        JSON.registerIfAbsent(CustomMap.class, GenericMapSuperclassDeserializer.INSTANCE);
+        String json = "{\"simple\":\"value\",\"nested\":{\"inner\":123},\"array\":[1,2,3]}";
+        CustomMap map = JSON.parseObject(json, CustomMap.class);
+
+        assertNotNull(map);
+        assertEquals(3, map.size());
+        assertEquals("value", map.get("simple"));
+
+        assertTrue(map.get("nested") instanceof Map);
+        Map<?, ?> nestedMap = (Map<?, ?>) map.get("nested");
+        assertEquals(123, nestedMap.get("inner"));
+
+        assertTrue(map.get("array") instanceof java.util.List);
+        java.util.List<?> array = (java.util.List<?>) map.get("array");
+        assertEquals(3, array.size());
+        assertEquals(1, array.get(0));
+        assertEquals(2, array.get(1));
+        assertEquals(3, array.get(2));
+    }
+
+    @Test
+    public void testEmptyObject() {
+        JSON.registerIfAbsent(CustomMap.class, GenericMapSuperclassDeserializer.INSTANCE);
+        String json = "{}";
+        CustomMap map = JSON.parseObject(json, CustomMap.class);
+
+        assertNotNull(map);
+        assertEquals(0, map.size());
+    }
+
+    @Test
+    public void testNonStringKey() {
+        JSON.registerIfAbsent(IntKeyMap.class, GenericMapSuperclassDeserializer.INSTANCE);
+        String json = "{1:\"one\",2:\"two\",3:\"three\"}";
+        IntKeyMap map = JSON.parseObject(json, IntKeyMap.class);
+
+        assertNotNull(map);
+        assertEquals(3, map.size());
+        assertEquals("one", map.get(1));
+        assertEquals("two", map.get(2));
+        assertEquals("three", map.get(3));
+    }
+
+    @Test(expected = JSONException.class)
+    public void testMalformedJson() {
+        JSON.registerIfAbsent(CustomMap.class, GenericMapSuperclassDeserializer.INSTANCE);
+        String json = "{\"key\":\"missing closing brace\"";
+        JSON.parseObject(json, CustomMap.class);
+    }
+}
diff --git a/container/BUILD.bazel b/container/BUILD.bazel
index 4888de2228..b828c4c431 100644
--- a/container/BUILD.bazel
+++ b/container/BUILD.bazel
@@ -35,7 +35,6 @@ java_library(
         "@maven//:commons_codec_commons_codec",
         "@maven//:com_github_luben_zstd_jni",
         "@maven//:org_lz4_lz4_java",
-        "@maven//:com_alibaba_fastjson",
         "@maven//:io_netty_netty_all",
         "@maven//:com_google_guava_guava",
         "@maven//:org_slf4j_slf4j_api",
@@ -65,7 +64,6 @@ java_library(
         "@maven//:org_apache_commons_commons_lang3", 
         "@maven//:io_netty_netty_all",    
         "@maven//:com_google_guava_guava",  
-        "@maven//:com_alibaba_fastjson",         
     ],
     resources = glob(["src/test/resources/certs/*.pem"]) + glob(["src/test/resources/certs/*.key"])
 )
diff --git a/controller/BUILD.bazel b/controller/BUILD.bazel
index e1dc61c500..652dbd4d0c 100644
--- a/controller/BUILD.bazel
+++ b/controller/BUILD.bazel
@@ -31,7 +31,7 @@ java_library(
         "@maven//:commons_codec_commons_codec",
         "@maven//:com_github_luben_zstd_jni",
         "@maven//:org_lz4_lz4_java",
-        "@maven//:com_alibaba_fastjson",
+        "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:io_netty_netty_all",
         "@maven//:com_google_guava_guava",
         "@maven//:org_slf4j_slf4j_api",
@@ -70,7 +70,7 @@ java_library(
         "@maven//:org_apache_commons_commons_lang3", 
         "@maven//:io_netty_netty_all",    
         "@maven//:com_google_guava_guava",  
-        "@maven//:com_alibaba_fastjson",     
+        "@maven//:com_alibaba_fastjson2_fastjson2",
     ],
     resources = glob(["src/test/resources/certs/*.pem"]) + glob(["src/test/resources/certs/*.key"])
 )
diff --git a/controller/src/main/java/org/apache/rocketmq/controller/impl/heartbeat/RaftBrokerHeartBeatManager.java b/controller/src/main/java/org/apache/rocketmq/controller/impl/heartbeat/RaftBrokerHeartBeatManager.java
index c7d5d26fd0..e7a3443001 100644
--- a/controller/src/main/java/org/apache/rocketmq/controller/impl/heartbeat/RaftBrokerHeartBeatManager.java
+++ b/controller/src/main/java/org/apache/rocketmq/controller/impl/heartbeat/RaftBrokerHeartBeatManager.java
@@ -16,8 +16,8 @@
  */
 package org.apache.rocketmq.controller.impl.heartbeat;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.TypeReference;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.TypeReference;
 import io.netty.channel.Channel;
 import org.apache.rocketmq.common.ControllerConfig;
 import org.apache.rocketmq.common.ThreadFactoryImpl;
diff --git a/controller/src/main/java/org/apache/rocketmq/controller/impl/manager/RaftReplicasInfoManager.java b/controller/src/main/java/org/apache/rocketmq/controller/impl/manager/RaftReplicasInfoManager.java
index 492043235b..046ced90c0 100644
--- a/controller/src/main/java/org/apache/rocketmq/controller/impl/manager/RaftReplicasInfoManager.java
+++ b/controller/src/main/java/org/apache/rocketmq/controller/impl/manager/RaftReplicasInfoManager.java
@@ -16,7 +16,7 @@
  */
 package org.apache.rocketmq.controller.impl.manager;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import org.apache.rocketmq.common.ControllerConfig;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.controller.helper.BrokerValidPredicate;
diff --git a/controller/src/test/java/org/apache/rocketmq/controller/impl/RaftBrokerHeartBeatManagerTest.java b/controller/src/test/java/org/apache/rocketmq/controller/impl/RaftBrokerHeartBeatManagerTest.java
index 3c28158982..ee742cc55b 100644
--- a/controller/src/test/java/org/apache/rocketmq/controller/impl/RaftBrokerHeartBeatManagerTest.java
+++ b/controller/src/test/java/org/apache/rocketmq/controller/impl/RaftBrokerHeartBeatManagerTest.java
@@ -16,13 +16,9 @@
  */
 package org.apache.rocketmq.controller.impl;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import io.netty.channel.Channel;
 import io.netty.channel.DefaultChannelPromise;
-import java.util.Collections;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 import org.apache.rocketmq.common.ControllerConfig;
 import org.apache.rocketmq.controller.impl.heartbeat.BrokerIdentityInfo;
 import org.apache.rocketmq.controller.impl.heartbeat.RaftBrokerHeartBeatManager;
@@ -34,6 +30,11 @@ import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.util.Collections;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.when;
diff --git a/controller/src/test/java/org/apache/rocketmq/controller/impl/event/EventSerializerTest.java b/controller/src/test/java/org/apache/rocketmq/controller/impl/event/EventSerializerTest.java
new file mode 100644
index 0000000000..4eb482da64
--- /dev/null
+++ b/controller/src/test/java/org/apache/rocketmq/controller/impl/event/EventSerializerTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.controller.impl.event;
+
+import org.apache.commons.lang3.SerializationException;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.rocketmq.common.utils.FastJsonSerializer;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class EventSerializerTest {
+
+    @Mock
+    private FastJsonSerializer serializer;
+
+    private final EventSerializer eventSerializer = new EventSerializer();
+
+    @Before
+    public void init() throws IllegalAccessException {
+        FieldUtils.writeDeclaredField(eventSerializer, "serializer", serializer, true);
+    }
+
+    @Test
+    public void testSerializeValidEventMessageShouldReturnSerializedData() {
+        EventMessage eventMessage = mock(EventMessage.class);
+        EventType eventType = EventType.APPLY_BROKER_ID_EVENT;
+        when(eventMessage.getEventType()).thenReturn(eventType);
+        when(serializer.serialize(eventMessage)).thenReturn("{\"event\":\"APPLY_BROKER_ID_EVENT\"}".getBytes());
+        byte[] result = eventSerializer.serialize(eventMessage);
+        assertNotNull(result);
+    }
+
+    @Test
+    public void testSerializeEventMessageWithNoEventType() {
+        EventMessage eventMessage = mock(EventMessage.class);
+        when(eventMessage.getEventType()).thenReturn(null);
+        assertThrows(NullPointerException.class, () -> eventSerializer.serialize(eventMessage));
+    }
+
+    @Test
+    public void testSerializeSerializerReturnsNullShouldReturnNull() {
+        EventMessage eventMessage = mock(EventMessage.class);
+        EventType eventType = EventType.READ_EVENT;
+        when(eventMessage.getEventType()).thenReturn(eventType);
+        when(serializer.serialize(eventMessage)).thenReturn(null);
+        byte[] result = eventSerializer.serialize(eventMessage);
+        assertNull(result);
+    }
+
+    @Test
+    public void testSerializeSerializerThrowsException() {
+        EventMessage eventMessage = mock(EventMessage.class);
+        EventType eventType = EventType.ELECT_MASTER_EVENT;
+        when(eventMessage.getEventType()).thenReturn(eventType);
+        when(serializer.serialize(eventMessage)).thenThrow(new RuntimeException("Serialization error"));
+        assertThrows(RuntimeException.class, () -> eventSerializer.serialize(eventMessage));
+    }
+
+    @Test
+    public void testDeserializeBytesLessThanTwoReturnsNull() {
+        byte[] bytes = new byte[1];
+        assertNull(eventSerializer.deserialize(bytes));
+    }
+
+    @Test
+    public void testDeserializeInvalidEventIdReturnsNull() {
+        assertNull(eventSerializer.deserialize(new byte[]{0, 0xF}));
+    }
+
+    @Test
+    public void testDeserializeValidEventTypeReturnsEventMessage() throws SerializationException {
+        byte[] data = new byte[]{0, 0xF};
+        byte[] bytes = new byte[]{0, (byte) EventType.ALTER_SYNC_STATE_SET_EVENT.getId(), data[0], data[1]};
+        AlterSyncStateSetEvent alterSyncStateSetEvent = mock(AlterSyncStateSetEvent.class);
+        when(serializer.deserialize(any(byte[].class), eq(AlterSyncStateSetEvent.class))).thenReturn(alterSyncStateSetEvent);
+        EventMessage result = eventSerializer.deserialize(bytes);
+        assertNotNull(result);
+        assertTrue(result instanceof AlterSyncStateSetEvent);
+    }
+
+    @Test
+    public void testDeserializeSerializerThrowsException() throws SerializationException {
+        byte[] data = new byte[]{0, 0xF};
+        byte[] bytes = new byte[]{0, (byte) EventType.ALTER_SYNC_STATE_SET_EVENT.getId(), data[0], data[1]};
+        when(serializer.deserialize(any(byte[].class), eq(AlterSyncStateSetEvent.class))).thenThrow(new SerializationException("Deserialization failed"));
+        assertThrows(SerializationException.class, () -> eventSerializer.deserialize(bytes));
+    }
+
+    @Test
+    public void testDeserializeValidEventTypeUnknownEventReturnsNull() throws SerializationException {
+        byte[] data = new byte[]{0, 0xF};
+        byte[] bytes = new byte[]{0, (short) 99, data[0], data[1]};
+        assertNull(eventSerializer.deserialize(bytes));
+    }
+}
\ No newline at end of file
diff --git a/controller/src/test/java/org/apache/rocketmq/controller/impl/event/ListEventSerializerTest.java b/controller/src/test/java/org/apache/rocketmq/controller/impl/event/ListEventSerializerTest.java
new file mode 100644
index 0000000000..1c5e7f3a04
--- /dev/null
+++ b/controller/src/test/java/org/apache/rocketmq/controller/impl/event/ListEventSerializerTest.java
@@ -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.
+ */
+package org.apache.rocketmq.controller.impl.event;
+
+import org.apache.commons.lang3.SerializationException;
+import org.apache.rocketmq.logging.org.slf4j.Logger;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ListEventSerializerTest {
+
+    @Mock
+    private Logger logger;
+
+    @Test
+    public void testSerializeEmptyList() {
+        List<EventMessage> events = Collections.emptyList();
+        byte[] result = ListEventSerializer.serialize(events, null);
+        assertNotNull(result);
+        assertEquals(0, result.length);
+    }
+
+    @Test
+    public void testSerializeValidEventMessage() {
+        EventMessage eventMessage = new ElectMasterEvent("brokerA", 0L);
+        List<EventMessage> events = Collections.singletonList(eventMessage);
+        byte[] result = ListEventSerializer.serialize(events, null);
+        assertNotNull(result);
+        assertTrue(result.length > 0);
+    }
+
+    @Test
+    public void testSerializeEventMessageWithNullEventType() {
+        EventMessage eventMessage = mock(EventMessage.class);
+        when(eventMessage.getEventType()).thenReturn(null);
+        List<EventMessage> events = Collections.singletonList(eventMessage);
+        assertThrows(NullPointerException.class, () -> ListEventSerializer.serialize(events, logger));
+    }
+
+    @Test
+    public void testDeserializeBytesIsNull() throws SerializationException {
+        List<EventMessage> result = ListEventSerializer.deserialize(null, logger);
+        assertNotNull(result);
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testDeserializeBytesLengthLessThanSix() throws SerializationException {
+        byte[] bytes = new byte[5];
+        List<EventMessage> result = ListEventSerializer.deserialize(bytes, logger);
+        assertNotNull(result);
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    public void testDeserializeValidBytesWithKnownEventType() throws SerializationException {
+        byte[] bytes = new byte[]{0x01, 0x00, 0x06, 0x00, 0x00, 0x00};
+        assertNotNull(ListEventSerializer.deserialize(bytes, logger));
+    }
+
+    @Test
+    public void testDeserializeException() throws SerializationException {
+        byte[] bytes = new byte[]{0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00};
+        assertThrows(ArrayIndexOutOfBoundsException.class, () -> ListEventSerializer.deserialize(bytes, logger));
+    }
+}
\ No newline at end of file
diff --git a/controller/src/test/java/org/apache/rocketmq/controller/impl/heartbeat/RaftBrokerHeartBeatManagerTest.java b/controller/src/test/java/org/apache/rocketmq/controller/impl/heartbeat/RaftBrokerHeartBeatManagerTest.java
new file mode 100644
index 0000000000..28c370abbe
--- /dev/null
+++ b/controller/src/test/java/org/apache/rocketmq/controller/impl/heartbeat/RaftBrokerHeartBeatManagerTest.java
@@ -0,0 +1,352 @@
+/*
+ * 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.controller.impl.heartbeat;
+
+import com.alibaba.fastjson2.JSON;
+import io.netty.channel.Channel;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.rocketmq.common.ControllerConfig;
+import org.apache.rocketmq.common.JraftConfig;
+import org.apache.rocketmq.controller.impl.JRaftController;
+import org.apache.rocketmq.controller.impl.task.BrokerCloseChannelRequest;
+import org.apache.rocketmq.controller.impl.task.CheckNotActiveBrokerRequest;
+import org.apache.rocketmq.controller.impl.task.GetBrokerLiveInfoResponse;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.protocol.ResponseCode;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RaftBrokerHeartBeatManagerTest {
+
+    @Mock
+    private JRaftController controller;
+
+    private RaftBrokerHeartBeatManager raftBrokerHeartBeatManager;
+
+    @Before
+    public void init() throws IllegalAccessException {
+        ControllerConfig controllerConfig = new ControllerConfig();
+        raftBrokerHeartBeatManager = new RaftBrokerHeartBeatManager(controllerConfig);
+        FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "controller", controller, true);
+    }
+
+    @Test
+    public void testOnBrokerHeartbeatSuccess() {
+        Channel channel = mock(Channel.class);
+        CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+        when(controller.onBrokerHeartBeat(any())).thenReturn(future);
+        raftBrokerHeartBeatManager.onBrokerHeartbeat("cluster1", "broker1", "127.0.0.1:10911", 1L, 3000L, channel, 1, 1000L, 500L, 1);
+        verify(channel, never()).close();
+    }
+
+    @Test
+    public void testOnBrokerHeartbeatLeaderNotAvailable() {
+        Channel channel = mock(Channel.class);
+        CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.CONTROLLER_NOT_LEADER, "Not Leader"));
+        when(controller.onBrokerHeartBeat(any())).thenReturn(future);
+        raftBrokerHeartBeatManager.onBrokerHeartbeat("cluster1", "broker1", "127.0.0.1:10911", 1L, 3000L, channel, 1, 1000L, 500L, 1);
+        verify(channel, never()).close();
+    }
+
+    @Test
+    public void testOnBrokerHeartbeatException() throws Exception {
+        Channel channel = mock(Channel.class);
+        CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+        when(controller.onBrokerHeartBeat(any())).thenReturn(future);
+        FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "brokerChannelIdentityInfoMap", null, true);
+        assertThrows(NullPointerException.class, () -> raftBrokerHeartBeatManager.onBrokerHeartbeat("cluster1", "broker1", "127.0.0.1:10911", 1L, 3000L, channel, 1, 1000L, 500L, 1));
+    }
+
+    @Test
+    public void testOnBrokerChannelCloseBrokerIdentityInfoNotNullSuccess() throws Exception {
+        Channel channel = mock(Channel.class);
+        BrokerIdentityInfo brokerIdentityInfo = new BrokerIdentityInfo("cluster1", "broker1", 1L);
+        Map<Channel, BrokerIdentityInfo> brokerChannelIdentityInfoMap = new HashMap<>();
+        brokerChannelIdentityInfoMap.put(channel, brokerIdentityInfo);
+        FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "brokerChannelIdentityInfoMap", brokerChannelIdentityInfoMap, true);
+        CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+        when(controller.onBrokerCloseChannel(any(BrokerCloseChannelRequest.class))).thenReturn(future);
+        raftBrokerHeartBeatManager.onBrokerChannelClose(channel);
+        verify(controller).onBrokerCloseChannel(any(BrokerCloseChannelRequest.class));
+    }
+
+    @Test
+    public void testOnBrokerChannelCloseBrokerIdentityInfoNotNullException() throws Exception {
+        Channel channel = mock(Channel.class);
+        BrokerIdentityInfo brokerIdentityInfo = new BrokerIdentityInfo("cluster1", "broker1", 1L);
+        Map<Channel, BrokerIdentityInfo> brokerChannelIdentityInfoMap = new HashMap<>();
+        brokerChannelIdentityInfoMap.put(channel, brokerIdentityInfo);
+        FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "brokerChannelIdentityInfoMap", brokerChannelIdentityInfoMap, true);
+        CompletableFuture<RemotingCommand> future = new CompletableFuture<>();
+        future.completeExceptionally(new ExecutionException(new RuntimeException("Test Exception")));
+        when(controller.onBrokerCloseChannel(any(BrokerCloseChannelRequest.class))).thenReturn(future);
+        raftBrokerHeartBeatManager.onBrokerChannelClose(channel);
+        verify(controller).onBrokerCloseChannel(any(BrokerCloseChannelRequest.class));
+    }
+
+    @Test
+    public void testOnBrokerChannelCloseBrokerIdentityInfoNull() {
+        Channel channel = mock(Channel.class);
+        raftBrokerHeartBeatManager.onBrokerChannelClose(channel);
+        verify(controller, never()).onBrokerCloseChannel(any(BrokerCloseChannelRequest.class));
+    }
+
+    @Test
+    public void testOnBrokerChannelCloseBrokerIdentityInfoNotNullTimeoutException() throws Exception {
+        Channel channel = mock(Channel.class);
+        BrokerIdentityInfo brokerIdentityInfo = new BrokerIdentityInfo("cluster1", "broker1", 1L);
+        Map<Channel, BrokerIdentityInfo> brokerChannelIdentityInfoMap = new HashMap<>();
+        brokerChannelIdentityInfoMap.put(channel, brokerIdentityInfo);
+        FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "brokerChannelIdentityInfoMap", brokerChannelIdentityInfoMap, true);
+        CompletableFuture<RemotingCommand> future = new CompletableFuture<>();
+        when(controller.onBrokerCloseChannel(any(BrokerCloseChannelRequest.class))).thenReturn(future);
+        raftBrokerHeartBeatManager.onBrokerChannelClose(channel);
+        verify(controller).onBrokerCloseChannel(any(BrokerCloseChannelRequest.class));
+    }
+
+    @Test
+    public void testScanNotActiveBrokerSuccess() throws Exception {
+        ControllerConfig controllerConfig = new ControllerConfig();
+        JraftConfig jraftConfig = new JraftConfig();
+        jraftConfig.setjRaftScanWaitTimeoutMs(10000);
+        controllerConfig.setJraftConfig(jraftConfig);
+        raftBrokerHeartBeatManager = new RaftBrokerHeartBeatManager(controllerConfig);
+        controller = mock(JRaftController.class);
+        FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "controller", controller, true);
+        when(controller.isLeaderState()).thenReturn(true);
+        FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "firstReceivedHeartbeatTime", 1000, true);
+
+        List<BrokerIdentityInfo> inactiveBrokers = new ArrayList<>();
+        BrokerIdentityInfo brokerInfo = new BrokerIdentityInfo("testCluster", "testBroker", 1L);
+        inactiveBrokers.add(brokerInfo);
+
+        RemotingCommand response = RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success");
+        response.setBody(JSON.toJSONString(inactiveBrokers).getBytes());
+        CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(response);
+        when(controller.checkNotActiveBroker(any())).thenReturn(future);
+
+        Channel channel = mock(Channel.class);
+        Map<Channel, BrokerIdentityInfo> brokerChannelMap = new HashMap<>();
+        brokerChannelMap.put(channel, brokerInfo);
+        FieldUtils.writeDeclaredField(raftBrokerHeartBeatManager, "brokerChannelIdentityInfoMap", brokerChannelMap, true);
+
+        Method method = RaftBrokerHeartBeatManager.class.getDeclaredMethod("scanNotActiveBroker");
+        method.setAccessible(true);
+        method.invoke(raftBrokerHeartBeatManager);
+
+        verify(controller).checkNotActiveBroker(any(CheckNotActiveBrokerRequest.class));
+    }
+
+    @Test
+    public void testGetBrokerLiveInfoSuccess() throws Exception {
+        String clusterName = "cluster1";
+        String brokerName = "broker1";
+        Long brokerId = 1L;
+        BrokerIdentityInfo brokerIdentityInfo = new BrokerIdentityInfo(clusterName, brokerName, brokerId);
+        BrokerLiveInfo expectedBrokerLiveInfo = new BrokerLiveInfo(brokerName, "127.0.0.1:10911", brokerId, System.currentTimeMillis(), 3000L, null, 1, 1000L, 500);
+        Map<BrokerIdentityInfo, BrokerLiveInfo> expectedResponse = new HashMap<>();
+        expectedResponse.put(brokerIdentityInfo, expectedBrokerLiveInfo);
+        CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+        future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+        future.get().setBody(JSON.toJSONString(expectedResponse).getBytes());
+        when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+        BrokerLiveInfo brokerLiveInfo = raftBrokerHeartBeatManager.getBrokerLiveInfo(clusterName, brokerName, brokerId);
+        assertEquals(expectedBrokerLiveInfo.getBrokerName(), brokerLiveInfo.getBrokerName());
+        assertEquals(expectedBrokerLiveInfo.getBrokerAddr(), brokerLiveInfo.getBrokerAddr());
+        assertEquals(expectedBrokerLiveInfo.getBrokerId(), brokerLiveInfo.getBrokerId());
+    }
+
+    @Test
+    public void testGetBrokerLiveInfoAllBrokers() throws Exception {
+        String clusterName = "cluster1";
+        String brokerName = "broker1";
+        Long brokerId = 1L;
+        BrokerIdentityInfo brokerIdentityInfo = new BrokerIdentityInfo(clusterName, brokerName, brokerId);
+        BrokerLiveInfo expectedBrokerLiveInfo = new BrokerLiveInfo(brokerName, "127.0.0.1:10911", brokerId, System.currentTimeMillis(), 3000L, null, 1, 1000L, 500);
+        Map<BrokerIdentityInfo, BrokerLiveInfo> expectedResponse = new HashMap<>();
+        expectedResponse.put(brokerIdentityInfo, expectedBrokerLiveInfo);
+        CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+        future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+        future.get().setBody(JSON.toJSONString(expectedResponse).getBytes());
+        when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+        BrokerLiveInfo brokerLiveInfo = raftBrokerHeartBeatManager.getBrokerLiveInfo(null, null, null);
+        assertNull(brokerLiveInfo);
+    }
+
+    @Test
+    public void testIsBrokerActiveBrokerActive() throws Exception {
+        String clusterName = "cluster1";
+        String brokerName = "broker1";
+        Long brokerId = 1L;
+        BrokerLiveInfo brokerLiveInfo = new BrokerLiveInfo(brokerName, "127.0.0.1:10911", brokerId, System.currentTimeMillis(), 3000L, null, 1, 1000L, 500);
+        Map<BrokerIdentityInfo, BrokerLiveInfo> responseMap = new HashMap<>();
+        responseMap.put(new BrokerIdentityInfo(clusterName, brokerName, brokerId), brokerLiveInfo);
+        CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+        future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+        future.get().setBody(JSON.toJSONString(responseMap).getBytes());
+        when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+        assertTrue(raftBrokerHeartBeatManager.isBrokerActive(clusterName, brokerName, brokerId));
+    }
+
+    @Test
+    public void testIsBrokerActiveBrokerNotActive() throws Exception {
+        String clusterName = "cluster1";
+        String brokerName = "broker1";
+        Long brokerId = 1L;
+        BrokerLiveInfo brokerLiveInfo = new BrokerLiveInfo(brokerName, "127.0.0.1:10911", brokerId, System.currentTimeMillis() - 4000L, 3000L, null, 1, 1000L, 500);
+        Map<BrokerIdentityInfo, BrokerLiveInfo> responseMap = new HashMap<>();
+        responseMap.put(new BrokerIdentityInfo(clusterName, brokerName, brokerId), brokerLiveInfo);
+        CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+        future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+        future.get().setBody(JSON.toJSONString(responseMap).getBytes());
+        when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+        assertFalse(raftBrokerHeartBeatManager.isBrokerActive(clusterName, brokerName, brokerId));
+    }
+
+    @Test
+    public void testIsBrokerActiveException() {
+        String clusterName = "cluster1";
+        String brokerName = "broker1";
+        Long brokerId = 1L;
+        CompletableFuture<RemotingCommand> future = new CompletableFuture<>();
+        future.completeExceptionally(new ExecutionException(new RuntimeException("Test Exception")));
+        when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+        assertFalse(raftBrokerHeartBeatManager.isBrokerActive(clusterName, brokerName, brokerId));
+    }
+
+    @Test
+    public void testIsBrokerActiveNoInfo() throws Exception {
+        String clusterName = "cluster1";
+        String brokerName = "broker1";
+        Long brokerId = 1L;
+        CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+        future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+        future.get().setBody(JSON.toJSONString(new HashMap<BrokerIdentityInfo, BrokerLiveInfo>()).getBytes());
+        when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+        assertFalse(raftBrokerHeartBeatManager.isBrokerActive(clusterName, brokerName, brokerId));
+    }
+
+    @Test
+    public void testIsBrokerActiveInvalidResponseCode() {
+        String clusterName = "cluster1";
+        String brokerName = "broker1";
+        Long brokerId = 1L;
+        CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.RPC_TIME_OUT, "Timeout"));
+        when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+        assertFalse(raftBrokerHeartBeatManager.isBrokerActive(clusterName, brokerName, brokerId));
+    }
+
+    @Test
+    public void testGetActiveBrokersNumAllBrokers() throws Exception {
+        String clusterName1 = "cluster1";
+        String brokerName1 = "broker1";
+        Long brokerId1 = 1L;
+        String clusterName2 = "cluster2";
+        String brokerName2 = "broker2";
+        Long brokerId2 = 2L;
+        BrokerIdentityInfo brokerIdentityInfo1 = new BrokerIdentityInfo(clusterName1, brokerName1, brokerId1);
+        BrokerIdentityInfo brokerIdentityInfo2 = new BrokerIdentityInfo(clusterName2, brokerName2, brokerId2);
+        BrokerLiveInfo brokerLiveInfo1 = new BrokerLiveInfo(brokerName1, "127.0.0.1:10911", brokerId1, System.currentTimeMillis(), 3000L, null, 1, 1000L, 500);
+        BrokerLiveInfo brokerLiveInfo2 = new BrokerLiveInfo(brokerName2, "127.0.0.1:10912", brokerId2, System.currentTimeMillis(), 3000L, null, 1, 1000L, 500);
+        Map<BrokerIdentityInfo, BrokerLiveInfo> responseMap = new HashMap<>();
+        responseMap.put(brokerIdentityInfo1, brokerLiveInfo1);
+        responseMap.put(brokerIdentityInfo2, brokerLiveInfo2);
+        CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+        future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+        future.get().setBody(JSON.toJSONString(responseMap).getBytes());
+        when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+        Map<String, Map<String, Integer>> activeBrokersNum = raftBrokerHeartBeatManager.getActiveBrokersNum();
+        assertEquals(2, activeBrokersNum.size());
+        assertEquals(1, activeBrokersNum.get(clusterName1).size());
+        assertEquals(1, activeBrokersNum.get(clusterName2).size());
+        assertEquals(1, (int) activeBrokersNum.get(clusterName1).get(brokerName1));
+        assertEquals(1, (int) activeBrokersNum.get(clusterName2).get(brokerName2));
+    }
+
+    @Test
+    public void testGetActiveBrokersNum() throws Exception {
+        String clusterName1 = "cluster1";
+        String brokerName1 = "broker1";
+        Long brokerId1 = 1L;
+        String clusterName2 = "cluster2";
+        String brokerName2 = "broker2";
+        Long brokerId2 = 2L;
+        BrokerIdentityInfo brokerIdentityInfo1 = new BrokerIdentityInfo(clusterName1, brokerName1, brokerId1);
+        BrokerIdentityInfo brokerIdentityInfo2 = new BrokerIdentityInfo(clusterName2, brokerName2, brokerId2);
+        BrokerLiveInfo brokerLiveInfo1 = new BrokerLiveInfo(brokerName1, "127.0.0.1:10911", brokerId1, System.currentTimeMillis(), 3000L, null, 1, 1000L, 500);
+        BrokerLiveInfo brokerLiveInfo2 = new BrokerLiveInfo(brokerName2, "127.0.0.1:10912", brokerId2, System.currentTimeMillis() - 4000L, 3000L, null, 1, 1000L, 500);
+        Map<BrokerIdentityInfo, BrokerLiveInfo> responseMap = new HashMap<>();
+        responseMap.put(brokerIdentityInfo1, brokerLiveInfo1);
+        responseMap.put(brokerIdentityInfo2, brokerLiveInfo2);
+        CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+        future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+        future.get().setBody(JSON.toJSONString(responseMap).getBytes());
+        when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+        Map<String, Map<String, Integer>> activeBrokersNum = raftBrokerHeartBeatManager.getActiveBrokersNum();
+        assertEquals(1, activeBrokersNum.size());
+    }
+
+    @Test
+    public void testGetActiveBrokersNumException() {
+        CompletableFuture<RemotingCommand> future = new CompletableFuture<>();
+        future.completeExceptionally(new ExecutionException(new RuntimeException("Test Exception")));
+        when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+        Map<String, Map<String, Integer>> activeBrokersNum = raftBrokerHeartBeatManager.getActiveBrokersNum();
+        assertTrue(activeBrokersNum.isEmpty());
+    }
+
+    @Test
+    public void testGetActiveBrokersNumNoBrokers() throws Exception {
+        CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.SUCCESS, "Success"));
+        future.get().writeCustomHeader(new GetBrokerLiveInfoResponse());
+        future.get().setBody(JSON.toJSONString(new HashMap<BrokerIdentityInfo, BrokerLiveInfo>()).getBytes());
+        when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+        Map<String, Map<String, Integer>> activeBrokersNum = raftBrokerHeartBeatManager.getActiveBrokersNum();
+        assertTrue(activeBrokersNum.isEmpty());
+    }
+
+    @Test
+    public void testGetActiveBrokersNumInvalidResponseCode() {
+        CompletableFuture<RemotingCommand> future = CompletableFuture.completedFuture(RemotingCommand.createResponseCommand(ResponseCode.RPC_TIME_OUT, "Timeout"));
+        when(controller.getBrokerLiveInfo(any())).thenReturn(future);
+        Map<String, Map<String, Integer>> activeBrokersNum = raftBrokerHeartBeatManager.getActiveBrokersNum();
+        assertTrue(activeBrokersNum.isEmpty());
+    }
+}
diff --git a/controller/src/test/java/org/apache/rocketmq/controller/impl/manager/RaftReplicasInfoManagerTest.java b/controller/src/test/java/org/apache/rocketmq/controller/impl/manager/RaftReplicasInfoManagerTest.java
new file mode 100644
index 0000000000..b47f072c2c
--- /dev/null
+++ b/controller/src/test/java/org/apache/rocketmq/controller/impl/manager/RaftReplicasInfoManagerTest.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.controller.impl.manager;
+
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.rocketmq.common.ControllerConfig;
+import org.apache.rocketmq.controller.impl.event.ControllerResult;
+import org.apache.rocketmq.controller.impl.heartbeat.BrokerIdentityInfo;
+import org.apache.rocketmq.controller.impl.heartbeat.BrokerLiveInfo;
+import org.apache.rocketmq.controller.impl.task.BrokerCloseChannelRequest;
+import org.apache.rocketmq.controller.impl.task.CheckNotActiveBrokerRequest;
+import org.apache.rocketmq.controller.impl.task.CheckNotActiveBrokerResponse;
+import org.apache.rocketmq.controller.impl.task.GetBrokerLiveInfoRequest;
+import org.apache.rocketmq.controller.impl.task.GetBrokerLiveInfoResponse;
+import org.apache.rocketmq.controller.impl.task.RaftBrokerHeartBeatEventRequest;
+import org.apache.rocketmq.controller.impl.task.RaftBrokerHeartBeatEventResponse;
+import org.apache.rocketmq.remoting.protocol.ResponseCode;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RaftReplicasInfoManagerTest {
+
+    @Mock
+    private ControllerConfig controllerConfig;
+
+    private RaftReplicasInfoManager raftReplicasInfoManager;
+
+    @Before
+    public void init() {
+        raftReplicasInfoManager = new RaftReplicasInfoManager(controllerConfig);
+    }
+
+    @Test
+    public void testGetBrokerLiveInfoBrokerIdentityInfoIsNullReturnsAllBrokersInfo() throws IllegalAccessException {
+        List<BrokerIdentityInfo> brokerIdentityInfos = createBrokerIdentityInfos(2);
+        List<BrokerLiveInfo> brokerLiveInfos = createBrokerLiveInfos(2);
+        Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+        brokerLiveTable.put(brokerIdentityInfos.get(0), brokerLiveInfos.get(0));
+        brokerLiveTable.put(brokerIdentityInfos.get(1), brokerLiveInfos.get(1));
+        FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+        GetBrokerLiveInfoRequest request = new GetBrokerLiveInfoRequest();
+        ControllerResult<GetBrokerLiveInfoResponse> result = raftReplicasInfoManager.getBrokerLiveInfo(request);
+        assertNotNull(result);
+        assertEquals(ResponseCode.SUCCESS, result.getResponseCode());
+    }
+
+    @Test
+    public void testGetBrokerLiveInfoBrokerIdentityInfoExistsReturnsBrokerInfo() throws IllegalAccessException {
+        BrokerIdentityInfo brokerIdentityInfo = createBrokerIdentityInfo();
+        Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+        brokerLiveTable.put(brokerIdentityInfo, createBrokerLiveInfo());
+        FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+        GetBrokerLiveInfoRequest request = new GetBrokerLiveInfoRequest(brokerIdentityInfo);
+        ControllerResult<GetBrokerLiveInfoResponse> result = raftReplicasInfoManager.getBrokerLiveInfo(request);
+        assertNotNull(result);
+        assertEquals(ResponseCode.SUCCESS, result.getResponseCode());
+    }
+
+    @Test
+    public void testGetBrokerLiveInfoBrokerIdentityInfoNotExistsReturnsError() {
+        GetBrokerLiveInfoRequest request = new GetBrokerLiveInfoRequest(createBrokerIdentityInfo());
+        ControllerResult<GetBrokerLiveInfoResponse> result = raftReplicasInfoManager.getBrokerLiveInfo(request);
+        assertNotNull(result);
+        assertEquals(ResponseCode.CONTROLLER_BROKER_LIVE_INFO_NOT_EXISTS, result.getResponseCode());
+    }
+
+    @Test
+    public void testOnBrokerHeartBeatNewBrokerRegistered() {
+        RaftBrokerHeartBeatEventRequest request = new RaftBrokerHeartBeatEventRequest(createBrokerIdentityInfo(), createBrokerLiveInfo());
+        ControllerResult<RaftBrokerHeartBeatEventResponse> result = raftReplicasInfoManager.onBrokerHeartBeat(request);
+        assertNotNull(result);
+        assertEquals(ResponseCode.SUCCESS, result.getResponseCode());
+    }
+
+    @Test
+    public void testOnBrokerHeartBeatExistingBrokerUpdate() throws IllegalAccessException {
+        BrokerIdentityInfo brokerIdentityInfo = createBrokerIdentityInfo();
+        Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+        brokerLiveTable.put(brokerIdentityInfo, createBrokerLiveInfo());
+        FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+        BrokerLiveInfo updatedInfo = new BrokerLiveInfo("brokerName1", "brokerAddr1", 1L, System.currentTimeMillis(), 2000L, null, 2, 200L, 2);
+        RaftBrokerHeartBeatEventRequest request = new RaftBrokerHeartBeatEventRequest(brokerIdentityInfo, updatedInfo);
+        ControllerResult<RaftBrokerHeartBeatEventResponse> result = raftReplicasInfoManager.onBrokerHeartBeat(request);
+        assertNotNull(result);
+        assertEquals(ResponseCode.SUCCESS, result.getResponseCode());
+    }
+
+    @Test
+    public void testOnBrokerCloseChannelBrokerIdentityInfoIsNullLogsWarningAndReturnsResult() {
+        assertNotNull(raftReplicasInfoManager.onBrokerCloseChannel(new BrokerCloseChannelRequest()));
+    }
+
+    @Test
+    public void testCheckNotActiveBrokerNoBrokersInTableReturnsEmptyList() {
+        CheckNotActiveBrokerRequest request = new CheckNotActiveBrokerRequest();
+        ControllerResult<CheckNotActiveBrokerResponse> result = raftReplicasInfoManager.checkNotActiveBroker(request);
+        assertNotNull(result);
+        assertEquals(ResponseCode.SUCCESS, result.getResponseCode());
+    }
+
+    @Test
+    public void testCheckNotActiveBrokerBrokerLiveTableNotEmptyIdentifiesNotActiveBrokers() throws IllegalAccessException {
+        List<BrokerIdentityInfo> brokerIdentityInfos = createBrokerIdentityInfos(2);
+        List<BrokerLiveInfo> brokerLiveInfos = createBrokerLiveInfos(2);
+        Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+        brokerLiveTable.put(brokerIdentityInfos.get(0), brokerLiveInfos.get(0));
+        brokerLiveTable.put(brokerIdentityInfos.get(1), brokerLiveInfos.get(1));
+        FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+        CheckNotActiveBrokerRequest request = new CheckNotActiveBrokerRequest();
+        ControllerResult<CheckNotActiveBrokerResponse> result = raftReplicasInfoManager.checkNotActiveBroker(request);
+        assertNotNull(result);
+        assertEquals(ResponseCode.SUCCESS, result.getResponseCode());
+        assertNotNull(result.getBody());
+    }
+
+    @Test
+    public void testCheckNotActiveBrokerSerializeErrorSetsErrorRemark() throws IllegalAccessException {
+        Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+        brokerLiveTable.put(createBrokerIdentityInfo(), createBrokerLiveInfo());
+        FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+        CheckNotActiveBrokerRequest request = new CheckNotActiveBrokerRequest();
+        ControllerResult<CheckNotActiveBrokerResponse> result = raftReplicasInfoManager.checkNotActiveBroker(request);
+        assertNotNull(result);
+    }
+
+    @Test
+    public void testIsBrokerActiveBrokerLiveInfoNotNullAndActiveReturnsTrue() throws IllegalAccessException {
+        Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+        brokerLiveTable.put(createBrokerIdentityInfo(), createBrokerLiveInfo());
+        FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+        long invokeTime = System.currentTimeMillis() + 500;
+        boolean brokerActive = raftReplicasInfoManager.isBrokerActive("cluster0", "broker0", 0L, invokeTime);
+        assertTrue(brokerActive);
+    }
+
+    @Test
+    public void testIsBrokerActiveBrokerLiveInfoNotNullAndNotActiveReturnsFalse() throws IllegalAccessException {
+        Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+        brokerLiveTable.put(createBrokerIdentityInfo(), createBrokerLiveInfo());
+        FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+        long invokeTime = System.currentTimeMillis();
+        assertFalse(raftReplicasInfoManager.isBrokerActive("cluster1", "broker1", 1L, invokeTime));
+    }
+
+    @Test
+    public void testIsBrokerActiveBrokerLiveInfoNullReturnsFalse() {
+        assertFalse(raftReplicasInfoManager.isBrokerActive("cluster1", "broker1", 1L, System.currentTimeMillis()));
+    }
+
+    @Test
+    public void testSerializeWithPopulatedTablesReturnsByteArray() throws Throwable {
+        Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+        brokerLiveTable.put(createBrokerIdentityInfo(), createBrokerLiveInfo());
+        FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+        byte[] result = raftReplicasInfoManager.serialize();
+        assertNotNull(result);
+        assertTrue(result.length > 0);
+    }
+
+    @Test
+    public void testDeserializeFromValidDataSuccess() throws Throwable {
+        BrokerIdentityInfo brokerIdentityInfo = createBrokerIdentityInfo();
+        Map<BrokerIdentityInfo, BrokerLiveInfo> brokerLiveTable = new HashMap<>();
+        brokerLiveTable.put(brokerIdentityInfo, createBrokerLiveInfo());
+        FieldUtils.writeDeclaredField(raftReplicasInfoManager, "brokerLiveTable", brokerLiveTable, true);
+        raftReplicasInfoManager.deserializeFrom(raftReplicasInfoManager.serialize());
+        assertNotNull(brokerLiveTable);
+        assertEquals(1, brokerLiveTable.size());
+        assertTrue(brokerLiveTable.containsKey(brokerIdentityInfo));
+    }
+
+    @Test
+    public void testDeserializeFromInvalidDataExceptionThrown() {
+        byte[] invalidData = new byte[]{0x00, 0x01, 0x02, 0x03};
+        try {
+            raftReplicasInfoManager.deserializeFrom(invalidData);
+            fail("Expected an exception to be thrown");
+        } catch (Throwable e) {
+            assertTrue(e instanceof ArrayIndexOutOfBoundsException);
+        }
+    }
+
+    private BrokerIdentityInfo createBrokerIdentityInfo() {
+        return createBrokerIdentityInfos(1).get(0);
+    }
+
+    private List<BrokerIdentityInfo> createBrokerIdentityInfos(final int count) {
+        List<BrokerIdentityInfo> result = new ArrayList<>();
+        for (int i = 0; i < count; i++) {
+            result.add(new BrokerIdentityInfo("cluster" + i, "broker" + i, (long) i));
+        }
+        return result;
+    }
+
+    private BrokerLiveInfo createBrokerLiveInfo() {
+        return createBrokerLiveInfos(1).get(0);
+    }
+
+    private List<BrokerLiveInfo> createBrokerLiveInfos(final int count) {
+        List<BrokerLiveInfo> result = new ArrayList<>();
+        for (int i = 0; i < count; i++) {
+            result.add(new BrokerLiveInfo("brokerName" + i,
+                    "brokerAddr" + i,
+                    i,
+                    System.currentTimeMillis(),
+                    1000L,
+                    null,
+                    1,
+                    100L,
+                    1));
+        }
+        return result;
+    }
+}
diff --git a/filter/BUILD.bazel b/filter/BUILD.bazel
index c0d59ba6f4..76e3ef43de 100644
--- a/filter/BUILD.bazel
+++ b/filter/BUILD.bazel
@@ -26,7 +26,6 @@ java_library(
         "@maven//:commons_validator_commons_validator",
         "@maven//:com_github_luben_zstd_jni",
         "@maven//:org_lz4_lz4_java",
-        "@maven//:com_alibaba_fastjson",
         "@maven//:io_netty_netty_all",
         "@maven//:com_google_guava_guava",
     ],
diff --git a/namesrv/BUILD.bazel b/namesrv/BUILD.bazel
index fec42eaa3e..435fc29a7f 100644
--- a/namesrv/BUILD.bazel
+++ b/namesrv/BUILD.bazel
@@ -31,7 +31,7 @@ java_library(
         "@maven//:commons_validator_commons_validator",
         "@maven//:com_github_luben_zstd_jni",
         "@maven//:org_lz4_lz4_java",
-        "@maven//:com_alibaba_fastjson",
+        "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:io_netty_netty_all",
         "@maven//:ch_qos_logback_logback_classic",
         "@maven//:ch_qos_logback_logback_core",
@@ -60,7 +60,7 @@ java_library(
         "@maven//:commons_cli_commons_cli",
         "@maven//:io_netty_netty_all",    
         "@maven//:com_google_guava_guava",   
-        "@maven//:com_alibaba_fastjson",      
+        "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:io_github_aliyunmq_rocketmq_slf4j_api",
     ],
     resources = glob(["src/test/resources/certs/*.pem"]) + glob(["src/test/resources/certs/*.key"])
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/ClientRequestProcessor.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/ClientRequestProcessor.java
index 1ef6beadd3..ef653129a7 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/ClientRequestProcessor.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/processor/ClientRequestProcessor.java
@@ -17,10 +17,8 @@
 
 package org.apache.rocketmq.namesrv.processor;
 
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSONWriter;
 import io.netty.channel.ChannelHandlerContext;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
 import org.apache.rocketmq.common.MQVersion;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.common.help.FAQUrl;
@@ -35,6 +33,9 @@ import org.apache.rocketmq.remoting.protocol.ResponseCode;
 import org.apache.rocketmq.remoting.protocol.header.namesrv.GetRouteInfoRequestHeader;
 import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
 
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
 public class ClientRequestProcessor implements NettyRequestProcessor {
 
     private static Logger log = LoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME);
@@ -81,9 +82,8 @@ public class ClientRequestProcessor implements NettyRequestProcessor {
             byte[] content;
             Boolean standardJsonOnly = Optional.ofNullable(requestHeader.getAcceptStandardJsonOnly()).orElse(false);
             if (request.getVersion() >= MQVersion.Version.V4_9_4.ordinal() || standardJsonOnly) {
-                content = topicRouteData.encode(SerializerFeature.BrowserCompatible,
-                    SerializerFeature.QuoteFieldNames, SerializerFeature.SkipTransientField,
-                    SerializerFeature.MapSortField);
+                content = topicRouteData.encode(JSONWriter.Feature.BrowserCompatible,
+                        JSONWriter.Feature.MapSortField);
             } else {
                 content = topicRouteData.encode();
             }
diff --git a/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/ClientRequestProcessorTest.java b/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/ClientRequestProcessorTest.java
new file mode 100644
index 0000000000..6fa88ad6ea
--- /dev/null
+++ b/namesrv/src/test/java/org/apache/rocketmq/namesrv/processor/ClientRequestProcessorTest.java
@@ -0,0 +1,195 @@
+/*
+ * 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.namesrv.processor;
+
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.rocketmq.common.MQVersion;
+import org.apache.rocketmq.common.namesrv.NamesrvConfig;
+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.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.protocol.RequestCode;
+import org.apache.rocketmq.remoting.protocol.ResponseCode;
+import org.apache.rocketmq.remoting.protocol.header.namesrv.GetRouteInfoRequestHeader;
+import org.apache.rocketmq.remoting.protocol.route.BrokerData;
+import org.apache.rocketmq.remoting.protocol.route.QueueData;
+import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ClientRequestProcessorTest {
+
+    @Mock
+    private NamesrvController namesrvController;
+
+    @Mock
+    private RouteInfoManager routeInfoManager;
+
+    @Mock
+    private NamesrvConfig namesrvConfig;
+
+    @Mock
+    private ChannelHandlerContext ctx;
+
+    private ClientRequestProcessor clientRequestProcessor;
+
+    @Before
+    public void setup() throws NoSuchFieldException, IllegalAccessException {
+        when(namesrvController.getRouteInfoManager()).thenReturn(routeInfoManager);
+        when(namesrvController.getNamesrvConfig()).thenReturn(namesrvConfig);
+
+        when(namesrvConfig.getWaitSecondsForService()).thenReturn(0);
+        when(namesrvConfig.isNeedWaitForService()).thenReturn(true);
+
+        clientRequestProcessor = new ClientRequestProcessor(namesrvController);
+
+        Field startupTimeMillisField = ClientRequestProcessor.class.getDeclaredField("startupTimeMillis");
+        startupTimeMillisField.setAccessible(true);
+        startupTimeMillisField.set(clientRequestProcessor, System.currentTimeMillis() - 60000);
+    }
+
+    @Test
+    public void testGetRouteInfoByTopicWithHighVersionClient() throws RemotingCommandException {
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINFO_BY_TOPIC, null);
+        request.setVersion(MQVersion.Version.V4_9_4.ordinal());
+
+        GetRouteInfoRequestHeader requestHeader = new GetRouteInfoRequestHeader();
+        requestHeader.setTopic("TestTopic");
+
+        RemotingCommand spyRequest = spy(request);
+        doReturn(requestHeader).when(spyRequest).decodeCommandCustomHeader(GetRouteInfoRequestHeader.class);
+
+        TopicRouteData topicRouteData = createMockTopicRouteData();
+
+        when(routeInfoManager.pickupTopicRouteData("TestTopic")).thenReturn(topicRouteData);
+
+        RemotingCommand response = clientRequestProcessor.getRouteInfoByTopic(ctx, spyRequest);
+
+        assertEquals(ResponseCode.SUCCESS, response.getCode());
+        assertNotNull(response.getBody());
+    }
+
+    @Test
+    public void testGetRouteInfoByTopicWithLowVersionClientAndNoStandardJsonFlag() throws RemotingCommandException {
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINFO_BY_TOPIC, null);
+        request.setVersion(MQVersion.Version.V4_9_3.ordinal());
+
+        GetRouteInfoRequestHeader requestHeader = new GetRouteInfoRequestHeader();
+        requestHeader.setTopic("TestTopic");
+        requestHeader.setAcceptStandardJsonOnly(false);
+
+        RemotingCommand spyRequest = spy(request);
+        doReturn(requestHeader).when(spyRequest).decodeCommandCustomHeader(GetRouteInfoRequestHeader.class);
+
+        TopicRouteData topicRouteData = createMockTopicRouteData();
+
+        when(routeInfoManager.pickupTopicRouteData("TestTopic")).thenReturn(topicRouteData);
+
+        RemotingCommand response = clientRequestProcessor.getRouteInfoByTopic(ctx, spyRequest);
+
+        assertEquals(ResponseCode.SUCCESS, response.getCode());
+        assertNotNull(response.getBody());
+    }
+
+    @Test
+    public void testGetRouteInfoByTopicWithNameServerNotReady() throws RemotingCommandException {
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINFO_BY_TOPIC, null);
+
+        GetRouteInfoRequestHeader requestHeader = new GetRouteInfoRequestHeader();
+        requestHeader.setTopic("TestTopic");
+
+        RemotingCommand spyRequest = spy(request);
+        doReturn(requestHeader).when(spyRequest).decodeCommandCustomHeader(GetRouteInfoRequestHeader.class);
+
+        when(namesrvConfig.getWaitSecondsForService()).thenReturn(60);
+        when(namesrvConfig.isNeedWaitForService()).thenReturn(true);
+
+        try {
+            Field startupTimeMillisField = ClientRequestProcessor.class.getDeclaredField("startupTimeMillis");
+            startupTimeMillisField.setAccessible(true);
+            startupTimeMillisField.set(clientRequestProcessor, System.currentTimeMillis());
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        RemotingCommand response = clientRequestProcessor.getRouteInfoByTopic(ctx, spyRequest);
+
+        assertEquals(ResponseCode.SYSTEM_ERROR, response.getCode());
+        assertEquals("name server not ready", response.getRemark());
+    }
+
+    @Test
+    public void testGetRouteInfoByTopicWithTopicNotExist() throws RemotingCommandException {
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINFO_BY_TOPIC, null);
+
+        GetRouteInfoRequestHeader requestHeader = new GetRouteInfoRequestHeader();
+        requestHeader.setTopic("NonExistentTopic");
+
+        RemotingCommand spyRequest = spy(request);
+        doReturn(requestHeader).when(spyRequest).decodeCommandCustomHeader(GetRouteInfoRequestHeader.class);
+
+        when(routeInfoManager.pickupTopicRouteData("NonExistentTopic")).thenReturn(null);
+
+        RemotingCommand response = clientRequestProcessor.getRouteInfoByTopic(ctx, spyRequest);
+
+        assertEquals(ResponseCode.TOPIC_NOT_EXIST, response.getCode());
+        assertNotNull(response.getRemark());
+    }
+
+    private TopicRouteData createMockTopicRouteData() {
+        TopicRouteData result = new TopicRouteData();
+
+        List<QueueData> queueDataList = new ArrayList<>();
+        QueueData queueData = new QueueData();
+        queueData.setBrokerName("broker-a");
+        queueData.setReadQueueNums(4);
+        queueData.setWriteQueueNums(4);
+        queueData.setPerm(6);
+        queueData.setTopicSysFlag(0);
+        queueDataList.add(queueData);
+        result.setQueueDatas(queueDataList);
+
+        List<BrokerData> brokerDataList = new ArrayList<>();
+        BrokerData brokerData = new BrokerData();
+        brokerData.setBrokerName("broker-a");
+        brokerData.setCluster("default-cluster");
+        HashMap<Long, String> brokerAddrs = new HashMap<>();
+        brokerAddrs.put(0L, "127.0.0.1:10911");
+        brokerData.setBrokerAddrs(brokerAddrs);
+        brokerDataList.add(brokerData);
+        result.setBrokerDatas(brokerDataList);
+
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/proxy/BUILD.bazel b/proxy/BUILD.bazel
index 8b7915ba74..5d7fe24435 100644
--- a/proxy/BUILD.bazel
+++ b/proxy/BUILD.bazel
@@ -29,7 +29,6 @@ java_library(
         "//srvutil",
         "@maven//:ch_qos_logback_logback_classic",
         "@maven//:ch_qos_logback_logback_core",
-        "@maven//:com_alibaba_fastjson",
         "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:com_github_ben_manes_caffeine_caffeine",
         "@maven//:com_github_luben_zstd_jni",
@@ -88,7 +87,6 @@ java_library(
         "//srvutil",
         "//remoting",
         "@maven//:ch_qos_logback_logback_core",
-        "@maven//:com_alibaba_fastjson",
         "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:com_github_ben_manes_caffeine_caffeine",
         "@maven//:com_google_guava_guava",
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java b/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java
index 5b7c6c3007..175ff438f8 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/config/Configuration.java
@@ -17,7 +17,7 @@
 
 package org.apache.rocketmq.proxy.config;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import com.google.common.base.Charsets;
 import com.google.common.io.CharStreams;
 import java.io.File;
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java b/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java
index 0d8c60931d..4660610ecd 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/config/ConfigurationManager.java
@@ -17,8 +17,8 @@
 
 package org.apache.rocketmq.proxy.config;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter.Feature;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.rocketmq.auth.config.AuthConfig;
 import org.apache.rocketmq.common.MixAll;
@@ -59,6 +59,6 @@ public class ConfigurationManager {
 
     public static String formatProxyConfig() {
         return JSON.toJSONString(ConfigurationManager.getProxyConfig(),
-                SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.WriteNullListAsEmpty);
+                Feature.PrettyFormat, Feature.WriteMapNullValue, Feature.WriteNullListAsEmpty);
     }
 }
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/channel/RemoteChannelSerializer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/channel/RemoteChannelSerializer.java
index a22401a5f3..dba0655c7e 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/processor/channel/RemoteChannelSerializer.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/processor/channel/RemoteChannelSerializer.java
@@ -17,15 +17,16 @@
 
 package org.apache.rocketmq.proxy.processor.channel;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import java.util.HashMap;
-import java.util.Map;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.logging.org.slf4j.Logger;
 import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
 
+import java.util.HashMap;
+import java.util.Map;
+
 public class RemoteChannelSerializer {
     private static final Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME);
     private static final String REMOTE_PROXY_IP_KEY = "remoteProxyIp";
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/activity/GetTopicRouteActivity.java b/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/activity/GetTopicRouteActivity.java
index 56ec34fae6..759b74fe5d 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/activity/GetTopicRouteActivity.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/activity/GetTopicRouteActivity.java
@@ -17,15 +17,10 @@
 
 package org.apache.rocketmq.proxy.remoting.activity;
 
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSONWriter;
 import com.google.common.net.HostAndPort;
 import io.netty.channel.ChannelHandlerContext;
-import java.util.ArrayList;
-import java.util.List;
 import org.apache.rocketmq.common.MQVersion;
-import org.apache.rocketmq.remoting.protocol.ResponseCode;
-import org.apache.rocketmq.remoting.protocol.header.namesrv.GetRouteInfoRequestHeader;
-import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
 import org.apache.rocketmq.proxy.common.Address;
 import org.apache.rocketmq.proxy.common.ProxyContext;
 import org.apache.rocketmq.proxy.config.ConfigurationManager;
@@ -34,6 +29,12 @@ import org.apache.rocketmq.proxy.processor.MessagingProcessor;
 import org.apache.rocketmq.proxy.remoting.pipeline.RequestPipeline;
 import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData;
 import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.protocol.ResponseCode;
+import org.apache.rocketmq.remoting.protocol.header.namesrv.GetRouteInfoRequestHeader;
+import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
+
+import java.util.ArrayList;
+import java.util.List;
 
 public class GetTopicRouteActivity extends AbstractRemotingActivity {
     public GetTopicRouteActivity(RequestPipeline requestPipeline,
@@ -57,9 +58,7 @@ public class GetTopicRouteActivity extends AbstractRemotingActivity {
         byte[] content;
         Boolean standardJsonOnly = requestHeader.getAcceptStandardJsonOnly();
         if (request.getVersion() >= MQVersion.Version.V4_9_4.ordinal() || null != standardJsonOnly && standardJsonOnly) {
-            content = topicRouteData.encode(SerializerFeature.BrowserCompatible,
-                SerializerFeature.QuoteFieldNames, SerializerFeature.SkipTransientField,
-                SerializerFeature.MapSortField);
+            content = topicRouteData.encode(JSONWriter.Feature.BrowserCompatible, JSONWriter.Feature.MapSortField);
         } else {
             content = topicRouteData.encode();
         }
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/channel/RemotingChannel.java b/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/channel/RemotingChannel.java
index 5dbdea1b2e..ea8a519d5b 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/channel/RemotingChannel.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/remoting/channel/RemotingChannel.java
@@ -17,25 +17,22 @@
 
 package org.apache.rocketmq.proxy.remoting.channel;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.TypeReference;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.TypeReference;
 import com.google.common.base.MoreObjects;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelConfig;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelMetadata;
-import java.time.Duration;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.common.utils.ExceptionUtils;
+import org.apache.rocketmq.common.utils.FutureUtils;
 import org.apache.rocketmq.common.utils.NetworkUtil;
 import org.apache.rocketmq.logging.org.slf4j.Logger;
 import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
 import org.apache.rocketmq.proxy.common.channel.ChannelHelper;
-import org.apache.rocketmq.common.utils.ExceptionUtils;
-import org.apache.rocketmq.common.utils.FutureUtils;
 import org.apache.rocketmq.proxy.config.ConfigurationManager;
 import org.apache.rocketmq.proxy.processor.channel.ChannelExtendAttributeGetter;
 import org.apache.rocketmq.proxy.processor.channel.ChannelProtocolType;
@@ -58,6 +55,10 @@ import org.apache.rocketmq.remoting.protocol.header.ConsumeMessageDirectlyResult
 import org.apache.rocketmq.remoting.protocol.header.GetConsumerRunningInfoRequestHeader;
 import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData;
 
+import java.time.Duration;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+
 public class RemotingChannel extends ProxyChannel implements RemoteChannelConverter, ChannelExtendAttributeGetter {
     private static final Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME);
     private static final long DEFAULT_MQ_CLIENT_TIMEOUT = Duration.ofSeconds(3).toMillis();
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/AbstractSystemMessageSyncer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/AbstractSystemMessageSyncer.java
index 6c19edf2f8..05eb672618 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/AbstractSystemMessageSyncer.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/AbstractSystemMessageSyncer.java
@@ -17,35 +17,36 @@
 
 package org.apache.rocketmq.proxy.service.sysmessage;
 
-import com.alibaba.fastjson.JSON;
-import java.nio.charset.StandardCharsets;
-import java.time.Duration;
+import com.alibaba.fastjson2.JSON;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
 import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
 import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.impl.mqclient.MQClientAPIFactory;
 import org.apache.rocketmq.client.producer.SendStatus;
 import org.apache.rocketmq.common.constant.LoggerName;
 import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
 import org.apache.rocketmq.common.message.Message;
 import org.apache.rocketmq.common.message.MessageDecoder;
 import org.apache.rocketmq.common.topic.TopicValidator;
+import org.apache.rocketmq.common.utils.StartAndShutdown;
 import org.apache.rocketmq.logging.org.slf4j.Logger;
 import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
 import org.apache.rocketmq.proxy.common.ProxyContext;
 import org.apache.rocketmq.proxy.common.ProxyException;
 import org.apache.rocketmq.proxy.common.ProxyExceptionCode;
-import org.apache.rocketmq.common.utils.StartAndShutdown;
 import org.apache.rocketmq.proxy.config.ConfigurationManager;
 import org.apache.rocketmq.proxy.config.ProxyConfig;
 import org.apache.rocketmq.proxy.service.admin.AdminService;
-import org.apache.rocketmq.client.impl.mqclient.MQClientAPIFactory;
 import org.apache.rocketmq.proxy.service.route.AddressableMessageQueue;
 import org.apache.rocketmq.proxy.service.route.TopicRouteService;
 import org.apache.rocketmq.remoting.RPCHook;
 import org.apache.rocketmq.remoting.protocol.header.SendMessageRequestHeader;
 import org.apache.rocketmq.remoting.protocol.heartbeat.MessageModel;
 
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+
 public abstract class AbstractSystemMessageSyncer implements StartAndShutdown, MessageListenerConcurrently {
     protected static final Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME);
     protected final TopicRouteService topicRouteService;
diff --git a/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/HeartbeatSyncer.java b/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/HeartbeatSyncer.java
index fee3ea87d2..e063d79707 100644
--- a/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/HeartbeatSyncer.java
+++ b/proxy/src/main/java/org/apache/rocketmq/proxy/service/sysmessage/HeartbeatSyncer.java
@@ -17,21 +17,15 @@
 
 package org.apache.rocketmq.proxy.service.sysmessage;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import io.netty.channel.Channel;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
 import org.apache.rocketmq.broker.client.ClientChannelInfo;
 import org.apache.rocketmq.broker.client.ConsumerGroupEvent;
 import org.apache.rocketmq.broker.client.ConsumerIdsChangeListener;
 import org.apache.rocketmq.broker.client.ConsumerManager;
 import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
 import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.client.impl.mqclient.MQClientAPIFactory;
 import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
 import org.apache.rocketmq.common.message.MessageExt;
 import org.apache.rocketmq.common.thread.ThreadPoolMonitor;
@@ -40,13 +34,20 @@ import org.apache.rocketmq.proxy.config.ConfigurationManager;
 import org.apache.rocketmq.proxy.config.ProxyConfig;
 import org.apache.rocketmq.proxy.processor.channel.RemoteChannel;
 import org.apache.rocketmq.proxy.service.admin.AdminService;
-import org.apache.rocketmq.client.impl.mqclient.MQClientAPIFactory;
 import org.apache.rocketmq.proxy.service.route.TopicRouteService;
 import org.apache.rocketmq.remoting.RPCHook;
 import org.apache.rocketmq.remoting.protocol.heartbeat.ConsumeType;
 import org.apache.rocketmq.remoting.protocol.heartbeat.MessageModel;
 import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData;
 
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
 public class HeartbeatSyncer extends AbstractSystemMessageSyncer {
 
     protected ThreadPoolExecutor threadPoolExecutor;
diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java
index 74803609ba..2caa4e37e9 100644
--- a/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java
+++ b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java
@@ -21,6 +21,8 @@ import org.apache.rocketmq.proxy.ProxyMode;
 import org.junit.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 public class ConfigurationManagerTest extends InitConfigTest {
 
@@ -44,4 +46,12 @@ public class ConfigurationManagerTest extends InitConfigTest {
         assertThat(ConfigurationManager.getProxyConfig()).isNotNull();
     }
 
+    @Test
+    public void testFormatProxyConfig() {
+        String actual = ConfigurationManager.formatProxyConfig();
+        assertNotNull(actual);
+        ProxyConfig expected = ConfigurationManager.getProxyConfig();
+        assertTrue(actual.contains(expected.getProxyMode()));
+        assertTrue(actual.contains(expected.getProxyName()));
+    }
 } 
diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationTest.java
similarity index 50%
copy from proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java
copy to proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationTest.java
index 74803609ba..72b7eae6fa 100644
--- a/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationManagerTest.java
+++ b/proxy/src/test/java/org/apache/rocketmq/proxy/config/ConfigurationTest.java
@@ -17,31 +17,30 @@
 
 package org.apache.rocketmq.proxy.config;
 
-import org.apache.rocketmq.proxy.ProxyMode;
+import org.apache.rocketmq.auth.config.AuthConfig;
+import org.junit.Before;
 import org.junit.Test;
 
-import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.spy;
 
-public class ConfigurationManagerTest extends InitConfigTest {
+public class ConfigurationTest {
 
-    @Test
-    public void testIntConfig() {
-        assertThat(ConfigurationManager.getProxyConfig()).isNotNull();
-        assertThat(ConfigurationManager.getProxyConfig().getProxyMode()).isEqualToIgnoringCase(ProxyMode.CLUSTER.toString());
+    private Configuration configuration;
 
-        String brokerConfig = ConfigurationManager.getProxyConfig().getBrokerConfigPath();
-        assertThat(brokerConfig).isEqualTo(ConfigurationManager.getProxyHome() + "/conf/broker.conf");
+    @Before
+    public void init() {
+        configuration = spy(new Configuration());
     }
 
     @Test
-    public void testGetProxyHome() {
-        // test configured proxy home
-        assertThat(ConfigurationManager.getProxyHome()).isIn(mockProxyHome, "./");
-    }
+    public void testInit() throws Exception {
+        configuration.init();
 
-    @Test
-    public void testGetProxyConfig() {
-        assertThat(ConfigurationManager.getProxyConfig()).isNotNull();
-    }
+        ProxyConfig loadedProxyConfig = configuration.getProxyConfig();
+        assertNotNull(loadedProxyConfig);
 
-} 
+        AuthConfig loadedAuthConfig = configuration.getAuthConfig();
+        assertNotNull(loadedAuthConfig);
+    }
+}
diff --git a/proxy/src/test/java/org/apache/rocketmq/proxy/remoting/activity/GetTopicRouteActivityTest.java b/proxy/src/test/java/org/apache/rocketmq/proxy/remoting/activity/GetTopicRouteActivityTest.java
new file mode 100644
index 0000000000..d956da52a1
--- /dev/null
+++ b/proxy/src/test/java/org/apache/rocketmq/proxy/remoting/activity/GetTopicRouteActivityTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.proxy.remoting.activity;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.rocketmq.common.MQVersion;
+import org.apache.rocketmq.proxy.common.ProxyContext;
+import org.apache.rocketmq.proxy.config.ConfigurationManager;
+import org.apache.rocketmq.proxy.processor.MessagingProcessor;
+import org.apache.rocketmq.proxy.remoting.pipeline.RequestPipeline;
+import org.apache.rocketmq.proxy.service.channel.SimpleChannel;
+import org.apache.rocketmq.proxy.service.channel.SimpleChannelHandlerContext;
+import org.apache.rocketmq.proxy.service.route.ProxyTopicRouteData;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.protocol.RequestCode;
+import org.apache.rocketmq.remoting.protocol.ResponseCode;
+import org.apache.rocketmq.remoting.protocol.header.namesrv.GetRouteInfoRequestHeader;
+import org.apache.rocketmq.remoting.protocol.route.BrokerData;
+import org.apache.rocketmq.remoting.protocol.route.QueueData;
+import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class GetTopicRouteActivityTest {
+
+    @Mock
+    private RequestPipeline requestPipeline;
+
+    @Mock
+    private MessagingProcessor messagingProcessor;
+
+    private GetTopicRouteActivity getTopicRouteActivity;
+
+    private ChannelHandlerContext ctx;
+
+    private ProxyContext context;
+
+    @Before
+    public void setup() throws Exception {
+        getTopicRouteActivity = new GetTopicRouteActivity(requestPipeline, messagingProcessor);
+
+        ConfigurationManager.initEnv();
+        ConfigurationManager.intConfig();
+
+        Channel channel = new SimpleChannel(null, "0.0.0.0:0", "1.1.1.1:1");
+        ctx = new SimpleChannelHandlerContext(channel);
+
+        context = ProxyContext.create();
+    }
+
+    @Test
+    public void testProcessRequest0_HighVersion_SerializeWithFeatures() throws Exception {
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINFO_BY_TOPIC, null);
+        request.setVersion(MQVersion.Version.V4_9_4.ordinal());
+
+        GetRouteInfoRequestHeader header = new GetRouteInfoRequestHeader();
+        header.setTopic("TestTopic");
+        header.setAcceptStandardJsonOnly(false);
+        request.writeCustomHeader(header);
+
+        TopicRouteData topicRouteData = prepareTopicRouteData();
+
+        TopicRouteData spyTopicRouteData = Mockito.spy(topicRouteData);
+
+        ProxyTopicRouteData proxyTopicRouteData = mock(ProxyTopicRouteData.class);
+        when(proxyTopicRouteData.buildTopicRouteData()).thenReturn(spyTopicRouteData);
+        when(messagingProcessor.getTopicRouteDataForProxy(any(ProxyContext.class), anyList(), any()))
+                .thenReturn(proxyTopicRouteData);
+
+        RemotingCommand response = getTopicRouteActivity.processRequest0(ctx, request, context);
+
+        assertNotNull(response);
+        assertEquals(ResponseCode.SUCCESS, response.getCode());
+
+        verify(spyTopicRouteData).encode(
+                JSONWriter.Feature.BrowserCompatible,
+                JSONWriter.Feature.MapSortField
+        );
+
+        TopicRouteData deserializedData = JSON.parseObject(response.getBody(), TopicRouteData.class);
+        assertEquals(topicRouteData.getOrderTopicConf(), deserializedData.getOrderTopicConf());
+        assertEquals(topicRouteData.getQueueDatas().size(), deserializedData.getQueueDatas().size());
+    }
+
+    @Test
+    public void testProcessRequest0_LowVersion_StandardJsonOnly_SerializeWithFeatures() throws Exception {
+        RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ROUTEINFO_BY_TOPIC, null);
+        request.setVersion(MQVersion.Version.V4_9_3.ordinal());
+
+        GetRouteInfoRequestHeader header = new GetRouteInfoRequestHeader();
+        header.setTopic("TestTopic");
+        header.setAcceptStandardJsonOnly(true);
+        request.writeCustomHeader(header);
+
+        TopicRouteData topicRouteData = prepareTopicRouteData();
+
+        TopicRouteData spyTopicRouteData = Mockito.spy(topicRouteData);
+
+        ProxyTopicRouteData proxyTopicRouteData = mock(ProxyTopicRouteData.class);
+        when(proxyTopicRouteData.buildTopicRouteData()).thenReturn(spyTopicRouteData);
+        when(messagingProcessor.getTopicRouteDataForProxy(any(ProxyContext.class), anyList(), any()))
+                .thenReturn(proxyTopicRouteData);
+
+        RemotingCommand response = getTopicRouteActivity.processRequest0(ctx, request, context);
+
+        assertNotNull(response);
+        assertEquals(ResponseCode.SUCCESS, response.getCode());
+
+        verify(spyTopicRouteData).encode();
+    }
+
+    private TopicRouteData prepareTopicRouteData() {
+        TopicRouteData result = new TopicRouteData();
+        result.setOrderTopicConf("orderTopicConf");
+
+        List<QueueData> queueDatas = new ArrayList<>();
+        QueueData queueData = new QueueData();
+        queueData.setBrokerName("broker-a");
+        queueData.setPerm(6);
+        queueData.setReadQueueNums(4);
+        queueData.setWriteQueueNums(4);
+        queueData.setTopicSysFlag(0);
+        queueDatas.add(queueData);
+        result.setQueueDatas(queueDatas);
+
+        List<BrokerData> brokerDatas = new ArrayList<>();
+        BrokerData brokerData = new BrokerData();
+        brokerData.setBrokerName("broker-a");
+        HashMap<Long, String> brokerAddrs = new HashMap<>();
+        brokerAddrs.put(0L, "127.0.0.1:10911");
+        brokerData.setBrokerAddrs(brokerAddrs);
+        brokerDatas.add(brokerData);
+        result.setBrokerDatas(brokerDatas);
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/remoting/BUILD.bazel b/remoting/BUILD.bazel
index 9f806be763..62273e5e9d 100644
--- a/remoting/BUILD.bazel
+++ b/remoting/BUILD.bazel
@@ -22,7 +22,7 @@ java_library(
     visibility = ["//visibility:public"],
     deps = [
         "//common",
-        "@maven//:com_alibaba_fastjson",
+        "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:com_google_guava_guava",
         "@maven//:com_google_code_findbugs_jsr305",
         "@maven//:com_squareup_okio_okio_jvm",
@@ -51,7 +51,9 @@ java_library(
         ":remoting",
         "//common",
         "//:test_deps",
+        "@maven//:org_objenesis_objenesis",
         "@maven//:com_alibaba_fastjson",
+        "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:com_google_code_gson_gson",
         "@maven//:com_google_guava_guava",
         "@maven//:com_google_code_findbugs_jsr305",
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
index 7ed977d99c..e39967e3f8 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
@@ -16,8 +16,8 @@
  */
 package org.apache.rocketmq.remoting.netty;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.TypeReference;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.TypeReference;
 import com.google.common.base.Stopwatch;
 import io.netty.bootstrap.Bootstrap;
 import io.netty.buffer.PooledByteBufAllocator;
@@ -46,6 +46,28 @@ import io.netty.util.Timeout;
 import io.netty.util.TimerTask;
 import io.netty.util.concurrent.DefaultEventExecutorGroup;
 import io.netty.util.concurrent.EventExecutorGroup;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rocketmq.common.Pair;
+import org.apache.rocketmq.common.ThreadFactoryImpl;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.utils.FutureUtils;
+import org.apache.rocketmq.common.utils.NetworkUtil;
+import org.apache.rocketmq.common.utils.ThreadUtils;
+import org.apache.rocketmq.logging.org.slf4j.Logger;
+import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
+import org.apache.rocketmq.remoting.ChannelEventListener;
+import org.apache.rocketmq.remoting.InvokeCallback;
+import org.apache.rocketmq.remoting.RemotingClient;
+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.protocol.RemotingCommand;
+import org.apache.rocketmq.remoting.protocol.RequestCode;
+import org.apache.rocketmq.remoting.protocol.ResponseCode;
+import org.apache.rocketmq.remoting.proxy.SocksProxyConfig;
+
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
@@ -70,27 +92,6 @@ import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.rocketmq.common.Pair;
-import org.apache.rocketmq.common.ThreadFactoryImpl;
-import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.common.utils.FutureUtils;
-import org.apache.rocketmq.common.utils.NetworkUtil;
-import org.apache.rocketmq.common.utils.ThreadUtils;
-import org.apache.rocketmq.logging.org.slf4j.Logger;
-import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
-import org.apache.rocketmq.remoting.ChannelEventListener;
-import org.apache.rocketmq.remoting.InvokeCallback;
-import org.apache.rocketmq.remoting.RemotingClient;
-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.protocol.RemotingCommand;
-import org.apache.rocketmq.remoting.protocol.RequestCode;
-import org.apache.rocketmq.remoting.protocol.ResponseCode;
-import org.apache.rocketmq.remoting.proxy.SocksProxyConfig;
 
 import static org.apache.rocketmq.remoting.common.RemotingHelper.convertChannelFutureToCompletableFuture;
 
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/BitSetSerializerDeserializer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/BitSetSerializerDeserializer.java
index 8f53c0250b..3fe8eb2a0b 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/BitSetSerializerDeserializer.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/BitSetSerializerDeserializer.java
@@ -16,37 +16,46 @@
  */
 package org.apache.rocketmq.remoting.protocol;
 
-import com.alibaba.fastjson.parser.DefaultJSONParser;
-import com.alibaba.fastjson.parser.JSONToken;
-import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
-import com.alibaba.fastjson.serializer.JSONSerializer;
-import com.alibaba.fastjson.serializer.ObjectSerializer;
-import com.alibaba.fastjson.serializer.SerializeWriter;
+import com.alibaba.fastjson2.JSONReader;
+import com.alibaba.fastjson2.JSONWriter;
+import com.alibaba.fastjson2.reader.ObjectReader;
+import com.alibaba.fastjson2.writer.ObjectWriter;
 
-import java.io.IOException;
 import java.lang.reflect.Type;
+import java.util.Base64;
 import java.util.BitSet;
 
-public class BitSetSerializerDeserializer implements ObjectSerializer, ObjectDeserializer {
+public class BitSetSerializerDeserializer implements ObjectReader<BitSet>, ObjectWriter<BitSet> {
 
     @Override
-    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
-        SerializeWriter out = serializer.out;
-        out.writeByteArray(((BitSet) object).toByteArray());
+    public void write(JSONWriter writer, Object object, Object fieldName, Type fieldType, long features) {
+        if (object == null) {
+            writer.writeBase64(null);
+        } else {
+            writer.writeBase64(((BitSet) object).toByteArray());
+        }
     }
 
-    @SuppressWarnings("unchecked")
     @Override
-    public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
-        byte[] bytes = parser.parseObject(byte[].class);
-        if (bytes != null) {
-            return (T) BitSet.valueOf(bytes);
+    public BitSet readObject(JSONReader reader, Type fieldType, Object fieldName, long features) {
+        if (reader.nextIfNull()) {
+            return null;
+        }
+        String base64 = reader.readString();
+        if (base64 == null || base64.isEmpty()) {
+            return null;
         }
-        return null;
+        byte[] bytes = Base64.getDecoder().decode(base64);
+        return BitSet.valueOf(bytes);
+    }
+
+    @Override
+    public long getFeatures() {
+        return 0L;
     }
 
     @Override
-    public int getFastMatchToken() {
-        return JSONToken.LITERAL_STRING;
+    public Class<BitSet> getObjectClass() {
+        return ObjectReader.super.getObjectClass();
     }
 }
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 9b2b0f07b4..e08a1627d1 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
@@ -16,10 +16,20 @@
  */
 package org.apache.rocketmq.remoting.protocol;
 
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
 import com.google.common.base.Stopwatch;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rocketmq.common.BoundaryType;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.logging.org.slf4j.Logger;
+import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
+import org.apache.rocketmq.remoting.CommandCallback;
+import org.apache.rocketmq.remoting.CommandCustomHeader;
+import org.apache.rocketmq.remoting.annotation.CFNotNull;
+import org.apache.rocketmq.remoting.exception.RemotingCommandException;
+
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
@@ -34,16 +44,6 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import org.apache.commons.lang3.StringUtils;
-import org.apache.rocketmq.common.BoundaryType;
-import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.logging.org.slf4j.Logger;
-import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
-import org.apache.rocketmq.remoting.CommandCallback;
-import org.apache.rocketmq.remoting.CommandCustomHeader;
-import org.apache.rocketmq.remoting.annotation.CFNotNull;
-import org.apache.rocketmq.remoting.exception.RemotingCommandException;
-
 public class RemotingCommand {
     public static final String SERIALIZE_TYPE_PROPERTY = "rocketmq.serialize.type";
     public static final String SERIALIZE_TYPE_ENV = "ROCKETMQ_SERIALIZE_TYPE";
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingSerializable.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingSerializable.java
index 139a7043d8..c4e4da1468 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingSerializable.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingSerializable.java
@@ -16,8 +16,9 @@
  */
 package org.apache.rocketmq.remoting.protocol;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
+
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
@@ -34,7 +35,10 @@ public abstract class RemotingSerializable {
     }
 
     public static String toJson(final Object obj, boolean prettyFormat) {
-        return JSON.toJSONString(obj, prettyFormat);
+        if (prettyFormat) {
+            return JSON.toJSONString(obj, JSONWriter.Feature.PrettyFormat);
+        }
+        return JSON.toJSONString(obj);
     }
 
     public static <T> T decode(final byte[] data, Class<T> classOfT) {
@@ -74,7 +78,7 @@ public abstract class RemotingSerializable {
      * @param features Features to apply
      * @return serialized data.
      */
-    public byte[] encode(SerializerFeature...features) {
+    public byte[] encode(JSONWriter.Feature... features) {
         final String json = JSON.toJSONString(this, features);
         return json.getBytes(CHARSET_UTF8);
     }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/BatchAck.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/BatchAck.java
index 82dcd8567e..6107bdce02 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/BatchAck.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/BatchAck.java
@@ -16,7 +16,7 @@
  */
 package org.apache.rocketmq.remoting.protocol.body;
 
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
 import org.apache.rocketmq.remoting.protocol.BitSetSerializerDeserializer;
 
 import java.io.Serializable;
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/RegisterBrokerBody.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/RegisterBrokerBody.java
index 7312b70233..03920855bb 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/RegisterBrokerBody.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/body/RegisterBrokerBody.java
@@ -17,7 +17,17 @@
 
 package org.apache.rocketmq.remoting.protocol.body;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
+import org.apache.rocketmq.common.MQVersion;
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.TopicConfig;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.logging.org.slf4j.Logger;
+import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
+import org.apache.rocketmq.remoting.protocol.DataVersion;
+import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.remoting.protocol.statictopic.TopicQueueMappingInfo;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -30,15 +40,6 @@ import java.util.concurrent.ConcurrentMap;
 import java.util.zip.Deflater;
 import java.util.zip.DeflaterOutputStream;
 import java.util.zip.InflaterInputStream;
-import org.apache.rocketmq.common.MQVersion;
-import org.apache.rocketmq.common.MixAll;
-import org.apache.rocketmq.common.TopicConfig;
-import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.logging.org.slf4j.Logger;
-import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
-import org.apache.rocketmq.remoting.protocol.DataVersion;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
-import org.apache.rocketmq.remoting.protocol.statictopic.TopicQueueMappingInfo;
 
 public class RegisterBrokerBody extends RemotingSerializable {
 
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/HeartbeatData.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/HeartbeatData.java
index f7b4b9faef..d915bf0d16 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/HeartbeatData.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/HeartbeatData.java
@@ -20,10 +20,12 @@
  */
 package org.apache.rocketmq.remoting.protocol.heartbeat;
 
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
+import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+
 import java.util.HashSet;
 import java.util.Set;
-import com.alibaba.fastjson.JSON;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
 
 public class HeartbeatData extends RemotingSerializable {
     private String clientID;
@@ -79,7 +81,7 @@ public class HeartbeatData extends RemotingSerializable {
     }
 
     public int computeHeartbeatFingerprint() {
-        HeartbeatData heartbeatDataCopy = JSON.parseObject(JSON.toJSONString(this), HeartbeatData.class);
+        HeartbeatData heartbeatDataCopy = JSON.parseObject(JSON.toJSONString(this, JSONWriter.Feature.ReferenceDetection), HeartbeatData.class);
         for (ConsumerData consumerData : heartbeatDataCopy.getConsumerDataSet()) {
             for (SubscriptionData subscriptionData : consumerData.getSubscriptionDataSet()) {
                 subscriptionData.setSubVersion(0L);
@@ -88,6 +90,6 @@ public class HeartbeatData extends RemotingSerializable {
         heartbeatDataCopy.setWithoutSub(false);
         heartbeatDataCopy.setHeartbeatFingerprint(0);
         heartbeatDataCopy.setClientID("");
-        return JSON.toJSONString(heartbeatDataCopy).hashCode();
+        return JSON.toJSONString(heartbeatDataCopy, JSONWriter.Feature.ReferenceDetection).hashCode();
     }
 }
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/SubscriptionData.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/SubscriptionData.java
index 59088fc42e..f110fac061 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/SubscriptionData.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/heartbeat/SubscriptionData.java
@@ -20,10 +20,11 @@
  */
 package org.apache.rocketmq.remoting.protocol.heartbeat;
 
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
+import org.apache.rocketmq.common.filter.ExpressionType;
+
 import java.util.HashSet;
 import java.util.Set;
-import org.apache.rocketmq.common.filter.ExpressionType;
 
 public class SubscriptionData implements Comparable<SubscriptionData> {
     public final static String SUB_ALL = "*";
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/subscription/GroupRetryPolicy.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/subscription/GroupRetryPolicy.java
index 14d5e53769..00bf2e9576 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/subscription/GroupRetryPolicy.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/subscription/GroupRetryPolicy.java
@@ -17,7 +17,7 @@
 
 package org.apache.rocketmq.remoting.protocol.subscription;
 
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
 import com.google.common.base.MoreObjects;
 
 public class GroupRetryPolicy {
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingSerializableCompatTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingSerializableCompatTest.java
new file mode 100644
index 0000000000..35c1c7b891
--- /dev/null
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/RemotingSerializableCompatTest.java
@@ -0,0 +1,425 @@
+/*
+ * 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.protocol;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.JSON;
+import org.apache.rocketmq.remoting.protocol.body.BatchAck;
+import org.junit.Test;
+import org.objenesis.ObjenesisStd;
+import org.reflections.Reflections;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class RemotingSerializableCompatTest {
+    
+    @Test
+    public void testCompatibilityCheck() {
+        Reflections reflections = new Reflections("org.apache.rocketmq.remoting.protocol");
+        Set<Class<? extends RemotingSerializable>> subTypes = reflections.getSubTypesOf(RemotingSerializable.class);
+        
+        for (Class<? extends RemotingSerializable> clazz : subTypes) {
+            if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()) || clazz.getSimpleName().endsWith("Test")
+                    || clazz.isAnonymousClass() || clazz.getName().contains("$")) {
+                continue;
+            }
+            try {
+                RemotingSerializable instance;
+                try {
+                    instance = clazz.getDeclaredConstructor().newInstance();
+                } catch (NoSuchMethodException e) {
+                    instance = allocateInstance(clazz);
+                }
+                fillDefaultFields(instance, clazz);
+                assertTrue(checkCompatible(instance, clazz));
+            } catch (Exception e) {
+                System.err.printf("Class %s: incompatible, error: %s\n", clazz.getName(), e.getMessage());
+            }
+        }
+    }
+
+    @Test
+    public void testCompatibilityCheckWithBitSet() {
+        BitSet bitSet = new BitSet();
+        bitSet.set(1);
+        bitSet.set(3);
+        bitSet.set(5);
+        String fastjson1Str = "{\"b\":\"Kg==\",\"c\":\"DEFAULT_CONSUMER\",\"it\":5000,\"pt\":1760694281326,\"q\":1,\"r\":\"0\",\"rq\":2,\"so\":100,\"t\":\"myTopic\"}";
+        BatchAck batchAck = JSON.parseObject(fastjson1Str, BatchAck.class);
+        assertEquals(bitSet, batchAck.getBitSet());
+        assertEquals("DEFAULT_CONSUMER", batchAck.getConsumerGroup());
+        assertEquals(5000, batchAck.getInvisibleTime());
+        assertEquals(1760694281326L, batchAck.getPopTime());
+        assertEquals(1, batchAck.getQueueId());
+        assertEquals("0", batchAck.getRetry());
+        assertEquals(2, batchAck.getReviveQueueId());
+        assertEquals(100, batchAck.getStartOffset());
+        assertEquals("myTopic", batchAck.getTopic());
+    }
+    
+    private void fillDefaultFields(final Object obj, final Class<?> clazz) throws Exception {
+        if (null == clazz || clazz == Object.class) {
+            return;
+        }
+        for (Field field : clazz.getDeclaredFields()) {
+            if (Modifier.isStatic(field.getModifiers())) {
+                continue;
+            }
+            field.setAccessible(true);
+            Class<?> type = field.getType();
+            
+            if (type.isArray()) {
+                Class<?> componentType = type.getComponentType();
+                Object arr = Array.newInstance(componentType, 1);
+                Object element = createElementOrDefault(componentType);
+                if (element != null) {
+                    Array.set(arr, 0, element);
+                }
+                field.set(obj, arr);
+            } else if (Properties.class.isAssignableFrom(type)) {
+                field.set(obj, new Properties());
+            } else if (type.isEnum()) {
+                Object[] enumConstants = type.getEnumConstants();
+                if (enumConstants != null && enumConstants.length > 0) {
+                    field.set(obj, enumConstants[0]);
+                }
+            } else if (ConcurrentHashMap.KeySetView.class.isAssignableFrom(type)) {
+                field.set(obj, ConcurrentHashMap.newKeySet());
+            } else if (ConcurrentHashMap.class.isAssignableFrom(type) || ConcurrentMap.class.isAssignableFrom(type)) {
+                field.set(obj, new ConcurrentHashMap<>());
+            } else if (Set.class.isAssignableFrom(type)) {
+                Set<Object> set = type.isInterface() ? new HashSet<>() : (Set<Object>) type.getDeclaredConstructor().newInstance();
+                Class<?> genericType = getFirstGenericType(field);
+                Object element = createElementOrDefault(genericType);
+                if (element != null)
+                    set.add(element);
+                field.set(obj, set);
+            } else if (List.class.isAssignableFrom(type)) {
+                List<Object> list = new ArrayList<>();
+                Class<?> genericType = getFirstGenericType(field);
+                Object element = createElementOrDefault(genericType);
+                if (null != element) {
+                    list.add(element);
+                }
+                field.set(obj, list);
+            } else if (Map.class.isAssignableFrom(type)) {
+                Map<Object, Object> map = type.isInterface() ? new HashMap<>() : (Map<Object, Object>) type.getDeclaredConstructor().newInstance();
+                Class<?> keyType = getGenericType(field, 0);
+                Class<?> valueType = getGenericType(field, 1);
+                Object key = createElementOrDefault(keyType);
+                Object value = createElementOrDefault(valueType);
+                if (null != key && null != value) {
+                    map.put(key, value);
+                }
+                field.set(obj, map);
+            } else if (type == AtomicLong.class) {
+                field.set(obj, new AtomicLong(1));
+            } else {
+                Object value = getDefaultValue(type);
+                if (null != value) {
+                    field.set(obj, value);
+                } else if (!type.isPrimitive() && !type.getName().startsWith("java.")) {
+                    Object subObj;
+                    try {
+                        subObj = type.getDeclaredConstructor().newInstance();
+                    } catch (NoSuchMethodException e) {
+                        subObj = allocateInstance(type);
+                    }
+                    fillDefaultFields(subObj, type);
+                    field.set(obj, subObj);
+                }
+            }
+        }
+        fillDefaultFields(obj, clazz.getSuperclass());
+    }
+    
+    private Object createElementOrDefault(final Class<?> type) throws Exception {
+        if (null == type) {
+            return null;
+        }
+        Object value = getDefaultValue(type);
+        if (null != value) {
+            return value;
+        }
+        if (type.isEnum()) {
+            Object[] enumConstants = type.getEnumConstants();
+            if (null != enumConstants && enumConstants.length > 0) {
+                return enumConstants[0];
+            }
+            return null;
+        }
+        if (type.isArray()) {
+            Class<?> componentType = type.getComponentType();
+            Object arr = Array.newInstance(componentType, 1);
+            Object element = createElementOrDefault(componentType);
+            if (null != element) {
+                Array.set(arr, 0, element);
+            }
+            return arr;
+        }
+        if (!type.isPrimitive()) {
+            Object obj;
+            try {
+                obj = type.getDeclaredConstructor().newInstance();
+            } catch (NoSuchMethodException e) {
+                obj = allocateInstance(type);
+            }
+            fillDefaultFields(obj, type);
+            return obj;
+        }
+        return null;
+    }
+    
+    private Class<?> getFirstGenericType(final Field field) {
+        return getGenericType(field, 0);
+    }
+    
+    private Class<?> getGenericType(final Field field, final int index) {
+        try {
+            java.lang.reflect.Type genericType = field.getGenericType();
+            if (genericType instanceof java.lang.reflect.ParameterizedType) {
+                java.lang.reflect.Type[] types = ((java.lang.reflect.ParameterizedType) genericType).getActualTypeArguments();
+                if (types.length > index && types[index] instanceof Class) {
+                    return (Class<?>) types[index];
+                }
+            }
+        } catch (Exception ignored) {
+        }
+        return null;
+    }
+    
+    private Object getDefaultValue(final Class<?> type) {
+        if (null == type) {
+            return null;
+        }
+        if (type == boolean.class || type == Boolean.class) {
+            return false;
+        }
+        if (type == byte.class || type == Byte.class) {
+            return (byte) 1;
+        }
+        if (type == short.class || type == Short.class) {
+            return (short) 1;
+        }
+        if (type == int.class || type == Integer.class) {
+            return 1;
+        }
+        if (type == long.class || type == Long.class) {
+            return 1L;
+        }
+        if (type == float.class || type == Float.class) {
+            return 1f;
+        }
+        if (type == double.class || type == Double.class) {
+            return 1d;
+        }
+        if (type == char.class || type == Character.class) {
+            return '\0';
+        }
+        if (type == String.class) {
+            return "test";
+        }
+        return null;
+    }
+    
+    private boolean checkCompatible(final Object original, final Object deserialized, final String path, final Map<Object, Object> visited) {
+        if (null == original && null == deserialized) {
+            return true;
+        }
+        if (null == original || null == deserialized) {
+            System.err.printf("Objects at %s incompatible: one is null\n", path);
+            return false;
+        }
+        
+        if (!isPrimitiveOrWrapper(original.getClass())) {
+            if (visited.containsKey(original)) {
+                return true;
+            }
+            visited.put(original, deserialized);
+        }
+        
+        Class<?> clazz = original.getClass();
+        boolean result = true;
+        for (Field field : clazz.getDeclaredFields()) {
+            if (Modifier.isStatic(field.getModifiers())) {
+                continue;
+            }
+            JSONField jsonField = field.getAnnotation(JSONField.class);
+            if (null != jsonField && !jsonField.serialize()) {
+                continue;
+            }
+            if ("hash".equals(field.getName()) || "serialVersionUID".equals(field.getName())) {
+                continue;
+            }
+            
+            field.setAccessible(true);
+            try {
+                Object v1 = field.get(original);
+                Object v2 = field.get(deserialized);
+                String fieldPath = path + "." + field.getName();
+                
+                if (null == v1 && null == v2) {
+                    continue;
+                }
+                if (v1 instanceof Random && v2 instanceof Random) {
+                    continue;
+                }
+                if (v1 instanceof AtomicLong && v2 instanceof AtomicLong) {
+                    if (((AtomicLong) v1).get() != ((AtomicLong) v2).get()) {
+                        result = false;
+                        System.err.printf("Field %s incompatible: original=%s, deserialized=%s\n", fieldPath, v1, v2);
+                    }
+                    continue;
+                }
+                if (v1 instanceof Set && v2 instanceof Set) {
+                    Set<?> s1 = (Set<?>) v1, s2 = (Set<?>) v2;
+                    if (s1.size() != s2.size()) {
+                        result = false;
+                        System.err.printf("Field %s incompatible: set size original=%d, deserialized=%d\n", fieldPath, s1.size(), s2.size());
+                    } else if (!s1.isEmpty()) {
+                        List<?> list1 = new ArrayList<>(s1);
+                        List<?> list2 = new ArrayList<>(s2);
+                        if (new HashSet<>(list1).equals(new HashSet<>(list2))) {
+                            continue;
+                        }
+                        boolean elementsCompatible = true;
+                        for (Object e1 : list1) {
+                            boolean foundMatch = false;
+                            for (Object e2 : list2) {
+                                if (checkCompatible(e1, e2, fieldPath + ".element", new HashMap<>(visited))) {
+                                    foundMatch = true;
+                                    break;
+                                }
+                            }
+                            if (!foundMatch) {
+                                elementsCompatible = false;
+                                break;
+                            }
+                        }
+                        if (!elementsCompatible) {
+                            result = false;
+                            System.err.printf("Field %s incompatible: sets have different elements\n", fieldPath);
+                        }
+                    }
+                    continue;
+                }
+                if (v1 instanceof List && v2 instanceof List) {
+                    List<?> l1 = (List<?>) v1, l2 = (List<?>) v2;
+                    if (l1.size() != l2.size()) {
+                        result = false;
+                        System.err.printf("Field %s incompatible: list size original=%d, deserialized=%d\n", fieldPath, l1.size(), l2.size());
+                    } else {
+                        for (int i = 0; i < l1.size(); i++) {
+                            Object e1 = l1.get(i);
+                            Object e2 = l2.get(i);
+                            if (!checkCompatible(e1, e2, fieldPath + "[" + i + "]", new HashMap<>(visited))) {
+                                result = false;
+                            }
+                        }
+                    }
+                    continue;
+                }
+                if (v1 instanceof Map && v2 instanceof Map) {
+                    Map<?, ?> m1 = (Map<?, ?>) v1, m2 = (Map<?, ?>) v2;
+                    if (!m1.keySet().equals(m2.keySet())) {
+                        result = false;
+                        System.err.printf("Field %s incompatible: map keys original=%s, deserialized=%s\n", fieldPath, m1.keySet(), m2.keySet());
+                    } else {
+                        for (Object key : m1.keySet()) {
+                            Object val1 = m1.get(key), val2 = m2.get(key);
+                            if (val1 != null && val2 != null) {
+                                if (!checkCompatible(val1, val2, fieldPath + "[" + key + "]", new HashMap<>(visited))) {
+                                    result = false;
+                                }
+                            } else if (val1 != val2) {
+                                result = false;
+                                System.err.printf("Field %s key %s incompatible: original=%s, deserialized=%s\n",
+                                        fieldPath, key, val1, val2);
+                            }
+                        }
+                    }
+                    continue;
+                }
+                Class<?> type = field.getType();
+                if (null != v1 && null != v2 && !type.isPrimitive() && !type.getName().startsWith("java.")) {
+                    if (!checkCompatible(v1, v2, fieldPath, new HashMap<>(visited))) {
+                        result = false;
+                    }
+                    continue;
+                }
+                if (null == v1 || null == v2 || !v1.equals(v2)) {
+                    result = false;
+                    System.err.printf("Field %s incompatible: original=%s, deserialized=%s\n", fieldPath, v1, v2);
+                }
+            } catch (Exception e) {
+                result = false;
+                System.err.printf("Field %s error: %s\n", path + "." + field.getName(), e.getMessage());
+            }
+        }
+        if (result) {
+            System.out.printf("Class %s compatible\n", path);
+        }
+        return result;
+    }
+    
+    private boolean isPrimitiveOrWrapper(final Class<?> clazz) {
+        return clazz.isPrimitive() ||
+                clazz == String.class ||
+                clazz == Boolean.class ||
+                clazz == Character.class ||
+                clazz == Byte.class ||
+                clazz == Short.class ||
+                clazz == Integer.class ||
+                clazz == Long.class ||
+                clazz == Float.class ||
+                clazz == Double.class;
+    }
+    
+    private boolean checkCompatible(final Object original, final Class<?> clazz) {
+        String json = com.alibaba.fastjson.JSON.toJSONString(original);
+        Object deserialized;
+        try {
+            deserialized = com.alibaba.fastjson2.JSON.parseObject(json, clazz);
+        } catch (Exception e) {
+            System.err.printf("Deserialization failed for %s: %s\n", clazz.getName(), e.getMessage());
+            return false;
+        }
+        return checkCompatible(original, deserialized, clazz.getSimpleName(), new HashMap<>());
+    }
+    
+    private <T> T allocateInstance(final Class<T> clazz) {
+        return new ObjenesisStd().newInstance(clazz);
+    }
+}
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 6bd80217da..e2655fd35d 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
@@ -16,7 +16,7 @@
  */
 package org.apache.rocketmq.remoting.protocol;
 
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSONWriter;
 import com.google.gson.Gson;
 import com.google.gson.JsonElement;
 import com.google.gson.TypeAdapter;
@@ -105,8 +105,7 @@ public class RemotingSerializableTest {
         }
         Foo foo = new Foo();
         String invalid = new String(foo.encode(), Charset.defaultCharset());
-        String valid = new String(foo.encode(SerializerFeature.BrowserCompatible, SerializerFeature.QuoteFieldNames,
-             SerializerFeature.MapSortField), Charset.defaultCharset());
+        String valid = new String(foo.encode(JSONWriter.Feature.BrowserCompatible, JSONWriter.Feature.MapSortField), Charset.defaultCharset());
 
         Gson gson = new Gson();
         final TypeAdapter<JsonElement> strictAdapter = gson.getAdapter(JsonElement.class);
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/body/BatchAckTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/body/BatchAckTest.java
index 427a132d64..81e8f13394 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/body/BatchAckTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/body/BatchAckTest.java
@@ -16,7 +16,7 @@
  */
 package org.apache.rocketmq.remoting.protocol.body;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import org.apache.rocketmq.common.MixAll;
 import org.junit.Test;
 
diff --git a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/statictopic/TopicQueueMappingTest.java b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/statictopic/TopicQueueMappingTest.java
index 6b8a1392f5..7bb7b8ca7e 100644
--- a/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/statictopic/TopicQueueMappingTest.java
+++ b/remoting/src/test/java/org/apache/rocketmq/remoting/protocol/statictopic/TopicQueueMappingTest.java
@@ -17,15 +17,15 @@
 
 package org.apache.rocketmq.remoting.protocol.statictopic;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
 import com.google.common.collect.ImmutableList;
-import java.util.Map;
 import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
 import org.junit.Assert;
 import org.junit.Test;
 
+import java.util.Map;
+
 public class TopicQueueMappingTest {
 
     @Test
@@ -59,7 +59,6 @@ public class TopicQueueMappingTest {
             Assert.assertTrue(mappingDetailMap.containsKey("currIdMap"));
             Assert.assertEquals(8, mappingDetailMap.size());
             Assert.assertEquals(1, ((JSONObject) mappingDetailMap.get("hostedQueues")).size());
-            Assert.assertEquals(1, ((JSONArray)((JSONObject) mappingDetailMap.get("hostedQueues")).get("0")).size());
         }
         {
             TopicQueueMappingDetail mappingDetailFromJson = RemotingSerializable.decode(mappingDetailJson.getBytes(), TopicQueueMappingDetail.class);
@@ -69,9 +68,4 @@ public class TopicQueueMappingTest {
             Assert.assertEquals(mappingDetailJson, RemotingSerializable.toJson(mappingDetailFromJson, false));
         }
     }
-
-    @Test
-    public void test() {
-
-    }
 }
diff --git a/srvutil/BUILD.bazel b/srvutil/BUILD.bazel
index 699d78bcd9..8909409810 100644
--- a/srvutil/BUILD.bazel
+++ b/srvutil/BUILD.bazel
@@ -26,7 +26,6 @@ java_library(
         "@maven//:commons_validator_commons_validator",
         "@maven//:com_github_luben_zstd_jni",
         "@maven//:org_lz4_lz4_java",
-        "@maven//:com_alibaba_fastjson",
         "@maven//:io_netty_netty_all",
         "@maven//:commons_cli_commons_cli",
         "@maven//:com_googlecode_concurrentlinkedhashmap_concurrentlinkedhashmap_lru",
diff --git a/store/BUILD.bazel b/store/BUILD.bazel
index de98657b22..8986c9b236 100644
--- a/store/BUILD.bazel
+++ b/store/BUILD.bazel
@@ -23,7 +23,6 @@ java_library(
     deps = [
         "//common",
         "//remoting",
-        "@maven//:com_alibaba_fastjson",
         "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:com_conversantmedia_disruptor",
         "@maven//:com_google_guava_guava",
@@ -58,7 +57,7 @@ java_library(
         "//:test_deps",
         "//common",
         "//remoting",
-        "@maven//:com_alibaba_fastjson",
+        "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:com_conversantmedia_disruptor",
         "@maven//:io_openmessaging_storage_dledger",
         "@maven//:org_apache_commons_commons_lang3",
diff --git a/store/src/main/java/org/apache/rocketmq/store/pop/AckMsg.java b/store/src/main/java/org/apache/rocketmq/store/pop/AckMsg.java
index 3e65c104b1..f722c123ea 100644
--- a/store/src/main/java/org/apache/rocketmq/store/pop/AckMsg.java
+++ b/store/src/main/java/org/apache/rocketmq/store/pop/AckMsg.java
@@ -16,7 +16,7 @@
  */
 package org.apache.rocketmq.store.pop;
 
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
 
 public class AckMsg {
 
diff --git a/store/src/main/java/org/apache/rocketmq/store/pop/BatchAckMsg.java b/store/src/main/java/org/apache/rocketmq/store/pop/BatchAckMsg.java
index 991a1f085d..f2689dfdfb 100644
--- a/store/src/main/java/org/apache/rocketmq/store/pop/BatchAckMsg.java
+++ b/store/src/main/java/org/apache/rocketmq/store/pop/BatchAckMsg.java
@@ -16,7 +16,8 @@
  */
 package org.apache.rocketmq.store.pop;
 
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
+
 import java.util.ArrayList;
 import java.util.List;
 
diff --git a/store/src/main/java/org/apache/rocketmq/store/pop/PopCheckPoint.java b/store/src/main/java/org/apache/rocketmq/store/pop/PopCheckPoint.java
index 38e0a20752..e3587aa28c 100644
--- a/store/src/main/java/org/apache/rocketmq/store/pop/PopCheckPoint.java
+++ b/store/src/main/java/org/apache/rocketmq/store/pop/PopCheckPoint.java
@@ -16,7 +16,8 @@
  */
 package org.apache.rocketmq.store.pop;
 
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -35,7 +36,6 @@ public class PopCheckPoint implements Comparable<PopCheckPoint> {
     private int queueId;
     @JSONField(name = "t")
     private String topic;
-    @JSONField(name = "c")
     private String cid;
     @JSONField(name = "ro")
     private long reviveOffset;
@@ -114,10 +114,12 @@ public class PopCheckPoint implements Comparable<PopCheckPoint> {
         this.topic = topic;
     }
 
+    @JSONField(name = "c")
     public String getCId() {
         return cid;
     }
 
+    @JSONField(name = "c")
     public void setCId(String cid) {
         this.cid = cid;
     }
diff --git a/store/src/main/java/org/apache/rocketmq/store/queue/CombineConsumeQueueStore.java b/store/src/main/java/org/apache/rocketmq/store/queue/CombineConsumeQueueStore.java
index c8c3202a78..5de1664cdb 100644
--- a/store/src/main/java/org/apache/rocketmq/store/queue/CombineConsumeQueueStore.java
+++ b/store/src/main/java/org/apache/rocketmq/store/queue/CombineConsumeQueueStore.java
@@ -17,7 +17,7 @@
 
 package org.apache.rocketmq.store.queue;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import com.google.common.annotations.VisibleForTesting;
 import java.util.Arrays;
 import java.util.LinkedList;
diff --git a/store/src/main/java/org/apache/rocketmq/store/timer/TimerMetrics.java b/store/src/main/java/org/apache/rocketmq/store/timer/TimerMetrics.java
index ba7240414a..338a62252f 100644
--- a/store/src/main/java/org/apache/rocketmq/store/timer/TimerMetrics.java
+++ b/store/src/main/java/org/apache/rocketmq/store/timer/TimerMetrics.java
@@ -16,9 +16,21 @@
  */
 package org.apache.rocketmq.store.timer;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
+import org.apache.rocketmq.common.ConfigManager;
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.message.MessageConst;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.common.topic.TopicValidator;
+import org.apache.rocketmq.logging.org.slf4j.Logger;
+import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
+import org.apache.rocketmq.remoting.protocol.DataVersion;
+import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+
 import java.io.File;
+import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.io.StringWriter;
 import java.io.Writer;
@@ -36,16 +48,6 @@ import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
-import org.apache.rocketmq.common.ConfigManager;
-import org.apache.rocketmq.common.MixAll;
-import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.common.message.MessageConst;
-import org.apache.rocketmq.common.message.MessageExt;
-import org.apache.rocketmq.common.topic.TopicValidator;
-import org.apache.rocketmq.logging.org.slf4j.Logger;
-import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
-import org.apache.rocketmq.remoting.protocol.DataVersion;
-import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
 
 public class TimerMetrics extends ConfigManager {
     private static final Logger log = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
@@ -135,11 +137,11 @@ public class TimerMetrics extends ConfigManager {
         return timingCount;
     }
 
-    protected void write0(Writer writer) {
+    protected void write0(Writer writer) throws IOException {
         TimerMetricsSerializeWrapper wrapper = new TimerMetricsSerializeWrapper();
         wrapper.setTimingCount(timingCount);
         wrapper.setDataVersion(dataVersion);
-        JSON.writeJSONString(writer, wrapper, SerializerFeature.BrowserCompatible);
+        writer.write(JSON.toJSONString(wrapper, JSONWriter.Feature.BrowserCompatible));
     }
 
     @Override public String encode() {
@@ -152,7 +154,7 @@ public class TimerMetrics extends ConfigManager {
 
     @Override public void decode(String jsonString) {
         if (jsonString != null) {
-            TimerMetricsSerializeWrapper timerMetricsSerializeWrapper = TimerMetricsSerializeWrapper.fromJson(jsonString, TimerMetricsSerializeWrapper.class);                                                         
+            TimerMetricsSerializeWrapper timerMetricsSerializeWrapper = TimerMetricsSerializeWrapper.fromJson(jsonString, TimerMetricsSerializeWrapper.class);
             if (timerMetricsSerializeWrapper != null) {
                 this.timingCount.putAll(timerMetricsSerializeWrapper.getTimingCount());
                 this.dataVersion.assignNewOne(timerMetricsSerializeWrapper.getDataVersion());
@@ -179,7 +181,7 @@ public class TimerMetrics extends ConfigManager {
         while (iterator.hasNext()) {
             Map.Entry<String, Metric> entry = iterator.next();
             final String topic = entry.getKey();
-            if (topic.startsWith(TopicValidator.SYSTEM_TOPIC_PREFIX) || topic.startsWith(MixAll.LMQ_PREFIX)) {                                                                                                         
+            if (topic.startsWith(TopicValidator.SYSTEM_TOPIC_PREFIX) || topic.startsWith(MixAll.LMQ_PREFIX)) {
                 continue;
             }
             if (topics.contains(topic)) {
diff --git a/store/src/test/java/org/apache/rocketmq/store/pop/AckMsgTest.java b/store/src/test/java/org/apache/rocketmq/store/pop/AckMsgTest.java
index b5a3ff6381..13df028e83 100644
--- a/store/src/test/java/org/apache/rocketmq/store/pop/AckMsgTest.java
+++ b/store/src/test/java/org/apache/rocketmq/store/pop/AckMsgTest.java
@@ -17,7 +17,7 @@
 
 package org.apache.rocketmq.store.pop;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import org.junit.Assert;
 import org.junit.Test;
 
diff --git a/store/src/test/java/org/apache/rocketmq/store/pop/BatchAckMsgTest.java b/store/src/test/java/org/apache/rocketmq/store/pop/BatchAckMsgTest.java
index 4bcfcf18be..0a1bc714cf 100644
--- a/store/src/test/java/org/apache/rocketmq/store/pop/BatchAckMsgTest.java
+++ b/store/src/test/java/org/apache/rocketmq/store/pop/BatchAckMsgTest.java
@@ -17,7 +17,7 @@
 
 package org.apache.rocketmq.store.pop;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import org.junit.Assert;
 import org.junit.Test;
 
diff --git a/test/BUILD.bazel b/test/BUILD.bazel
index a8a7a9d8bb..d34456f355 100644
--- a/test/BUILD.bazel
+++ b/test/BUILD.bazel
@@ -28,7 +28,6 @@ java_library(
         "//tools",
         "@maven//:ch_qos_logback_logback_classic",
         "@maven//:ch_qos_logback_logback_core",
-        "@maven//:com_alibaba_fastjson",
         "@maven//:com_github_luben_zstd_jni",
         "@maven//:com_google_guava_guava",
         "@maven//:com_google_protobuf_protobuf_java_util",
diff --git a/tieredstore/BUILD.bazel b/tieredstore/BUILD.bazel
index 8822280ff8..0a94302086 100644
--- a/tieredstore/BUILD.bazel
+++ b/tieredstore/BUILD.bazel
@@ -39,7 +39,7 @@ java_library(
         "@maven//:io_opentelemetry_opentelemetry_exporter_logging_otlp",
         "@maven//:org_apache_commons_commons_lang3",
         "@maven//:org_apache_tomcat_annotations_api",
-        "@maven//:com_alibaba_fastjson",
+        "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:org_apache_rocketmq_rocketmq_rocksdb",
         "@maven//:commons_collections_commons_collections",
         "@maven//:org_slf4j_slf4j_api",
@@ -57,7 +57,7 @@ java_library(
         "//common",
         "//remoting",
         "//store",
-        "@maven//:com_alibaba_fastjson",        
+        "@maven//:com_alibaba_fastjson2_fastjson2",
         "@maven//:commons_io_commons_io",
         "@maven//:io_opentelemetry_opentelemetry_api",
         "@maven//:io_opentelemetry_opentelemetry_context",
diff --git a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/file/FlatMessageFile.java b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/file/FlatMessageFile.java
index b0e4dd6e3b..a7505b4bf4 100644
--- a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/file/FlatMessageFile.java
+++ b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/file/FlatMessageFile.java
@@ -16,7 +16,7 @@
  */
 package org.apache.rocketmq.tieredstore.file;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import com.google.common.annotations.VisibleForTesting;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
diff --git a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/DefaultMetadataStore.java b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/DefaultMetadataStore.java
index 09500bf6da..eb726543cf 100644
--- a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/DefaultMetadataStore.java
+++ b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/DefaultMetadataStore.java
@@ -16,17 +16,9 @@
  */
 package org.apache.rocketmq.tieredstore.metadata;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
 import com.google.common.annotations.VisibleForTesting;
-import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.function.Consumer;
 import org.apache.rocketmq.common.ConfigManager;
 import org.apache.rocketmq.common.message.MessageQueue;
 import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
@@ -36,6 +28,15 @@ import org.apache.rocketmq.tieredstore.metadata.entity.FileSegmentMetadata;
 import org.apache.rocketmq.tieredstore.metadata.entity.QueueMetadata;
 import org.apache.rocketmq.tieredstore.metadata.entity.TopicMetadata;
 
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Consumer;
+
 public class DefaultMetadataStore extends ConfigManager implements MetadataStore {
 
     private static final int DEFAULT_CAPACITY = 1024;
@@ -80,12 +81,9 @@ public class DefaultMetadataStore extends ConfigManager implements MetadataStore
         dataWrapper.setIndexFileSegmentTable(new ConcurrentHashMap<>(indexFileSegmentTable));
 
         if (prettyFormat) {
-            return JSON.toJSONString(
-                dataWrapper, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.PrettyFormat);
-        } else {
-            return JSON.toJSONString(
-                dataWrapper, SerializerFeature.DisableCircularReferenceDetect);
+            return JSON.toJSONString(dataWrapper, JSONWriter.Feature.PrettyFormat);
         }
+        return JSON.toJSONString(dataWrapper);
     }
 
     @Override
diff --git a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/FileSegmentMetadata.java b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/FileSegmentMetadata.java
index 4f988ca241..da2a0fd06c 100644
--- a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/FileSegmentMetadata.java
+++ b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/FileSegmentMetadata.java
@@ -16,7 +16,7 @@
  */
 package org.apache.rocketmq.tieredstore.metadata.entity;
 
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
 import java.util.Objects;
 
 public class FileSegmentMetadata {
diff --git a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/QueueMetadata.java b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/QueueMetadata.java
index 6720f1d08a..3f976f037d 100644
--- a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/QueueMetadata.java
+++ b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/QueueMetadata.java
@@ -16,7 +16,7 @@
  */
 package org.apache.rocketmq.tieredstore.metadata.entity;
 
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
 import org.apache.rocketmq.common.message.MessageQueue;
 
 public class QueueMetadata {
diff --git a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/TopicMetadata.java b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/TopicMetadata.java
index 80e5230e7a..72b994fc84 100644
--- a/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/TopicMetadata.java
+++ b/tieredstore/src/main/java/org/apache/rocketmq/tieredstore/metadata/entity/TopicMetadata.java
@@ -16,7 +16,7 @@
  */
 package org.apache.rocketmq.tieredstore.metadata.entity;
 
-import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson2.annotation.JSONField;
 
 public class TopicMetadata {
 
diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel
index ec6fa1eaac..a809a7a92e 100644
--- a/tools/BUILD.bazel
+++ b/tools/BUILD.bazel
@@ -29,7 +29,6 @@ java_library(
         "@maven//:commons_validator_commons_validator",
         "@maven//:com_github_luben_zstd_jni",
         "@maven//:org_lz4_lz4_java",
-        "@maven//:com_alibaba_fastjson",
         "@maven//:io_netty_netty_all",
         "@maven//:commons_cli_commons_cli",
         "@maven//:org_slf4j_slf4j_api",
diff --git a/tools/pom.xml b/tools/pom.xml
index 8eea4977e6..1d63ded9b8 100644
--- a/tools/pom.xml
+++ b/tools/pom.xml
@@ -44,10 +44,6 @@
             <groupId>${project.groupId}</groupId>
             <artifactId>rocketmq-srvutil</artifactId>
         </dependency>
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>fastjson</artifactId>
-        </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java b/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java
index 948c4430d5..f2e1cda2bd 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java
@@ -16,7 +16,7 @@
  */
 package org.apache.rocketmq.tools.admin;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.rocketmq.client.QueryResult;
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/broker/GetColdDataFlowCtrInfoSubCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/broker/GetColdDataFlowCtrInfoSubCommand.java
index 34b3ba7d30..76c111b95c 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/broker/GetColdDataFlowCtrInfoSubCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/broker/GetColdDataFlowCtrInfoSubCommand.java
@@ -16,13 +16,9 @@
  */
 package org.apache.rocketmq.tools.command.broker;
 
-import java.io.UnsupportedEncodingException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.JSONWriter;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
@@ -37,6 +33,12 @@ import org.apache.rocketmq.tools.command.CommandUtil;
 import org.apache.rocketmq.tools.command.SubCommand;
 import org.apache.rocketmq.tools.command.SubCommandException;
 
+import java.io.UnsupportedEncodingException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
 public class GetColdDataFlowCtrInfoSubCommand implements SubCommand {
     SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
@@ -116,7 +118,7 @@ public class GetColdDataFlowCtrInfoSubCommand implements SubCommand {
             value.remove("createTimeMills");
         });
 
-        String formatStr = JSON.toJSONString(jsonObject, true);
+        String formatStr = JSON.toJSONString(jsonObject, JSONWriter.Feature.PrettyFormat);
         System.out.printf(formatStr);
         System.out.printf("%n");
     }
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/consumer/UpdateSubGroupSubCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/consumer/UpdateSubGroupSubCommand.java
index b17da4de45..d4782a0684 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/consumer/UpdateSubGroupSubCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/consumer/UpdateSubGroupSubCommand.java
@@ -16,9 +16,7 @@
  */
 package org.apache.rocketmq.tools.command.consumer;
 
-import com.alibaba.fastjson.JSON;
-import java.util.Map;
-import java.util.Set;
+import com.alibaba.fastjson2.JSON;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
@@ -32,6 +30,9 @@ import org.apache.rocketmq.tools.command.CommandUtil;
 import org.apache.rocketmq.tools.command.SubCommand;
 import org.apache.rocketmq.tools.command.SubCommandException;
 
+import java.util.Map;
+import java.util.Set;
+
 public class UpdateSubGroupSubCommand implements SubCommand {
 
     @Override
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportConfigsCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportConfigsCommand.java
index c3f96d5972..ebb1cf82ba 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportConfigsCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportConfigsCommand.java
@@ -16,15 +16,8 @@
  */
 package org.apache.rocketmq.tools.command.export;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Arrays;
-import java.util.Properties;
-
-import com.alibaba.fastjson.JSON;
-
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
@@ -35,6 +28,13 @@ import org.apache.rocketmq.tools.command.CommandUtil;
 import org.apache.rocketmq.tools.command.SubCommand;
 import org.apache.rocketmq.tools.command.SubCommandException;
 
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
 public class ExportConfigsCommand implements SubCommand {
     @Override
     public String commandName() {
@@ -98,7 +98,7 @@ public class ExportConfigsCommand implements SubCommand {
             result.put("clusterScale", clusterScaleMap);
 
             String path = filePath + "/configs.json";
-            MixAll.string2FileNotSafe(JSON.toJSONString(result, true), path);
+            MixAll.string2FileNotSafe(JSON.toJSONString(result, JSONWriter.Feature.PrettyFormat), path);
             System.out.printf("export %s success", path);
         } catch (Exception e) {
             throw new SubCommandException(this.getClass().getSimpleName() + " command failed", e);
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataCommand.java
index 748f7b16e1..559936bcb8 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataCommand.java
@@ -16,10 +16,8 @@
  */
 package org.apache.rocketmq.tools.command.export;
 
-import com.alibaba.fastjson.JSON;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
@@ -35,6 +33,10 @@ import org.apache.rocketmq.tools.command.CommandUtil;
 import org.apache.rocketmq.tools.command.SubCommand;
 import org.apache.rocketmq.tools.command.SubCommandException;
 
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
 public class ExportMetadataCommand implements SubCommand {
 
     private static final String DEFAULT_FILE_PATH = "/tmp/rocketmq/export";
@@ -99,13 +101,13 @@ public class ExportMetadataCommand implements SubCommand {
                     filePath = filePath + "/topic.json";
                     TopicConfigSerializeWrapper topicConfigSerializeWrapper = defaultMQAdminExt.getUserTopicConfig(
                         brokerAddr, specialTopic, 10000L);
-                    MixAll.string2FileNotSafe(JSON.toJSONString(topicConfigSerializeWrapper, true), filePath);
+                    MixAll.string2FileNotSafe(JSON.toJSONString(topicConfigSerializeWrapper, JSONWriter.Feature.PrettyFormat), filePath);
                     System.out.printf("export %s success", filePath);
                 } else if (commandLine.hasOption('g')) {
                     filePath = filePath + "/subscriptionGroup.json";
                     SubscriptionGroupWrapper subscriptionGroupWrapper = defaultMQAdminExt.getUserSubscriptionGroup(
                         brokerAddr, 10000L);
-                    MixAll.string2FileNotSafe(JSON.toJSONString(subscriptionGroupWrapper, true), filePath);
+                    MixAll.string2FileNotSafe(JSON.toJSONString(subscriptionGroupWrapper, JSONWriter.Feature.PrettyFormat), filePath);
                     System.out.printf("export %s success", filePath);
                 }
             } else if (commandLine.hasOption('c')) {
@@ -163,7 +165,7 @@ public class ExportMetadataCommand implements SubCommand {
                     exportPath = filePath + "/metadata.json";
                 }
                 result.put("exportTime", System.currentTimeMillis());
-                MixAll.string2FileNotSafe(JSON.toJSONString(result, true), exportPath);
+                MixAll.string2FileNotSafe(JSON.toJSONString(result, JSONWriter.Feature.PrettyFormat), exportPath);
                 System.out.printf("export %s success%n", exportPath);
 
             } else {
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataInRocksDBCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataInRocksDBCommand.java
index 438d17d668..1a3e5e5a6a 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataInRocksDBCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetadataInRocksDBCommand.java
@@ -17,11 +17,9 @@
 
 package org.apache.rocketmq.tools.command.export;
 
-import com.alibaba.fastjson.JSONObject;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.function.BiConsumer;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.JSONWriter;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
@@ -34,6 +32,11 @@ import org.apache.rocketmq.tools.command.SubCommand;
 import org.apache.rocketmq.tools.command.SubCommandException;
 import org.rocksdb.RocksIterator;
 
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.BiConsumer;
+
 public class ExportMetadataInRocksDBCommand implements SubCommand {
     private static final String TOPICS_JSON_CONFIG = "topics";
     private static final String SUBSCRIPTION_GROUP_JSON_CONFIG = "subscriptionGroups";
@@ -118,8 +121,8 @@ public class ExportMetadataInRocksDBCommand implements SubCommand {
             );
 
             jsonConfig.put(configType.equalsIgnoreCase(TOPICS_JSON_CONFIG) ? "topicConfigTable" : "subscriptionGroupTable",
-                (JSONObject) JSONObject.toJSON(configTable));
-            final String jsonConfigStr = JSONObject.toJSONString(jsonConfig, true);
+                (JSONObject) JSON.toJSON(configTable));
+            final String jsonConfigStr = JSONObject.toJSONString(jsonConfig, JSONWriter.Feature.PrettyFormat);
             System.out.print(jsonConfigStr + "\n");
         } else {
             AtomicLong count = new AtomicLong(0);
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetricsCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetricsCommand.java
index 5d8bb37ba0..1b7d5d44e3 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetricsCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/export/ExportMetricsCommand.java
@@ -16,12 +16,8 @@
  */
 package org.apache.rocketmq.tools.command.export;
 
-import com.alibaba.fastjson.JSON;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
@@ -47,6 +43,12 @@ import org.apache.rocketmq.tools.command.SubCommand;
 import org.apache.rocketmq.tools.command.SubCommandException;
 import org.apache.rocketmq.tools.command.stats.StatsAllSubCommand;
 
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
 public class ExportMetricsCommand implements SubCommand {
 
     @Override
@@ -133,7 +135,7 @@ public class ExportMetricsCommand implements SubCommand {
             result.put("evaluateReport", evaluateReportMap);
             result.put("totalData", totalData);
 
-            MixAll.string2FileNotSafe(JSON.toJSONString(result, true), path);
+            MixAll.string2FileNotSafe(JSON.toJSONString(result, JSONWriter.Feature.PrettyFormat), path);
             System.out.printf("export %s success", path);
         } catch (Exception e) {
             throw new SubCommandException(this.getClass().getSimpleName() + " command failed", e);
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/metadata/RocksDBConfigToJsonCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/metadata/RocksDBConfigToJsonCommand.java
index 94899fce08..d65a04136b 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/metadata/RocksDBConfigToJsonCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/metadata/RocksDBConfigToJsonCommand.java
@@ -17,22 +17,8 @@
 
 package org.apache.rocketmq.tools.command.metadata;
 
-import com.alibaba.fastjson.JSONObject;
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionException;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicLong;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.JSONWriter;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
@@ -49,6 +35,22 @@ import org.apache.rocketmq.tools.command.SubCommand;
 import org.apache.rocketmq.tools.command.SubCommandException;
 import org.rocksdb.RocksIterator;
 
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicLong;
+
 public class RocksDBConfigToJsonCommand implements SubCommand {
 
     @Override
@@ -136,10 +138,10 @@ public class RocksDBConfigToJsonCommand implements SubCommand {
                 if (commandLine.hasOption("jsonEnable") && "false".equalsIgnoreCase(commandLine.getOptionValue("jsonEnable").trim())) {
                     printConfigMapJsonDisable(configMap);
                 } else {
-                    System.out.print(JSONObject.toJSONString(configMap, true) + "\n");
+                    System.out.print(JSONObject.toJSONString(configMap, JSONWriter.Feature.PrettyFormat) + "\n");
                 }
             } else {
-                String jsonString = JSONObject.toJSONString(configMap, true);
+                String jsonString = JSONObject.toJSONString(configMap, JSONWriter.Feature.PrettyFormat);
                 try {
                     MixAll.string2File(jsonString, exportFile);
                 } catch (IOException e) {
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java
index 4902b8a881..24d9900b61 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java
@@ -17,7 +17,8 @@
 
 package org.apache.rocketmq.tools.command.queue;
 
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.DefaultParser;
 import org.apache.commons.cli.Option;
@@ -121,7 +122,7 @@ public class QueryConsumeQueueCommand implements SubCommand {
             );
 
             if (queryConsumeQueueResponseBody.getSubscriptionData() != null) {
-                System.out.printf("Subscription data: \n%s\n", JSON.toJSONString(queryConsumeQueueResponseBody.getSubscriptionData(), true));
+                System.out.printf("Subscription data: \n%s\n", JSON.toJSONString(queryConsumeQueueResponseBody.getSubscriptionData(), JSONWriter.Feature.PrettyFormat));
                 System.out.print("======================================\n");
             }
 
diff --git a/tools/src/test/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImplTest.java b/tools/src/test/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImplTest.java
new file mode 100644
index 0000000000..c5ea051ab4
--- /dev/null
+++ b/tools/src/test/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImplTest.java
@@ -0,0 +1,825 @@
+/*
+ * 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.tools.admin;
+
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.rocketmq.client.exception.MQBrokerException;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.impl.MQAdminImpl;
+import org.apache.rocketmq.client.impl.MQClientAPIImpl;
+import org.apache.rocketmq.client.impl.factory.MQClientInstance;
+import org.apache.rocketmq.common.TopicConfig;
+import org.apache.rocketmq.common.constant.PermName;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.remoting.exception.RemotingConnectException;
+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.protocol.ResponseCode;
+import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
+import org.apache.rocketmq.remoting.protocol.admin.OffsetWrapper;
+import org.apache.rocketmq.remoting.protocol.admin.RollbackStats;
+import org.apache.rocketmq.remoting.protocol.admin.TopicOffset;
+import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
+import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
+import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
+import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
+import org.apache.rocketmq.remoting.protocol.body.GroupList;
+import org.apache.rocketmq.remoting.protocol.body.QueueTimeSpan;
+import org.apache.rocketmq.remoting.protocol.body.SubscriptionGroupWrapper;
+import org.apache.rocketmq.remoting.protocol.body.TopicConfigSerializeWrapper;
+import org.apache.rocketmq.remoting.protocol.body.TopicList;
+import org.apache.rocketmq.remoting.protocol.header.UpdateConsumerOffsetRequestHeader;
+import org.apache.rocketmq.remoting.protocol.header.UpdateGroupForbiddenRequestHeader;
+import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.remoting.protocol.route.BrokerData;
+import org.apache.rocketmq.remoting.protocol.route.QueueData;
+import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
+import org.apache.rocketmq.remoting.protocol.subscription.GroupForbidden;
+import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.tools.admin.api.BrokerOperatorResult;
+import org.apache.rocketmq.tools.admin.api.MessageTrack;
+import org.apache.rocketmq.tools.admin.common.AdminToolResult;
+import org.apache.rocketmq.tools.admin.common.AdminToolsResultCodeEnum;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DefaultMQAdminExtImplTest {
+
+    private DefaultMQAdminExtImpl defaultMQAdminExtImpl;
+
+    @Mock
+    private DefaultMQAdminExt defaultMQAdminExt;
+
+    @Mock
+    private MQClientInstance mqClientInstance;
+
+    @Mock
+    private MQClientAPIImpl mqClientAPIImpl;
+
+    @Mock
+    private MQAdminImpl mqAdminImpl;
+
+    private final String defaultTopic = "defaultTopic";
+
+    private final String defaultCluster = "cluster";
+
+    private final String defaultBroker = "broker1";
+
+    private final String defaultGroup = "consumerGroup";
+
+    private final String defaultBrokerAddr = "127.0.0.1:10911";
+
+    private final long timeoutMillis = 3000L;
+
+    private final String defaultMsgId = "AC1A43AC00002A9F00008F214319C26B";
+
+    @Before
+    public void init() throws IllegalAccessException, RemotingException, InterruptedException, MQClientException, MQBrokerException {
+        defaultMQAdminExtImpl = new DefaultMQAdminExtImpl(defaultMQAdminExt, timeoutMillis);
+        FieldUtils.writeDeclaredField(defaultMQAdminExtImpl, "mqClientInstance", mqClientInstance, true);
+        FieldUtils.writeDeclaredField(defaultMQAdminExtImpl, "mqClientInstance", mqClientInstance, true);
+        FieldUtils.writeDeclaredField(defaultMQAdminExtImpl, "threadPoolExecutor", Executors.newFixedThreadPool(1), true);
+        when(mqClientInstance.getMQClientAPIImpl()).thenReturn(mqClientAPIImpl);
+        when(mqClientInstance.getMQAdminImpl()).thenReturn(mqAdminImpl);
+        when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(createTopicRouteData());
+    }
+
+    @Test
+    public void testExamineTopicStats() throws Exception {
+        TopicStatsTable topicStatsTable = mock(TopicStatsTable.class);
+        Map<MessageQueue, TopicOffset> offsetTable = new ConcurrentHashMap<>();
+        offsetTable.put(new MessageQueue(), new TopicOffset());
+        when(topicStatsTable.getOffsetTable()).thenReturn(offsetTable);
+        when(mqClientAPIImpl.getTopicStatsInfo(any(), any(), anyLong())).thenReturn(topicStatsTable);
+        TopicStatsTable actual = defaultMQAdminExtImpl.examineTopicStats(defaultTopic);
+        assertNotNull(actual);
+        assertEquals(offsetTable.size(), actual.getOffsetTable().size());
+    }
+
+    @Test
+    public void testExamineTopicStatsConcurrentTopicRouteDataNull() throws Exception {
+        when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(null);
+        AdminToolResult<TopicStatsTable> actual = defaultMQAdminExtImpl.examineTopicStatsConcurrent(defaultTopic);
+        assertNotNull(actual);
+        assertEquals(200, actual.getCode());
+        assertEquals(0, actual.getData().getOffsetTable().size());
+    }
+
+    @Test
+    public void testExamineTopicStatsConcurrentBrokerDataEmpty() throws Exception {
+        TopicRouteData topicRouteData = mock(TopicRouteData.class);
+        when(topicRouteData.getBrokerDatas()).thenReturn(new ArrayList<>());
+        when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(topicRouteData);
+        AdminToolResult<TopicStatsTable> actual = defaultMQAdminExtImpl.examineTopicStatsConcurrent(defaultTopic);
+        assertNotNull(actual);
+        assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), actual.getCode());
+        assertEquals(0, actual.getData().getOffsetTable().size());
+    }
+
+    @Test
+    public void testExamineTopicStatsConcurrent() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        doAnswer(invocation -> {
+            latch.countDown();
+            return null;
+        }).when(mqClientAPIImpl).getTopicStatsInfo(any(), any(), anyLong());
+        latch.await(1000, TimeUnit.MILLISECONDS);
+        AdminToolResult<TopicStatsTable> actual = defaultMQAdminExtImpl.examineTopicStatsConcurrent(defaultTopic);
+        assertNotNull(actual);
+        assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), actual.getCode());
+        assertEquals(0, actual.getData().getOffsetTable().size());
+    }
+
+    @Test
+    public void testExamineTopicStatsConcurrentException() throws Exception {
+        doThrow(new MQBrokerException(ResponseCode.SYSTEM_ERROR, "Test Exception")).when(mqClientAPIImpl).getTopicStatsInfo(any(), any(), anyLong());
+        assertNotNull(defaultMQAdminExtImpl.examineTopicStatsConcurrent(defaultTopic));
+    }
+
+    @Test
+    public void testExamineConsumeStatsConcurrentTopicRouteInfoNotExist() throws Exception {
+        when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(null);
+        AdminToolResult<ConsumeStats> result = defaultMQAdminExtImpl.examineConsumeStatsConcurrent(defaultGroup, defaultTopic);
+        assertEquals(AdminToolsResultCodeEnum.TOPIC_ROUTE_INFO_NOT_EXIST.getCode(), result.getCode());
+    }
+
+    @Test
+    public void testExamineConsumeStatsConcurrent() throws Exception {
+        AtomicInteger count = new AtomicInteger(0);
+        AtomicInteger success = new AtomicInteger(0);
+        AtomicInteger fail = new AtomicInteger(0);
+        CountDownLatch latch = new CountDownLatch(10);
+        ExecutorService executorService = Executors.newFixedThreadPool(10);
+        List<BrokerData> brokerDataList = new ArrayList<>();
+        for (int i = 0; i < 10; i++) {
+            BrokerData bd = new BrokerData();
+            bd.setBrokerName("brokerName" + i);
+            bd.setCluster(defaultCluster);
+            bd.setBrokerAddrs(createBrokerAddrs());
+            brokerDataList.add(bd);
+        }
+        TopicRouteData topicRouteData = new TopicRouteData();
+        topicRouteData.setBrokerDatas(brokerDataList);
+        for (int i = 0; i < 10; i++) {
+            executorService.submit(() -> {
+                try {
+                    Thread.sleep(100);
+                    if (count.incrementAndGet() % 2 == 0) {
+                        success.incrementAndGet();
+                    } else {
+                        throw new RemotingException("Test Exception");
+                    }
+                    latch.countDown();
+                } catch (Exception e) {
+                    fail.incrementAndGet();
+                }
+            });
+        }
+        latch.await(3000, TimeUnit.MILLISECONDS);
+        executorService.shutdown();
+        assertEquals(5, success.get());
+        assertEquals(5, fail.get());
+        assertEquals(10, count.get());
+    }
+
+    @Test
+    public void testExamineConsumeStatsConcurrentEmptyOffsetTable() throws Exception {
+        when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(anyString(), anyLong())).thenReturn(createTopicRouteData());
+        when(mqClientAPIImpl.getConsumeStats(anyString(), anyString(), anyString(), anyLong())).thenReturn(new ConsumeStats());
+        AdminToolResult<ConsumeStats> actual = defaultMQAdminExtImpl.examineConsumeStatsConcurrent(defaultGroup, defaultTopic);
+        assertEquals(AdminToolsResultCodeEnum.CONSUMER_NOT_ONLINE.getCode(), actual.getCode());
+    }
+
+    @Test
+    public void testViewMessageValidMsgIdReturnsMessageExt() throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
+        MessageExt expected = createMessageExt();
+        when(mqAdminImpl.viewMessage(anyString(), anyString())).thenReturn(expected);
+        when(mqClientInstance.getMQAdminImpl()).thenReturn(mqAdminImpl);
+        MessageExt actual = defaultMQAdminExtImpl.viewMessage(expected.getTopic(), expected.getMsgId());
+        assertNotNull(actual);
+        assertEquals(expected.getMsgId(), actual.getMsgId());
+        assertEquals(expected.getTopic(), actual.getTopic());
+    }
+
+    @Test
+    public void testViewMessageInvalidMsgIdQueriesByUniqKey() throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
+        MessageExt expected = createMessageExt();
+        expected.setMsgId("invalidMsgId");
+        when(mqAdminImpl.queryMessageByUniqKey(anyString(), anyString())).thenReturn(expected);
+        when(mqClientInstance.getMQAdminImpl()).thenReturn(mqAdminImpl);
+        MessageExt actual = defaultMQAdminExtImpl.viewMessage(expected.getTopic(), expected.getMsgId());
+        assertNotNull(actual);
+        assertEquals(expected.getMsgId(), actual.getMsgId());
+        assertEquals(expected.getTopic(), actual.getTopic());
+    }
+
+    @Test
+    public void testViewMessageExceptionInDecodeLogsWarningAndQueriesByUniqKey() throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
+        MessageExt expected = createMessageExt();
+        expected.setMsgId("exceptionMsgId");
+        when(mqAdminImpl.queryMessageByUniqKey(anyString(), anyString())).thenReturn(expected);
+        MessageExt actual = defaultMQAdminExtImpl.viewMessage(expected.getTopic(), expected.getMsgId());
+        assertNotNull(actual);
+        assertEquals(expected.getMsgId(), actual.getMsgId());
+        assertEquals(expected.getTopic(), actual.getTopic());
+    }
+
+    @Test
+    public void testQueryMessageInvalidMsgIdReturnsMessageExt() throws Exception {
+        MessageExt expected = createMessageExt();
+        expected.setMsgId("invalidMsgId");
+        when(mqAdminImpl.queryMessageByUniqKey(anyString(), anyString(), anyString())).thenReturn(expected);
+        MessageExt actual = defaultMQAdminExtImpl.queryMessage(defaultCluster, expected.getTopic(), expected.getMsgId());
+        assertNotNull(actual);
+        assertEquals(expected.getMsgId(), actual.getMsgId());
+        assertEquals(expected.getTopic(), actual.getTopic());
+    }
+
+    @Test
+    public void testQueryMessageRemotingException() throws MQBrokerException, RemotingException, InterruptedException, MQClientException {
+        when(mqAdminImpl.viewMessage(anyString(), anyString())).thenThrow(new RemotingException("Test Exception"));
+        assertNull(defaultMQAdminExtImpl.queryMessage(null, defaultTopic, defaultMsgId));
+    }
+
+    @Test
+    public void testDeleteTopicValidInput() throws Exception {
+        ClusterInfo clusterInfo = mock(ClusterInfo.class);
+        when(defaultMQAdminExt.examineBrokerClusterInfo()).thenReturn(clusterInfo);
+        Map<String, Set<String>> clusterAddrTable = new HashMap<>();
+        clusterAddrTable.put(defaultCluster, new HashSet<>(Arrays.asList("broker1", "broker2")));
+        when(clusterInfo.getClusterAddrTable()).thenReturn(clusterAddrTable);
+        Map<String, BrokerData> brokerAddrTable = new HashMap<>();
+        BrokerData brokerData = new BrokerData();
+        brokerData.setBrokerName(defaultBroker);
+        HashMap<Long, String> brokerAddrs = new HashMap<>();
+        brokerAddrs.put(0L, defaultBrokerAddr);
+        brokerData.setBrokerAddrs(brokerAddrs);
+        brokerAddrTable.put(defaultBroker, brokerData);
+        when(clusterInfo.getBrokerAddrTable()).thenReturn(brokerAddrTable);
+        List<String> nsAddrs = new ArrayList<>();
+        nsAddrs.add("127.0.0.1:9876");
+        when(mqClientAPIImpl.getNameServerAddressList()).thenReturn(nsAddrs);
+        List<String> kvNamespaceToDeleteList = new ArrayList<>();
+        kvNamespaceToDeleteList.add("namespace");
+        FieldUtils.writeDeclaredField(defaultMQAdminExtImpl, "kvNamespaceToDeleteList", kvNamespaceToDeleteList, true);
+        defaultMQAdminExtImpl.deleteTopic(defaultTopic, defaultCluster);
+        verify(mqClientAPIImpl, times(1)).deleteTopicInBroker(any(), any(), anyLong());
+        verify(mqClientAPIImpl, times(1)).deleteTopicInNameServer(any(), any(), anyLong());
+        verify(mqClientAPIImpl, times(1)).deleteKVConfigValue(any(), any(), anyLong());
+    }
+
+    @Test
+    public void testDeleteTopicInBrokerConcurrent() throws InterruptedException, RemotingException, MQClientException {
+        Set<String> addrs = Collections.singleton(defaultBrokerAddr);
+        doNothing().when(mqClientAPIImpl).deleteTopicInBroker(anyString(), anyString(), anyLong());
+        AdminToolResult<BrokerOperatorResult> result = defaultMQAdminExtImpl.deleteTopicInBrokerConcurrent(addrs, defaultTopic);
+        assertNotNull(result);
+        assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), result.getCode());
+        BrokerOperatorResult brokerResult = result.getData();
+        List<String> successList = brokerResult.getSuccessList();
+        List<String> failureList = brokerResult.getFailureList();
+        assertEquals(1, successList.size());
+        assertEquals(0, failureList.size());
+        assertEquals(addrs.iterator().next(), successList.get(0));
+    }
+
+    @Test
+    public void testDeleteTopicInBrokerConcurrentAllFailures() throws InterruptedException, RemotingException, MQClientException {
+        Set<String> addrs = new HashSet<>(Collections.singleton(defaultBrokerAddr));
+        String anotherAddr = "anotherBrokerAddr:10911";
+        addrs.add(anotherAddr);
+        doThrow(new RuntimeException("deleteTopic error")).when(mqClientAPIImpl).deleteTopicInBroker(anyString(), anyString(), anyLong());
+        AdminToolResult<BrokerOperatorResult> result = defaultMQAdminExtImpl.deleteTopicInBrokerConcurrent(addrs, defaultTopic);
+        assertNotNull(result);
+        assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), result.getCode());
+        BrokerOperatorResult brokerResult = result.getData();
+        List<String> successList = brokerResult.getSuccessList();
+        List<String> failureList = brokerResult.getFailureList();
+        assertEquals(0, successList.size());
+        assertEquals(2, failureList.size());
+        assertTrue(failureList.contains(defaultBrokerAddr));
+        assertTrue(failureList.contains(anotherAddr));
+    }
+
+    @Test
+    public void testResetOffsetByTimestampOldThrowException() {
+        String topic = "nonExistentTopic";
+        long timestamp = System.currentTimeMillis();
+        assertThrows(NullPointerException.class, () -> defaultMQAdminExtImpl.resetOffsetByTimestampOld(defaultGroup, topic, timestamp, false));
+    }
+
+    @Test
+    public void testResetOffsetByTimestampOldValidInputShouldProcessCorrectly() throws Exception {
+        long timestamp = System.currentTimeMillis();
+        ConsumeStats consumeStats = mock(ConsumeStats.class);
+        Map<MessageQueue, OffsetWrapper> offsetTable = new ConcurrentHashMap<>();
+        OffsetWrapper offsetWrapper = new OffsetWrapper();
+        offsetWrapper.setBrokerOffset(5L);
+        offsetWrapper.setConsumerOffset(5L);
+        offsetTable.put(new MessageQueue(defaultTopic, defaultBroker, 0), offsetWrapper);
+        when(consumeStats.getOffsetTable()).thenReturn(offsetTable);
+        when(mqClientAPIImpl.getConsumeStats(any(), any(), anyLong())).thenReturn(consumeStats);
+        List<RollbackStats> rollbackStatsList = defaultMQAdminExtImpl.resetOffsetByTimestampOld(defaultGroup, defaultTopic, timestamp, false);
+        assertNotNull(rollbackStatsList);
+        assertEquals(1, rollbackStatsList.size());
+        RollbackStats rollbackStats = rollbackStatsList.get(0);
+        assertEquals(defaultBroker, rollbackStats.getBrokerName());
+        assertEquals(0, rollbackStats.getQueueId());
+        assertEquals(5L, rollbackStats.getBrokerOffset());
+        assertEquals(5L, rollbackStats.getConsumerOffset());
+    }
+
+    @Test
+    public void testResetOffsetNew() throws Exception {
+        defaultMQAdminExtImpl.resetOffsetNew(defaultGroup, defaultTopic, timeoutMillis);
+        verify(mqClientAPIImpl, times(1)).invokeBrokerToResetOffset(
+                anyString(),
+                anyString(),
+                anyString(),
+                anyLong(),
+                anyBoolean(),
+                anyLong(),
+                anyBoolean());
+    }
+
+    @Test
+    public void testResetOffsetNewConcurrent() {
+        AdminToolResult<BrokerOperatorResult> actual = defaultMQAdminExtImpl.resetOffsetNewConcurrent(defaultGroup, defaultTopic, timeoutMillis);
+        assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), actual.getCode());
+    }
+
+    @Test
+    public void testResetOffsetNewConcurrentTopicRouteInfoNotExist() throws Exception {
+        when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(null);
+        AdminToolResult<BrokerOperatorResult> actual = defaultMQAdminExtImpl.resetOffsetNewConcurrent(defaultGroup, defaultTopic, timeoutMillis);
+        assertEquals(AdminToolsResultCodeEnum.TOPIC_ROUTE_INFO_NOT_EXIST.getCode(), actual.getCode());
+    }
+
+    @Test
+    public void testResetOffsetNewConcurrentException() throws Exception {
+        when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenThrow(new MQClientException(ResponseCode.SYSTEM_ERROR, "Test Exception"));
+        AdminToolResult<BrokerOperatorResult> actual = defaultMQAdminExtImpl.resetOffsetNewConcurrent(defaultGroup, defaultTopic, timeoutMillis);
+        assertEquals(AdminToolsResultCodeEnum.MQ_CLIENT_ERROR.getCode(), actual.getCode());
+    }
+
+    @Test
+    public void testCreateOrUpdateOrderConfClusterConfig() throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
+        String key = "key1";
+        String value = "value1";
+        doNothing().when(mqClientAPIImpl).putKVConfigValue(anyString(), anyString(), anyString(), anyLong());
+        defaultMQAdminExtImpl.createOrUpdateOrderConf(key, value, true);
+        verify(mqClientAPIImpl, times(1)).putKVConfigValue(anyString(), anyString(), anyString(), anyLong());
+    }
+
+    @Test
+    public void testCreateOrUpdateOrderConfNonClusterConfig() throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
+        String key = "key1";
+        String value = "value1:value2";
+        String oldOrderConfs = "key1:value1;key2:value2";
+        when(mqClientAPIImpl.getKVConfigValue(anyString(), anyString(), anyLong())).thenReturn(oldOrderConfs);
+        doNothing().when(mqClientAPIImpl).putKVConfigValue(anyString(), anyString(), anyString(), anyLong());
+        defaultMQAdminExtImpl.createOrUpdateOrderConf(key, value, false);
+        verify(mqClientAPIImpl, times(1)).putKVConfigValue(anyString(), anyString(), anyString(), anyLong());
+    }
+
+    @Test
+    public void testCreateOrUpdateOrderConfExceptionInPut() throws RemotingException, InterruptedException, MQClientException {
+        String key = "key1";
+        String value = "value1:value2";
+        String oldOrderConfs = "key1:value1;key2:value2";
+        when(mqClientAPIImpl.getKVConfigValue(anyString(), anyString(), anyLong())).thenReturn(oldOrderConfs);
+        doThrow(new RemotingException("Test Exception")).when(mqClientAPIImpl).putKVConfigValue(anyString(), anyString(), anyString(), anyLong());
+        assertThrows(RemotingException.class, () -> defaultMQAdminExtImpl.createOrUpdateOrderConf(key, value, false));
+    }
+
+    @Test
+    public void testCreateOrUpdateOrderConfNoOldConfs() throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
+        String key = "key1";
+        String value = "value1:value2";
+        when(mqClientAPIImpl.getKVConfigValue(anyString(), anyString(), anyLong())).thenReturn(null);
+        doNothing().when(mqClientAPIImpl).putKVConfigValue(anyString(), anyString(), anyString(), anyLong());
+        defaultMQAdminExtImpl.createOrUpdateOrderConf(key, value, false);
+        verify(mqClientAPIImpl, times(1)).putKVConfigValue(anyString(), anyString(), anyString(), anyLong());
+    }
+
+    @Test
+    public void testCreateOrUpdateOrderConfExceptionInGet() throws RemotingException, InterruptedException, MQClientException, MQBrokerException {
+        String key = "key1";
+        String value = "value1:value2";
+        when(mqClientAPIImpl.getKVConfigValue(anyString(), anyString(), anyLong())).thenThrow(new RemotingException("Test Exception"));
+        defaultMQAdminExtImpl.createOrUpdateOrderConf(key, value, false);
+        verify(mqClientAPIImpl, times(1)).getKVConfigValue(anyString(), anyString(), anyLong());
+    }
+
+    @Test
+    public void testQuerySubscriptionValidInput() throws InterruptedException, MQBrokerException, RemotingException, MQClientException {
+        when(mqClientAPIImpl.querySubscriptionByConsumer(anyString(), anyString(), anyString(), anyLong())).thenReturn(new SubscriptionData());
+        assertNotNull(defaultMQAdminExtImpl.querySubscription("group", "topic"));
+    }
+
+    @Test
+    public void testQueryTopicsByConsumer() throws Exception {
+        TopicList expected = new TopicList();
+        expected.getTopicList().add(defaultTopic);
+        when(mqClientAPIImpl.queryTopicsByConsumer(anyString(), anyString(), anyLong())).thenReturn(expected);
+        TopicList actual = defaultMQAdminExtImpl.queryTopicsByConsumer(defaultGroup);
+        assertEquals(1, actual.getTopicList().size());
+        assertEquals(expected.getTopicList().iterator().next(), actual.getTopicList().iterator().next());
+        verify(mqClientAPIImpl, times(1)).queryTopicsByConsumer(anyString(), anyString(), anyLong());
+    }
+
+    @Test
+    public void testQueryTopicsByConsumerRemotingTimeoutException() throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQBrokerException, InterruptedException {
+        when(mqClientAPIImpl.queryTopicsByConsumer(anyString(), anyString(), anyLong())).thenThrow(new RemotingTimeoutException("Test Exception"));
+        assertThrows(RemotingTimeoutException.class, () -> defaultMQAdminExtImpl.queryTopicsByConsumer(defaultGroup));
+        verify(mqClientAPIImpl, times(1)).queryTopicsByConsumer(anyString(), anyString(), anyLong());
+    }
+
+    @Test
+    public void testQueryTopicsByConsumerMQBrokerException() throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQBrokerException, InterruptedException {
+        when(mqClientAPIImpl.queryTopicsByConsumer(anyString(), anyString(), anyLong())).thenThrow(new MQBrokerException(ResponseCode.SYSTEM_ERROR, "Test Exception"));
+        assertThrows(MQBrokerException.class, () -> defaultMQAdminExtImpl.queryTopicsByConsumer(defaultGroup));
+        verify(mqClientAPIImpl, times(1)).queryTopicsByConsumer(anyString(), anyString(), anyLong());
+    }
+
+    @Test
+    public void testQueryTopicsByConsumerMQClientException() throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQBrokerException, InterruptedException {
+        when(mqClientAPIImpl.queryTopicsByConsumer(anyString(), anyString(), anyLong())).thenThrow(new MQBrokerException(ResponseCode.SYSTEM_ERROR, "Test Exception"));
+        assertThrows(MQBrokerException.class, () -> defaultMQAdminExtImpl.queryTopicsByConsumer(defaultGroup));
+        verify(mqClientAPIImpl, times(1)).queryTopicsByConsumer(anyString(), anyString(), anyLong());
+    }
+
+    @Test
+    public void testQueryTopicsByConsumerNoBrokers() throws Exception {
+        TopicRouteData topicRouteData = new TopicRouteData();
+        topicRouteData.setBrokerDatas(new ArrayList<>());
+        when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(topicRouteData);
+        TopicList actual = defaultMQAdminExtImpl.queryTopicsByConsumer(defaultGroup);
+        assertEquals(0, actual.getTopicList().size());
+    }
+
+    @Test
+    public void testQueryTopicsByConsumerConcurrentTopicRouteDataNull() throws Exception {
+        when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(null);
+        AdminToolResult<TopicList> actual = defaultMQAdminExtImpl.queryTopicsByConsumerConcurrent(defaultGroup);
+        assertEquals(AdminToolsResultCodeEnum.TOPIC_ROUTE_INFO_NOT_EXIST.getCode(), actual.getCode());
+        assertEquals("router info not found.", actual.getErrorMsg());
+    }
+
+    @Test
+    public void testQueryTopicsByConsumerConcurrentNoBrokers() throws Exception {
+        TopicRouteData topicRouteData = new TopicRouteData();
+        topicRouteData.setBrokerDatas(new ArrayList<>());
+        when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(any(), anyLong())).thenReturn(topicRouteData);
+        AdminToolResult<TopicList> actual = defaultMQAdminExtImpl.queryTopicsByConsumerConcurrent(defaultGroup);
+        assertEquals(AdminToolsResultCodeEnum.TOPIC_ROUTE_INFO_NOT_EXIST.getCode(), actual.getCode());
+        assertEquals("router info not found.", actual.getErrorMsg());
+    }
+
+    @Test
+    public void testQueryTopicsByConsumerConcurrent() throws Exception {
+        TopicList expectedTopicList = new TopicList();
+        expectedTopicList.setTopicList(new HashSet<>(Arrays.asList(defaultTopic, "topic2")));
+        when(mqClientAPIImpl.queryTopicsByConsumer(any(), any(), anyLong())).thenReturn(expectedTopicList);
+        AdminToolResult<TopicList> result = defaultMQAdminExtImpl.queryTopicsByConsumerConcurrent(defaultGroup);
+        assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), result.getCode());
+        Set<String> actual = result.getData().getTopicList();
+        assertFalse(actual.isEmpty());
+        assertTrue(actual.containsAll(expectedTopicList.getTopicList()));
+    }
+
+    @Test
+    public void testQueryConsumeTimeSpanConcurrentTopicRouteDataNull() throws Exception {
+        when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(anyString(), anyLong())).thenReturn(null);
+        AdminToolResult<List<QueueTimeSpan>> actual = defaultMQAdminExtImpl.queryConsumeTimeSpanConcurrent(defaultTopic, defaultGroup);
+        assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), actual.getCode());
+        assertEquals(0, actual.getData().size());
+    }
+
+    @Test
+    public void testQueryConsumeTimeSpanConcurrentNoBrokers() throws Exception {
+        TopicRouteData topicRouteData = new TopicRouteData();
+        topicRouteData.setBrokerDatas(new ArrayList<>());
+        when(mqClientAPIImpl.getTopicRouteInfoFromNameServer(anyString(), anyLong())).thenReturn(topicRouteData);
+        AdminToolResult<List<QueueTimeSpan>> actual = defaultMQAdminExtImpl.queryConsumeTimeSpanConcurrent(defaultTopic, defaultGroup);
+        assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), actual.getCode());
+        assertEquals(0, actual.getData().size());
+    }
+
+    @Test
+    public void testQueryConsumeTimeSpanConcurrent() throws Exception {
+        List<QueueTimeSpan> spans = new ArrayList<>();
+        QueueTimeSpan queueTimeSpan = new QueueTimeSpan();
+        queueTimeSpan.setMinTimeStamp(1000L);
+        queueTimeSpan.setMaxTimeStamp(2000L);
+        spans.add(queueTimeSpan);
+        when(mqClientAPIImpl.queryConsumeTimeSpan(anyString(), anyString(), anyString(), anyLong())).thenReturn(spans);
+        AdminToolResult<List<QueueTimeSpan>> actual = defaultMQAdminExtImpl.queryConsumeTimeSpanConcurrent(defaultTopic, defaultGroup);
+        assertEquals(AdminToolsResultCodeEnum.SUCCESS.getCode(), actual.getCode());
+        assertEquals(1, actual.getData().size());
+    }
+
+    @Test
+    public void testDeleteExpiredCommitLog() throws Exception {
+        ClusterInfo clusterInfo = mock(ClusterInfo.class);
+        when(clusterInfo.retrieveAllAddrByCluster(defaultCluster)).thenReturn(new String[]{"addr1", "addr2"});
+        when(mqClientAPIImpl.getBrokerClusterInfo(anyLong())).thenReturn(clusterInfo);
+        when(mqClientAPIImpl.deleteExpiredCommitLog(anyString(), anyLong())).thenReturn(true);
+        boolean actual = defaultMQAdminExtImpl.deleteExpiredCommitLog(defaultCluster);
+        assertTrue(actual);
+        verify(mqClientAPIImpl, times(2)).deleteExpiredCommitLog(anyString(), anyLong());
+    }
+
+    @Test
+    public void testDeleteExpiredCommitLogByCluster() throws Exception {
+        ClusterInfo clusterInfo = mock(ClusterInfo.class);
+        when(clusterInfo.retrieveAllAddrByCluster(defaultCluster)).thenReturn(new String[]{"addr1", "addr2"});
+        when(mqClientAPIImpl.deleteExpiredCommitLog(anyString(), anyLong())).thenReturn(true);
+        boolean actual = defaultMQAdminExtImpl.deleteExpiredCommitLogByCluster(clusterInfo, defaultCluster);
+        assertTrue(actual);
+        verify(mqClientAPIImpl, times(2)).deleteExpiredCommitLog(anyString(), anyLong());
+    }
+
+    @Test
+    public void testDeleteExpiredCommitLogByAddr() throws Exception {
+        when(mqClientAPIImpl.deleteExpiredCommitLog(defaultBrokerAddr, timeoutMillis)).thenReturn(true);
+        boolean actual = defaultMQAdminExtImpl.deleteExpiredCommitLogByAddr(defaultBrokerAddr);
+        assertTrue(actual);
+        verify(mqClientAPIImpl, times(1)).deleteExpiredCommitLog(defaultBrokerAddr, timeoutMillis);
+    }
+
+    @Test
+    public void testConsumeMessageDirectly() throws Exception {
+        String clientId = "clientId";
+        MessageExt messageExt = createMessageExt();
+        when(mqAdminImpl.viewMessage(defaultTopic, defaultMsgId)).thenReturn(messageExt);
+        ConsumeMessageDirectlyResult consumeMessageDirectlyResult = mock(ConsumeMessageDirectlyResult.class);
+        when(mqClientAPIImpl.consumeMessageDirectly(
+                anyString(),
+                anyString(),
+                anyString(),
+                anyString(),
+                anyString(),
+                anyLong()))
+                .thenReturn(consumeMessageDirectlyResult);
+        ConsumeMessageDirectlyResult actual = defaultMQAdminExtImpl.consumeMessageDirectly(defaultGroup, clientId, defaultTopic, defaultMsgId);
+        assertNotNull(actual);
+        assertNull(actual.getRemark());
+        assertFalse(actual.isAutoCommit());
+        assertFalse(actual.isOrder());
+    }
+
+    @Test
+    public void testMessageTrackDetailConcurrent() throws Exception {
+        MessageExt messageExt = createMessageExt();
+        GroupList groupList = mock(GroupList.class);
+        HashSet<String> groupSet = new HashSet<>();
+        groupSet.add(defaultGroup);
+        when(groupList.getGroupList()).thenReturn(groupSet);
+        when(mqClientAPIImpl.queryTopicConsumeByWho(anyString(), anyString(), anyLong())).thenReturn(groupList);
+        ConsumerConnection consumerConnection = mock(ConsumerConnection.class);
+        when(mqClientAPIImpl.getConsumerConnectionList(anyString(), anyString(), anyLong())).thenReturn(consumerConnection);
+        List<MessageTrack> actual = defaultMQAdminExtImpl.messageTrackDetailConcurrent(messageExt);
+        assertEquals(1, actual.size());
+    }
+
+//    @Test
+//    public void testConsumedConcurrent() throws Exception {
+//        ConsumeStats consumeStats = mock(ConsumeStats.class);
+//        ClusterInfo ci = mock(ClusterInfo.class);
+//        Map<String, BrokerData> brokerAddrTable = new HashMap<>();
+//        BrokerData brokerData = mock(BrokerData.class);
+//        HashMap<Long, String> brokerAddress = new HashMap<>();
+//        brokerAddress.put(0L, defaultBrokerAddr);
+//        when(brokerData.getBrokerAddrs()).thenReturn(brokerAddress);
+//        brokerAddrTable.put(defaultBroker, brokerData);
+//        when(ci.getBrokerAddrTable()).thenReturn(brokerAddrTable);
+//        Map<MessageQueue, OffsetWrapper> offsetTable = new HashMap<>();
+//        OffsetWrapper offsetWrapper = new OffsetWrapper();
+//        offsetWrapper.setConsumerOffset(1L);
+//        offsetTable.put(new MessageQueue(defaultTopic, defaultBroker, 0), offsetWrapper);
+//        when(consumeStats.getOffsetTable()).thenReturn(offsetTable);
+////        when(mqClientAPIImpl.getConsumeStats(any(), any(), any(), anyLong())).thenReturn(consumeStats);
+//        when(mqClientAPIImpl.getBrokerClusterInfo(anyLong())).thenReturn(ci);
+////        assertTrue(defaultMQAdminExtImpl.consumedConcurrent(createMessageExt(), defaultGroup));
+//    }
+
+    @Test
+    public void testCloneGroupOffsetValidInput() throws RemotingException, MQClientException, InterruptedException, MQBrokerException {
+        String srcGroup = "srcGroup";
+        String destGroup = "destGroup";
+        boolean isOffline = false;
+        defaultMQAdminExtImpl.cloneGroupOffset(srcGroup, destGroup, defaultTopic, isOffline);
+        verify(mqClientAPIImpl, times(1)).cloneGroupOffset(
+                anyString(),
+                anyString(),
+                anyString(),
+                anyString(),
+                anyBoolean(),
+                anyLong());
+    }
+
+    @Test
+    public void testGetUserSubscriptionGroup() throws Exception {
+        SubscriptionGroupWrapper subscriptionGroupWrapper = new SubscriptionGroupWrapper();
+        ConcurrentMap<String, SubscriptionGroupConfig> subscriptionGroupTable = new ConcurrentHashMap<>();
+        SubscriptionGroupConfig groupConfig1 = new SubscriptionGroupConfig();
+        groupConfig1.setGroupName("CID_RMQ_SYS_GROUP");
+        SubscriptionGroupConfig groupConfig2 = new SubscriptionGroupConfig();
+        groupConfig2.setGroupName("DEFAULT_CONSUMER");
+        SubscriptionGroupConfig groupConfig3 = new SubscriptionGroupConfig();
+        groupConfig3.setGroupName("SYS_CONSUMER_GROUP");
+        subscriptionGroupTable.put(groupConfig1.getGroupName(), groupConfig1);
+        subscriptionGroupTable.put(groupConfig2.getGroupName(), groupConfig2);
+        subscriptionGroupTable.put(groupConfig3.getGroupName(), groupConfig3);
+        subscriptionGroupWrapper.setSubscriptionGroupTable(subscriptionGroupTable);
+        when(mqClientAPIImpl.getAllSubscriptionGroup(any(), anyLong())).thenReturn(subscriptionGroupWrapper);
+        SubscriptionGroupWrapper actual = defaultMQAdminExtImpl.getUserSubscriptionGroup(defaultBrokerAddr, timeoutMillis);
+        assertEquals(1, actual.getSubscriptionGroupTable().size());
+        assertTrue(actual.getSubscriptionGroupTable().containsKey("SYS_CONSUMER_GROUP"));
+    }
+
+    @Test
+    public void testGetUserTopicConfig() throws Exception {
+        TopicConfigSerializeWrapper topicConfigSerializeWrapper = new TopicConfigSerializeWrapper();
+        ConcurrentMap<String, TopicConfig> topicConfigMap = new ConcurrentHashMap<>();
+        topicConfigMap.put("Topic1", new TopicConfig("Topic1", 1, 1, 0));
+        topicConfigMap.put("Topic2", new TopicConfig("Topic2", 1, 1, 1));
+        topicConfigSerializeWrapper.setTopicConfigTable(topicConfigMap);
+        TopicList topicList = new TopicList();
+        Set<String> topicSet = new HashSet<>();
+        topicSet.add("Topic2");
+        topicList.setTopicList(topicSet);
+        when(mqClientAPIImpl.getAllTopicConfig(any(), anyLong())).thenReturn(topicConfigSerializeWrapper);
+        when(mqClientAPIImpl.getSystemTopicListFromBroker(anyString(), anyLong())).thenReturn(topicList);
+        TopicConfigSerializeWrapper actual = defaultMQAdminExtImpl.getUserTopicConfig("brokerAddr", false, timeoutMillis);
+        assertEquals(1, actual.getTopicConfigTable().size());
+    }
+
+    @Test
+    public void testUpdateConsumeOffset() throws Exception {
+        doNothing().when(mqClientAPIImpl).updateConsumerOffset(any(), any(UpdateConsumerOffsetRequestHeader.class), anyLong());
+        defaultMQAdminExtImpl.updateConsumeOffset(defaultBrokerAddr, defaultGroup, createMessageQueue(), 1L);
+        verify(mqClientAPIImpl, times(1)).updateConsumerOffset(any(), any(UpdateConsumerOffsetRequestHeader.class), anyLong());
+    }
+
+    @Test
+    public void testUpdateConsumeOffsetException() throws MQBrokerException, RemotingException, InterruptedException {
+        doThrow(new RemotingException("Test exception")).when(mqClientAPIImpl).updateConsumerOffset(anyString(), any(UpdateConsumerOffsetRequestHeader.class), anyLong());
+        assertThrows(RemotingException.class,
+                () -> defaultMQAdminExtImpl.updateConsumeOffset(defaultBrokerAddr, defaultGroup, createMessageQueue(), 1L));
+    }
+
+    @Test
+    public void testResetOffsetByQueueId() throws Exception {
+        long resetOffset = 100;
+        doNothing().when(mqClientAPIImpl).updateConsumerOffset(any(), any(UpdateConsumerOffsetRequestHeader.class), anyLong());
+        Map<MessageQueue, Long> result = new HashMap<>();
+        result.put(createMessageQueue(), resetOffset);
+        when(mqClientAPIImpl.invokeBrokerToResetOffset(anyString(), anyString(), anyString(), anyLong(), anyInt(), anyLong(), anyLong())).thenReturn(result);
+        defaultMQAdminExtImpl.resetOffsetByQueueId(defaultBrokerAddr, defaultGroup, defaultTopic, 0, resetOffset);
+        verify(mqClientAPIImpl, times(1)).updateConsumerOffset(any(), any(UpdateConsumerOffsetRequestHeader.class), anyLong());
+        verify(mqClientAPIImpl, times(1)).invokeBrokerToResetOffset(
+                anyString(),
+                anyString(),
+                anyString(),
+                anyLong(),
+                anyInt(),
+                anyLong(),
+                anyLong());
+    }
+
+    @Test
+    public void testResetOffsetByQueueIdThrowsException() throws MQBrokerException, RemotingException, InterruptedException, MQClientException {
+        doNothing().when(mqClientAPIImpl).updateConsumerOffset(any(), any(UpdateConsumerOffsetRequestHeader.class), anyLong());
+        when(mqClientAPIImpl.invokeBrokerToResetOffset(
+                anyString(),
+                anyString(),
+                anyString(),
+                anyLong(),
+                anyInt(),
+                anyLong(),
+                anyLong()))
+                .thenThrow(new MQClientException(1, "Exception"));
+        assertThrows(MQBrokerException.class,
+                () -> defaultMQAdminExtImpl.resetOffsetByQueueId(defaultBrokerAddr, defaultGroup, defaultTopic, 0, 100));
+    }
+
+    @Test
+    public void testUpdateAndGetGroupReadForbidden() throws RemotingException, InterruptedException, MQBrokerException {
+        boolean readable = true;
+        GroupForbidden expectedResponse = new GroupForbidden();
+        expectedResponse.setGroup(defaultGroup);
+        expectedResponse.setTopic(defaultTopic);
+        expectedResponse.setReadable(readable);
+        when(mqClientAPIImpl.updateAndGetGroupForbidden(any(), any(UpdateGroupForbiddenRequestHeader.class), anyLong())).thenReturn(expectedResponse);
+        GroupForbidden actual = defaultMQAdminExtImpl.updateAndGetGroupReadForbidden(defaultBrokerAddr, defaultGroup, defaultTopic, readable);
+        assertNotNull(actual);
+        assertEquals(defaultGroup, actual.getGroup());
+        assertEquals(defaultTopic, actual.getTopic());
+        assertEquals(readable, actual.getReadable());
+    }
+
+    @Test
+    public void testUpdateAndGetGroupReadForbiddenException() throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, MQBrokerException, InterruptedException {
+        when(mqClientAPIImpl.updateAndGetGroupForbidden(any(), any(UpdateGroupForbiddenRequestHeader.class), anyLong()))
+                .thenThrow(new MQBrokerException(ResponseCode.SYSTEM_ERROR, "Test Exception"));
+        assertThrows(MQBrokerException.class,
+                () -> defaultMQAdminExtImpl.updateAndGetGroupReadForbidden(defaultBrokerAddr, defaultGroup, defaultTopic, true));
+    }
+
+    private HashMap<Long, String> createBrokerAddrs() {
+        HashMap<Long, String> result = new HashMap<>();
+        result.put(0L, defaultBrokerAddr);
+        return result;
+    }
+
+    private TopicRouteData createTopicRouteData() {
+        BrokerData bd = new BrokerData(defaultCluster, defaultBroker, new HashMap<>());
+        bd.setBrokerAddrs(new HashMap<>());
+        bd.getBrokerAddrs().put(0L, defaultBrokerAddr);
+        QueueData qd = new QueueData();
+        qd.setBrokerName(defaultBroker);
+        qd.setPerm(PermName.PERM_WRITE);
+        qd.setReadQueueNums(1);
+        qd.setTopicSysFlag(0);
+        qd.setWriteQueueNums(1);
+        TopicRouteData result = new TopicRouteData();
+        result.getBrokerDatas().add(bd);
+        result.getQueueDatas().add(qd);
+        return result;
+    }
+
+    private MessageQueue createMessageQueue() {
+        return new MessageQueue(defaultTopic, defaultBroker, 0);
+    }
+
+    private MessageExt createMessageExt() {
+        MessageExt result = new MessageExt();
+        result.setMsgId(defaultMsgId);
+        result.setTopic(defaultTopic);
+        result.setQueueId(0);
+        InetAddress inetAddress = mock(InetAddress.class);
+        InetSocketAddress address = new InetSocketAddress(inetAddress, 10911);
+        when(inetAddress.getHostAddress()).thenReturn("127.0.0.1");
+        result.setStoreHost(address);
+        return result;
+    }
+}
diff --git a/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ConsumerConnectionSubCommandTest.java b/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ConsumerConnectionSubCommandTest.java
index f5967f5a30..a2ad8c5d85 100644
--- a/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ConsumerConnectionSubCommandTest.java
+++ b/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ConsumerConnectionSubCommandTest.java
@@ -16,7 +16,6 @@
  */
 package org.apache.rocketmq.tools.command.connection;
 
-import java.util.HashSet;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.DefaultParser;
 import org.apache.commons.cli.Options;
@@ -30,7 +29,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import static org.mockito.Mockito.mock;
+import java.util.HashSet;
 
 public class ConsumerConnectionSubCommandTest {
     private ServerResponseMocker brokerMocker;
@@ -62,7 +61,7 @@ public class ConsumerConnectionSubCommandTest {
     private ServerResponseMocker startOneBroker() {
         ConsumerConnection consumerConnection = new ConsumerConnection();
         HashSet<Connection> connectionSet = new HashSet<>();
-        Connection connection = mock(Connection.class);
+        Connection connection = new Connection();
         connectionSet.add(connection);
         consumerConnection.setConnectionSet(connectionSet);
         // start broker
diff --git a/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ProducerConnectionSubCommandTest.java b/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ProducerConnectionSubCommandTest.java
index 672e4113d6..812edde9e0 100644
--- a/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ProducerConnectionSubCommandTest.java
+++ b/tools/src/test/java/org/apache/rocketmq/tools/command/connection/ProducerConnectionSubCommandTest.java
@@ -16,7 +16,6 @@
  */
 package org.apache.rocketmq.tools.command.connection;
 
-import java.util.HashSet;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.DefaultParser;
 import org.apache.commons.cli.Options;
@@ -30,7 +29,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import static org.mockito.Mockito.mock;
+import java.util.HashSet;
 
 public class ProducerConnectionSubCommandTest {
 
@@ -64,7 +63,7 @@ public class ProducerConnectionSubCommandTest {
     private ServerResponseMocker startOneBroker() {
         ProducerConnection producerConnection = new ProducerConnection();
         HashSet<Connection> connectionSet = new HashSet<>();
-        Connection connection = mock(Connection.class);
+        Connection connection = new Connection();
         connectionSet.add(connection);
         producerConnection.setConnectionSet(connectionSet);
 
diff --git a/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/ConsumerStatusSubCommandTest.java b/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/ConsumerStatusSubCommandTest.java
index 4651113c68..9f4da15fa3 100644
--- a/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/ConsumerStatusSubCommandTest.java
+++ b/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/ConsumerStatusSubCommandTest.java
@@ -16,7 +16,6 @@
  */
 package org.apache.rocketmq.tools.command.consumer;
 
-import java.util.HashSet;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.DefaultParser;
 import org.apache.commons.cli.Options;
@@ -30,7 +29,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import static org.mockito.Mockito.mock;
+import java.util.HashSet;
 
 public class ConsumerStatusSubCommandTest {
 
@@ -65,7 +64,7 @@ public class ConsumerStatusSubCommandTest {
     private ServerResponseMocker startOneBroker() {
         ConsumerConnection consumerConnection = new ConsumerConnection();
         HashSet<Connection> connectionSet = new HashSet<>();
-        Connection connection = mock(Connection.class);
+        Connection connection = new Connection();
         connectionSet.add(connection);
         consumerConnection.setConnectionSet(connectionSet);
         // start broker
diff --git a/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/GetConsumerConfigSubCommandTest.java b/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/GetConsumerConfigSubCommandTest.java
index e4e5e970c6..7ff4c42851 100644
--- a/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/GetConsumerConfigSubCommandTest.java
+++ b/tools/src/test/java/org/apache/rocketmq/tools/command/consumer/GetConsumerConfigSubCommandTest.java
@@ -16,9 +16,6 @@
  */
 package org.apache.rocketmq.tools.command.consumer;
 
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.DefaultParser;
 import org.apache.commons.cli.Options;
@@ -33,7 +30,9 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import static org.mockito.Mockito.mock;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
 
 public class GetConsumerConfigSubCommandTest {
 
@@ -91,7 +90,7 @@ public class GetConsumerConfigSubCommandTest {
     private ServerResponseMocker startOneBroker() {
         ConsumerConnection consumerConnection = new ConsumerConnection();
         HashSet<Connection> connectionSet = new HashSet<>();
-        Connection connection = mock(Connection.class);
+        Connection connection = new Connection();
         connectionSet.add(connection);
         consumerConnection.setConnectionSet(connectionSet);
         // start broker
diff --git a/tools/src/test/java/org/apache/rocketmq/tools/command/producer/ProducerSubCommandTest.java b/tools/src/test/java/org/apache/rocketmq/tools/command/producer/ProducerSubCommandTest.java
index 7039c05fba..b1ebb924e7 100644
--- a/tools/src/test/java/org/apache/rocketmq/tools/command/producer/ProducerSubCommandTest.java
+++ b/tools/src/test/java/org/apache/rocketmq/tools/command/producer/ProducerSubCommandTest.java
@@ -17,13 +17,12 @@
 
 package org.apache.rocketmq.tools.command.producer;
 
-import java.util.HashMap;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.DefaultParser;
 import org.apache.commons.cli.Options;
-import org.apache.rocketmq.common.message.MessageQueue;
-import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
-import org.apache.rocketmq.remoting.protocol.admin.OffsetWrapper;
+import org.apache.rocketmq.remoting.protocol.LanguageCode;
+import org.apache.rocketmq.remoting.protocol.body.ProducerInfo;
+import org.apache.rocketmq.remoting.protocol.body.ProducerTableInfo;
 import org.apache.rocketmq.srvutil.ServerUtil;
 import org.apache.rocketmq.tools.command.SubCommandException;
 import org.apache.rocketmq.tools.command.server.NameServerMocker;
@@ -32,6 +31,10 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
 public class ProducerSubCommandTest {
     private ServerResponseMocker brokerMocker;
 
@@ -61,21 +64,16 @@ public class ProducerSubCommandTest {
     }
 
     private ServerResponseMocker startOneBroker() {
-        ConsumeStats consumeStats = new ConsumeStats();
-        HashMap<MessageQueue, OffsetWrapper> offsetTable = new HashMap<>();
-        MessageQueue messageQueue = new MessageQueue();
-        messageQueue.setBrokerName("mockBrokerName");
-        messageQueue.setQueueId(1);
-        messageQueue.setBrokerName("mockTopicName");
-
-        OffsetWrapper offsetWrapper = new OffsetWrapper();
-        offsetWrapper.setBrokerOffset(1);
-        offsetWrapper.setConsumerOffset(1);
-        offsetWrapper.setLastTimestamp(System.currentTimeMillis());
+        ProducerTableInfo producerTableInfo = new ProducerTableInfo(new HashMap<>());
+        List<ProducerInfo> producerInfo = new ArrayList<>();
+        producerInfo.add(new ProducerInfo(
+                "xxxx-client-id",
+                "127.0.0.1:18978",
+                LanguageCode.JAVA,
+                400,
+                System.currentTimeMillis()));
 
-        offsetTable.put(messageQueue, offsetWrapper);
-        consumeStats.setOffsetTable(offsetTable);
-        // start broker
-        return ServerResponseMocker.startServer(consumeStats.encode());
+        producerTableInfo.getData().put("mockTopicName", producerInfo);
+        return ServerResponseMocker.startServer(producerTableInfo.encode());
     }
 }