mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
Adjust proxy tunnel sizing defaults
This commit is contained in:
@@ -87,19 +87,19 @@ sudo aether-proxy uninstall
|
||||
| `--tunnel-connections` | `AETHER_PROXY_TUNNEL_CONNECTIONS` | 自动(硬件估算) | 最小连接池大小;显式设置后默认固定为该值 |
|
||||
| `--tunnel-connections-max` | `AETHER_PROXY_TUNNEL_CONNECTIONS_MAX` | 自动(硬件估算) | 连接池自动扩容上限;大于 `tunnel_connections` 时启用 autoscale |
|
||||
| `--tunnel-max-streams` | `AETHER_PROXY_TUNNEL_MAX_STREAMS` | 自动(硬件估算) | 单连接最大并发 stream 数 |
|
||||
| `--tunnel-ping-interval-ms` | `AETHER_PROXY_TUNNEL_PING_INTERVAL_MS` | `250` | fast-fail 探测周期(毫秒) |
|
||||
| `--tunnel-connect-timeout-ms` | `AETHER_PROXY_TUNNEL_CONNECT_TIMEOUT_MS` | `800` | fast-reconnect 建连超时(毫秒) |
|
||||
| `--tunnel-stale-timeout-ms` | `AETHER_PROXY_TUNNEL_STALE_TIMEOUT_MS` | `900` | 无入站数据断连阈值(毫秒) |
|
||||
| `--tunnel-ping-interval-ms` | `AETHER_PROXY_TUNNEL_PING_INTERVAL_MS` | `10000` | WebSocket ping 周期(毫秒) |
|
||||
| `--tunnel-connect-timeout-ms` | `AETHER_PROXY_TUNNEL_CONNECT_TIMEOUT_MS` | `3000` | tunnel 建连超时(毫秒) |
|
||||
| `--tunnel-stale-timeout-ms` | `AETHER_PROXY_TUNNEL_STALE_TIMEOUT_MS` | `30000` | 无入站数据断连阈值(毫秒) |
|
||||
| `--tunnel-scale-check-interval-ms` | `AETHER_PROXY_TUNNEL_SCALE_CHECK_INTERVAL_MS` | `1000` | autoscale 采样周期(毫秒) |
|
||||
| `--tunnel-scale-up-threshold-percent` | `AETHER_PROXY_TUNNEL_SCALE_UP_THRESHOLD_PERCENT` | `70` | 单 tunnel 占用率超过该值时扩容 |
|
||||
| `--tunnel-scale-up-threshold-percent` | `AETHER_PROXY_TUNNEL_SCALE_UP_THRESHOLD_PERCENT` | `50` | 单 tunnel 占用率超过该值时扩容 |
|
||||
| `--tunnel-scale-down-threshold-percent` | `AETHER_PROXY_TUNNEL_SCALE_DOWN_THRESHOLD_PERCENT` | `35` | 单 tunnel 占用率持续低于该值时允许缩容 |
|
||||
| `--tunnel-scale-down-grace-secs` | `AETHER_PROXY_TUNNEL_SCALE_DOWN_GRACE_SECS` | `15` | 低负载持续时间达到该值后才回收次级 tunnel |
|
||||
| `--tunnel-tcp-keepalive-secs` | `AETHER_PROXY_TUNNEL_TCP_KEEPALIVE_SECS` | `30` | TCP keepalive 初始延迟(秒) |
|
||||
| `--tunnel-tcp-nodelay` | `AETHER_PROXY_TUNNEL_TCP_NODELAY` | `true` | 禁用 Nagle 算法 |
|
||||
| `--tunnel-reconnect-base-ms` | `AETHER_PROXY_TUNNEL_RECONNECT_BASE_MS` | `50` | 指数退避基础延迟(毫秒) |
|
||||
| `--tunnel-reconnect-max-ms` | `AETHER_PROXY_TUNNEL_RECONNECT_MAX_MS` | `30000` | 指数退避上限(毫秒) |
|
||||
| `--tunnel-reconnect-max-ms` | `AETHER_PROXY_TUNNEL_RECONNECT_MAX_MS` | `250` | 指数退避上限(毫秒) |
|
||||
|
||||
省略 `tunnel_connections` 时,proxy 会按设备能力自动计算一个基线值和扩容上限;如果显式设置了 `tunnel_connections` 但没有设置 `tunnel_connections_max`,则保持固定连接池,不自动扩缩。
|
||||
省略 `tunnel_connections` 时,proxy 会按设备能力自动计算一个基线值和偏单机上限的扩容上限:默认至少保留 2 条常驻 tunnel,并会更早触发扩容;如果显式设置了 `tunnel_connections` 但没有设置 `tunnel_connections_max`,则保持固定连接池,不自动扩缩。
|
||||
|
||||
#### 上游 HTTP 请求
|
||||
|
||||
|
||||
@@ -59,12 +59,15 @@ pub const DEFAULT_TUNNEL_PING_INTERVAL_MS: u64 = 10_000;
|
||||
pub const DEFAULT_TUNNEL_CONNECT_TIMEOUT_MS: u64 = 3_000;
|
||||
pub const DEFAULT_TUNNEL_STALE_TIMEOUT_MS: u64 = 30_000;
|
||||
pub const DEFAULT_TUNNEL_SCALE_CHECK_INTERVAL_MS: u64 = 1_000;
|
||||
pub const DEFAULT_TUNNEL_SCALE_UP_THRESHOLD_PERCENT: u32 = 70;
|
||||
pub const DEFAULT_TUNNEL_SCALE_UP_THRESHOLD_PERCENT: u32 = 50;
|
||||
pub const DEFAULT_TUNNEL_SCALE_DOWN_THRESHOLD_PERCENT: u32 = 35;
|
||||
pub const DEFAULT_TUNNEL_SCALE_DOWN_GRACE_SECS: u64 = 15;
|
||||
const AUTO_TUNNEL_CONNECTIONS_REDUNDANT_FLOOR: u64 = 2;
|
||||
const AUTO_TUNNEL_CONNECTIONS_BASE_CAP: u64 = 4;
|
||||
const AUTO_TUNNEL_CONNECTIONS_MAX_CAP: u64 = 8;
|
||||
// Bias the automatic pool toward a per-device upper band without letting
|
||||
// tiny nodes fan out into too many idle tunnels.
|
||||
const AUTO_TUNNEL_CONNECTIONS_PER_CPU_CAP: u64 = 4;
|
||||
const AUTO_TUNNEL_CONNECTIONS_MAX_CAP: u64 = 32;
|
||||
|
||||
const TUNNEL_PING_INTERVAL_MS_ENV: &str = "AETHER_PROXY_TUNNEL_PING_INTERVAL_MS";
|
||||
const TUNNEL_CONNECT_TIMEOUT_MS_ENV: &str = "AETHER_PROXY_TUNNEL_CONNECT_TIMEOUT_MS";
|
||||
@@ -754,15 +757,27 @@ impl Config {
|
||||
) -> anyhow::Result<TunnelPoolSizing> {
|
||||
let per_tunnel_capacity = u64::from(self.tunnel_max_streams.unwrap_or(128).max(1));
|
||||
let estimated = hw_info.estimated_max_concurrency.max(per_tunnel_capacity);
|
||||
let cpu_cap = u64::from(hw_info.cpu_cores).clamp(1, AUTO_TUNNEL_CONNECTIONS_MAX_CAP);
|
||||
let auto_initial_floor = AUTO_TUNNEL_CONNECTIONS_REDUNDANT_FLOOR.min(cpu_cap);
|
||||
let cpu_soft_cap = u64::from(hw_info.cpu_cores.max(1))
|
||||
.saturating_mul(AUTO_TUNNEL_CONNECTIONS_PER_CPU_CAP)
|
||||
.clamp(
|
||||
AUTO_TUNNEL_CONNECTIONS_BASE_CAP,
|
||||
AUTO_TUNNEL_CONNECTIONS_MAX_CAP,
|
||||
);
|
||||
let auto_initial_floor = AUTO_TUNNEL_CONNECTIONS_REDUNDANT_FLOOR.min(cpu_soft_cap);
|
||||
let auto_initial_cap = AUTO_TUNNEL_CONNECTIONS_BASE_CAP
|
||||
.min(cpu_soft_cap)
|
||||
.max(auto_initial_floor);
|
||||
|
||||
let auto_initial = div_ceil_u64(estimated, per_tunnel_capacity.saturating_mul(8))
|
||||
.clamp(auto_initial_floor, AUTO_TUNNEL_CONNECTIONS_BASE_CAP)
|
||||
.min(cpu_cap);
|
||||
let auto_max = div_ceil_u64(estimated, per_tunnel_capacity.saturating_mul(4))
|
||||
.clamp(auto_initial, AUTO_TUNNEL_CONNECTIONS_MAX_CAP)
|
||||
.min(cpu_cap.max(auto_initial));
|
||||
.clamp(auto_initial_floor, auto_initial_cap);
|
||||
let high_water_per_tunnel = div_ceil_u64(
|
||||
per_tunnel_capacity.saturating_mul(u64::from(self.tunnel_scale_up_threshold_percent)),
|
||||
100,
|
||||
)
|
||||
.max(1);
|
||||
let auto_max_floor = auto_initial.max(AUTO_TUNNEL_CONNECTIONS_BASE_CAP.min(cpu_soft_cap));
|
||||
let auto_max =
|
||||
div_ceil_u64(estimated, high_water_per_tunnel).clamp(auto_max_floor, cpu_soft_cap);
|
||||
|
||||
let initial_connections = u64::from(self.tunnel_connections.unwrap_or(auto_initial as u32));
|
||||
let max_connections = match self.tunnel_connections_max {
|
||||
@@ -1539,7 +1554,7 @@ node_name = "proxy-test"
|
||||
.resolve_tunnel_pool_sizing(&hw)
|
||||
.expect("sizing should resolve");
|
||||
assert_eq!(sizing.initial_connections, 3);
|
||||
assert_eq!(sizing.max_connections, 6);
|
||||
assert_eq!(sizing.max_connections, 32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1567,7 +1582,35 @@ node_name = "proxy-test"
|
||||
.resolve_tunnel_pool_sizing(&hw)
|
||||
.expect("sizing should resolve");
|
||||
assert_eq!(sizing.initial_connections, 2);
|
||||
assert_eq!(sizing.max_connections, 2);
|
||||
assert_eq!(sizing.max_connections, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_tunnel_pool_sizing_keeps_single_core_nodes_redundant() {
|
||||
let config = Config::parse_from([
|
||||
"aether-proxy",
|
||||
"--aether-url",
|
||||
"https://example.com",
|
||||
"--management-token",
|
||||
"ae_test",
|
||||
"--node-name",
|
||||
"proxy-test",
|
||||
"--tunnel-max-streams",
|
||||
"200",
|
||||
]);
|
||||
let hw = HardwareInfo {
|
||||
cpu_cores: 1,
|
||||
total_memory_mb: 183,
|
||||
os_info: "test".to_string(),
|
||||
fd_limit: 65_535,
|
||||
estimated_max_concurrency: 2_000,
|
||||
};
|
||||
|
||||
let sizing = config
|
||||
.resolve_tunnel_pool_sizing(&hw)
|
||||
.expect("sizing should resolve");
|
||||
assert_eq!(sizing.initial_connections, 2);
|
||||
assert_eq!(sizing.max_connections, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user