You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2019/05/13 03:45:27 UTC

[skywalking] 01/01: Make backend fits new topology query protocol and logic.

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

wusheng pushed a commit to branch new-topo
in repository https://gitbox.apache.org/repos/asf/skywalking.git

commit 3174d4f6a3c7e0547a4c5dba351929c36862159c
Author: Wu Sheng <wu...@foxmail.com>
AuthorDate: Mon May 13 11:45:11 2019 +0800

    Make backend fits new topology query protocol and logic.
---
 .../skywalking/apm/toolkit/trace/TraceContext.java |  2 +-
 .../apm/network/trace/component/Component.java     |  2 +-
 .../apm/agent/core/context/trace/AbstractSpan.java |  2 +-
 .../core/context/trace/AbstractTracingSpan.java    |  4 +-
 .../apm/agent/core/logging/api/ILog.java           |  2 +-
 .../apm/agent/core/logging/api/LogManager.java     |  2 +-
 .../http/v9/DefaultHttpClientInterceptor.java      |  2 +-
 .../apm/plugin/okhttp/v3/RealCallInterceptor.java  |  2 +-
 docker/config/component-libraries.yml              |  6 +-
 docs/en/guides/Java-Plugin-Development-Guide.md    |  4 +-
 .../ServiceRelationClientSideMetrics.java          |  5 +-
 .../servicerelation/ServiceRelationDefineUtil.java | 55 +++++++++++++++++++
 .../ServiceRelationServerSideMetrics.java          |  5 +-
 .../config/ComponentLibraryCatalogService.java     | 10 ++--
 .../oap/server/core/query/TopologyBuilder.java     | 46 +++++++++-------
 .../server/core/query/TopologyQueryService.java    | 26 +++++----
 .../oap/server/core/query/entity/Call.java         | 64 ++++++++++++++++++++--
 .../oap/server/core/source/ServiceRelation.java    | 22 +-------
 .../core/storage/query/ITopologyQueryDAO.java      | 10 ++--
 .../src/test/resources/component-libraries.yml     |  6 +-
 .../src/main/resources/query-protocol              |  2 +-
 .../receiver/mesh/TelemetryDataDispatcher.java     |  6 +-
 .../parser/standardization/SpanIdExchanger.java    |  2 +-
 .../src/main/resources/component-libraries.yml     |  6 +-
 .../elasticsearch/query/TopologyQueryEsDAO.java    | 39 ++++++-------
 .../plugin/jdbc/h2/dao/H2TopologyQueryDAO.java     | 54 +++++++++---------
 26 files changed, 241 insertions(+), 145 deletions(-)

