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 2020/03/06 13:07:52 UTC

[skywalking] branch master updated: support http api for upstream trace. (#4399)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new aa21765  support http api for upstream trace. (#4399)
aa21765 is described below

commit aa2176562842aba0966524fbc6c2b444e69c285d
Author: Jared Tan <ji...@daocloud.io>
AuthorDate: Fri Mar 6 21:07:39 2020 +0800

    support http api for upstream trace. (#4399)
    
    * support http api.
    
    * e2e
    
    Co-authored-by: 吴晟 Wu Sheng <wu...@foxmail.com>
    Co-authored-by: kezhenxu94 <ke...@apache.org>
---
 .github/workflows/e2e.yaml                         |   2 +
 .gitignore                                         |   1 +
 docs/en/protocols/HTTP-API-Protocol.md             | 200 +++++++++++
 docs/en/protocols/Trace-Data-Protocol-v2.md        |   3 +
 oap-server/pom.xml                                 |   8 +
 .../library/server/jetty/JettyJsonHandler.java     |  19 +-
 oap-server/server-library/library-util/pom.xml     |  12 +
 .../oap/server/library/util/ProtoBufJsonUtils.java |  46 +++
 .../register/provider/RegisterModuleProvider.java  |  11 +
 .../v6/rest/ServiceInstancePingServletHandler.java | 111 ++++++
 .../ServiceInstanceRegisterServletHandler.java     | 152 ++++++++
 .../v6/rest/ServiceRegisterServletHandler.java     |  92 +++++
 .../trace/provider/TraceModuleProvider.java        |  25 +-
 .../v6/rest/TraceSegmentCollectServletHandler.java |  76 ++++
 .../handler/v6/rest/reader/SegmentJsonReader.java  |  33 ++
 .../handler/v6/rest/reader/StreamJsonReader.java   |  25 ++
 .../v6/rest/reader/UpstreamSegmentJsonReader.java  |  41 +++
 .../listener/segment/ProtoBufJsonUtilsTest.java    | 139 ++++++++
 test/e2e/e2e-http-api-with-nginx-lua/pom.xml       | 195 +++++++++++
 .../src/docker/rc.d/rc0-prepare.sh                 |  95 +++++
 .../src/docker/rc.d/rc1-startup.sh                 |  48 +++
 .../e2e/sample/client/SampleClientApplication.java |  29 ++
 .../e2e/sample/client/TestController.java          |  32 ++
 .../src/main/resources/application.yml             |  22 ++
 .../skywalking/e2e/SampleVerificationITCase.java   | 386 +++++++++++++++++++++
 ...king.e2e.SampleVerificationITCase.endpoints.yml |  28 ++
 ...king.e2e.SampleVerificationITCase.instances.yml |  34 ++
 ...ampleVerificationITCase.serviceInstanceTopo.yml |  41 +++
 ...lking.e2e.SampleVerificationITCase.services.yml |  27 ++
 ...kywalking.e2e.SampleVerificationITCase.topo.yml |  47 +++
 ...walking.e2e.SampleVerificationITCase.traces.yml |  40 +++
 test/e2e/pom.xml                                   |   1 +
 .../known-oap-backend-dependencies-es7.txt         |   3 +-
 .../known-oap-backend-dependencies.txt             |   3 +-
 34 files changed, 2014 insertions(+), 13 deletions(-)

diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml
index e19c1de..513f9e8 100644
--- a/.github/workflows/e2e.yaml
+++ b/.github/workflows/e2e.yaml
@@ -116,6 +116,8 @@ jobs:
           ./mvnw --batch-mode -f test/e2e/pom.xml -pl e2e-base clean install
       - name: 6.x Agents & 7.x Backend
         run: export E2E_VERSION=jdk8-1.5 && bash -x test/e2e/run.sh e2e-6.x-agent-7.x-oap-compatibility
+      - name: Http API with Nginx Lua Tests In Single Node Mode(JDK8)
+        run: export E2E_VERSION=jdk8-1.5 && bash -x test/e2e/run.sh e2e-http-api-with-nginx-lua
 
   Profile:
     runs-on: ubuntu-latest
diff --git a/.gitignore b/.gitignore
index c8c8488..a5bd42a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,4 @@ OALLexer.tokens
 .externalToolBuilders
 /test/plugin/dist
 /test/plugin/workspace
+e2e-*
diff --git a/docs/en/protocols/HTTP-API-Protocol.md b/docs/en/protocols/HTTP-API-Protocol.md
new file mode 100644
index 0000000..3b42a42
--- /dev/null
+++ b/docs/en/protocols/HTTP-API-Protocol.md
@@ -0,0 +1,200 @@
+# HTTP API Protocol
+
+HTTP API Protocol defines the API data format, including api request and response data format.
+
+### Do register
+
+Detail information about data format can be found in  [Register service](https://github.com/apache/skywalking-data-collect-protocol/tree/master/register/Register.proto).
+And register steps followings [SkyWalking Trace Data Protocol v2](Trace-Data-Protocol-v2.md).
+
+- Service Register
+
+> POST http://localhost:12800/v2/service/register
+
+Input:
+
+```json
+{
+  "services": [
+    {
+      "type": "normal",
+      "serviceName": "Service Name"
+    }
+  ]
+}
+```
+
+Output JSON Array:
+
+```json
+[
+    {
+        "key": "Service Name",
+        "value": 2
+    }
+]
+```
+
+- Service instance Register
+
+> POST http://localhost:12800/v2/instance/register
+
+Input:
+
+```json
+{
+  "instances": [
+    {
+      "time": 1582428603392,
+      "instanceUUID": "NAME:Service Instance Name",
+      "properties": [
+        {
+          "key": "language",
+          "value": "Lua"
+        }
+      ],
+      "serviceId": 2
+    }
+  ]
+}
+```
+
+OutPut:
+
+```json
+[
+    {
+        "key": "NAME:Service Instance Name",
+        "value": 0
+    }
+]
+```
+
+- Service instance heartbeat
+
+> POST http://localhost:12800/v2/instance/heartbeat
+
+Input:
+
+```json
+{
+  "serviceInstanceId":20,
+  "time": 1582428603392,
+  "serviceInstanceUUID":"NAME:Service Instance Name"
+}
+```
+
+OutPut:
+
+```json
+{}
+```
+If your instance does not exist, you need to clean your local service instance metadata in your application and re-do register:
+
+```json
+{
+    "commands": [
+        {
+            "command": "ServiceMetadataReset",
+            "args": [
+                {
+                    "key": "SerialNumber",
+                    "value": "44bd2664-03c7-46bc-8652-52fcde0e7699"
+                }
+            ]
+        }
+    ]
+}
+```  
+
+## Trace Report
+
+### POST http://localhost:12800/v2/segments
+
+Input:
+
+```json
+{
+  "spans": [
+    {
+      "operationName": "/tier2/lb",
+      "startTime": 1582461179910,
+      "tags": [],
+      "endTime": 1582461179922,
+      "spanType": "Exit",
+      "logs":[],
+      "spanId": 1,
+      "isError": false,
+      "parentSpanId": 0,
+      "componentId": 6000,
+      "peer": "User Service Name-nginx:upstream_ip:port",
+      "spanLayer": "HTTP"
+    },
+    {
+      "operationName": "/tier2/lb",
+      "startTime": 1582461179910,
+      "tags": [
+        {
+          "key": "http.method",
+          "value": "GET"
+        },
+        {
+          "key": "http.params",
+          "value": "http://127.0.0.1/tier2/lb"
+        }
+      ],
+      "endTime": 1582461179922,
+      "spanType": "Entry",
+      "logs": [],
+      "spanId": 0,
+      "isError": false,
+      "parentSpanId": -1,
+      "componentId": 6000,
+      "refs": [
+        {
+          "parentTraceSegmentId": {
+            "idParts": [
+              1582461179038,
+              794206293,
+              69887
+            ]
+          },
+          "parentEndpointId": 0,
+          "entryEndpointId": 0,
+          "parentServiceInstanceId": 1,
+          "parentEndpoint": "/ingress",
+          "networkAddress": "#User Service Name-nginx:upstream_ip:port",
+          "parentSpanId": 1,
+          "entryServiceInstanceId": 1,
+          "networkAddressId": 0,
+          "entryEndpoint": "/ingress"
+        }
+      ],
+      "spanLayer": "HTTP"
+    }
+  ],
+  "serviceInstanceId": 1,
+  "serviceId": 1,
+  "traceSegmentId": {
+    "idParts": [
+      1582461179044,
+      794206293,
+      69887
+    ]
+  },
+  "globalTraceIds": [
+    {
+      "idParts": [
+        1582461179038,
+        794206293,
+        69887
+      ]
+    }
+  ]
+}
+```
+ OutPut:
+ 
+ ```json
+
+```
\ No newline at end of file
diff --git a/docs/en/protocols/Trace-Data-Protocol-v2.md b/docs/en/protocols/Trace-Data-Protocol-v2.md
index a80a840..26079bc 100644
--- a/docs/en/protocols/Trace-Data-Protocol-v2.md
+++ b/docs/en/protocols/Trace-Data-Protocol-v2.md
@@ -7,6 +7,9 @@ Trace data protocol is defined and provided in [gRPC format](https://github.com/
 For each agent/SDK, it needs to register service id and service instance id before reporting any kind of trace 
 or metrics data.
 
+Since SkyWalking v7.x, SkyWalking provided register and uplink trace data through HTTP API way.
+[HTTP API Protocol](HTTP-API-Protocol.md) defined the API data format.
+
 ### Step 1. Do register
 [Register service](https://github.com/apache/skywalking-data-collect-protocol/tree/master/register/Register.proto) takes charge of 
 all register methods. At step 1, we need `doServiceRegister`, then `doServiceInstanceRegister`.
diff --git a/oap-server/pom.xml b/oap-server/pom.xml
index a90031f..88562cb 100755
--- a/oap-server/pom.xml
+++ b/oap-server/pom.xml
@@ -90,6 +90,7 @@
         <javaassist.version>3.25.0-GA</javaassist.version>
 
         <zookeeper.image.version>3.5</zookeeper.image.version>
+        <protobuf-java-util.version>3.11.4</protobuf-java-util.version>
 
     </properties>
 
@@ -263,6 +264,13 @@
                 <artifactId>grpc-protobuf</artifactId>
                 <version>${grpc.version}</version>
             </dependency>
+
+            <dependency>
+                <groupId>com.google.protobuf</groupId>
+                <artifactId>protobuf-java-util</artifactId>
+                <version>${protobuf-java-util.version}</version>
+            </dependency>
+
             <dependency>
                 <groupId>io.grpc</groupId>
                 <artifactId>grpc-stub</artifactId>
diff --git a/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/jetty/JettyJsonHandler.java b/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/jetty/JettyJsonHandler.java
index f2bbded..b48a324 100644
--- a/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/jetty/JettyJsonHandler.java
+++ b/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/jetty/JettyJsonHandler.java
@@ -19,6 +19,7 @@
 package org.apache.skywalking.oap.server.library.server.jetty;
 
 import com.google.gson.JsonElement;
+import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.Enumeration;
@@ -84,25 +85,25 @@ public abstract class JettyJsonHandler extends JettyHandler {
 
     @Override
     protected final void doDelete(HttpServletRequest req,
-        HttpServletResponse resp) throws ServletException, IOException {
+                                  HttpServletResponse resp) throws ServletException, IOException {
         super.doDelete(req, resp);
     }
 
     @Override
     protected final void doOptions(HttpServletRequest req,
-        HttpServletResponse resp) throws ServletException, IOException {
+                                   HttpServletResponse resp) throws ServletException, IOException {
         super.doOptions(req, resp);
     }
 
     @Override
     protected final void doTrace(HttpServletRequest req,
-        HttpServletResponse resp) throws ServletException, IOException {
+                                 HttpServletResponse resp) throws ServletException, IOException {
         super.doTrace(req, resp);
     }
 
     @Override
     protected final void service(HttpServletRequest req,
-        HttpServletResponse resp) throws ServletException, IOException {
+                                 HttpServletResponse resp) throws ServletException, IOException {
         super.service(req, resp);
     }
 
@@ -189,4 +190,14 @@ public abstract class JettyJsonHandler extends JettyHandler {
         out.flush();
         out.close();
     }
+
+    public String getJsonBody(HttpServletRequest req) throws IOException {
+        StringBuffer stringBuffer = new StringBuffer();
+        String line = null;
+        BufferedReader reader = req.getReader();
+        while ((line = reader.readLine()) != null) {
+            stringBuffer.append(line);
+        }
+        return stringBuffer.toString();
+    }
 }
diff --git a/oap-server/server-library/library-util/pom.xml b/oap-server/server-library/library-util/pom.xml
index 93b2fa7..6f5b29a 100644
--- a/oap-server/server-library/library-util/pom.xml
+++ b/oap-server/server-library/library-util/pom.xml
@@ -31,6 +31,7 @@
 
     <properties>
         <ststem-rules.version>1.18.0</ststem-rules.version>
+        <protobuf-java.version>3.11.4</protobuf-java.version>
     </properties>
 
     <dependencies>
@@ -53,5 +54,16 @@
             <version>${ststem-rules.version}</version>
             <scope>test</scope>
         </dependency>
+
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protobuf-java</artifactId>
+            <version>${protobuf-java.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protobuf-java-util</artifactId>
+        </dependency>
     </dependencies>
 </project>
diff --git a/oap-server/server-library/library-util/src/main/java/org/apache/skywalking/oap/server/library/util/ProtoBufJsonUtils.java b/oap-server/server-library/library-util/src/main/java/org/apache/skywalking/oap/server/library/util/ProtoBufJsonUtils.java
new file mode 100644
index 0000000..09aba12
--- /dev/null
+++ b/oap-server/server-library/library-util/src/main/java/org/apache/skywalking/oap/server/library/util/ProtoBufJsonUtils.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.library.util;
+
+import com.google.protobuf.Message;
+import com.google.protobuf.util.JsonFormat;
+import java.io.IOException;
+
+public class ProtoBufJsonUtils {
+
+    public static String toJSON(Message sourceMessage) throws IOException {
+        return JsonFormat.printer().print(sourceMessage);
+    }
+
+    /**
+     * Extract data from a JSON String and use them to construct a Protocol Buffers Message.
+     *
+     * @param json          A JSON data string to parse
+     * @param targetBuilder A Message builder to use to construct the resulting Message
+     * @throws com.google.protobuf.InvalidProtocolBufferException Thrown in case of invalid Message data
+     */
+    public static void fromJSON(String json, Message.Builder targetBuilder) throws IOException {
+        JsonFormat.parser()
+                  .usingTypeRegistry(JsonFormat.TypeRegistry.newBuilder()
+                                                            .add(targetBuilder.getDescriptorForType())
+                                                            .build())
+                  .ignoringUnknownFields()
+                  .merge(json, targetBuilder);
+    }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/RegisterModuleProvider.java b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/RegisterModuleProvider.java
index 798dea3..f7b3dc0 100644
--- a/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/RegisterModuleProvider.java
+++ b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/RegisterModuleProvider.java
@@ -20,12 +20,16 @@ package org.apache.skywalking.oap.server.receiver.register.provider;
 
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.server.GRPCHandlerRegister;
+import org.apache.skywalking.oap.server.core.server.JettyHandlerRegister;
 import org.apache.skywalking.oap.server.library.module.ModuleConfig;
 import org.apache.skywalking.oap.server.library.module.ModuleDefine;
 import org.apache.skywalking.oap.server.library.module.ModuleProvider;
 import org.apache.skywalking.oap.server.receiver.register.module.RegisterModule;
 import org.apache.skywalking.oap.server.receiver.register.provider.handler.v6.grpc.RegisterServiceHandler;
 import org.apache.skywalking.oap.server.receiver.register.provider.handler.v6.grpc.ServiceInstancePingServiceHandler;
+import org.apache.skywalking.oap.server.receiver.register.provider.handler.v6.rest.ServiceInstancePingServletHandler;
+import org.apache.skywalking.oap.server.receiver.register.provider.handler.v6.rest.ServiceInstanceRegisterServletHandler;
+import org.apache.skywalking.oap.server.receiver.register.provider.handler.v6.rest.ServiceRegisterServletHandler;
 import org.apache.skywalking.oap.server.receiver.sharing.server.SharingServerModule;
 
 public class RegisterModuleProvider extends ModuleProvider {
@@ -56,6 +60,13 @@ public class RegisterModuleProvider extends ModuleProvider {
                                                               .getService(GRPCHandlerRegister.class);
         grpcHandlerRegister.addHandler(new RegisterServiceHandler(getManager()));
         grpcHandlerRegister.addHandler(new ServiceInstancePingServiceHandler(getManager()));
+
+        JettyHandlerRegister jettyHandlerRegister = getManager().find(SharingServerModule.NAME)
+                                                                .provider()
+                                                                .getService(JettyHandlerRegister.class);
+        jettyHandlerRegister.addHandler(new ServiceRegisterServletHandler(getManager()));
+        jettyHandlerRegister.addHandler(new ServiceInstanceRegisterServletHandler(getManager()));
+        jettyHandlerRegister.addHandler(new ServiceInstancePingServletHandler(getManager()));
     }
 
     @Override
diff --git a/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceInstancePingServletHandler.java b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceInstancePingServletHandler.java
new file mode 100644
index 0000000..738f661
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceInstancePingServletHandler.java
@@ -0,0 +1,111 @@
+/*
+ * 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.receiver.register.provider.handler.v6.rest;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.Objects;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.skywalking.apm.network.common.Command;
+import org.apache.skywalking.apm.network.common.Commands;
+import org.apache.skywalking.apm.network.register.v2.ServiceInstancePingPkg;
+import org.apache.skywalking.apm.network.trace.component.command.ServiceResetCommand;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.cache.ServiceInstanceInventoryCache;
+import org.apache.skywalking.oap.server.core.command.CommandService;
+import org.apache.skywalking.oap.server.core.register.ServiceInstanceInventory;
+import org.apache.skywalking.oap.server.core.register.service.IServiceInstanceInventoryRegister;
+import org.apache.skywalking.oap.server.core.register.service.IServiceInventoryRegister;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.library.server.jetty.ArgumentsParseException;
+import org.apache.skywalking.oap.server.library.server.jetty.JettyJsonHandler;
+import org.apache.skywalking.oap.server.library.util.ProtoBufJsonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ServiceInstancePingServletHandler extends JettyJsonHandler {
+
+    private static final Logger logger = LoggerFactory.getLogger(ServiceInstancePingServletHandler.class);
+
+    private final IServiceInstanceInventoryRegister serviceInstanceInventoryRegister;
+    private final ServiceInstanceInventoryCache serviceInstanceInventoryCache;
+    private final IServiceInventoryRegister serviceInventoryRegister;
+    private final CommandService commandService;
+    private final Gson gson = new Gson();
+
+    public ServiceInstancePingServletHandler(ModuleManager moduleManager) {
+        this.serviceInstanceInventoryRegister = moduleManager.find(CoreModule.NAME).provider().getService(
+            IServiceInstanceInventoryRegister.class);
+        this.serviceInstanceInventoryCache = moduleManager.find(CoreModule.NAME).provider().getService(
+            ServiceInstanceInventoryCache.class);
+        this.serviceInventoryRegister = moduleManager.find(CoreModule.NAME).provider().getService(
+            IServiceInventoryRegister.class);
+        this.commandService = moduleManager.find(CoreModule.NAME).provider().getService(CommandService.class);
+    }
+
+    @Override
+    public String pathSpec() {
+        return "/v2/instance/heartbeat";
+    }
+
+    @Override
+    protected JsonElement doGet(HttpServletRequest req) throws ArgumentsParseException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected JsonElement doPost(HttpServletRequest req) throws ArgumentsParseException, IOException {
+        JsonObject responseJson = new JsonObject();
+
+        try {
+            ServiceInstancePingPkg.Builder builder = ServiceInstancePingPkg.newBuilder();
+            ProtoBufJsonUtils.fromJSON(getJsonBody(req), builder);
+            ServiceInstancePingPkg instancePingPkg = builder.build();
+
+            int serviceInstanceId = instancePingPkg.getServiceInstanceId();
+            long heartBeatTime = instancePingPkg.getTime();
+            String serviceInstanceUUID = instancePingPkg.getServiceInstanceUUID();
+            serviceInstanceInventoryRegister.heartbeat(serviceInstanceId, heartBeatTime);
+
+            ServiceInstanceInventory serviceInstanceInventory = serviceInstanceInventoryCache.get(serviceInstanceId);
+            if (Objects.nonNull(serviceInstanceInventory)) {
+                serviceInventoryRegister.heartbeat(serviceInstanceInventory.getServiceId(), heartBeatTime);
+            } else {
+                logger.warn(
+                    "Can't found service by service instance id from cache, service instance id is: {}",
+                    serviceInstanceId
+                );
+
+                final ServiceResetCommand resetCommand = commandService.newResetCommand(
+                    serviceInstanceId, heartBeatTime, serviceInstanceUUID);
+                final Command command = resetCommand.serialize().build();
+                final Commands nextCommands = Commands.newBuilder().addCommands(command).build();
+                return gson.fromJson(ProtoBufJsonUtils.toJSON(nextCommands), JsonElement.class);
+            }
+
+        } catch (IOException e) {
+            responseJson.addProperty("error", e.getMessage());
+            logger.error(e.getMessage(), e);
+        }
+
+        return responseJson;
+    }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceInstanceRegisterServletHandler.java b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceInstanceRegisterServletHandler.java
new file mode 100644
index 0000000..f930fc3
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceInstanceRegisterServletHandler.java
@@ -0,0 +1,152 @@
+/*
+ * 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.receiver.register.provider.handler.v6.rest;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.skywalking.apm.network.common.KeyStringValuePair;
+import org.apache.skywalking.apm.network.register.v2.ServiceInstance;
+import org.apache.skywalking.apm.network.register.v2.ServiceInstances;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.cache.ServiceInventoryCache;
+import org.apache.skywalking.oap.server.core.register.ServiceInstanceInventory;
+import org.apache.skywalking.oap.server.core.register.ServiceInventory;
+import org.apache.skywalking.oap.server.core.register.service.IServiceInstanceInventoryRegister;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.library.server.jetty.ArgumentsParseException;
+import org.apache.skywalking.oap.server.library.server.jetty.JettyJsonHandler;
+import org.apache.skywalking.oap.server.library.util.ProtoBufJsonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.skywalking.oap.server.core.register.ServiceInstanceInventory.PropertyUtil.HOST_NAME;
+import static org.apache.skywalking.oap.server.core.register.ServiceInstanceInventory.PropertyUtil.IPV4S;
+import static org.apache.skywalking.oap.server.core.register.ServiceInstanceInventory.PropertyUtil.LANGUAGE;
+import static org.apache.skywalking.oap.server.core.register.ServiceInstanceInventory.PropertyUtil.OS_NAME;
+import static org.apache.skywalking.oap.server.core.register.ServiceInstanceInventory.PropertyUtil.PROCESS_NO;
+
+public class ServiceInstanceRegisterServletHandler extends JettyJsonHandler {
+
+    private static final Logger logger = LoggerFactory.getLogger(ServiceInstanceRegisterServletHandler.class);
+    private static final String INSTANCE_CUSTOMIZED_NAME_PREFIX = "NAME:";
+
+    private final IServiceInstanceInventoryRegister serviceInstanceInventoryRegister;
+    private final ServiceInventoryCache serviceInventoryCache;
+
+    private static final String KEY = "key";
+    private static final String VALUE = "value";
+
+    public ServiceInstanceRegisterServletHandler(ModuleManager moduleManager) {
+        this.serviceInventoryCache = moduleManager.find(CoreModule.NAME)
+                                                  .provider()
+                                                  .getService(ServiceInventoryCache.class);
+        this.serviceInstanceInventoryRegister = moduleManager.find(CoreModule.NAME).provider().getService(
+            IServiceInstanceInventoryRegister.class);
+    }
+
+    @Override
+    public String pathSpec() {
+        return "/v2/instance/register";
+    }
+
+    @Override
+    protected JsonElement doGet(HttpServletRequest req) throws ArgumentsParseException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected JsonElement doPost(HttpServletRequest req) throws ArgumentsParseException {
+
+        JsonObject responseJson = new JsonObject();
+        JsonArray jsonArray = new JsonArray();
+
+        try {
+            ServiceInstances.Builder builder = ServiceInstances.newBuilder();
+            ProtoBufJsonUtils.fromJSON(getJsonBody(req), builder);
+            List<ServiceInstance> serviceInstances = builder.build().getInstancesList();
+
+            serviceInstances.forEach(instance -> {
+                long time = instance.getTime();
+                int serviceId = instance.getServiceId();
+                String instanceUUID = instance.getInstanceUUID();
+
+                JsonObject instanceProperties = new JsonObject();
+                List<String> ipv4s = new ArrayList<>();
+
+                for (KeyStringValuePair property : instance.getPropertiesList()) {
+                    String key = property.getKey();
+                    switch (key) {
+                        case HOST_NAME:
+                            instanceProperties.addProperty(HOST_NAME, property.getValue());
+                            break;
+                        case OS_NAME:
+                            instanceProperties.addProperty(OS_NAME, property.getValue());
+                            break;
+                        case LANGUAGE:
+                            instanceProperties.addProperty(LANGUAGE, property.getValue());
+                            break;
+                        case "ipv4":
+                            ipv4s.add(property.getValue());
+                            break;
+                        case PROCESS_NO:
+                            instanceProperties.addProperty(PROCESS_NO, property.getValue());
+                            break;
+                        default:
+                            instanceProperties.addProperty(key, property.getValue());
+                    }
+                }
+                instanceProperties.addProperty(IPV4S, ServiceInstanceInventory.PropertyUtil.ipv4sSerialize(ipv4s));
+
+                String instanceName = null;
+                if (instanceUUID.startsWith(INSTANCE_CUSTOMIZED_NAME_PREFIX)) {
+                    instanceName = instanceUUID.substring(INSTANCE_CUSTOMIZED_NAME_PREFIX.length());
+                }
+
+                ServiceInventory serviceInventory = serviceInventoryCache.get(serviceId);
+
+                if (instanceName == null) {
+                    instanceName = serviceInventory.getName();
+                    if (instanceProperties.has(PROCESS_NO)) {
+                        instanceName += "-pid:" + instanceProperties.get(PROCESS_NO).getAsString();
+                    }
+                    if (instanceProperties.has(HOST_NAME)) {
+                        instanceName += "@" + instanceProperties.get(HOST_NAME).getAsString();
+                    }
+                }
+                int instanceId = serviceInstanceInventoryRegister.getOrCreate(
+                    serviceId, instanceName, instanceUUID, time, instanceProperties);
+
+                responseJson.addProperty(KEY, instanceUUID);
+                responseJson.addProperty(VALUE, instanceId);
+                jsonArray.add(responseJson);
+            });
+
+            return jsonArray;
+        } catch (IOException e) {
+            responseJson.addProperty("error", e.getMessage());
+            logger.error(e.getMessage(), e);
+        }
+        return responseJson;
+    }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceRegisterServletHandler.java b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceRegisterServletHandler.java
new file mode 100644
index 0000000..10242bc
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceRegisterServletHandler.java
@@ -0,0 +1,92 @@
+/*
+ * 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.receiver.register.provider.handler.v6.rest;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.skywalking.apm.network.register.v2.Service;
+import org.apache.skywalking.apm.network.register.v2.Services;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.register.NodeType;
+import org.apache.skywalking.oap.server.core.register.service.IServiceInventoryRegister;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.library.server.jetty.ArgumentsParseException;
+import org.apache.skywalking.oap.server.library.server.jetty.JettyJsonHandler;
+import org.apache.skywalking.oap.server.library.util.ProtoBufJsonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ServiceRegisterServletHandler extends JettyJsonHandler {
+
+    private static final Logger logger = LoggerFactory.getLogger(ServiceRegisterServletHandler.class);
+
+    private final IServiceInventoryRegister serviceInventoryRegister;
+
+    private static final String KEY = "key";
+    private static final String VALUE = "value";
+
+    public ServiceRegisterServletHandler(ModuleManager moduleManager) {
+        serviceInventoryRegister = moduleManager.find(CoreModule.NAME)
+                                                .provider()
+                                                .getService(IServiceInventoryRegister.class);
+    }
+
+    @Override
+    public String pathSpec() {
+        return "/v2/service/register";
+    }
+
+    @Override
+    protected JsonElement doGet(HttpServletRequest req) throws ArgumentsParseException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected JsonElement doPost(HttpServletRequest req) throws ArgumentsParseException {
+        JsonArray responseArray = new JsonArray();
+
+        try {
+            Services.Builder builder = Services.newBuilder();
+            ProtoBufJsonUtils.fromJSON(getJsonBody(req), builder);
+            List<Service> serviceList = builder.build().getServicesList();
+
+            serviceList.forEach(service -> {
+                int serviceId = serviceInventoryRegister.getOrCreate(service.getServiceName(),
+                                                                     NodeType.fromRegisterServiceType(
+                                                                         service.getType()), null
+                );
+
+                JsonObject mapping = new JsonObject();
+                mapping.addProperty(KEY, service.getServiceName());
+                mapping.addProperty(VALUE, serviceId);
+                responseArray.add(mapping);
+            });
+        } catch (IOException e) {
+            JsonObject mapping = new JsonObject();
+            mapping.addProperty("error", e.getMessage());
+            responseArray.add(mapping);
+            logger.error(e.getMessage(), e);
+        }
+        return responseArray;
+    }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceModuleProvider.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceModuleProvider.java
index 3eb3d5f..b087241 100755
--- a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceModuleProvider.java
+++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceModuleProvider.java
@@ -18,10 +18,12 @@
 
 package org.apache.skywalking.oap.server.receiver.trace.provider;
 
+import java.io.IOException;
 import org.apache.skywalking.oap.server.configuration.api.ConfigurationModule;
 import org.apache.skywalking.oap.server.configuration.api.DynamicConfigurationService;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.server.GRPCHandlerRegister;
+import org.apache.skywalking.oap.server.core.server.JettyHandlerRegister;
 import org.apache.skywalking.oap.server.library.module.ModuleConfig;
 import org.apache.skywalking.oap.server.library.module.ModuleDefine;
 import org.apache.skywalking.oap.server.library.module.ModuleProvider;
@@ -30,6 +32,7 @@ import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedExcepti
 import org.apache.skywalking.oap.server.receiver.sharing.server.SharingServerModule;
 import org.apache.skywalking.oap.server.receiver.trace.module.TraceModule;
 import org.apache.skywalking.oap.server.receiver.trace.provider.handler.v6.grpc.TraceSegmentReportServiceHandler;
+import org.apache.skywalking.oap.server.receiver.trace.provider.handler.v6.rest.TraceSegmentCollectServletHandler;
 import org.apache.skywalking.oap.server.receiver.trace.provider.parser.ISegmentParserService;
 import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SegmentParseV2;
 import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SegmentParserListenerManager;
@@ -41,8 +44,6 @@ import org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.
 import org.apache.skywalking.oap.server.receiver.trace.provider.parser.standardization.SegmentStandardizationWorker;
 import org.apache.skywalking.oap.server.telemetry.TelemetryModule;
 
-import java.io.IOException;
-
 public class TraceModuleProvider extends ModuleProvider {
 
     private final TraceServiceModuleConfig moduleConfig;
@@ -80,7 +81,8 @@ public class TraceModuleProvider extends ModuleProvider {
 
         segmentProducerV2 = new SegmentParseV2.Producer(getManager(), listenerManager(), moduleConfig);
 
-        this.registerServiceImplementation(ISegmentParserService.class, new SegmentParserServiceImpl(segmentProducerV2));
+        this.registerServiceImplementation(
+            ISegmentParserService.class, new SegmentParserServiceImpl(segmentProducerV2));
     }
 
     public SegmentParserListenerManager listenerManager() {
@@ -99,19 +101,28 @@ public class TraceModuleProvider extends ModuleProvider {
     public void start() throws ModuleStartException {
         DynamicConfigurationService dynamicConfigurationService = getManager().find(ConfigurationModule.NAME)
                                                                               .provider()
-                                                                              .getService(DynamicConfigurationService.class);
+                                                                              .getService(
+                                                                                  DynamicConfigurationService.class);
         GRPCHandlerRegister grpcHandlerRegister = getManager().find(SharingServerModule.NAME)
                                                               .provider()
                                                               .getService(GRPCHandlerRegister.class);
+        JettyHandlerRegister jettyHandlerRegister = getManager().find(SharingServerModule.NAME)
+                                                                .provider()
+                                                                .getService(JettyHandlerRegister.class);
         try {
             dynamicConfigurationService.registerConfigChangeWatcher(thresholds);
             dynamicConfigurationService.registerConfigChangeWatcher(uninstrumentedGatewaysConfig);
 
             grpcHandlerRegister.addHandler(new TraceSegmentReportServiceHandler(segmentProducerV2, getManager()));
 
-            SegmentStandardizationWorker standardizationWorkerV2 = new SegmentStandardizationWorker(getManager(), segmentProducerV2, moduleConfig
-                .getBufferPath(), moduleConfig.getBufferOffsetMaxFileSize(), moduleConfig.getBufferDataMaxFileSize(), moduleConfig
-                .isBufferFileCleanWhenRestart());
+            jettyHandlerRegister.addHandler(new TraceSegmentCollectServletHandler(segmentProducerV2));
+
+            SegmentStandardizationWorker standardizationWorkerV2 = new SegmentStandardizationWorker(
+                getManager(), segmentProducerV2, moduleConfig
+                .getBufferPath(), moduleConfig.getBufferOffsetMaxFileSize(), moduleConfig.getBufferDataMaxFileSize(),
+                moduleConfig
+                    .isBufferFileCleanWhenRestart()
+            );
             segmentProducerV2.setStandardizationWorker(standardizationWorkerV2);
         } catch (IOException e) {
             throw new ModuleStartException(e.getMessage(), e);
diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/TraceSegmentCollectServletHandler.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/TraceSegmentCollectServletHandler.java
new file mode 100644
index 0000000..44bb243
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/TraceSegmentCollectServletHandler.java
@@ -0,0 +1,76 @@
+/*
+ * 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.receiver.trace.provider.handler.v6.rest;
+
+import com.google.gson.JsonElement;
+import java.io.BufferedReader;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.skywalking.apm.network.language.agent.UpstreamSegment;
+import org.apache.skywalking.oap.server.library.server.jetty.JettyJsonHandler;
+import org.apache.skywalking.oap.server.receiver.trace.provider.handler.v6.rest.reader.UpstreamSegmentJsonReader;
+import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SegmentParseV2;
+import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SegmentSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TraceSegmentCollectServletHandler extends JettyJsonHandler {
+
+    private static final Logger logger = LoggerFactory.getLogger(TraceSegmentCollectServletHandler.class);
+
+    private final SegmentParseV2.Producer segmentProducer;
+
+    private UpstreamSegmentJsonReader upstreamSegmentJsonReader = new UpstreamSegmentJsonReader();
+
+    public TraceSegmentCollectServletHandler(SegmentParseV2.Producer segmentProducer) {
+        this.segmentProducer = segmentProducer;
+    }
+
+    @Override
+    public String pathSpec() {
+        return "/v2/segments";
+    }
+
+    @Override
+    protected JsonElement doGet(HttpServletRequest req) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected JsonElement doPost(HttpServletRequest req) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("receive stream segment");
+        }
+
+        StringBuilder stringBuilder = new StringBuilder();
+        String line = null;
+        try {
+            BufferedReader reader = req.getReader();
+            while ((line = reader.readLine()) != null) {
+                stringBuilder.append(line);
+            }
+            UpstreamSegment upstreamSegment = upstreamSegmentJsonReader.read(stringBuilder.toString()).build();
+
+            segmentProducer.send(upstreamSegment, SegmentSource.Agent);
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+        }
+
+        return null;
+    }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/SegmentJsonReader.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/SegmentJsonReader.java
new file mode 100644
index 0000000..2e78dc1
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/SegmentJsonReader.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.receiver.trace.provider.handler.v6.rest.reader;
+
+import java.io.IOException;
+import org.apache.skywalking.apm.network.language.agent.v2.SegmentObject;
+import org.apache.skywalking.oap.server.library.util.ProtoBufJsonUtils;
+
+public class SegmentJsonReader implements StreamJsonReader<SegmentObject.Builder> {
+
+    @Override
+    public SegmentObject.Builder read(String json) throws IOException {
+        SegmentObject.Builder builder = SegmentObject.newBuilder();
+        ProtoBufJsonUtils.fromJSON(json, builder);
+        return builder;
+    }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/StreamJsonReader.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/StreamJsonReader.java
new file mode 100644
index 0000000..13b7028
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/StreamJsonReader.java
@@ -0,0 +1,25 @@
+/*
+ * 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.receiver.trace.provider.handler.v6.rest.reader;
+
+import java.io.IOException;
+
+public interface StreamJsonReader<T> {
+    T read(String json) throws IOException;
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/UpstreamSegmentJsonReader.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/UpstreamSegmentJsonReader.java
new file mode 100644
index 0000000..3344952
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/UpstreamSegmentJsonReader.java
@@ -0,0 +1,41 @@
+/*
+ * 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.receiver.trace.provider.handler.v6.rest.reader;
+
+import java.io.IOException;
+import org.apache.skywalking.apm.network.language.agent.UpstreamSegment;
+import org.apache.skywalking.apm.network.language.agent.v2.SegmentObject;
+import org.apache.skywalking.oap.server.library.util.ProtoBufJsonUtils;
+
+public class UpstreamSegmentJsonReader implements StreamJsonReader<UpstreamSegment.Builder> {
+
+    private final SegmentJsonReader segmentJsonReader = new SegmentJsonReader();
+
+    @Override
+    public UpstreamSegment.Builder read(String json) throws IOException {
+        UpstreamSegment.Builder upstreamSegmentBuilder = UpstreamSegment.newBuilder();
+        ProtoBufJsonUtils.fromJSON(json, upstreamSegmentBuilder);
+
+        SegmentObject.Builder segmentBuilder = segmentJsonReader.read(json);
+
+        upstreamSegmentBuilder.setSegment(segmentBuilder.build().toByteString());
+
+        return upstreamSegmentBuilder;
+    }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/listener/segment/ProtoBufJsonUtilsTest.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/listener/segment/ProtoBufJsonUtilsTest.java
new file mode 100644
index 0000000..559a908
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/listener/segment/ProtoBufJsonUtilsTest.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.skywalking.oap.server.receiver.trace.provider.parser.listener.segment;
+
+import java.io.IOException;
+import org.apache.skywalking.apm.network.common.Command;
+import org.apache.skywalking.apm.network.common.Commands;
+import org.apache.skywalking.apm.network.language.agent.UpstreamSegment;
+import org.apache.skywalking.apm.network.language.agent.v2.SegmentObject;
+import org.apache.skywalking.oap.server.library.util.ProtoBufJsonUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ProtoBufJsonUtilsTest {
+    @Test
+    public void testProtoBuf() {
+        String json = "{\n" +
+            "  \"spans\": [\n" +
+            "    {\n" +
+            "      \"operationName\": \"/tier2/lb\",\n" +
+            "      \"startTime\": 1582526028207,\n" +
+            "      \"endTime\": 1582526028221,\n" +
+            "      \"spanType\": \"Exit\",\n" +
+            "      \"spanId\": 1,\n" +
+            "      \"isError\": false,\n" +
+            "      \"parentSpanId\": 0,\n" +
+            "      \"componentId\": 6000,\n" +
+            "      \"peer\": \"User Service Name-nginx:upstream_ip:port\",\n" +
+            "      \"spanLayer\": \"HTTP\"\n" +
+            "    },\n" +
+            "    {\n" +
+            "      \"operationName\": \"/tier2/lb\",\n" +
+            "      \"startTime\": 1582526028207,\n" +
+            "      \"tags\": [\n" +
+            "        {\n" +
+            "          \"key\": \"http.method\",\n" +
+            "          \"value\": \"GET\"\n" +
+            "        },\n" +
+            "        {\n" +
+            "          \"key\": \"http.params\",\n" +
+            "          \"value\": \"http://127.0.0.1/tier2/lb\"\n" +
+            "        }\n" +
+            "      ],\n" +
+            "      \"endTime\": 1582526028221,\n" +
+            "      \"spanType\": \"Entry\",\n" +
+            "      \"spanId\": 0,\n" +
+            "      \"isError\": false,\n" +
+            "      \"parentSpanId\": -1,\n" +
+            "      \"componentId\": 6000,\n" +
+            "      \"refs\": [\n" +
+            "        {\n" +
+            "          \"parentTraceSegmentId\": {\n" +
+            "            \"idParts\": [\n" +
+            "              1582526028032,\n" +
+            "              794206293,\n" +
+            "              69887\n" +
+            "            ]\n" +
+            "          },\n" +
+            "          \"parentEndpointId\": 0,\n" +
+            "          \"entryEndpointId\": 0,\n" +
+            "          \"parentServiceInstanceId\": 1,\n" +
+            "          \"parentEndpoint\": \"/ingress\",\n" +
+            "          \"networkAddress\": \"#User Service Name-nginx:upstream_ip:port\",\n" +
+            "          \"parentSpanId\": 1,\n" +
+            "          \"entryServiceInstanceId\": 1,\n" +
+            "          \"networkAddressId\": 0,\n" +
+            "          \"entryEndpoint\": \"/ingress\"\n" +
+            "        }\n" +
+            "      ],\n" +
+            "      \"spanLayer\": \"HTTP\"\n" +
+            "    }\n" +
+            "  ],\n" +
+            "  \"serviceInstanceId\": 1,\n" +
+            "  \"serviceId\": 1,\n" +
+            "  \"traceSegmentId\": {\n" +
+            "    \"idParts\": [\n" +
+            "      1582526028040,\n" +
+            "      794206293,\n" +
+            "      69887\n" +
+            "    ]\n" +
+            "  },\n" +
+            "  \"globalTraceIds\": [\n" +
+            "    {\n" +
+            "      \"idParts\": [\n" +
+            "        1582526028032,\n" +
+            "        794206293,\n" +
+            "        69887\n" +
+            "      ]\n" +
+            "    }\n" +
+            "  ]\n" +
+            "}";
+
+        UpstreamSegment.Builder builder = UpstreamSegment.newBuilder();
+        try {
+            ProtoBufJsonUtils.fromJSON(json, builder);
+            UpstreamSegment upstreamSegment = builder.build();
+            Assert.assertEquals(1582526028032L, upstreamSegment.getGlobalTraceIds(0).getIdParts(0));
+
+            SegmentObject.Builder segBuilder = SegmentObject.newBuilder();
+            ProtoBufJsonUtils.fromJSON(json, segBuilder);
+            SegmentObject segmentObject = segBuilder.build();
+            Assert.assertEquals(2, segmentObject.getSpansCount());
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    @Test
+    public void testToJson() {
+        String json = "{\n" +
+            "  \"commands\": [{\n" +
+            "  }]\n" +
+            "}";
+        try {
+            Command command = Command.newBuilder().build();
+            final Commands nextCommands = Commands.newBuilder().addCommands(command).build();
+            Assert.assertEquals(json, ProtoBufJsonUtils.toJSON(nextCommands));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/pom.xml b/test/e2e/e2e-http-api-with-nginx-lua/pom.xml
new file mode 100755
index 0000000..012723a
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/pom.xml
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>apache-skywalking-e2e</artifactId>
+        <groupId>org.apache.skywalking</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>e2e-http-api-with-nginx-lua</artifactId>
+
+    <properties>
+        <e2e.container.version>1.1</e2e.container.version>
+        <e2e.container.name.prefix>skywalking-e2e-container-${build.id}-http-api-with-nginx-lua
+        </e2e.container.name.prefix>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>e2e-base</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring.boot.version}</version>
+                <configuration>
+                    <executable>true</executable>
+                    <addResources>true</addResources>
+                    <excludeDevtools>true</excludeDevtools>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>io.fabric8</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+                <configuration>
+                    <containerNamePattern>%a-%t-%i</containerNamePattern>
+                    <images>
+                        <image>
+                            <name>skyapm/e2e-container:${e2e.container.version}</name>
+                            <alias>e2e-container-app-for-nginx-lua</alias>
+                            <run>
+                                <env>
+                                    <INSTRUMENTED_SERVICE>${project.build.finalName}.jar</INSTRUMENTED_SERVICE>
+                                    <INSTRUMENTED_SERVICE_OPTS>-Dskywalking.agent.cool_down_threshold=1
+                                    </INSTRUMENTED_SERVICE_OPTS>
+                                </env>
+                                <ports>
+                                    <port>+webapp.host:webapp.port:8080</port>
+                                    <port>+client.host:client.port:9090</port>
+                                </ports>
+                                <volumes>
+                                    <bind>
+                                        <volume>${sw.home}:/sw</volume>
+                                        <volume>${project.build.directory}:/home</volume>
+                                        <volume>
+                                            ${project.basedir}/src/docker/rc.d/rc1-startup.sh:/rc.d/rc1-startup.sh:ro
+                                        </volume>
+                                    </bind>
+                                </volumes>
+                                <wait>
+                                    <http>
+                                        <url>
+                                            http://${docker.host.address}:${client.port}/e2e/info
+                                        </url>
+                                        <method>GET</method>
+                                        <status>200</status>
+                                    </http>
+                                    <time>300000</time>
+                                </wait>
+                            </run>
+                        </image>
+
+                        <image>
+                            <name>openresty/openresty</name>
+                            <alias>${e2e.container.name.prefix}-openresty</alias>
+
+                            <run>
+                                <env>
+                                    <SKYWALKING_NINGX_LUA_GIT_COMMIT_ID>c6aca516200573a64db7060cefb5d3608c571c3a
+                                    </SKYWALKING_NINGX_LUA_GIT_COMMIT_ID>
+                                </env>
+                                <links>
+                                    <link>e2e-container-app-for-nginx-lua:upstream</link>
+                                </links>
+                                <ports>
+                                    <port>+nginx.host:nginx.port:8080</port>
+                                </ports>
+                                <volumes>
+                                    <bind>
+                                        <volume>${project.basedir}/src/docker/rc.d:/rc.d:ro</volume>
+                                    </bind>
+                                </volumes>
+                                <wait>
+                                    <http>
+                                        <url>
+                                            http://${docker.host.address}:${nginx.port}
+                                        </url>
+                                    </http>
+                                    <time>3000000</time>
+                                </wait>
+                                <cmd>/rc.d/rc0-prepare.sh</cmd>
+                            </run>
+                        </image>
+                    </images>
+                </configuration>
+            </plugin>
+
+            <!-- set the system properties that can be used in test codes -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-failsafe-plugin</artifactId>
+                <configuration>
+                    <systemPropertyVariables>
+                        <sw.webapp.host>
+                            ${webapp.host}
+                        </sw.webapp.host>
+                        <sw.webapp.port>
+                            ${webapp.port}
+                        </sw.webapp.port>
+                        <client.host>
+                            ${client.host}
+                        </client.host>
+                        <client.port>
+                            ${client.port}
+                        </client.port>
+                        <nginx.port>
+                            ${nginx.port}
+                        </nginx.port>
+                    </systemPropertyVariables>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>verify</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-failsafe-plugin</artifactId>
+                <version>${maven-failsafe-plugin.version}</version>
+                <configuration>
+                    <systemPropertyVariables>
+                        <ping.url>
+                            http://${nginx.host}:${nginx.port}/ingress
+                        </ping.url>
+                    </systemPropertyVariables>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>verify</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/docker/rc.d/rc0-prepare.sh b/test/e2e/e2e-http-api-with-nginx-lua/src/docker/rc.d/rc0-prepare.sh
new file mode 100755
index 0000000..39b7ed5
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/docker/rc.d/rc0-prepare.sh
@@ -0,0 +1,95 @@
+#!/usr/bin/env bash
+# Licensed to the SkyAPM 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.
+
+#!/bin/bash
+
+set -e
+
+var_application_file="/var/nginx/conf.d/nginx.conf"
+
+var_upstream_ip=$(cat /etc/hosts|grep upstream|awk '{print $1'})
+
+apt-get update && apt-get -y install git
+
+echo 'git clone skyalking-nginx-lua lib from https://github.com/apache/skywalking-nginx-lua.git'
+
+git clone https://github.com/apache/skywalking-nginx-lua.git /usr/share/skywalking-nginx-lua \
+  && cd /usr/share/skywalking-nginx-lua \
+  && git checkout ${SKYWALKING_NINGX_LUA_GIT_COMMIT_ID} \
+  && ls ./ \
+  && mkdir -p /var/nginx/conf.d
+
+
+generateNginxConf() {
+     cat <<EOT >> ${var_application_file}
+worker_processes  1;
+daemon off;
+error_log /dev/stdout error;
+
+events {
+    worker_connections 1024;
+}
+http {
+    lua_package_path "/usr/share/skywalking-nginx-lua/lib/skywalking/?.lua;;";
+    # Buffer represents the register inform and the queue of the finished segment
+    lua_shared_dict tracing_buffer 100m;
+
+    # Init is the timer setter and keeper
+    # Setup an infinite loop timer to do register and trace report.
+    init_worker_by_lua_block {
+        local metadata_buffer = ngx.shared.tracing_buffer
+
+        metadata_buffer:set('serviceName', 'User_Service_Name')
+        -- Instance means the number of Nginx deloyment, does not mean the worker instances
+        metadata_buffer:set('serviceInstanceName', 'User_Service_Instance_Name')
+
+        require("client"):startBackendTimer("http://${var_upstream_ip}:12800")
+    }
+    log_format sw_trace escape=json "$uri $request_body";
+
+    server {
+        listen 8080;
+
+        location /nginx/e2e/info {
+
+            rewrite_by_lua_block {
+                require("tracer"):start("User_Service_Name")
+            }
+
+            proxy_pass http://upstream:9090/e2e/info;
+
+            body_filter_by_lua_block {
+                require("tracer"):finish()
+            }
+
+            log_by_lua_block {
+                require("tracer"):prepareForReport()
+            }
+        }
+    }
+}
+EOT
+}
+
+generateNginxConf;
+
+echo 'generated nginx.conf:'
+
+cat ${var_application_file}
+
+/usr/bin/openresty -c ${var_application_file}
+sync
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/docker/rc.d/rc1-startup.sh b/test/e2e/e2e-http-api-with-nginx-lua/src/docker/rc.d/rc1-startup.sh
new file mode 100755
index 0000000..9328f7c
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/docker/rc.d/rc1-startup.sh
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+# Licensed to the SkyAPM 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.
+
+echo 'starting OAP server...' \
+    && SW_STORAGE_ES_BULK_ACTIONS=1 \
+    && SW_STORAGE_ES_FLUSH_INTERVAL=1 \
+    && SW_RECEIVER_BUFFER_PATH=/tmp/oap/trace_buffer1 \
+    && SW_SERVICE_MESH_BUFFER_PATH=/tmp/oap/mesh_buffer1 \
+    && start_oap 'init'
+
+echo 'starting Web app...' \
+    && start_webapp '0.0.0.0' 8080
+
+echo 'starting instrumented services...' \
+    && start_instrumented_services
+
+check_tcp 127.0.0.1 \
+          9090 \
+          60 \
+          10 \
+          "waiting for the instrumented service to be ready"
+
+if [[ $? -ne 0 ]]; then
+    echo "instrumented service failed to start in 30 * 10 seconds: "
+    cat ${SERVICE_LOG}/*
+    exit 1
+fi
+
+echo "SkyWalking e2e container is ready for tests"
+
+tail -f ${OAP_LOG_DIR}/* \
+        ${WEBAPP_LOG_DIR}/* \
+        ${SERVICE_LOG}/* \
+        ${ES_HOME}/logs/stdout.log
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/main/java/org/apache/skywalking/e2e/sample/client/SampleClientApplication.java b/test/e2e/e2e-http-api-with-nginx-lua/src/main/java/org/apache/skywalking/e2e/sample/client/SampleClientApplication.java
new file mode 100644
index 0000000..c661c17
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/main/java/org/apache/skywalking/e2e/sample/client/SampleClientApplication.java
@@ -0,0 +1,29 @@
+/*
+ * 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.e2e.sample.client;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SampleClientApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(SampleClientApplication.class, args);
+    }
+}
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/main/java/org/apache/skywalking/e2e/sample/client/TestController.java b/test/e2e/e2e-http-api-with-nginx-lua/src/main/java/org/apache/skywalking/e2e/sample/client/TestController.java
new file mode 100644
index 0000000..03319c7
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/main/java/org/apache/skywalking/e2e/sample/client/TestController.java
@@ -0,0 +1,32 @@
+/*
+ * 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.e2e.sample.client;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/e2e")
+public class TestController {
+    @GetMapping("/info")
+    public String hello() {
+        return "e2e-container-info";
+    }
+}
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/main/resources/application.yml b/test/e2e/e2e-http-api-with-nginx-lua/src/main/resources/application.yml
new file mode 100644
index 0000000..83d1e3d
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/main/resources/application.yml
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+server:
+  port: 9090
+
+spring:
+  main:
+    banner-mode: 'off'
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java b/test/e2e/e2e-http-api-with-nginx-lua/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java
new file mode 100644
index 0000000..33eafb4
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java
@@ -0,0 +1,386 @@
+/*
+ * 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.e2e;
+
+import java.io.InputStream;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.skywalking.e2e.metrics.AtLeastOneOfMetricsMatcher;
+import org.apache.skywalking.e2e.metrics.Metrics;
+import org.apache.skywalking.e2e.metrics.MetricsQuery;
+import org.apache.skywalking.e2e.metrics.MetricsValueMatcher;
+import org.apache.skywalking.e2e.service.Service;
+import org.apache.skywalking.e2e.service.ServicesMatcher;
+import org.apache.skywalking.e2e.service.ServicesQuery;
+import org.apache.skywalking.e2e.service.endpoint.Endpoint;
+import org.apache.skywalking.e2e.service.endpoint.EndpointQuery;
+import org.apache.skywalking.e2e.service.endpoint.Endpoints;
+import org.apache.skywalking.e2e.service.endpoint.EndpointsMatcher;
+import org.apache.skywalking.e2e.service.instance.Instance;
+import org.apache.skywalking.e2e.service.instance.Instances;
+import org.apache.skywalking.e2e.service.instance.InstancesMatcher;
+import org.apache.skywalking.e2e.service.instance.InstancesQuery;
+import org.apache.skywalking.e2e.topo.Call;
+import org.apache.skywalking.e2e.topo.ServiceInstanceTopoData;
+import org.apache.skywalking.e2e.topo.ServiceInstanceTopoMatcher;
+import org.apache.skywalking.e2e.topo.ServiceInstanceTopoQuery;
+import org.apache.skywalking.e2e.topo.TopoData;
+import org.apache.skywalking.e2e.topo.TopoMatcher;
+import org.apache.skywalking.e2e.topo.TopoQuery;
+import org.apache.skywalking.e2e.trace.Trace;
+import org.apache.skywalking.e2e.trace.TracesMatcher;
+import org.apache.skywalking.e2e.trace.TracesQuery;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.web.client.RestTemplate;
+import org.yaml.snakeyaml.Yaml;
+
+import static org.apache.skywalking.e2e.metrics.MetricsMatcher.verifyMetrics;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_ENDPOINT_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_INSTANCE_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_INSTANCE_RELATION_CLIENT_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_INSTANCE_RELATION_SERVER_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_RELATION_CLIENT_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_RELATION_SERVER_METRICS;
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+public class SampleVerificationITCase {
+    private static final Logger LOGGER = LoggerFactory.getLogger(SampleVerificationITCase.class);
+
+    private final RestTemplate restTemplate = new RestTemplate();
+    private final int retryInterval = 30;
+
+    private SimpleQueryClient queryClient;
+    private String nginxServiceUrl;
+
+    @Before
+    public void setUp() {
+        final String swWebappHost = System.getProperty("sw.webapp.host", "127.0.0.1");
+        final String swWebappPort = System.getProperty("sw.webapp.port", "32783");
+        final String nginxHost = System.getProperty("nginx.host", "127.0.0.1");
+        final String nginxPort = System.getProperty("nginx.port", "32782");
+        queryClient = new SimpleQueryClient(swWebappHost, swWebappPort);
+        nginxServiceUrl = "http://" + nginxHost + ":" + nginxPort;
+    }
+
+    @Test(timeout = 1200000)
+    @DirtiesContext
+    public void verify() throws Exception {
+        final LocalDateTime minutesAgo = LocalDateTime.now(ZoneOffset.UTC);
+
+        while (true) {
+            final List<Service> services = queryClient.services(
+                new ServicesQuery().start(minutesAgo).end(LocalDateTime.now()));
+
+            if (!services.isEmpty() && services.size() >= 2) {
+                break;
+            }
+            Thread.sleep(10000L);
+        }
+
+        while (true) {
+            try {
+                final Map<String, String> user = new HashMap<>();
+                user.put("name", "SkyWalking");
+                final ResponseEntity<String> responseEntity = restTemplate.getForEntity(
+                    nginxServiceUrl + "/nginx/e2e/info", String.class);
+                LOGGER.info("responseEntity: {}", responseEntity);
+                assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
+                assertThat(responseEntity.getBody()).isEqualTo("e2e-container-info");
+                final List<Trace> traces = queryClient.traces(new TracesQuery().start(minutesAgo)
+                                                                               .end(LocalDateTime.now())
+                                                                               .orderByDuration());
+                if (!traces.isEmpty() && traces.size() >= 2) {
+                    break;
+                }
+                Thread.sleep(10000L);
+            } catch (Exception ignored) {
+            }
+        }
+
+        doRetryableVerification(() -> {
+            try {
+                verifyTraces(minutesAgo);
+            } catch (Exception e) {
+                LOGGER.warn(e.getMessage(), e);
+            }
+        });
+
+        doRetryableVerification(() -> {
+            try {
+                verifyServices(minutesAgo);
+            } catch (Exception e) {
+                LOGGER.warn(e.getMessage(), e);
+            }
+        });
+
+        doRetryableVerification(() -> {
+            try {
+                verifyTopo(minutesAgo);
+            } catch (Exception e) {
+                LOGGER.warn(e.getMessage(), e);
+            }
+        });
+
+        doRetryableVerification(() -> {
+            try {
+                verifyServiceInstanceTopo(minutesAgo);
+            } catch (Exception e) {
+                LOGGER.warn(e.getMessage(), e);
+            }
+        });
+    }
+
+    private void verifyTopo(LocalDateTime minutesAgo) throws Exception {
+        final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
+
+        final TopoData topoData = queryClient.topo(new TopoQuery().stepByMinute()
+                                                                  .start(minutesAgo.minusDays(1))
+                                                                  .end(now));
+        LOGGER.info("topoData: {}", topoData);
+
+        InputStream expectedInputStream = new ClassPathResource(
+            "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml")
+            .getInputStream();
+
+        final TopoMatcher topoMatcher = new Yaml().loadAs(expectedInputStream, TopoMatcher.class);
+        topoMatcher.verify(topoData);
+        verifyServiceRelationMetrics(topoData.getCalls(), minutesAgo);
+    }
+
+    private void verifyServiceInstanceTopo(LocalDateTime minutesAgo) throws Exception {
+        final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
+
+        final ServiceInstanceTopoData topoData = queryClient.serviceInstanceTopo(
+            new ServiceInstanceTopoQuery().stepByMinute()
+                                          .start(minutesAgo
+                                                     .minusDays(1))
+                                          .end(now)
+                                          .clientServiceId("1")
+                                          .serverServiceId("3"));
+        LOGGER.info("instanceTopoData: {}", topoData);
+
+        InputStream expectedInputStream = new ClassPathResource(
+            "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml")
+            .getInputStream();
+
+        final ServiceInstanceTopoMatcher topoMatcher = new Yaml().loadAs(
+            expectedInputStream, ServiceInstanceTopoMatcher.class);
+        topoMatcher.verify(topoData);
+        verifyServiceInstanceRelationMetrics(topoData.getCalls(), minutesAgo);
+    }
+
+    private void verifyServices(LocalDateTime minutesAgo) throws Exception {
+        final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
+
+        final List<Service> services = queryClient.services(new ServicesQuery().start(minutesAgo).end(now));
+        LOGGER.info("services: {}", services);
+
+        InputStream expectedInputStream = new ClassPathResource(
+            "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml")
+            .getInputStream();
+
+        final ServicesMatcher servicesMatcher = new Yaml().loadAs(expectedInputStream, ServicesMatcher.class);
+        servicesMatcher.verify(services);
+
+        for (Service service : services) {
+            LOGGER.info("verifying service instances: {}", service);
+
+            verifyServiceMetrics(service);
+
+            Instances instances = verifyServiceInstances(minutesAgo, now, service);
+
+            verifyInstancesMetrics(instances);
+
+            Endpoints endpoints = verifyServiceEndpoints(minutesAgo, now, service);
+
+            verifyEndpointsMetrics(endpoints);
+        }
+    }
+
+    private Instances verifyServiceInstances(LocalDateTime minutesAgo, LocalDateTime now,
+                                             Service service) throws Exception {
+        Instances instances = queryClient.instances(new InstancesQuery().serviceId(service.getKey())
+                                                                        .start(minutesAgo)
+                                                                        .end(now));
+        LOGGER.info("instances: {}", instances);
+        InputStream expectedInputStream;
+        if ("User_Service_Name".equals(service.getLabel())) {
+            expectedInputStream = new ClassPathResource(
+                "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.nginxInstances.yml")
+                .getInputStream();
+        } else {
+            expectedInputStream = new ClassPathResource(
+                "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml")
+                .getInputStream();
+        }
+        final InstancesMatcher instancesMatcher = new Yaml().loadAs(expectedInputStream, InstancesMatcher.class);
+        instancesMatcher.verify(instances);
+        return instances;
+    }
+
+    private Endpoints verifyServiceEndpoints(LocalDateTime minutesAgo, LocalDateTime now,
+                                             Service service) throws Exception {
+        Endpoints endpoints = queryClient.endpoints(new EndpointQuery().serviceId(service.getKey()));
+        LOGGER.info("instances: {}", endpoints);
+        InputStream expectedInputStream;
+
+        if ("/e2e/health-check".equals(endpoints.getEndpoints().get(0).getLabel())) {
+            expectedInputStream = new ClassPathResource(
+                "org.apache.skywalking.e2e.SampleVerificationITCase.nginxEndpoints.yml")
+                .getInputStream();
+        } else {
+            expectedInputStream = new ClassPathResource(
+                "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml")
+                .getInputStream();
+        }
+        final EndpointsMatcher endpointsMatcher = new Yaml().loadAs(expectedInputStream, EndpointsMatcher.class);
+        endpointsMatcher.verify(endpoints);
+        return endpoints;
+    }
+
+    private void verifyInstancesMetrics(Instances instances) throws Exception {
+        for (Instance instance : instances.getInstances()) {
+            for (String metricsName : ALL_INSTANCE_METRICS) {
+                LOGGER.info("verifying service instance response time: {}", instance);
+                final Metrics instanceMetrics = queryClient.metrics(new MetricsQuery().stepByMinute()
+                                                                                      .metricsName(metricsName)
+                                                                                      .id(instance.getKey()));
+                LOGGER.info("instanceMetrics: {}", instanceMetrics);
+                AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher();
+                MetricsValueMatcher greaterThanZero = new MetricsValueMatcher();
+                greaterThanZero.setValue("ge 0");
+                instanceRespTimeMatcher.setValue(greaterThanZero);
+                instanceRespTimeMatcher.verify(instanceMetrics);
+                LOGGER.info("{}: {}", metricsName, instanceMetrics);
+            }
+        }
+    }
+
+    private void verifyEndpointsMetrics(Endpoints endpoints) throws Exception {
+        for (Endpoint endpoint : endpoints.getEndpoints()) {
+            if (!endpoint.getLabel().equals("/e2e/info") || !endpoint.getLabel()
+                                                                             .equals("/nginx/e2e/info")) {
+                continue;
+            }
+            for (String metricName : ALL_ENDPOINT_METRICS) {
+                LOGGER.info("verifying endpoint {}, metrics: {}", endpoint, metricName);
+                final Metrics metrics = queryClient.metrics(new MetricsQuery().stepByMinute()
+                                                                              .metricsName(metricName)
+                                                                              .id(endpoint.getKey()));
+                LOGGER.info("metrics: {}", metrics);
+                AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher();
+                MetricsValueMatcher greaterThanZero = new MetricsValueMatcher();
+                greaterThanZero.setValue("ge 0");
+                instanceRespTimeMatcher.setValue(greaterThanZero);
+                instanceRespTimeMatcher.verify(metrics);
+                LOGGER.info("{}: {}", metricName, metrics);
+            }
+        }
+    }
+
+    private void verifyServiceMetrics(Service service) throws Exception {
+        for (String metricName : ALL_SERVICE_METRICS) {
+            LOGGER.info("verifying service {}, metrics: {}", service, metricName);
+            final Metrics serviceMetrics = queryClient.metrics(new MetricsQuery().stepByMinute()
+                                                                                 .metricsName(metricName)
+                                                                                 .id(service.getKey()));
+            LOGGER.info("serviceMetrics: {}", serviceMetrics);
+            AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher();
+            MetricsValueMatcher greaterThanZero = new MetricsValueMatcher();
+            greaterThanZero.setValue("ge 0");
+            instanceRespTimeMatcher.setValue(greaterThanZero);
+            instanceRespTimeMatcher.verify(serviceMetrics);
+            LOGGER.info("{}: {}", metricName, serviceMetrics);
+        }
+    }
+
+    private void verifyTraces(LocalDateTime minutesAgo) throws Exception {
+        final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
+
+        final List<Trace> traces = queryClient.traces(new TracesQuery().start(minutesAgo).end(now).orderByDuration());
+        LOGGER.info("traces: {}", traces);
+
+        InputStream expectedInputStream = new ClassPathResource(
+            "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml")
+            .getInputStream();
+
+        final TracesMatcher tracesMatcher = new Yaml().loadAs(expectedInputStream, TracesMatcher.class);
+        tracesMatcher.verifyLoosely(traces);
+    }
+
+    private void verifyServiceInstanceRelationMetrics(List<Call> calls,
+                                                      final LocalDateTime minutesAgo) throws Exception {
+        verifyRelationMetrics(
+            calls, minutesAgo, ALL_SERVICE_INSTANCE_RELATION_CLIENT_METRICS,
+            ALL_SERVICE_INSTANCE_RELATION_SERVER_METRICS
+        );
+    }
+
+    private void verifyServiceRelationMetrics(List<Call> calls, final LocalDateTime minutesAgo) throws Exception {
+        verifyRelationMetrics(
+            calls, minutesAgo, ALL_SERVICE_RELATION_CLIENT_METRICS, ALL_SERVICE_RELATION_SERVER_METRICS);
+    }
+
+    private void verifyRelationMetrics(List<Call> calls, final LocalDateTime minutesAgo, String[] relationClientMetrics,
+                                       String[] relationServerMetrics) throws Exception {
+        for (Call call : calls) {
+            for (String detectPoint : call.getDetectPoints()) {
+                switch (detectPoint) {
+                    case "CLIENT": {
+                        for (String metricName : relationClientMetrics) {
+                            verifyMetrics(queryClient, metricName, call.getId(), minutesAgo);
+                        }
+                        break;
+                    }
+                    case "SERVER": {
+                        for (String metricName : relationServerMetrics) {
+                            verifyMetrics(queryClient, metricName, call.getId(), minutesAgo);
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    private void doRetryableVerification(Runnable runnable) throws InterruptedException {
+        while (true) {
+            try {
+                runnable.run();
+                break;
+            } catch (Throwable ignored) {
+                Thread.sleep(retryInterval);
+            }
+        }
+    }
+}
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml
new file mode 100644
index 0000000..ed06316
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml
@@ -0,0 +1,28 @@
+# 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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+endpoints:
+  - key: not null
+    label: /e2e/info
+
+
+
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml
new file mode 100644
index 0000000..26bb314
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml
@@ -0,0 +1,34 @@
+# 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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+instances:
+  - key: 2
+    label: not null
+    attributes:
+      - name: os_name
+        value: not null
+      - name: host_name
+        value: not null
+      - name: process_no
+        value: gt 0
+      - name: ipv4s
+        value: not null
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml
new file mode 100644
index 0000000..6661a99
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml
@@ -0,0 +1,41 @@
+# 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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+nodes:
+  - id: 1
+    name: User
+    type: USER
+    serviceId: 1
+    serviceName: User
+    isReal: false
+  - id: 3
+    name: not null
+    serviceId: 3
+    serviceName: User_Service_Name
+    type: not null
+    isReal: true
+calls:
+  - id: 1_3
+    source: 1
+    detectPoints:
+      - SERVER
+    target: 3
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml
new file mode 100644
index 0000000..ef0df12
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml
@@ -0,0 +1,27 @@
+# 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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+services:
+  - key: 2
+    label: "Your_ApplicationName"
+  - key: 3
+    label: "User_Service_Name"
\ No newline at end of file
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml
new file mode 100644
index 0000000..2ca7456
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml
@@ -0,0 +1,47 @@
+# 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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+nodes:
+  - id: 1
+    name: User
+    type: USER
+    isReal: false
+  - id: 2
+    name: Your_ApplicationName
+    type: Tomcat
+    isReal: true
+  - id: 3
+    name: User_Service_Name
+    type: Nginx
+    isReal: true
+calls:
+  - id: 1_3
+    source: 1
+    detectPoints:
+      - SERVER
+    target: 3
+  - id: 3_2
+    source: 3
+    detectPoints:
+      - CLIENT
+      - SERVER
+    target: 2
\ No newline at end of file
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml
new file mode 100644
index 0000000..0552a1c
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml
@@ -0,0 +1,40 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+traces:
+  - key: not null
+    endpointNames:
+      - /e2e/info
+    duration: ge 0
+    start: gt 0
+    isError: false
+    traceIds:
+      - not null
+
+  - key: not null
+    endpointNames:
+      - /nginx/e2e/info
+    duration: ge 0
+    start: gt 0
+    isError: false
+    traceIds:
+      - not null
\ No newline at end of file
diff --git a/test/e2e/pom.xml b/test/e2e/pom.xml
index 0a6c8b5..31790ae 100644
--- a/test/e2e/pom.xml
+++ b/test/e2e/pom.xml
@@ -44,6 +44,7 @@
         <module>e2e-6.x-agent-7.x-oap-compatibility</module>
         <module>e2e-profile</module>
         <module>e2e-protocol</module>
+        <module>e2e-http-api-with-nginx-lua</module>
     </modules>
 
     <properties>
diff --git a/tools/dependencies/known-oap-backend-dependencies-es7.txt b/tools/dependencies/known-oap-backend-dependencies-es7.txt
index 59c3f8d..2f20ac2 100755
--- a/tools/dependencies/known-oap-backend-dependencies-es7.txt
+++ b/tools/dependencies/known-oap-backend-dependencies-es7.txt
@@ -142,7 +142,8 @@ opencensus-contrib-grpc-metrics-0.24.0.jar
 parent-join-client-7.0.0.jar
 perfmark-api-0.19.0.jar
 proto-google-common-protos-1.12.0.jar
-protobuf-java-3.4.0.jar
+protobuf-java-3.11.4.jar
+protobuf-java-util-3.11.4.jar
 rank-eval-client-7.0.0.jar
 reactive-streams-1.0.2.jar
 reflectasm-1.11.7.jar
diff --git a/tools/dependencies/known-oap-backend-dependencies.txt b/tools/dependencies/known-oap-backend-dependencies.txt
index 836cced..8b9e854 100755
--- a/tools/dependencies/known-oap-backend-dependencies.txt
+++ b/tools/dependencies/known-oap-backend-dependencies.txt
@@ -140,7 +140,8 @@ opencensus-contrib-grpc-metrics-0.24.0.jar
 parent-join-client-6.3.2.jar
 perfmark-api-0.19.0.jar
 proto-google-common-protos-1.12.0.jar
-protobuf-java-3.4.0.jar
+protobuf-java-3.11.4.jar
+protobuf-java-util-3.11.4.jar
 rank-eval-client-6.3.2.jar
 reactive-streams-1.0.2.jar
 reflectasm-1.11.7.jar