Repository: googleapis/java-datastore
Pull request #1706 (2025-01-09 19:22:43)

feat: Improve upon the default gRPC Connection Pool size
The current Java SDK uses a default gRPC connection pool with only [ one channel ](https://github.com/googleapis/sdk-platform-java/blob/816b1608e52543b4b5ade40056c89740fe35a459/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java#L627). This can cause performance issues for clients with high request rates (over 100 queries per second) because they may experience throttling.

To address this, this PR update proposes changing the default connection pool settings to allow for multiple channels (minimum 1, maximum 4). This should improve performance for clients with high request rates, without requiring any changes to their code. Customers can still customize the connection pool settings if needed.


Please refer here for more details: 
[configure a more reasonable default grpc connection pool config](https://b.corp.google.com/issues/378924444)


cindy-peng: > Could you use constants for gRPC minimum and maximum channel counts?

Good catch! Fixed.
generated-files-bot[bot]: <!-- probot comment [12634855]-->
*Warning*: This pull request is touching the following templated files:

* .github/workflows/ci.yaml

Patch:
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreOptions.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreOptions.java
index 7dda76f7..1ea79298 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreOptions.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/DatastoreOptions.java
@@ -19,6 +19,7 @@ package com.google.cloud.datastore;
 import static com.google.cloud.datastore.Validator.validateNamespace;
 
 import com.google.api.core.BetaApi;
+import com.google.api.gax.grpc.ChannelPoolSettings;
 import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
 import com.google.api.gax.rpc.TransportChannelProvider;
 import com.google.cloud.ServiceDefaults;
@@ -50,6 +51,9 @@ public class DatastoreOptions extends ServiceOptions<Datastore, DatastoreOptions
   private static final String DEFAULT_DATABASE_ID = "";
   public static final String PROJECT_ID_ENV_VAR = "DATASTORE_PROJECT_ID";
   public static final String LOCAL_HOST_ENV_VAR = "DATASTORE_EMULATOR_HOST";
+  public static final int INIT_CHANNEL_COUNT = 1;
+  public static final int MIN_CHANNEL_COUNT = 1;
+  public static final int MAX_CHANNEL_COUNT = 4;
 
   private transient TransportChannelProvider channelProvider = null;
 
@@ -218,11 +222,20 @@ public class DatastoreOptions extends ServiceOptions<Datastore, DatastoreOptions
       throw new IllegalArgumentException(
           "Only gRPC transport allows setting of channel provider or credentials provider");
     } else if (getTransportOptions() instanceof GrpcTransportOptions) {
+      // For grpc transport options, configure default gRPC Connection pool with minChannelCount = 1
+      // and maxChannelCount = 4
       this.channelProvider =
           builder.channelProvider != null
               ? builder.channelProvider
               : GrpcTransportOptions.setUpChannelProvider(
-                  DatastoreSettings.defaultGrpcTransportProviderBuilder(), this);
+                  DatastoreSettings.defaultGrpcTransportProviderBuilder()
+                      .setChannelPoolSettings(
+                          ChannelPoolSettings.builder()
+                              .setInitialChannelCount(INIT_CHANNEL_COUNT)
+                              .setMinChannelCount(MIN_CHANNEL_COUNT)
+                              .setMaxChannelCount(MAX_CHANNEL_COUNT)
+                              .build()),
+                  this);
     }
   }
 
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/spi/v1/GrpcDatastoreRpc.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/spi/v1/GrpcDatastoreRpc.java
index e8e11373..ea9043bb 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/spi/v1/GrpcDatastoreRpc.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/spi/v1/GrpcDatastoreRpc.java
@@ -24,6 +24,7 @@ import static java.util.concurrent.TimeUnit.SECONDS;
 import com.google.api.core.InternalApi;
 import com.google.api.gax.core.BackgroundResource;
 import com.google.api.gax.core.GaxProperties;
+import com.google.api.gax.grpc.ChannelPoolSettings;
 import com.google.api.gax.grpc.GrpcCallContext;
 import com.google.api.gax.grpc.GrpcTransportChannel;
 import com.google.api.gax.rpc.ClientContext;
@@ -74,9 +75,19 @@ public class GrpcDatastoreRpc implements DatastoreRpc {
               ? getClientContextForEmulator(datastoreOptions)
               : getClientContext(datastoreOptions);
 
+      /* For grpc transport options, configure default gRPC Connection pool with minChannelCount = 1 and maxChannelCount = 4 */
       DatastoreStubSettings datastoreStubSettings =
           DatastoreStubSettings.newBuilder(clientContext)
               .applyToAllUnaryMethods(retrySettingSetter(datastoreOptions))
+              .setTransportChannelProvider(
+                  DatastoreSettings.defaultGrpcTransportProviderBuilder()
+                      .setChannelPoolSettings(
+                          ChannelPoolSettings.builder()
+                              .setInitialChannelCount(DatastoreOptions.INIT_CHANNEL_COUNT)
+                              .setMinChannelCount(DatastoreOptions.MIN_CHANNEL_COUNT)
+                              .setMaxChannelCount(DatastoreOptions.MAX_CHANNEL_COUNT)
+                              .build())
+                      .build())
               .build();
       datastoreStub = GrpcDatastoreStub.create(datastoreStubSettings);
     } catch (IOException e) {


Test patch:
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/DatastoreOptionsTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/DatastoreOptionsTest.java
index aff77138..c6a26d05 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/DatastoreOptionsTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/DatastoreOptionsTest.java
@@ -103,6 +103,25 @@ public class DatastoreOptionsTest {
     assertSame(datastoreRpc, options.build().getRpc());
   }
 
+  @Test
+  public void testGrpcDefaultChannelConfigurations() {
+    DatastoreOptions datastoreOptions =
+        DatastoreOptions.newBuilder()
+            .setServiceRpcFactory(datastoreRpcFactory)
+            .setProjectId(PROJECT_ID)
+            .setDatabaseId(DATABASE_ID)
+            .setTransportOptions(GrpcTransportOptions.newBuilder().build())
+            .setCredentials(NoCredentials.getInstance())
+            .setHost("http://localhost:" + PORT)
+            .build();
+    ChannelPoolSettings channelPoolSettings =
+        ((InstantiatingGrpcChannelProvider) datastoreOptions.getTransportChannelProvider())
+            .getChannelPoolSettings();
+    assertEquals(channelPoolSettings.getInitialChannelCount(), DatastoreOptions.INIT_CHANNEL_COUNT);
+    assertEquals(channelPoolSettings.getMinChannelCount(), DatastoreOptions.MIN_CHANNEL_COUNT);
+    assertEquals(channelPoolSettings.getMaxChannelCount(), DatastoreOptions.MAX_CHANNEL_COUNT);
+  }
+
   @Test
   public void testCustomChannelAndCredentials() {
     InstantiatingGrpcChannelProvider channelProvider =