diff --git a/apm-application-toolkit/apm-toolkit-trace/src/main/java/org/apache/skywalking/apm/toolkit/trace/TraceContext.java b/apm-application-toolkit/apm-toolkit-trace/src/main/java/org/apache/skywalking/apm/toolkit/trace/TraceContext.java
index a890b6f..868caec 100644
--- a/apm-application-toolkit/apm-toolkit-trace/src/main/java/org/apache/skywalking/apm/toolkit/trace/TraceContext.java
+++ b/apm-application-toolkit/apm-toolkit-trace/src/main/java/org/apache/skywalking/apm/toolkit/trace/TraceContext.java
@@ -22,7 +22,7 @@ package org.apache.skywalking.apm.toolkit.trace;
 /**
  * Try to access the sky-walking tracer context.
  * The context is not existed, always.
- * only the middleware, component, or rpc-framework are supported in the current invoke stack, in the same thread,
+ * only the middleware, componentId, or rpc-framework are supported in the current invoke stack, in the same thread,
  * the context will be available.
  * <p>
  * Created by xin on 2016/12/15.
diff --git a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/Component.java b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/Component.java
index b2f118d..18ab8e5 100644
--- a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/Component.java
+++ b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/Component.java
@@ -20,7 +20,7 @@
 package org.apache.skywalking.apm.network.trace.component;
 
 /**
- * The <code>Component</code> represents component library,
+ * The <code>Component</code> represents componentId library,
  * which has been supported by skywalking sniffer.
  *
  * The supported list is in {@link ComponentsDefine}.
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractSpan.java
index 4353a30..22f8610 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractSpan.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractSpan.java
@@ -31,7 +31,7 @@ import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
  */
 public interface AbstractSpan extends AsyncSpan {
     /**
-     * Set the component id, which defines in {@link ComponentsDefine}
+     * Set the componentId id, which defines in {@link ComponentsDefine}
      *
      * @param component
      * @return the span for chaining.
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java
index 4c14aa2..75e3333 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/AbstractTracingSpan.java
@@ -234,7 +234,7 @@ public abstract class AbstractTracingSpan implements AbstractSpan {
     }
 
     /**
-     * Set the component of this span, with internal supported. Highly recommend to use this way.
+     * Set the componentId of this span, with internal supported. Highly recommend to use this way.
      *
      * @param component
      * @return span instance, for chaining.
@@ -246,7 +246,7 @@ public abstract class AbstractTracingSpan implements AbstractSpan {
     }
 
     /**
-     * Set the component name. By using this, cost more memory and network.
+     * Set the componentId name. By using this, cost more memory and network.
      *
      * @param componentName
      * @return span instance, for chaining.
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/logging/api/ILog.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/logging/api/ILog.java
index 5c4d496..b7cabce 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/logging/api/ILog.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/logging/api/ILog.java
@@ -21,7 +21,7 @@ package org.apache.skywalking.apm.agent.core.logging.api;
 
 /**
  * The Log interface.
- * It's very easy to understand, like any other log-component.
+ * It's very easy to understand, like any other log-componentId.
  * Do just like log4j or log4j2 does.
  * <p>
  * Created by xin on 2016/11/10.
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/logging/api/LogManager.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/logging/api/LogManager.java
index 8adf888..ea1e264 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/logging/api/LogManager.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/logging/api/LogManager.java
@@ -24,7 +24,7 @@ import org.apache.skywalking.apm.agent.core.logging.core.EasyLogResolver;
 /**
  * LogManager is the {@link LogResolver} implementation manager. By using {@link LogResolver}, {@link
  * LogManager#getLogger(Class)} returns a {@link ILog} implementation. This module use this class as the main entrance,
- * and block the implementation detail about log-component. In different modules, like server or sniffer, it will use
+ * and block the implementation detail about log-componentId. In different modules, like server or sniffer, it will use
  * different implementations. <p> If no {@link LogResolver} is registered, return {@link NoopLogger#INSTANCE} to avoid
  * {@link NullPointerException}. If {@link LogManager#setLogResolver(LogResolver)} is called twice, the second will
  * override the first without any warning or exception. <p> Created by xin on 2016/11/10.
diff --git a/apm-sniffer/apm-sdk-plugin/feign-default-http-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/feign/http/v9/DefaultHttpClientInterceptor.java b/apm-sniffer/apm-sdk-plugin/feign-default-http-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/feign/http/v9/DefaultHttpClientInterceptor.java
index eef05b7..f59c260 100644
--- a/apm-sniffer/apm-sdk-plugin/feign-default-http-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/feign/http/v9/DefaultHttpClientInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/feign-default-http-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/feign/http/v9/DefaultHttpClientInterceptor.java
@@ -52,7 +52,7 @@ public class DefaultHttpClientInterceptor implements InstanceMethodsAroundInterc
 
     /**
      * Get the {@link feign.Request} from {@link EnhancedInstance}, then create {@link AbstractSpan} and set host, port,
-     * kind, component, url from {@link feign.Request}. Through the reflection of the way, set the http header of
+     * kind, componentId, url from {@link feign.Request}. Through the reflection of the way, set the http header of
      * context data into {@link feign.Request#headers}.
      *
      * @param method
diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v3/RealCallInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v3/RealCallInterceptor.java
index d9a9ae7..0b7e079 100644
--- a/apm-sniffer/apm-sdk-plugin/okhttp-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v3/RealCallInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/okhttp-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v3/RealCallInterceptor.java
@@ -52,7 +52,7 @@ public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, In
 
     /**
      * Get the {@link okhttp3.Request} from {@link EnhancedInstance}, then create {@link AbstractSpan} and set host,
-     * port, kind, component, url from {@link okhttp3.Request}.
+     * port, kind, componentId, url from {@link okhttp3.Request}.
      * Through the reflection of the way, set the http header of context data into {@link okhttp3.Request#headers}.
      *
      * @param method
diff --git a/docker/config/component-libraries.yml b/docker/config/component-libraries.yml
index 767e636..88fc167 100644
--- a/docker/config/component-libraries.yml
+++ b/docker/config/component-libraries.yml
@@ -14,8 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Define all component libraries' names and IDs, used in monitored application.
-# This is a bothway mapping, agent or SDK could use the value(ID) to represent the component name in uplink data.
+# Define all componentId libraries' names and IDs, used in monitored application.
+# This is a bothway mapping, agent or SDK could use the value(ID) to represent the componentId name in uplink data.
 #
 # ######
 #   id
@@ -28,7 +28,7 @@
 # ######
 # languages
 # ######
-# Languages declare which languages are using this component. Multi languages should be separated by `,`
+# Languages declare which languages are using this componentId. Multi languages should be separated by `,`
 
 Tomcat:
   id: 1
diff --git a/docs/en/guides/Java-Plugin-Development-Guide.md b/docs/en/guides/Java-Plugin-Development-Guide.md
index 4d57a8b..ffba686 100644
--- a/docs/en/guides/Java-Plugin-Development-Guide.md
+++ b/docs/en/guides/Java-Plugin-Development-Guide.md
@@ -96,9 +96,9 @@ Create ExitSpan by operation name(e.g. service name, uri) and new **ContextCarri
 ### AbstractSpan
 ```java
     /**
-     * Set the component id, which defines in {@link ComponentsDefine}
+     *componentId{@link ComponentsDefine}
      *
-     * @param component
+     * @param componentId
      * @return the span for chaining.
      */
     AbstractSpan setComponent(Component component);
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/servicerelation/ServiceRelationClientSideMetrics.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/servicerelation/ServiceRelationClientSideMetrics.java
index 6b815c5..a12384c 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/servicerelation/ServiceRelationClientSideMetrics.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/servicerelation/ServiceRelationClientSideMetrics.java
@@ -46,9 +46,8 @@ public class ServiceRelationClientSideMetrics extends Metrics {
 
     @Override public String id() {
         String splitJointId = String.valueOf(getTimeBucket());
-        splitJointId += Const.ID_SPLIT + String.valueOf(sourceServiceId);
-        splitJointId += Const.ID_SPLIT + String.valueOf(destServiceId);
-        splitJointId += Const.ID_SPLIT + String.valueOf(componentId);
+        splitJointId += Const.ID_SPLIT + ServiceRelationDefineUtil.buildEntityId(
+            new ServiceRelationDefineUtil.RelationDefine(sourceServiceId, destServiceId, componentId));
         return splitJointId;
     }
 
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/servicerelation/ServiceRelationDefineUtil.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/servicerelation/ServiceRelationDefineUtil.java
new file mode 100644
index 0000000..d74e2a3
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/servicerelation/ServiceRelationDefineUtil.java
@@ -0,0 +1,55 @@
+/*
+ * 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.skywalking.oap.server.core.analysis.manual.servicerelation;
+
+import lombok.Getter;
+import org.apache.skywalking.oap.server.core.Const;
+
+public class ServiceRelationDefineUtil {
+    public static String buildEntityId(RelationDefine define) {
+        return String.valueOf(define.source)
+            + Const.ID_SPLIT + String.valueOf(define.dest)
+            + Const.ID_SPLIT + String.valueOf(define.componentId);
+    }
+
+    /**
+     * @param entityId
+     * @return 1. sourceServiceId 2. destServiceId 3. componentId
+     */
+    public static RelationDefine splitEntityId(String entityId) {
+        String[] parts = entityId.split(Const.ID_SPLIT);
+        if (parts.length != 3) {
+            throw new RuntimeException("Illegal ServiceRelation eneity id");
+        }
+        return new RelationDefine(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), Integer.parseInt(parts[2]));
+    }
+
+    @Getter
+    public static class RelationDefine {
+        private int source;
+        private int dest;
+        private int componentId;
+
+        public RelationDefine(int source, int dest, int componentId) {
+            this.source = source;
+            this.dest = dest;
+            this.componentId = componentId;
+        }
+    }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/servicerelation/ServiceRelationServerSideMetrics.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/servicerelation/ServiceRelationServerSideMetrics.java
index 2257653..563a0d9 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/servicerelation/ServiceRelationServerSideMetrics.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/manual/servicerelation/ServiceRelationServerSideMetrics.java
@@ -47,9 +47,8 @@ public class ServiceRelationServerSideMetrics extends Metrics {
 
     @Override public String id() {
         String splitJointId = String.valueOf(getTimeBucket());
-        splitJointId += Const.ID_SPLIT + String.valueOf(sourceServiceId);
-        splitJointId += Const.ID_SPLIT + String.valueOf(destServiceId);
-        splitJointId += Const.ID_SPLIT + String.valueOf(componentId);
+        splitJointId += Const.ID_SPLIT + ServiceRelationDefineUtil.buildEntityId(
+            new ServiceRelationDefineUtil.RelationDefine(sourceServiceId, destServiceId, componentId));
         return splitJointId;
     }
 
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/ComponentLibraryCatalogService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/ComponentLibraryCatalogService.java
index 9e0b383..0e6150d 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/ComponentLibraryCatalogService.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/ComponentLibraryCatalogService.java
@@ -26,8 +26,8 @@ import org.slf4j.*;
 import org.yaml.snakeyaml.Yaml;
 
 /**
- * Load settings from component-libraries.yml
- * this file includes all component defines, and the component mappings, which declare the real server type based on client component.
+ * Load settings from componentId-libraries.yml
+ * this file includes all componentId defines, and the componentId mappings, which declare the real server type based on client componentId.
  *
  * @author wusheng
  */
@@ -95,17 +95,17 @@ public class ComponentLibraryCatalogService implements IComponentLibraryCatalogS
 
             nameMapping.forEach((name, serverName) -> {
                 if (!componentName2Id.containsKey(name)) {
-                    throw new InitialComponentCatalogException("Component name [" + name + "] in Component-Server-Mappings doesn't exist in component define. ");
+                    throw new InitialComponentCatalogException("Component name [" + name + "] in Component-Server-Mappings doesn't exist in componentId define. ");
                 }
                 if (!componentName2Id.containsKey(serverName)) {
-                    throw new InitialComponentCatalogException("Server component name [" + serverName + "] in Component-Server-Mappings doesn't exist in component define. ");
+                    throw new InitialComponentCatalogException("Server componentId name [" + serverName + "] in Component-Server-Mappings doesn't exist in componentId define. ");
                 }
 
                 componentId2ServerId.put(componentName2Id.get(name), componentName2Id.get(serverName));
             });
             nameMapping.clear();
         } catch (FileNotFoundException e) {
-            logger.error("component-libraries.yml not found.", e);
+            logger.error("componentId-libraries.yml not found.", e);
         }
 
     }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyBuilder.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyBuilder.java
