You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by xi...@apache.org on 2022/05/31 08:19:33 UTC

[iotdb] branch master updated: [IOTDB-3316] Add 'SHOW CLUSTER' implementation for IoTDB cluster mode (#6062)

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

xingtanzjr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new b940a652dd [IOTDB-3316] Add 'SHOW CLUSTER' implementation for IoTDB cluster mode (#6062)
b940a652dd is described below

commit b940a652ddb03868428ad8774b18cf08b31d7c73
Author: Beyyes <ca...@apache.org>
AuthorDate: Tue May 31 16:19:28 2022 +0800

    [IOTDB-3316] Add 'SHOW CLUSTER' implementation for IoTDB cluster mode (#6062)
---
 .../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4   |   7 +-
 .../antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4  |   4 +
 .../thrift/ConfigNodeRPCServiceProcessor.java      |  20 ++++
 .../thrift/ConfigNodeRPCServiceProcessorTest.java  |  28 +++++
 .../apache/iotdb/commons/conf/IoTDBConstant.java   |   6 +
 .../apache/iotdb/db/client/ConfigNodeClient.java   |  17 +++
 .../iotdb/db/mpp/common/header/HeaderConstant.java |  22 ++++
 .../apache/iotdb/db/mpp/plan/analyze/Analyzer.java |  10 ++
 .../plan/execution/config/ConfigTaskVisitor.java   |   7 ++
 .../mpp/plan/execution/config/ShowClusterTask.java | 122 +++++++++++++++++++++
 .../iotdb/db/mpp/plan/parser/ASTVisitor.java       |   7 ++
 .../db/mpp/plan/statement/StatementVisitor.java    |   5 +
 .../statement/metadata/ShowClusterStatement.java   |  36 ++++++
 .../src/main/thrift/confignode.thrift              |  10 ++
 14 files changed, 300 insertions(+), 1 deletion(-)

diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index bc8167772e..eae63f02f4 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -43,7 +43,7 @@ ddlStatement
     | dropFunction | dropTrigger | dropContinuousQuery | dropSchemaTemplate
     | setTTL | unsetTTL | startTrigger | stopTrigger | setSchemaTemplate | unsetSchemaTemplate
     | showStorageGroup | showDevices | showTimeseries | showChildPaths | showChildNodes
-    | showFunctions | showTriggers | showContinuousQueries | showTTL | showAllTTL
+    | showFunctions | showTriggers | showContinuousQueries | showTTL | showAllTTL | showCluster
     | showSchemaTemplates | showNodesInSchemaTemplate
     | showPathsUsingSchemaTemplate | showPathsSetSchemaTemplate
     | countStorageGroup | countDevices | countTimeseries | countNodes
@@ -303,6 +303,11 @@ showAllTTL
     : SHOW ALL TTL
     ;
 
+// Show Cluster
+showCluster
+    : SHOW CLUSTER
+    ;
+
 // Show Schema Template
 showSchemaTemplates
     : SHOW SCHEMA? TEMPLATES
diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
index 52b3eaa823..5dc57c5406 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
@@ -117,6 +117,10 @@ CLEAR
     : C L E A R
     ;
 
+CLUSTER
+    : C L U S T E R
+    ;
+
 CONCAT
     : C O N C A T
     ;
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java b/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
index 045a8e3b1f..4a6a8cb6b2 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
@@ -19,6 +19,8 @@
 package org.apache.iotdb.confignode.service.thrift;
 
 import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation;
+import org.apache.iotdb.common.rpc.thrift.TDataNodeInfo;
+import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
 import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.commons.auth.AuthException;
 import org.apache.iotdb.commons.conf.CommonDescriptor;
@@ -53,6 +55,7 @@ import org.apache.iotdb.confignode.rpc.thrift.ConfigIService;
 import org.apache.iotdb.confignode.rpc.thrift.TAuthorizerReq;
 import org.apache.iotdb.confignode.rpc.thrift.TAuthorizerResp;
 import org.apache.iotdb.confignode.rpc.thrift.TCheckUserPrivilegesReq;
+import org.apache.iotdb.confignode.rpc.thrift.TClusterNodeInfos;
 import org.apache.iotdb.confignode.rpc.thrift.TConfigNodeRegisterReq;
 import org.apache.iotdb.confignode.rpc.thrift.TConfigNodeRegisterResp;
 import org.apache.iotdb.confignode.rpc.thrift.TCountStorageGroupResp;
@@ -80,6 +83,7 @@ import org.apache.iotdb.confignode.rpc.thrift.TStorageGroupSchema;
 import org.apache.iotdb.confignode.rpc.thrift.TStorageGroupSchemaResp;
 import org.apache.iotdb.db.mpp.common.schematree.PathPatternTree;
 import org.apache.iotdb.db.qp.logical.sys.AuthorOperator;
+import org.apache.iotdb.rpc.TSStatusCode;
 
 import org.apache.thrift.TException;
 import org.slf4j.Logger;
@@ -90,6 +94,7 @@ import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /** ConfigNodeRPCServer exposes the interface that interacts with the DataNode */
 public class ConfigNodeRPCServiceProcessor implements ConfigIService.Iface {
@@ -137,6 +142,21 @@ public class ConfigNodeRPCServiceProcessor implements ConfigIService.Iface {
     return resp;
   }
 
+  @Override
+  public TClusterNodeInfos getAllClusterNodeInfos() throws TException {
+    List<TConfigNodeLocation> configNodeLocations =
+        configManager.getNodeManager().getOnlineConfigNodes();
+    List<TDataNodeLocation> dataNodeInfoLocations =
+        configManager.getNodeManager().getOnlineDataNodes(-1).stream()
+            .map(TDataNodeInfo::getLocation)
+            .collect(Collectors.toList());
+
+    return new TClusterNodeInfos(
+        new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()),
+        configNodeLocations,
+        dataNodeInfoLocations);
+  }
+
   @Override
   public TSStatus setStorageGroup(TSetStorageGroupReq req) throws TException {
     TStorageGroupSchema storageGroupSchema = req.getStorageGroup();
diff --git a/confignode/src/test/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessorTest.java b/confignode/src/test/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessorTest.java
index 263d7a2472..f0d5f09178 100644
--- a/confignode/src/test/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessorTest.java
+++ b/confignode/src/test/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessorTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.iotdb.confignode.service.thrift;
 
+import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation;
 import org.apache.iotdb.common.rpc.thrift.TConsensusGroupType;
 import org.apache.iotdb.common.rpc.thrift.TDataNodeInfo;
 import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation;
@@ -45,6 +46,7 @@ import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv;
 import org.apache.iotdb.confignode.rpc.thrift.TAuthorizerReq;
 import org.apache.iotdb.confignode.rpc.thrift.TAuthorizerResp;
 import org.apache.iotdb.confignode.rpc.thrift.TCheckUserPrivilegesReq;
+import org.apache.iotdb.confignode.rpc.thrift.TClusterNodeInfos;
 import org.apache.iotdb.confignode.rpc.thrift.TCountStorageGroupResp;
 import org.apache.iotdb.confignode.rpc.thrift.TDataNodeInfoResp;
 import org.apache.iotdb.confignode.rpc.thrift.TDataNodeRegisterReq;
@@ -221,6 +223,32 @@ public class ConfigNodeRPCServiceProcessorTest {
     Assert.assertEquals(dataNodeLocation, infoMap.get(1).getLocation());
   }
 
+  @Test
+  public void getAllClusterNodeInfosTest() throws TException {
+    registerDataNodes();
+
+    TClusterNodeInfos clusterNodes = processor.getAllClusterNodeInfos();
+
+    List<TConfigNodeLocation> configNodeInfos = clusterNodes.getConfigNodeList();
+    Assert.assertEquals(1, configNodeInfos.size());
+    TConfigNodeLocation configNodeLocation =
+        new TConfigNodeLocation(new TEndPoint("0.0.0.0", 22277), new TEndPoint("0.0.0.0", 22278));
+    Assert.assertEquals(configNodeLocation, configNodeInfos.get(0));
+
+    List<TDataNodeLocation> dataNodeInfos = clusterNodes.getDataNodeList();
+    Assert.assertEquals(3, dataNodeInfos.size());
+    TDataNodeLocation dataNodeLocation = new TDataNodeLocation();
+    for (int i = 0; i < 3; i++) {
+      dataNodeLocation.setDataNodeId(i);
+      dataNodeLocation.setExternalEndPoint(new TEndPoint("0.0.0.0", 6667 + i));
+      dataNodeLocation.setInternalEndPoint(new TEndPoint("0.0.0.0", 9003 + i));
+      dataNodeLocation.setDataBlockManagerEndPoint(new TEndPoint("0.0.0.0", 8777 + i));
+      dataNodeLocation.setDataRegionConsensusEndPoint(new TEndPoint("0.0.0.0", 40010 + i));
+      dataNodeLocation.setSchemaRegionConsensusEndPoint(new TEndPoint("0.0.0.0", 50010 + i));
+      Assert.assertEquals(dataNodeLocation, dataNodeInfos.get(i));
+    }
+  }
+
   @Test
   public void testSetAndQueryStorageGroup() throws TException {
     TSStatus status;
diff --git a/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java b/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
index d7e08bcadb..171c6c058f 100644
--- a/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
+++ b/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
@@ -232,6 +232,12 @@ public class IoTDBConstant {
   public static final String WAL_VERSION_ID = "versionId";
   public static final String WAL_START_SEARCH_INDEX = "startSearchIndex";
 
+  // show cluster status
+  public static final String NODE_TYPE_CONFIG_NODE = "ConfigNode";
+  public static final String NODE_TYPE_DATA_NODE = "DataNode";
+  public static final String NODE_STATUS_RUNNING = "Running";
+  public static final String NODE_STATUS_Down = "Down";
+
   // client version number
   public enum ClientVersion {
     V_0_12,
diff --git a/server/src/main/java/org/apache/iotdb/db/client/ConfigNodeClient.java b/server/src/main/java/org/apache/iotdb/db/client/ConfigNodeClient.java
index 563897078d..cef015d09e 100644
--- a/server/src/main/java/org/apache/iotdb/db/client/ConfigNodeClient.java
+++ b/server/src/main/java/org/apache/iotdb/db/client/ConfigNodeClient.java
@@ -33,6 +33,7 @@ import org.apache.iotdb.confignode.rpc.thrift.ConfigIService;
 import org.apache.iotdb.confignode.rpc.thrift.TAuthorizerReq;
 import org.apache.iotdb.confignode.rpc.thrift.TAuthorizerResp;
 import org.apache.iotdb.confignode.rpc.thrift.TCheckUserPrivilegesReq;
+import org.apache.iotdb.confignode.rpc.thrift.TClusterNodeInfos;
 import org.apache.iotdb.confignode.rpc.thrift.TConfigNodeRegisterReq;
 import org.apache.iotdb.confignode.rpc.thrift.TConfigNodeRegisterResp;
 import org.apache.iotdb.confignode.rpc.thrift.TCountStorageGroupResp;
@@ -265,6 +266,22 @@ public class ConfigNodeClient implements ConfigIService.Iface, SyncThriftClient,
     throw new TException(MSG_RECONNECTION_FAIL);
   }
 
+  @Override
+  public TClusterNodeInfos getAllClusterNodeInfos() throws TException {
+    for (int i = 0; i < RETRY_NUM; i++) {
+      try {
+        TClusterNodeInfos resp = client.getAllClusterNodeInfos();
+        if (!updateConfigNodeLeader(resp.status)) {
+          return resp;
+        }
+      } catch (TException e) {
+        configLeader = null;
+      }
+      reconnect();
+    }
+    throw new TException(MSG_RECONNECTION_FAIL);
+  }
+
   @Override
   public TSStatus setStorageGroup(TSetStorageGroupReq req) throws TException {
     for (int i = 0; i < RETRY_NUM; i++) {
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/common/header/HeaderConstant.java b/server/src/main/java/org/apache/iotdb/db/mpp/common/header/HeaderConstant.java
index e9951b13ca..0f2a26469e 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/common/header/HeaderConstant.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/common/header/HeaderConstant.java
@@ -57,6 +57,13 @@ public class HeaderConstant {
   public static final String COLUMN_COUNT_TIMESERIES = "count(timeseries)";
   public static final String COLUMN_COUNT_STORAGE_GROUP = "count(storage group)";
 
+  // column names for show cluster statement
+  public static final String COLUMN_NODE_ID = "NodeID";
+  public static final String COLUMN_NODE_TYPE = "NodeType";
+  public static final String COLUMN_STATUS = "Status";
+  public static final String COLUMN_HOST_ADDRESS = "HostAdress";
+  public static final String COLUMN_PORT = "Port";
+
   // dataset header for schema statement
   public static final DatasetHeader showTimeSeriesHeader;
   public static final DatasetHeader showDevicesHeader;
@@ -73,6 +80,9 @@ public class HeaderConstant {
   public static final DatasetHeader countTimeSeriesHeader;
   public static final DatasetHeader countLevelTimeSeriesHeader;
 
+  // dataset header for show cluster statement
+  public static final DatasetHeader showClusterHeader;
+
   // dataset header for last query
   public static final DatasetHeader LAST_QUERY_HEADER;
 
@@ -160,4 +170,16 @@ public class HeaderConstant {
                 new ColumnHeader(COLUMN_TIMESERIES_DATATYPE, TSDataType.TEXT)),
             false);
   }
+
+  static {
+    showClusterHeader =
+        new DatasetHeader(
+            Arrays.asList(
+                new ColumnHeader(COLUMN_NODE_ID, TSDataType.INT32),
+                new ColumnHeader(COLUMN_NODE_TYPE, TSDataType.TEXT),
+                new ColumnHeader(COLUMN_STATUS, TSDataType.TEXT),
+                new ColumnHeader(COLUMN_HOST_ADDRESS, TSDataType.TEXT),
+                new ColumnHeader(COLUMN_PORT, TSDataType.INT32)),
+            true);
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analyzer.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analyzer.java
index e81ae8cca2..0b3dcf578e 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analyzer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analyzer.java
@@ -72,6 +72,7 @@ import org.apache.iotdb.db.mpp.plan.statement.metadata.CreateTimeSeriesByDeviceS
 import org.apache.iotdb.db.mpp.plan.statement.metadata.CreateTimeSeriesStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowChildNodesStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowChildPathsStatement;
+import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowClusterStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowDevicesStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowStorageGroupStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowTTLStatement;
@@ -1209,6 +1210,15 @@ public class Analyzer {
       return analysis;
     }
 
+    @Override
+    public Analysis visitShowCluster(
+        ShowClusterStatement showClusterStatement, MPPQueryContext context) {
+      Analysis analysis = new Analysis();
+      analysis.setStatement(showClusterStatement);
+      analysis.setRespDatasetHeader(HeaderConstant.showClusterHeader);
+      return analysis;
+    }
+
     @Override
     public Analysis visitCountStorageGroup(
         CountStorageGroupStatement countStorageGroupStatement, MPPQueryContext context) {
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigTaskVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigTaskVisitor.java
index 7e6038049b..9ef88cd17b 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigTaskVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigTaskVisitor.java
@@ -28,6 +28,7 @@ import org.apache.iotdb.db.mpp.plan.statement.metadata.DeleteStorageGroupStateme
 import org.apache.iotdb.db.mpp.plan.statement.metadata.DropFunctionStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.SetStorageGroupStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.SetTTLStatement;
+import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowClusterStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowStorageGroupStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowTTLStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.UnSetTTLStatement;
@@ -86,6 +87,12 @@ public class ConfigTaskVisitor
     return new ShowTTLTask(showTTLStatement);
   }
 
+  @Override
+  public IConfigTask visitShowCluster(
+      ShowClusterStatement showClusterStatement, TaskContext context) {
+    return new ShowClusterTask(showClusterStatement);
+  }
+
   @Override
   public IConfigTask visitAuthor(AuthorStatement statement, TaskContext context) {
     return new AuthorizerConfigTask(statement);
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ShowClusterTask.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ShowClusterTask.java
new file mode 100644
index 0000000000..1be47b1c9d
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ShowClusterTask.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.iotdb.db.mpp.plan.execution.config;
+
+import org.apache.iotdb.commons.client.IClientManager;
+import org.apache.iotdb.commons.consensus.PartitionRegionId;
+import org.apache.iotdb.confignode.rpc.thrift.TClusterNodeInfos;
+import org.apache.iotdb.db.client.ConfigNodeClient;
+import org.apache.iotdb.db.client.ConfigNodeInfo;
+import org.apache.iotdb.db.conf.IoTDBConfig;
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.mpp.common.header.DatasetHeader;
+import org.apache.iotdb.db.mpp.common.header.HeaderConstant;
+import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowClusterStatement;
+import org.apache.iotdb.rpc.TSStatusCode;
+import org.apache.iotdb.tsfile.read.common.block.TsBlockBuilder;
+import org.apache.iotdb.tsfile.utils.Binary;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import org.apache.thrift.TException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.apache.iotdb.commons.conf.IoTDBConstant.NODE_STATUS_RUNNING;
+import static org.apache.iotdb.commons.conf.IoTDBConstant.NODE_TYPE_CONFIG_NODE;
+import static org.apache.iotdb.commons.conf.IoTDBConstant.NODE_TYPE_DATA_NODE;
+
+public class ShowClusterTask implements IConfigTask {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(ShowClusterTask.class);
+
+  private static final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig();
+
+  public ShowClusterTask(ShowClusterStatement showClusterStatement) {}
+
+  @Override
+  public ListenableFuture<ConfigTaskResult> execute(
+      IClientManager<PartitionRegionId, ConfigNodeClient> clientManager)
+      throws InterruptedException {
+    SettableFuture<ConfigTaskResult> future = SettableFuture.create();
+    TClusterNodeInfos clusterNodeInfos = new TClusterNodeInfos();
+
+    if (config.isClusterMode()) {
+      try (ConfigNodeClient client = clientManager.borrowClient(ConfigNodeInfo.partitionRegionId)) {
+        clusterNodeInfos = client.getAllClusterNodeInfos();
+      } catch (TException | IOException e) {
+        LOGGER.error("Failed to connect to config node.");
+        future.setException(e);
+      }
+    }
+
+    // build TSBlock
+    TsBlockBuilder builder =
+        new TsBlockBuilder(HeaderConstant.showClusterHeader.getRespDataTypes());
+
+    AtomicInteger configNodeId = new AtomicInteger();
+    clusterNodeInfos
+        .getConfigNodeList()
+        .forEach(
+            e ->
+                buildTsBlock(
+                    builder,
+                    configNodeId.getAndIncrement(),
+                    NODE_TYPE_CONFIG_NODE,
+                    NODE_STATUS_RUNNING,
+                    e.getInternalEndPoint().getIp(),
+                    e.getInternalEndPoint().getPort()));
+
+    clusterNodeInfos
+        .getDataNodeList()
+        .forEach(
+            e ->
+                buildTsBlock(
+                    builder,
+                    e.getDataNodeId(),
+                    NODE_TYPE_DATA_NODE,
+                    NODE_STATUS_RUNNING,
+                    e.getInternalEndPoint().getIp(),
+                    e.getInternalEndPoint().getPort()));
+
+    DatasetHeader datasetHeader = HeaderConstant.showClusterHeader;
+    future.set(new ConfigTaskResult(TSStatusCode.SUCCESS_STATUS, builder.build(), datasetHeader));
+    return future;
+  }
+
+  private void buildTsBlock(
+      TsBlockBuilder builder,
+      int nodeId,
+      String nodeType,
+      String nodeStatus,
+      String hostAddress,
+      int port) {
+    builder.getTimeColumnBuilder().writeLong(0L);
+    builder.getColumnBuilder(0).writeInt(nodeId);
+    builder.getColumnBuilder(1).writeBinary(new Binary(nodeType));
+    builder.getColumnBuilder(2).writeBinary(new Binary(nodeStatus));
+    builder.getColumnBuilder(3).writeBinary(new Binary(hostAddress));
+    builder.getColumnBuilder(4).writeInt(port);
+    builder.declarePosition();
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
index 890dac8d9c..ced604bfbf 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
@@ -90,6 +90,7 @@ import org.apache.iotdb.db.mpp.plan.statement.metadata.SetStorageGroupStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.SetTTLStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowChildNodesStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowChildPathsStatement;
+import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowClusterStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowDevicesStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowStorageGroupStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowTTLStatement;
@@ -1762,6 +1763,12 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
     return showTTLStatement;
   }
 
+  @Override
+  public Statement visitShowCluster(IoTDBSqlParser.ShowClusterContext ctx) {
+    ShowClusterStatement showClusterStatement = new ShowClusterStatement();
+    return showClusterStatement;
+  }
+
   @Override
   public Statement visitDeleteStorageGroup(IoTDBSqlParser.DeleteStorageGroupContext ctx) {
     DeleteStorageGroupStatement deleteStorageGroupStatement = new DeleteStorageGroupStatement();
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/StatementVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/StatementVisitor.java
index 44f7b0919c..adadae7760 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/StatementVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/StatementVisitor.java
@@ -47,6 +47,7 @@ import org.apache.iotdb.db.mpp.plan.statement.metadata.SetStorageGroupStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.SetTTLStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowChildNodesStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowChildPathsStatement;
+import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowClusterStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowDevicesStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowStorageGroupStatement;
 import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowTTLStatement;
@@ -131,6 +132,10 @@ public abstract class StatementVisitor<R, C> {
     return visitStatement(showTTLStatement, context);
   }
 
+  public R visitShowCluster(ShowClusterStatement showClusterStatement, C context) {
+    return visitStatement(showClusterStatement, context);
+  }
+
   // UDF
   public R visitCreateFunction(CreateFunctionStatement createFunctionStatement, C context) {
     return visitStatement(createFunctionStatement, context);
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/ShowClusterStatement.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/ShowClusterStatement.java
new file mode 100644
index 0000000000..0f356b7f03
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/ShowClusterStatement.java
@@ -0,0 +1,36 @@
+/*
+ * 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.iotdb.db.mpp.plan.statement.metadata;
+
+import org.apache.iotdb.db.mpp.plan.analyze.QueryType;
+import org.apache.iotdb.db.mpp.plan.statement.IConfigStatement;
+import org.apache.iotdb.db.mpp.plan.statement.StatementVisitor;
+
+public class ShowClusterStatement extends ShowStatement implements IConfigStatement {
+
+  @Override
+  public QueryType getQueryType() {
+    return QueryType.READ;
+  }
+
+  @Override
+  public <R, C> R accept(StatementVisitor<R, C> visitor, C context) {
+    return visitor.visitShowCluster(this, context);
+  }
+}
diff --git a/thrift-confignode/src/main/thrift/confignode.thrift b/thrift-confignode/src/main/thrift/confignode.thrift
index 3bba5e3bc5..8719cb98a3 100644
--- a/thrift-confignode/src/main/thrift/confignode.thrift
+++ b/thrift-confignode/src/main/thrift/confignode.thrift
@@ -208,6 +208,13 @@ struct TConfigNodeRegisterResp {
   3: optional list<common.TConfigNodeLocation> configNodeList
 }
 
+// Show cluster
+struct TClusterNodeInfos {
+  1: required common.TSStatus status
+  2: required list<common.TConfigNodeLocation> configNodeList
+  3: required list<common.TDataNodeLocation> dataNodeList
+}
+
 // UDF
 struct TCreateFunctionReq {
   1: required string udfName
@@ -227,6 +234,9 @@ service ConfigIService {
 
   TDataNodeInfoResp getDataNodeInfo(i32 dataNodeId)
 
+  /* Show Cluster */
+  TClusterNodeInfos getAllClusterNodeInfos()
+
   /* StorageGroup */
 
   common.TSStatus setStorageGroup(TSetStorageGroupReq req)