blob: 20cf072ea96e93287d2bdb1ad6f85a011c35ff8c [file]
/*
* Copyright 2023 CeresDB Project Authors. Licensed under Apache-2.0.
*/
package io.ceresdb.rpc;
import java.util.concurrent.TimeUnit;
import io.ceresdb.common.Copiable;
import io.ceresdb.common.util.Cpus;
/**
* RPC client options.
*
*/
public class RpcOptions implements Copiable<RpcOptions> {
/**
* RPC request default timeout in milliseconds
* Default: 10000(10s)
*/
private int defaultRpcTimeout = 10000;
/**
* RPC process thread pool size
* Default: 32
*/
private int rpcThreadPoolSize = 0;
private int rpcThreadPoolQueueSize = Cpus.cpus() << 1;
/**
* Sets the maximum message size allowed to be received on a channel.
*/
private int maxInboundMessageSize = 64 * 1024 * 1024;
private int flowControlWindow = 64 * 1024 * 1024;
/**
* Set the duration without ongoing RPCs before going to idle mode.
* In idle mode the channel shuts down all connections.
*/
private long idleTimeoutSeconds = TimeUnit.MINUTES.toSeconds(5);
// --- keep-alive options: default will disable keep-alive
/**
* Sets the time without read activity before sending a keep-alive ping.
*/
private long keepAliveTimeSeconds = Long.MAX_VALUE;
/**
* Sets the time waiting for read activity after sending a keep-alive ping.
* If the time expires without any read activity on the connection, the
* connection is considered dead.
*/
private long keepAliveTimeoutSeconds = 3;
/**
* Sets whether keep-alive will be performed when there are no outstanding
* RPC on a connection.
*/
private boolean keepAliveWithoutCalls = false;
// --- keep-alive options: default will disable keep-alive
private LimitKind limitKind = LimitKind.Gradient;
/**
* Initial limit used by the limiter
*/
private int initialLimit = 64;
/**
* Maximum allowable concurrency. Any estimated concurrency will be capped
* at this value
*/
private int maxLimit = 1024;
private int longRttWindow = 100;
/**
* Smoothing factor to limit how aggressively the estimated limit can shrink
* when queuing has been detected.
*/
private double smoothing = 0.2;
/**
* When set to true new calls to the channel will block when the limit has
* been reached instead of failing fast with an UNAVAILABLE status.
*/
private boolean blockOnLimit = false;
private boolean logOnLimitChange = true;
/**
* Max time in milliseconds a connection can live, 0 means forever.
*/
private long connectionMaxAgeMs = 0;
public int getDefaultRpcTimeout() {
return defaultRpcTimeout;
}
public void setDefaultRpcTimeout(int defaultRpcTimeout) {
this.defaultRpcTimeout = defaultRpcTimeout;
}
public long getConnectionMaxAgeMs() {
return connectionMaxAgeMs;
}
public void setConnectionMaxAgeMs(long connectionMaxAgeMs) {
this.connectionMaxAgeMs = connectionMaxAgeMs;
}
public int getRpcThreadPoolSize() {
return rpcThreadPoolSize;
}
public void setRpcThreadPoolSize(int rpcThreadPoolSize) {
this.rpcThreadPoolSize = rpcThreadPoolSize;
}
public int getRpcThreadPoolQueueSize() {
return rpcThreadPoolQueueSize;
}
public void setRpcThreadPoolQueueSize(int rpcThreadPoolQueueSize) {
this.rpcThreadPoolQueueSize = rpcThreadPoolQueueSize;
}
public int getMaxInboundMessageSize() {
return maxInboundMessageSize;
}
public void setMaxInboundMessageSize(int maxInboundMessageSize) {
this.maxInboundMessageSize = maxInboundMessageSize;
}
public int getFlowControlWindow() {
return flowControlWindow;
}
public void setFlowControlWindow(int flowControlWindow) {
this.flowControlWindow = flowControlWindow;
}
public long getIdleTimeoutSeconds() {
return idleTimeoutSeconds;
}
public void setIdleTimeoutSeconds(long idleTimeoutSeconds) {
this.idleTimeoutSeconds = idleTimeoutSeconds;
}
public long getKeepAliveTimeSeconds() {
return keepAliveTimeSeconds;
}
public void setKeepAliveTimeSeconds(long keepAliveTimeSeconds) {
this.keepAliveTimeSeconds = keepAliveTimeSeconds;
}
public long getKeepAliveTimeoutSeconds() {
return keepAliveTimeoutSeconds;
}
public void setKeepAliveTimeoutSeconds(long keepAliveTimeoutSeconds) {
this.keepAliveTimeoutSeconds = keepAliveTimeoutSeconds;
}
public boolean isKeepAliveWithoutCalls() {
return keepAliveWithoutCalls;
}
public void setKeepAliveWithoutCalls(boolean keepAliveWithoutCalls) {
this.keepAliveWithoutCalls = keepAliveWithoutCalls;
}
public LimitKind getLimitKind() {
return limitKind;
}
public void setLimitKind(LimitKind limitKind) {
this.limitKind = limitKind;
}
public int getInitialLimit() {
return initialLimit;
}
public void setInitialLimit(int initialLimit) {
this.initialLimit = initialLimit;
}
public int getMaxLimit() {
return maxLimit;
}
public void setMaxLimit(int maxLimit) {
this.maxLimit = maxLimit;
}
public int getLongRttWindow() {
return longRttWindow;
}
public void setLongRttWindow(int longRttWindow) {
this.longRttWindow = longRttWindow;
}
public double getSmoothing() {
return smoothing;
}
public void setSmoothing(double smoothing) {
this.smoothing = smoothing;
}
public boolean isBlockOnLimit() {
return blockOnLimit;
}
public void setBlockOnLimit(boolean blockOnLimit) {
this.blockOnLimit = blockOnLimit;
}
public boolean isLogOnLimitChange() {
return logOnLimitChange;
}
public void setLogOnLimitChange(boolean logOnLimitChange) {
this.logOnLimitChange = logOnLimitChange;
}
@Override
public RpcOptions copy() {
final RpcOptions opts = new RpcOptions();
opts.defaultRpcTimeout = this.defaultRpcTimeout;
opts.rpcThreadPoolSize = this.rpcThreadPoolSize;
opts.rpcThreadPoolQueueSize = this.rpcThreadPoolQueueSize;
opts.maxInboundMessageSize = this.maxInboundMessageSize;
opts.flowControlWindow = this.flowControlWindow;
opts.idleTimeoutSeconds = this.idleTimeoutSeconds;
opts.keepAliveTimeSeconds = this.keepAliveTimeSeconds;
opts.keepAliveTimeoutSeconds = this.keepAliveTimeoutSeconds;
opts.keepAliveWithoutCalls = this.keepAliveWithoutCalls;
opts.limitKind = this.limitKind;
opts.initialLimit = this.initialLimit;
opts.maxLimit = this.maxLimit;
opts.longRttWindow = this.longRttWindow;
opts.smoothing = this.smoothing;
opts.blockOnLimit = this.blockOnLimit;
opts.logOnLimitChange = this.logOnLimitChange;
opts.connectionMaxAgeMs = this.connectionMaxAgeMs;
return opts;
}
@Override
public String toString() {
return "RpcOptions{" + "defaultRpcTimeout=" + defaultRpcTimeout + ", rpcThreadPoolSize=" + rpcThreadPoolSize
+ ", rpcThreadPoolQueueSize=" + rpcThreadPoolQueueSize + ", maxInboundMessageSize="
+ maxInboundMessageSize + ", flowControlWindow=" + flowControlWindow + ", idleTimeoutSeconds="
+ idleTimeoutSeconds + ", keepAliveTimeSeconds=" + keepAliveTimeSeconds + ", keepAliveTimeoutSeconds="
+ keepAliveTimeoutSeconds + ", keepAliveWithoutCalls=" + keepAliveWithoutCalls + ", limitKind="
+ limitKind + ", initialLimit=" + initialLimit + ", maxLimit=" + maxLimit + ", longRttWindow="
+ longRttWindow + ", smoothing=" + smoothing + ", blockOnLimit=" + blockOnLimit + ", logOnLimitChange="
+ logOnLimitChange + ", connectionMaxAge=" + connectionMaxAgeMs + '}';
}
public static RpcOptions newDefault() {
return new RpcOptions();
}
public enum LimitKind {
/**
* Limiter based on TCP Vegas where the limit increases by alpha if the
* queue_use is small ({@literal <} alpha) and decreases by alpha if
* the queue_use is large ({@literal >} beta).
*/
Vegas,
/**
* Concurrency limit algorithm that adjusts the limit based on the gradient
* of change of the current average RTT and a long term exponentially smoothed
* average RTT. Unlike traditional congestion control algorithms we use average
* instead of minimum since RPC methods can be very bursty due to various
* factors such as non-homogenous request processing complexity as well as a
* wide distribution of data size.
*/
Gradient,
None
}
}