index c9d10f4..17f7dec 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyBuilder.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyBuilder.java
@@ -44,15 +44,15 @@ class TopologyBuilder {
         this.componentLibraryCatalogService = moduleManager.find(CoreModule.NAME).provider().getService(IComponentLibraryCatalogService.class);
     }
 
-    Topology build(List<Call> serviceRelationClientCalls, List<Call> serviceRelationServerCalls) {
+    Topology build(List<Call.CallDetail> serviceRelationClientCalls, List<Call.CallDetail> serviceRelationServerCalls) {
         filterZeroSourceOrTargetReference(serviceRelationClientCalls);
         filterZeroSourceOrTargetReference(serviceRelationServerCalls);
 
         Map<Integer, Node> nodes = new HashMap<>();
         List<Call> calls = new LinkedList<>();
-        Set<String> callIds = new HashSet<>();
+        HashMap<String, Call> callMap = new HashMap<>();
 
-        for (Call clientCall : serviceRelationClientCalls) {
+        for (Call.CallDetail clientCall : serviceRelationClientCalls) {
             ServiceInventory source = serviceInventoryCache.get(clientCall.getSource());
             ServiceInventory target = serviceInventoryCache.get(clientCall.getTarget());
 
@@ -72,20 +72,25 @@ class TopologyBuilder {
             }
 
             String callId = source.getSequence() + Const.ID_SPLIT + target.getSequence();
-            if (!callIds.contains(callId)) {
-                callIds.add(callId);
-
+            if (!callMap.containsKey(callId)) {
                 Call call = new Call();
+
+                callMap.put(callId, call);
+
                 call.setSource(clientCall.getSource());
                 call.setTarget(clientCall.getTarget());
                 call.setId(clientCall.getId());
-                call.setDetectPoint(DetectPoint.CLIENT);
-                call.setCallType(componentLibraryCatalogService.getComponentName(clientCall.getComponentId()));
+                call.addDetectPoint(DetectPoint.CLIENT);
+                call.addSourceComponent(componentLibraryCatalogService.getComponentName(clientCall.getComponentId()));
                 calls.add(call);
+            } else {
+                Call call = callMap.get(callId);
+                call.addDetectPoint(DetectPoint.CLIENT);
+                call.addSourceComponent(componentLibraryCatalogService.getComponentName(clientCall.getComponentId()));
             }
         }
 
-        for (Call serverCall : serviceRelationServerCalls) {
+        for (Call.CallDetail serverCall : serviceRelationServerCalls) {
             ServiceInventory source = serviceInventoryCache.get(serverCall.getSource());
             ServiceInventory target = serviceInventoryCache.get(serverCall.getTarget());
 
@@ -112,21 +117,22 @@ class TopologyBuilder {
             }
 
             String callId = source.getSequence() + Const.ID_SPLIT + target.getSequence();
-            if (!callIds.contains(callId)) {
-                callIds.add(callId);
-
+            if (!callMap.containsKey(callId)) {
                 Call call = new Call();
+                callMap.put(callId, call);
+
                 call.setSource(serverCall.getSource());
                 call.setTarget(serverCall.getTarget());
                 call.setId(serverCall.getId());
-                call.setDetectPoint(DetectPoint.SERVER);
+                call.addDetectPoint(DetectPoint.SERVER);
+                call.addTargetComponent(componentLibraryCatalogService.getComponentName(serverCall.getComponentId()));
+
                 calls.add(call);
+            } else {
+                Call call = callMap.get(callId);
 
-                if (source.getSequence() == Const.USER_SERVICE_ID) {
-                    call.setCallType(Const.EMPTY_STRING);
-                } else {
-                    call.setCallType(componentLibraryCatalogService.getComponentName(serverCall.getComponentId()));
-                }
+                call.addDetectPoint(DetectPoint.SERVER);
+                call.addTargetComponent(componentLibraryCatalogService.getComponentName(serverCall.getComponentId()));
             }
 
             if (!nodes.containsKey(source.getSequence())) {
@@ -160,9 +166,9 @@ class TopologyBuilder {
         return serviceNode;
     }
 
-    private void filterZeroSourceOrTargetReference(List<Call> serviceRelationClientCalls) {
+    private void filterZeroSourceOrTargetReference(List<Call.CallDetail> serviceRelationClientCalls) {
         for (int i = serviceRelationClientCalls.size() - 1; i >= 0; i--) {
-            Call call = serviceRelationClientCalls.get(i);
+            Call.CallDetail call = serviceRelationClientCalls.get(i);
             if (call.getSource() == 0 || call.getTarget() == 0) {
                 serviceRelationClientCalls.remove(i);
             }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyQueryService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyQueryService.java
index 667941b..6b506a0 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyQueryService.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopologyQueryService.java
@@ -81,8 +81,8 @@ public class TopologyQueryService implements Service {
     public Topology getGlobalTopology(final Step step, final long startTB, final long endTB, final long startTimestamp,
         final long endTimestamp) throws IOException {
         logger.debug("step: {}, startTimeBucket: {}, endTimeBucket: {}", step, startTB, endTB);
-        List<Call> serviceRelationServerCalls = getTopologyQueryDAO().loadServerSideServiceRelations(step, startTB, endTB);
-        List<Call> serviceRelationClientCalls = getTopologyQueryDAO().loadClientSideServiceRelations(step, startTB, endTB);
+        List<Call.CallDetail> serviceRelationServerCalls = getTopologyQueryDAO().loadServerSideServiceRelations(step, startTB, endTB);
+        List<Call.CallDetail> serviceRelationClientCalls = getTopologyQueryDAO().loadClientSideServiceRelations(step, startTB, endTB);
 
         TopologyBuilder builder = new TopologyBuilder(moduleManager);
         Topology topology = builder.build(serviceRelationClientCalls, serviceRelationServerCalls);
@@ -95,8 +95,8 @@ public class TopologyQueryService implements Service {
         List<Integer> serviceIds = new ArrayList<>();
         serviceIds.add(serviceId);
 
-        List<Call> serviceRelationClientCalls = getTopologyQueryDAO().loadSpecifiedClientSideServiceRelations(step, startTB, endTB, serviceIds);
-        List<Call> serviceRelationServerCalls = getTopologyQueryDAO().loadSpecifiedServerSideServiceRelations(step, startTB, endTB, serviceIds);
+        List<Call.CallDetail> serviceRelationClientCalls = getTopologyQueryDAO().loadSpecifiedClientSideServiceRelations(step, startTB, endTB, serviceIds);
+        List<Call.CallDetail> serviceRelationServerCalls = getTopologyQueryDAO().loadSpecifiedServerSideServiceRelations(step, startTB, endTB, serviceIds);
 
         TopologyBuilder builder = new TopologyBuilder(moduleManager);
         Topology topology = builder.build(serviceRelationClientCalls, serviceRelationServerCalls);
@@ -104,10 +104,10 @@ public class TopologyQueryService implements Service {
         List<Integer> sourceServiceIds = new ArrayList<>();
         serviceRelationClientCalls.forEach(call -> sourceServiceIds.add(call.getSource()));
         if (CollectionUtils.isNotEmpty(sourceServiceIds)) {
-            List<Call> sourceCalls = getTopologyQueryDAO().loadSpecifiedServerSideServiceRelations(step, startTB, endTB, sourceServiceIds);
+            List<Call.CallDetail> sourceCalls = getTopologyQueryDAO().loadSpecifiedServerSideServiceRelations(step, startTB, endTB, sourceServiceIds);
             topology.getNodes().forEach(node -> {
                 if (Strings.isNullOrEmpty(node.getType())) {
-                    for (Call call : sourceCalls) {
+                    for (Call.CallDetail call : sourceCalls) {
                         if (node.getId() == call.getTarget()) {
                             node.setType(getComponentLibraryCatalogService().getComponentName(call.getComponentId()));
                             break;
@@ -122,13 +122,17 @@ public class TopologyQueryService implements Service {
 
     public Topology getEndpointTopology(final Step step, final long startTB, final long endTB,
         final int endpointId) throws IOException {
-        List<Call> serverSideCalls = getTopologyQueryDAO().loadSpecifiedDestOfServerSideEndpointRelations(step, startTB, endTB, endpointId);
-        serverSideCalls.forEach(call -> call.setDetectPoint(DetectPoint.SERVER));
-
-        serverSideCalls.forEach(call -> call.setCallType(Const.EMPTY_STRING));
+        List<Call.CallDetail> serverSideCalls = getTopologyQueryDAO().loadSpecifiedDestOfServerSideEndpointRelations(step, startTB, endTB, endpointId);
 
         Topology topology = new Topology();
-        topology.getCalls().addAll(serverSideCalls);
+        serverSideCalls.forEach(callDetail -> {
+            Call call = new Call();
+            call.setId(callDetail.getId());
+            call.setSource(callDetail.getSource());
+            call.setTarget(callDetail.getTarget());
+            call.addDetectPoint(DetectPoint.SERVER);
+
+        });
 
         Set<Integer> nodeIds = new HashSet<>();
         serverSideCalls.forEach(call -> {
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/Call.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/Call.java
index 650ef18..1b42582 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/Call.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/entity/Call.java
@@ -18,6 +18,7 @@
 
 package org.apache.skywalking.oap.server.core.query.entity;
 
+import java.util.*;
 import lombok.*;
 import org.apache.skywalking.oap.server.core.source.DetectPoint;
 
@@ -27,10 +28,63 @@ import org.apache.skywalking.oap.server.core.source.DetectPoint;
 @Getter
 @Setter
 public class Call {
-    private int source;
-    private int target;
-    private int componentId;
-    private String callType;
+    private Integer source;
+    private Integer target;
+    private List<String> sourceComponents;
+    private List<String> targetComponents;
     private String id;
-    private DetectPoint detectPoint;
+    private List<DetectPoint> detectPoints;
+
+    private List<Integer> sourceComponentIDs;
+    private List<Integer> targetComponentIDs;
+
+    public Call() {
+        sourceComponents = new ArrayList<>();
+        targetComponents = new ArrayList<>();
+        detectPoints = new ArrayList<>();
+    }
+
+    public void setSource(int source) {
+        this.source = source;
+    }
+
+    public void setTarget(int target) {
+        this.target = target;
+    }
+
+    public void addSourceComponentId(int componentId) {
+        sourceComponentIDs.add(componentId);
+    }
+
+    public void addTargetComponentId(int componentId) {
+        targetComponentIDs.add(componentId);
+    }
+
+    public void addSourceComponent(String component) {
+        if (!sourceComponents.contains(component)) {
+            sourceComponents.add(component);
+        }
+    }
+
+    public void addTargetComponent(String component) {
+        if (!targetComponents.contains(component)) {
+            targetComponents.add(component);
+        }
+    }
+
+    public void addDetectPoint(DetectPoint point) {
+        if (!detectPoints.contains(point)) {
+            detectPoints.add(point);
+        }
+    }
+
+    @Setter
+    @Getter
+    public static class CallDetail {
+        private String id;
+        private Integer source;
+        private Integer target;
+        private DetectPoint detectPoint;
+        private Integer componentId;
+    }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/ServiceRelation.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/ServiceRelation.java
index 1f0d62b..8f10250 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/ServiceRelation.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/ServiceRelation.java
@@ -34,27 +34,7 @@ public class ServiceRelation extends Source {
     }
 
     @Override public String getEntityId() {
-        return String.valueOf(sourceServiceId) + Const.ID_SPLIT + String.valueOf(destServiceId) + Const.ID_SPLIT + String.valueOf(componentId);
-    }
-
-    public static String buildEntityId(int sourceServiceId, int destServiceId, int componentId) {
-        return String.valueOf(sourceServiceId) + Const.ID_SPLIT + String.valueOf(destServiceId) + Const.ID_SPLIT + String.valueOf(componentId);
-    }
-
-    /**
-     * @param entityId
-     * @return 1. sourceServiceId 2. destServiceId 3. componentId
-     */
-    public static Integer[] splitEntityId(String entityId) {
-        String[] parts = entityId.split(Const.ID_SPLIT);
-        if (parts.length != 3) {
-            throw new RuntimeException("Illegal ServiceRelation eneity id");
-        }
-        Integer[] ids = new Integer[3];
-        ids[0] = Integer.parseInt(parts[0]);
-        ids[1] = Integer.parseInt(parts[1]);
-        ids[2] = Integer.parseInt(parts[2]);
-        return ids;
+        return String.valueOf(sourceServiceId) + Const.ID_SPLIT + String.valueOf(destServiceId);
     }
 
     @Getter @Setter private int sourceServiceId;
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITopologyQueryDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITopologyQueryDAO.java
index b17a7eb..e274dfe 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITopologyQueryDAO.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITopologyQueryDAO.java
@@ -28,16 +28,16 @@ import org.apache.skywalking.oap.server.library.module.Service;
  */
 public interface ITopologyQueryDAO extends Service {
 
-    List<Call> loadSpecifiedServerSideServiceRelations(Step step, long startTB, long endTB,
+    List<Call.CallDetail> loadSpecifiedServerSideServiceRelations(Step step, long startTB, long endTB,
         List<Integer> serviceIds) throws IOException;
 
-    List<Call> loadSpecifiedClientSideServiceRelations(Step step, long startTB, long endTB,
+    List<Call.CallDetail> loadSpecifiedClientSideServiceRelations(Step step, long startTB, long endTB,
         List<Integer> serviceIds) throws IOException;
 
-    List<Call> loadServerSideServiceRelations(Step step, long startTB, long endTB) throws IOException;
+    List<Call.CallDetail> loadServerSideServiceRelations(Step step, long startTB, long endTB) throws IOException;
 
-    List<Call> loadClientSideServiceRelations(Step step, long startTB, long endTB) throws IOException;
+    List<Call.CallDetail> loadClientSideServiceRelations(Step step, long startTB, long endTB) throws IOException;
 
-    List<Call> loadSpecifiedDestOfServerSideEndpointRelations(Step step, long startTB, long endTB,
+    List<Call.CallDetail> loadSpecifiedDestOfServerSideEndpointRelations(Step step, long startTB, long endTB,
         int destEndpointId) throws IOException;
 }
diff --git a/oap-server/server-core/src/test/resources/component-libraries.yml b/oap-server/server-core/src/test/resources/component-libraries.yml
index 86b97dd..4372d0f 100644
--- a/oap-server/server-core/src/test/resources/component-libraries.yml
+++ b/oap-server/server-core/src/test/resources/component-libraries.yml
@@ -14,8 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Define all component libraries' names and IDs, used in monitored application.
-# This is a bothway mapping, agent or SDK could use the value(ID) to represent the component name in uplink data.
+# Define all componentId libraries' names and IDs, used in monitored application.
+# This is a bothway mapping, agent or SDK could use the value(ID) to represent the componentId name in uplink data.
 #
 # ######
 #   id
@@ -28,7 +28,7 @@
 # ######
 # languages
 # ######
-# Languages declare which languages are using this component. Multi languages should be separated by `,`
+# Languages declare which languages are using this componentId. Multi languages should be separated by `,`
 
 Tomcat:
   id: 1
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
index 02ddbfa..6fc9665 160000
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
@@ -1 +1 @@
-Subproject commit 02ddbfa8d84865e1a85a25f49933307970d0ab71
+Subproject commit 6fc96650acc7f539fcdf6d51648525ce93e5fa1a
diff --git a/oap-server/server-receiver-plugin/skywalking-mesh-receiver-plugin/src/main/java/org/apache/skywalking/aop/server/receiver/mesh/TelemetryDataDispatcher.java b/oap-server/server-receiver-plugin/skywalking-mesh-receiver-plugin/src/main/java/org/apache/skywalking/aop/server/receiver/mesh/TelemetryDataDispatcher.java
index 5bcf54b..03742fa 100644
--- a/oap-server/server-receiver-plugin/skywalking-mesh-receiver-plugin/src/main/java/org/apache/skywalking/aop/server/receiver/mesh/TelemetryDataDispatcher.java
+++ b/oap-server/server-receiver-plugin/skywalking-mesh-receiver-plugin/src/main/java/org/apache/skywalking/aop/server/receiver/mesh/TelemetryDataDispatcher.java
@@ -259,14 +259,14 @@ public class TelemetryDataDispatcher {
     private static int protocol2Component(Protocol protocol) {
         switch (protocol) {
             case gRPC:
-                // GRPC in component-libraries.yml
+                // GRPC in componentId-libraries.yml
                 return 23;
             case HTTP:
-                // HTTP in component-libraries.yml
+                // HTTP in componentId-libraries.yml
                 return 49;
             case UNRECOGNIZED:
             default:
-                // RPC in component-libraries.yml
+                // RPC in componentId-libraries.yml
                 return 50;
         }
     }
diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/standardization/SpanIdExchanger.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/standardization/SpanIdExchanger.java
index 42bf56c..77e468c 100644
--- a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/standardization/SpanIdExchanger.java
+++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/standardization/SpanIdExchanger.java
@@ -70,7 +70,7 @@ public class SpanIdExchanger implements IdExchanger<SpanDecorator> {
 
             if (componentId == 0) {
                 if (logger.isDebugEnabled()) {
-                    logger.debug("component: {} in service: {} exchange failed", standardBuilder.getComponent(), serviceId);
+                    logger.debug("componentId: {} in service: {} exchange failed", standardBuilder.getComponent(), serviceId);
                 }
 
                 exchanged = false;
diff --git a/oap-server/server-starter/src/main/resources/component-libraries.yml b/oap-server/server-starter/src/main/resources/component-libraries.yml
index 8759266..81c956c 100644
--- a/oap-server/server-starter/src/main/resources/component-libraries.yml
+++ b/oap-server/server-starter/src/main/resources/component-libraries.yml
@@ -14,8 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Define all component libraries' names and IDs, used in monitored application.
-# This is a bothway mapping, agent or SDK could use the value(ID) to represent the component name in uplink data.
+# Define all componentId libraries' names and IDs, used in monitored application.
+# This is a bothway mapping, agent or SDK could use the value(ID) to represent the componentId name in uplink data.
 #
 # ######
 #   id
@@ -28,7 +28,7 @@
 # ######
 # languages
 # ######
-# Languages declare which languages are using this component. Multi languages should be separated by `,`
+# Languages declare which languages are using this componentId. Multi languages should be separated by `,`
 
 Tomcat:
   id: 1
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TopologyQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TopologyQueryEsDAO.java
index 52d8e26..b3ef528 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TopologyQueryEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TopologyQueryEsDAO.java
@@ -19,25 +19,20 @@
 package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
 import org.apache.skywalking.oap.server.core.UnexpectedException;
+import org.apache.skywalking.oap.server.core.analysis.manual.endpointrelation.EndpointRelationServerSideMetrics;
 import org.apache.skywalking.oap.server.core.analysis.manual.servicerelation.*;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.core.analysis.manual.endpointrelation.EndpointRelationServerSideMetrics;
-import org.apache.skywalking.oap.server.core.analysis.manual.servicerelation.ServiceRelationServerSideMetrics;
-import org.apache.skywalking.oap.server.core.query.entity.Call;
-import org.apache.skywalking.oap.server.core.query.entity.Step;
+import org.apache.skywalking.oap.server.core.query.entity.*;
 import org.apache.skywalking.oap.server.core.source.DetectPoint;
-import org.apache.skywalking.oap.server.core.source.ServiceRelation;
 import org.apache.skywalking.oap.server.core.storage.DownSamplingModelNameBuilder;
 import org.apache.skywalking.oap.server.core.storage.query.ITopologyQueryDAO;
 import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
 import org.apache.skywalking.oap.server.library.util.CollectionUtils;
 import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO;
 import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.index.query.BoolQueryBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.index.query.*;
 import org.elasticsearch.search.aggregations.AggregationBuilders;
 import org.elasticsearch.search.aggregations.bucket.terms.Terms;
 import org.elasticsearch.search.builder.SearchSourceBuilder;
@@ -52,7 +47,7 @@ public class TopologyQueryEsDAO extends EsDAO implements ITopologyQueryDAO {
     }
 
     @Override
-    public List<Call> loadSpecifiedServerSideServiceRelations(Step step, long startTB, long endTB,
+    public List<Call.CallDetail> loadSpecifiedServerSideServiceRelations(Step step, long startTB, long endTB,
         List<Integer> serviceIds) throws IOException {
         if (CollectionUtils.isEmpty(serviceIds)) {
             throw new UnexpectedException("Service id is empty");
@@ -67,7 +62,7 @@ public class TopologyQueryEsDAO extends EsDAO implements ITopologyQueryDAO {
     }
 
     @Override
-    public List<Call> loadSpecifiedClientSideServiceRelations(Step step, long startTB, long endTB,
+    public List<Call.CallDetail> loadSpecifiedClientSideServiceRelations(Step step, long startTB, long endTB,
         List<Integer> serviceIds) throws IOException {
         if (CollectionUtils.isEmpty(serviceIds)) {
             throw new UnexpectedException("Service id is empty");
@@ -99,7 +94,8 @@ public class TopologyQueryEsDAO extends EsDAO implements ITopologyQueryDAO {
         sourceBuilder.query(boolQuery);
     }
 
-    @Override public List<Call> loadServerSideServiceRelations(Step step, long startTB, long endTB) throws IOException {
+    @Override public List<Call.CallDetail> loadServerSideServiceRelations(Step step, long startTB,
+        long endTB) throws IOException {
         String indexName = DownSamplingModelNameBuilder.build(step, ServiceRelationServerSideMetrics.INDEX_NAME);
         SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
         sourceBuilder.query(QueryBuilders.rangeQuery(ServiceRelationServerSideMetrics.TIME_BUCKET).gte(startTB).lte(endTB));
@@ -108,7 +104,8 @@ public class TopologyQueryEsDAO extends EsDAO implements ITopologyQueryDAO {
         return load(sourceBuilder, indexName, DetectPoint.SERVER);
     }
 
-    @Override public List<Call> loadClientSideServiceRelations(Step step, long startTB, long endTB) throws IOException {
+    @Override public List<Call.CallDetail> loadClientSideServiceRelations(Step step, long startTB,
+        long endTB) throws IOException {
         String indexName = DownSamplingModelNameBuilder.build(step, ServiceRelationClientSideMetrics.INDEX_NAME);
         SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
         sourceBuilder.query(QueryBuilders.rangeQuery(ServiceRelationServerSideMetrics.TIME_BUCKET).gte(startTB).lte(endTB));
@@ -118,7 +115,7 @@ public class TopologyQueryEsDAO extends EsDAO implements ITopologyQueryDAO {
     }
 
     @Override
-    public List<Call> loadSpecifiedDestOfServerSideEndpointRelations(Step step, long startTB, long endTB,
+    public List<Call.CallDetail> loadSpecifiedDestOfServerSideEndpointRelations(Step step, long startTB, long endTB,
         int destEndpointId) throws IOException {
         String indexName = DownSamplingModelNameBuilder.build(step, EndpointRelationServerSideMetrics.INDEX_NAME);
 
@@ -138,23 +135,23 @@ public class TopologyQueryEsDAO extends EsDAO implements ITopologyQueryDAO {
         return load(sourceBuilder, indexName, DetectPoint.SERVER);
     }
 
-    private List<Call> load(SearchSourceBuilder sourceBuilder, String indexName,
+    private List<Call.CallDetail> load(SearchSourceBuilder sourceBuilder, String indexName,
         DetectPoint detectPoint) throws IOException {
         sourceBuilder.aggregation(AggregationBuilders.terms(Metrics.ENTITY_ID).field(Metrics.ENTITY_ID).size(1000));
 
         SearchResponse response = getClient().search(indexName, sourceBuilder);
 
-        List<Call> calls = new ArrayList<>();
+        List<Call.CallDetail> calls = new ArrayList<>();
         Terms entityTerms = response.getAggregations().get(Metrics.ENTITY_ID);
         for (Terms.Bucket entityBucket : entityTerms.getBuckets()) {
             String entityId = entityBucket.getKeyAsString();
 
-            Integer[] entityIds = ServiceRelation.splitEntityId(entityId);
-            Call call = new Call();
+            ServiceRelationDefineUtil.RelationDefine relationDefine = ServiceRelationDefineUtil.splitEntityId(entityId);
+            Call.CallDetail call = new Call.CallDetail();
             call.setId(entityId);
-            call.setSource(entityIds[0]);
-            call.setTarget(entityIds[1]);
-            call.setComponentId(entityIds[2]);
+            call.setSource(relationDefine.getSource());
+            call.setTarget(relationDefine.getDest());
+            call.setComponentId(relationDefine.getComponentId());
             call.setDetectPoint(detectPoint);
             calls.add(call);
         }
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2TopologyQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2TopologyQueryDAO.java
index 653c74e..45d45a0 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2TopologyQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2TopologyQueryDAO.java
@@ -19,19 +19,13 @@
 package org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao;
 
 import java.io.IOException;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
+import java.sql.*;
+import java.util.*;
 import org.apache.skywalking.oap.server.core.analysis.manual.endpointrelation.EndpointRelationServerSideMetrics;
 import org.apache.skywalking.oap.server.core.analysis.manual.servicerelation.*;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
-import org.apache.skywalking.oap.server.core.analysis.manual.servicerelation.ServiceRelationServerSideMetrics;
-import org.apache.skywalking.oap.server.core.query.entity.Call;
-import org.apache.skywalking.oap.server.core.query.entity.Step;
+import org.apache.skywalking.oap.server.core.query.entity.*;
 import org.apache.skywalking.oap.server.core.source.DetectPoint;
-import org.apache.skywalking.oap.server.core.source.ServiceRelation;
 import org.apache.skywalking.oap.server.core.storage.DownSamplingModelNameBuilder;
 import org.apache.skywalking.oap.server.core.storage.query.ITopologyQueryDAO;
 import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
@@ -46,38 +40,41 @@ public class H2TopologyQueryDAO implements ITopologyQueryDAO {
         this.h2Client = h2Client;
     }
 
-    @Override public List<Call> loadSpecifiedServerSideServiceRelations(Step step, long startTB, long endTB,
+    @Override public List<Call.CallDetail> loadSpecifiedServerSideServiceRelations(Step step, long startTB, long endTB,
         List<Integer> serviceIds) throws IOException {
         String tableName = DownSamplingModelNameBuilder.build(step, ServiceRelationServerSideMetrics.INDEX_NAME);
         return loadServiceCalls(tableName, startTB, endTB, ServiceRelationServerSideMetrics.SOURCE_SERVICE_ID, ServiceRelationServerSideMetrics.DEST_SERVICE_ID, serviceIds, true);
     }
 
-    @Override public List<Call> loadSpecifiedClientSideServiceRelations(Step step, long startTB, long endTB,
+    @Override public List<Call.CallDetail> loadSpecifiedClientSideServiceRelations(Step step, long startTB, long endTB,
         List<Integer> serviceIds) throws IOException {
         String tableName = DownSamplingModelNameBuilder.build(step, ServiceRelationClientSideMetrics.INDEX_NAME);
         return loadServiceCalls(tableName, startTB, endTB, ServiceRelationServerSideMetrics.SOURCE_SERVICE_ID, ServiceRelationServerSideMetrics.DEST_SERVICE_ID, serviceIds, false);
     }
 
-    @Override public List<Call> loadServerSideServiceRelations(Step step, long startTB, long endTB) throws IOException {
+    @Override public List<Call.CallDetail> loadServerSideServiceRelations(Step step, long startTB,
+        long endTB) throws IOException {
         String tableName = DownSamplingModelNameBuilder.build(step, ServiceRelationServerSideMetrics.INDEX_NAME);
         return loadServiceCalls(tableName, startTB, endTB, ServiceRelationServerSideMetrics.SOURCE_SERVICE_ID, ServiceRelationServerSideMetrics.DEST_SERVICE_ID, new ArrayList<>(0), false);
     }
 
-    @Override public List<Call> loadClientSideServiceRelations(Step step, long startTB, long endTB) throws IOException {
+    @Override public List<Call.CallDetail> loadClientSideServiceRelations(Step step, long startTB,
+        long endTB) throws IOException {
         String tableName = DownSamplingModelNameBuilder.build(step, ServiceRelationClientSideMetrics.INDEX_NAME);
         return loadServiceCalls(tableName, startTB, endTB, ServiceRelationServerSideMetrics.SOURCE_SERVICE_ID, ServiceRelationServerSideMetrics.DEST_SERVICE_ID, new ArrayList<>(0), true);
     }
 
-    @Override public List<Call> loadSpecifiedDestOfServerSideEndpointRelations(Step step, long startTB, long endTB,
+    @Override
+    public List<Call.CallDetail> loadSpecifiedDestOfServerSideEndpointRelations(Step step, long startTB, long endTB,
         int destEndpointId) throws IOException {
         String tableName = DownSamplingModelNameBuilder.build(step, EndpointRelationServerSideMetrics.INDEX_NAME);
 
-        List<Call> calls = loadEndpointFromSide(tableName, startTB, endTB, EndpointRelationServerSideMetrics.SOURCE_ENDPOINT_ID, EndpointRelationServerSideMetrics.DEST_ENDPOINT_ID, destEndpointId, false);
+        List<Call.CallDetail> calls = loadEndpointFromSide(tableName, startTB, endTB, EndpointRelationServerSideMetrics.SOURCE_ENDPOINT_ID, EndpointRelationServerSideMetrics.DEST_ENDPOINT_ID, destEndpointId, false);
         calls.addAll(loadEndpointFromSide(tableName, startTB, endTB, EndpointRelationServerSideMetrics.SOURCE_ENDPOINT_ID, EndpointRelationServerSideMetrics.DEST_ENDPOINT_ID, destEndpointId, true));
         return calls;
     }
 
-    private List<Call> loadServiceCalls(String tableName, long startTB, long endTB, String sourceCName,
+    private List<Call.CallDetail> loadServiceCalls(String tableName, long startTB, long endTB, String sourceCName,
         String destCName, List<Integer> serviceIds, boolean isClientSide) throws IOException {
         Object[] conditions = new Object[serviceIds.size() * 2 + 2];
         conditions[0] = startTB;
@@ -95,7 +92,7 @@ public class H2TopologyQueryDAO implements ITopologyQueryDAO {
             }
             serviceIdMatchSql.append(")");
         }
-        List<Call> calls = new ArrayList<>();
+        List<Call.CallDetail> calls = new ArrayList<>();
         try (Connection connection = h2Client.getConnection()) {
             try (ResultSet resultSet = h2Client.executeQuery(connection, "select "
                     + Metrics.ENTITY_ID
@@ -112,13 +109,13 @@ public class H2TopologyQueryDAO implements ITopologyQueryDAO {
         return calls;
     }
 
-    private List<Call> loadEndpointFromSide(String tableName, long startTB, long endTB, String sourceCName,
+    private List<Call.CallDetail> loadEndpointFromSide(String tableName, long startTB, long endTB, String sourceCName,
         String destCName, int id, boolean isSourceId) throws IOException {
         Object[] conditions = new Object[3];
         conditions[0] = startTB;
         conditions[1] = endTB;
         conditions[2] = id;
-        List<Call> calls = new ArrayList<>();
+        List<Call.CallDetail> calls = new ArrayList<>();
         try (Connection connection = h2Client.getConnection()) {
             try (ResultSet resultSet = h2Client.executeQuery(connection, "select "
                     + Metrics.ENTITY_ID
@@ -135,16 +132,21 @@ public class H2TopologyQueryDAO implements ITopologyQueryDAO {
         return calls;
     }
 
-    private void buildCalls(ResultSet resultSet, List<Call> calls, boolean isClientSide) throws SQLException {
+    private void buildCalls(ResultSet resultSet, List<Call.CallDetail> calls,
+        boolean isClientSide) throws SQLException {
         while (resultSet.next()) {
-            Call call = new Call();
+            Call.CallDetail call = new Call.CallDetail();
             String entityId = resultSet.getString(Metrics.ENTITY_ID);
-            Integer[] entityIds = ServiceRelation.splitEntityId(entityId);
+            ServiceRelationDefineUtil.RelationDefine relationDefine = ServiceRelationDefineUtil.splitEntityId(entityId);
 
-            call.setSource(entityIds[0]);
-            call.setTarget(entityIds[1]);
-            call.setComponentId(entityIds[2]);
-            call.setDetectPoint(isClientSide ? DetectPoint.CLIENT : DetectPoint.SERVER);
+            call.setSource(relationDefine.getSource());
+            call.setTarget(relationDefine.getDest());
+            call.setComponentId(relationDefine.getComponentId());
+            if (isClientSide) {
+                call.setDetectPoint(DetectPoint.CLIENT);
+            } else {
+                call.setDetectPoint(DetectPoint.SERVER);
+            }
             call.setId(entityId);
             calls.add(call);
         }