Skip to content

Commit

Permalink
Merge pull request #36128 from cescoffier/traffic-shaping
Browse files Browse the repository at this point in the history
Add support for traffic shaping
  • Loading branch information
cescoffier authored Sep 29, 2023
2 parents b10a14f + 06724f7 commit c53d8dd
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 5 deletions.
42 changes: 38 additions & 4 deletions docs/src/main/asciidoc/http-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ include::_attributes.adoc[]
:sectnums:
:sectnumlevels: 4

:numbered:
:sectnums:
:sectnumlevels: 4


This document explains various HTTP features that you can use in Quarkus.

Expand Down Expand Up @@ -394,6 +390,44 @@ It is important that you enable all origins only for the dev profile, allowing a

include::{generated-dir}/config/quarkus-vertx-http-config-group-server-limits-config.adoc[leveloffset=+1, opts=optional]

== Configure traffic shaping

Traffic shaping allows you to limit the bandwidth across all channels (i.e. connections), regardless of the number of open channels.
This can be useful when you want to control the overall network traffic to prevent congestion or prioritize certain types of traffic.

To enable traffic shaping, add the following property in your application configuration:


[source, properties]
----
quarkus.http.traffic-shaping.enabled=true # Required to enable traffic shaping
----

The traffic shaping allows you to configure various parameters, such as write and read limitations (in bytes per second), check interval (the delay between two computations of the bandwidth), and maximum time to wait:

[source, properties]
----
quarkus.http.traffic-shaping.enabled=true # Required to enable traffic shaping
quarkus.http.traffic-shaping.check-interval=30s
quarkus.http.traffic-shaping.outbound-global-bandwidth=1M
quarkus.http.traffic-shaping.inbound-global-bandwidth=1M
quarkus.http.traffic-shaping.max-delay=10s
----

The check interval represents the period at which the traffic is computed, and a higher interval may result in
less precise traffic shaping.
Despite 0 being accepted (no accounting), it is recommended to set a positive value for the check interval, even if it is high since the precision of the traffic shaping depends on the period where the traffic is computed.
In this case, a suggested value is something close to 5 or 10 minutes.

The `outbound-global-bandwidth` and `inbound-global-bandwidth` parameters represent the maximum number of bytes per second for write and read operations, respectively.
You shall also consider to have object size in read or write operations relatively adapted to the bandwidth you required.
For instance having 10 MB objects for 10KB/s will lead to burst effect, while having 100 KB objects for 1 MB/s should be smoothly handle by the traffic shaping.

Additionally, you can set the maximum time to wait (`max-delay`), which specifies an upper bound for time shaping.
By default, it is set to 15 seconds.
It must be less than the HTTP timeout.
When one of the threshold is reached, no write happens for that period of time.

== Configuring HTTP Access Logs

