You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2018/12/04 10:46:07 UTC

[servicecomb-java-chassis] 01/03: [SCB-1063]Improve the time cost when first time loading schema

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

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit b60605b7118c0271a3041650761138e0b02e43ca
Author: liubao <ba...@huawei.com>
AuthorDate: Tue Dec 4 10:51:23 2018 +0800

    [SCB-1063]Improve the time cost when first time loading schema
---
 .../definition/schema/ConsumerSchemaFactory.java   |  8 +++-
 .../client/http/ServiceRegistryClientImpl.java     | 46 ++++++++++++++++++++--
 .../client/http/TestServiceRegistryClientImpl.java | 20 ++++++++++
 3 files changed, 69 insertions(+), 5 deletions(-)

diff --git a/core/src/main/java/org/apache/servicecomb/core/definition/schema/ConsumerSchemaFactory.java b/core/src/main/java/org/apache/servicecomb/core/definition/schema/ConsumerSchemaFactory.java
index c9b8ed2..36148ab 100644
--- a/core/src/main/java/org/apache/servicecomb/core/definition/schema/ConsumerSchemaFactory.java
+++ b/core/src/main/java/org/apache/servicecomb/core/definition/schema/ConsumerSchemaFactory.java
@@ -37,7 +37,9 @@ public class ConsumerSchemaFactory extends AbstractSchemaFactory<ConsumerSchemaC
   // 允许consumerIntf与schemaId对应的interface原型不同,用于支持context类型的参数
   // consumerIntf为null,表示原型与契约相同
   public void createConsumerSchema(MicroserviceMeta microserviceMeta, Microservice microservice) {
-    for (String schemaId : microservice.getSchemas()) {
+    // concurrently compile will improve performance, so we force using parallel stream
+    long start = System.currentTimeMillis();
+    microservice.getSchemas().parallelStream().forEach(schemaId -> {
       ConsumerSchemaContext context = new ConsumerSchemaContext();
       context.setMicroserviceMeta(microserviceMeta);
       context.setMicroservice(microservice);
@@ -45,7 +47,9 @@ public class ConsumerSchemaFactory extends AbstractSchemaFactory<ConsumerSchemaC
       context.setProviderClass(null);
 
       getOrCreateSchema(context);
-    }
+    });
+    LOGGER.info("Loading schema for service {} token {}", microservice.getServiceId(),
+        (System.currentTimeMillis() - start));
   }
 
   @Override
diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java
index c27ba96..3ee0fe8 100644
--- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java
+++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java
@@ -21,10 +21,13 @@ import static java.util.Collections.emptyList;
 
 import java.nio.charset.Charset;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 
 import javax.ws.rs.core.Response.Status;
 
@@ -60,6 +63,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
 
 import io.netty.handler.codec.http.HttpStatusClass;
 import io.vertx.core.Handler;
@@ -79,6 +85,18 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
     this.ipPortManager = ipPortManager;
   }
 
+  private LoadingCache<String, Map<String, String>> schemaCache = CacheBuilder.newBuilder()
+      .expireAfterAccess(60, TimeUnit.SECONDS).build(new CacheLoader<String, Map<String, String>>() {
+        public Map<String, String> load(String key) {
+          Holder<List<GetSchemaResponse>> result = getSchemas(key, true, true);
+          Map<String, String> schemas = new HashMap<>();
+          if (result.getStatusCode() == Status.OK.getStatusCode() ) {
+            result.value.stream().forEach(r -> schemas.put(r.getSchemaId(), r.getSchema()));
+          }
+          return schemas;
+        }
+      });
+
   @Override
   public void init() {
   }
@@ -350,6 +368,16 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
   }
 
   private String doGetSchema(String microserviceId, String schemaId, boolean global) {
+    try {
+      // avoid query too many times of schema when first time loading
+      String cachedSchema = schemaCache.get(microserviceId).get(schemaId);
+      if (cachedSchema != null) {
+        return cachedSchema;
+      }
+    } catch (ExecutionException e) {
+      // ignore this error.
+    }
+
     Holder<GetSchemaResponse> holder = new Holder<>();
     IpPort ipPort = ipPortManager.getAvailableAddress();
 
@@ -383,15 +411,27 @@ public final class ServiceRegistryClientImpl implements ServiceRegistryClient {
 
   @Override
   public Holder<List<GetSchemaResponse>> getSchemas(String microserviceId) {
+    return getSchemas(microserviceId, false, false);
+  }
+
+  private Holder<List<GetSchemaResponse>> getSchemas(String microserviceId, boolean withSchema, boolean global) {
     Holder<GetSchemasResponse> holder = new Holder<>();
     IpPort ipPort = ipPortManager.getAvailableAddress();
     Holder<List<GetSchemaResponse>> resultHolder = new Holder<>();
 
     CountDownLatch countDownLatch = new CountDownLatch(1);
-    // default not return schema content, just return summary!
+    String url = Const.REGISTRY_API.MICROSERVICE_ALL_SCHEMAs;
+    RequestParam requestParam = new RequestParam();
+    if (withSchema) {
+      url = Const.REGISTRY_API.MICROSERVICE_ALL_SCHEMAs + "?withSchema=1";
+    }
+    if (global) {
+      requestParam.addQueryParam("global", "true");
+    }
+
     RestUtils.get(ipPort,
-        String.format(Const.REGISTRY_API.MICROSERVICE_ALL_SCHEMAs, microserviceId),
-        new RequestParam(),
+        String.format(url, microserviceId),
+        requestParam,
         syncHandler(countDownLatch, GetSchemasResponse.class, holder));
     try {
       countDownLatch.await();
diff --git a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
index cba18e2..900f534 100644
--- a/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
+++ b/service-registry/src/test/java/org/apache/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
@@ -20,8 +20,11 @@ package org.apache.servicecomb.serviceregistry.client.http;
 import static org.hamcrest.core.Is.is;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 import javax.ws.rs.core.Response.Status;
 
@@ -47,6 +50,10 @@ import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
 
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
 import io.vertx.core.Handler;
 import io.vertx.core.buffer.Buffer;
 import io.vertx.core.http.HttpClientOptions;
@@ -343,8 +350,21 @@ public class TestServiceRegistryClientImpl {
         Assert.assertEquals("global=true", requestParam.getQueryParams());
       }
     };
+
+    LoadingCache<String, Map<String, String>> oldCache = Deencapsulation.getField(oClient, "schemaCache");
+    LoadingCache<String, Map<String, String>> newCache = CacheBuilder.newBuilder()
+        .expireAfterAccess(60, TimeUnit.SECONDS).build(new CacheLoader<String, Map<String, String>>() {
+          public Map<String, String> load(String key) {
+            Map<String, String> schemas = new HashMap<>();
+            return schemas;
+          }
+        });
+    Deencapsulation.setField(oClient, "schemaCache", newCache);
+
     String str = oClient.getAggregatedSchema(microserviceId, schemaId);
     Assert.assertEquals("schema", str);
+
+    Deencapsulation.setField(oClient, "schemaCache", oldCache);
   }
 
   @Test