com.google.api.gax.grpc.ChannelPoolSettings Maven / Gradle / Ivy
Show all versions of gax-grpc Show documentation
/*
* Copyright 2021 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.api.gax.grpc;
import com.google.api.core.BetaApi;
import com.google.auto.value.AutoValue;
import com.google.common.base.Preconditions;
import java.time.Duration;
/**
* Settings to control {@link ChannelPool} behavior.
*
* To facilitate low latency/high throughout applications, gax provides a {@link ChannelPool}.
* The pool is meant to facilitate high throughput/low latency clients. By splitting load across
* multiple gRPC channels the client can spread load across multiple frontends and overcome gRPC's
* limit of 100 concurrent RPCs per channel. However oversizing the {@link ChannelPool} can lead to
* underutilized channels which will lead to high tail latency due to GFEs disconnecting idle
* channels.
*
*
The {@link ChannelPool} is designed to adapt to varying traffic patterns by tracking
* outstanding RPCs and resizing the pool size. This class configures the behavior. In general
* clients should aim to have less than 50 concurrent RPCs per channel and at least 1 outstanding
* per channel per minute.
*
*
The settings in this class will be applied every minute.
*/
@BetaApi("surface for channel pool sizing is not yet stable")
@AutoValue
public abstract class ChannelPoolSettings {
/** How often to check and possibly resize the {@link ChannelPool}. */
static final Duration RESIZE_INTERVAL = Duration.ofMinutes(1);
/** The maximum number of channels that can be added or removed at a time. */
static final int MAX_RESIZE_DELTA = 2;
/**
* Threshold to start scaling down the channel pool.
*
*
When the average of the maximum number of outstanding RPCs in a single minute drop below
* this threshold, channels will be removed from the pool.
*/
public abstract int getMinRpcsPerChannel();
/**
* Threshold to start scaling up the channel pool.
*
*
When the average of the maximum number of outstanding RPCs in a single minute surpass this
* threshold, channels will be added to the pool. For google services, gRPC channels will start
* locally queuing RPC when there are 100 concurrent RPCs.
*/
public abstract int getMaxRpcsPerChannel();
/**
* The absolute minimum size of the channel pool.
*
*
Regardless of the current throughput, the number of channels will not drop below this limit
*/
public abstract int getMinChannelCount();
/**
* The absolute maximum size of the channel pool.
*
*
Regardless of the current throughput, the number of channels will not exceed this limit
*/
public abstract int getMaxChannelCount();
/**
* The initial size of the channel pool.
*
*
During client construction the client open this many connections. This will be scaled up or
* down in the next period.
*/
public abstract int getInitialChannelCount();
/**
* If all of the channels should be replaced on an hourly basis.
*
*
The GFE will forcibly disconnect active channels after an hour. To minimize the cost of
* reconnects, this will create a new channel asynchronuously, prime it and then swap it with an
* old channel.
*/
public abstract boolean isPreemptiveRefreshEnabled();
/** Helper to check if the {@link ChannelPool} implementation can skip dynamic size logic */
boolean isStaticSize() {
// When range is restricted to a single size
if (getMinChannelCount() == getMaxChannelCount()) {
return true;
}
// When the scaling threshold are not set
if (getMinRpcsPerChannel() == 0 && getMaxRpcsPerChannel() == Integer.MAX_VALUE) {
return true;
}
return false;
}
public abstract Builder toBuilder();
public static ChannelPoolSettings staticallySized(int size) {
return builder()
.setInitialChannelCount(size)
.setMinRpcsPerChannel(0)
.setMaxRpcsPerChannel(Integer.MAX_VALUE)
.setMinChannelCount(size)
.setMaxChannelCount(size)
.build();
}
public static Builder builder() {
return new AutoValue_ChannelPoolSettings.Builder()
.setInitialChannelCount(1)
.setMinChannelCount(1)
.setMaxChannelCount(200)
.setMinRpcsPerChannel(0)
.setMaxRpcsPerChannel(Integer.MAX_VALUE)
.setPreemptiveRefreshEnabled(false);
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setMinRpcsPerChannel(int count);
public abstract Builder setMaxRpcsPerChannel(int count);
public abstract Builder setMinChannelCount(int count);
public abstract Builder setMaxChannelCount(int count);
public abstract Builder setInitialChannelCount(int count);
public abstract Builder setPreemptiveRefreshEnabled(boolean enabled);
abstract ChannelPoolSettings autoBuild();
public ChannelPoolSettings build() {
ChannelPoolSettings s = autoBuild();
Preconditions.checkState(
s.getMinRpcsPerChannel() <= s.getMaxRpcsPerChannel(), "rpcsPerChannel range is invalid");
Preconditions.checkState(
s.getMinChannelCount() > 0, "Minimum channel count must be at least 1");
Preconditions.checkState(
s.getMinChannelCount() <= s.getMaxRpcsPerChannel(), "absolute channel range is invalid");
Preconditions.checkState(
s.getMinChannelCount() <= s.getInitialChannelCount(),
"initial channel count be at least minChannelCount");
Preconditions.checkState(
s.getInitialChannelCount() <= s.getMaxChannelCount(),
"initial channel count must be less than maxChannelCount");
Preconditions.checkState(
s.getInitialChannelCount() > 0, "Initial channel count must be greater than 0");
return s;
}
}
}