You can add HTTP request logging by configuring it in `application.properties`. There are two options for logging,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,9 @@ public class HttpConfiguration {
@ConfigItem
public boolean recordRequestStartTime;

AccessLogConfig accessLog;
public AccessLogConfig accessLog;

public TrafficShapingConfig trafficShaping;

/**
* Configuration that allows setting the same site attributes for cookies.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package io.quarkus.vertx.http.runtime;

import java.time.Duration;
import java.util.Optional;

import io.quarkus.runtime.annotations.ConfigGroup;
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.configuration.MemorySize;

/**
* Configure the global traffic shaping functionality.
* It allows you to limit the bandwidth across all channels, regardless of the number of open channels.
* This can be useful when you want to control the overall network traffic to prevent congestion
* or prioritize certain types of traffic.
* <p>
* The traffic shaping allows you to configure various parameters, such as write and read limitations (in bytes per
* second), check interval (the delay between two computations of the bandwidth), and maximum time to wait.
* The check interval represents the period at which the traffic is computed, and a higher interval may result in
* less precise traffic shaping. It is recommended to set a positive value for the check interval, even if it is high,
* to ensure traffic shaping without accounting. A suggested value is something close to 5 or 10 minutes.
* <p>
* The `outbound-global-bandwidth` and `inbound-global-bandwidth` parameters represent the maximum number of bytes per second
* for write and read operations, respectively.
* Additionally, you can set the maximum time to wait, which specifies an upper bound for time shaping.
* By default, it is set to 15 seconds.
*/
@ConfigGroup
public class TrafficShapingConfig {

/**
* Enables the traffic shaping.
*/
@ConfigItem(defaultValue = "false")
public boolean enabled;

/**
* Set bandwidth limit in bytes per second for inbound connections.
* If not set, no limits are applied.
*/
@ConfigItem
public Optional<MemorySize> inboundGlobalBandwidth;

/**
* Set bandwidth limit in bytes per second for outbound connections.
* If not set, no limits are applied.
*/
@ConfigItem
public Optional<MemorySize> outboundGlobalBandwidth;

/**
* Set the maximum delay to wait in case of traffic excess.
* Default is 15s. Must be less than the HTTP timeout.
*/
@ConfigItem
public Optional<Duration> maxDelay;

/**
* Set the delay between two computations of performances for channels.
* If set to 0, no stats are computed.
* Despite 0 is accepted (no accounting), it is recommended to set a positive value for the check interval,
* even if it is high since the precision of the traffic shaping depends on the period where the traffic is computed.
* In this case, a suggested value is something close to 5 or 10 minutes.
* <p>
* If not default, it defaults to 1s.
*/
@ConfigItem
public Optional<Duration> checkInterval;

/**
* Set the maximum global write size in bytes per second allowed in the buffer globally for all channels before write
* are suspended.
* The default value is 400 MB.
*/
@ConfigItem
public Optional<MemorySize> peakOutboundGlobalBandwidth;

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
import io.vertx.core.net.JdkSSLEngineOptions;
import io.vertx.core.net.KeyStoreOptions;
import io.vertx.core.net.PemKeyCertOptions;
import io.vertx.core.net.TrafficShapingOptions;

@SuppressWarnings("OptionalIsPresent")
public class HttpServerOptionsUtils {

/**
Expand Down Expand Up @@ -276,6 +278,34 @@ public static void applyCommonOptions(HttpServerOptions httpServerOptions,
}

httpServerOptions.setUseProxyProtocol(httpConfiguration.proxy.useProxyProtocol);
configureTrafficShapingIfEnabled(httpServerOptions, httpConfiguration);
}

private static void configureTrafficShapingIfEnabled(HttpServerOptions httpServerOptions,
HttpConfiguration httpConfiguration) {
if (httpConfiguration.trafficShaping.enabled) {
TrafficShapingOptions options = new TrafficShapingOptions();
if (httpConfiguration.trafficShaping.checkInterval.isPresent()) {
options.setCheckIntervalForStats(httpConfiguration.trafficShaping.checkInterval.get().toSeconds());
options.setCheckIntervalForStatsTimeUnit(TimeUnit.SECONDS);
}
if (httpConfiguration.trafficShaping.maxDelay.isPresent()) {
options.setMaxDelayToWait(httpConfiguration.trafficShaping.maxDelay.get().toSeconds());
options.setMaxDelayToWaitUnit(TimeUnit.SECONDS);
}
if (httpConfiguration.trafficShaping.inboundGlobalBandwidth.isPresent()) {
options.setInboundGlobalBandwidth(httpConfiguration.trafficShaping.inboundGlobalBandwidth.get().asLongValue());
}
if (httpConfiguration.trafficShaping.outboundGlobalBandwidth.isPresent()) {
options.setOutboundGlobalBandwidth(
httpConfiguration.trafficShaping.outboundGlobalBandwidth.get().asLongValue());
}
if (httpConfiguration.trafficShaping.peakOutboundGlobalBandwidth.isPresent()) {
options.setPeakOutboundGlobalBandwidth(
httpConfiguration.trafficShaping.peakOutboundGlobalBandwidth.get().asLongValue());
}
httpServerOptions.setTrafficShapingOptions(options);
}
}

public static void applyCommonOptionsForManagementInterface(HttpServerOptions options,
Expand Down

0 comments on commit c53d8dd

Please sign in to comment.