增加timing环境变量

This commit is contained in:
xiuting.xu 2026-04-15 16:26:09 +08:00
parent 17c1a02c90
commit 99250f8aa9
7 changed files with 107 additions and 29 deletions

View File

@ -78,7 +78,11 @@ RTR Server 运行时从 `CCR` 目录中扫描最新的 `.ccr` 文件作为输入
| `RPKI_RTR_MAX_DELTA` | 最多保留多少条 delta。 | `100` | `100` | | `RPKI_RTR_MAX_DELTA` | 最多保留多少条 delta。 | `100` | `100` |
| `RPKI_RTR_PRUNE_DELTA_BY_SNAPSHOT_SIZE` | 是否启用“累计 delta 估算 wire size 不小于 snapshot 时,继续裁剪最老 delta”的策略。 | `false` | `false` | | `RPKI_RTR_PRUNE_DELTA_BY_SNAPSHOT_SIZE` | 是否启用“累计 delta 估算 wire size 不小于 snapshot 时,继续裁剪最老 delta”的策略。 | `false` | `false` |
| `RPKI_RTR_STRICT_CCR_VALIDATION` | 是否对 CCR 中的非法 VRP / VAP 采用严格模式;`true` 表示整份 CCR 拒绝,`false` 表示跳过非法项并告警。 | `false` | `false` | | `RPKI_RTR_STRICT_CCR_VALIDATION` | 是否对 CCR 中的非法 VRP / VAP 采用严格模式;`true` 表示整份 CCR 拒绝,`false` 表示跳过非法项并告警。 | `false` | `false` |
| `RPKI_RTR_REFRESH_INTERVAL_SECS` | 刷新 CCR 目录并重新加载最新 `.ccr` 的间隔,单位秒,必须 `>= 1`。 | `300` | `300` | | `RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS` | 数据源刷新周期:扫描 CCR/SLURM 并尝试更新缓存的间隔,单位秒,必须 `>= 1`。 | `300` | `30` |
| `RPKI_RTR_REFRESH_INTERVAL_SECS` | 旧变量名(已兼容,建议迁移到 `RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS`)。 | `300` | `300` |
| `RPKI_RTR_TIMING_REFRESH_SECS` | RTR EndOfData timing 的 `refresh` 字段,单位秒。 | `3600` | `300` |
| `RPKI_RTR_TIMING_RETRY_SECS` | RTR EndOfData timing 的 `retry` 字段,单位秒。 | `600` | `60` |
| `RPKI_RTR_TIMING_EXPIRE_SECS` | RTR EndOfData timing 的 `expire` 字段,单位秒(需大于 refresh/retry。 | `7200` | `1800` |
| `RPKI_RTR_MAX_CONNECTIONS` | 最大并发 RTR 客户端连接数。 | `512` | `512` | | `RPKI_RTR_MAX_CONNECTIONS` | 最大并发 RTR 客户端连接数。 | `512` | `512` |
| `RPKI_RTR_NOTIFY_QUEUE_SIZE` | Serial Notify 广播队列大小。 | `1024` | `1024` | | `RPKI_RTR_NOTIFY_QUEUE_SIZE` | Serial Notify 广播队列大小。 | `1024` | `1024` |
| `RPKI_RTR_TCP_KEEPALIVE_SECS` | TCP keepalive 时间,单位秒;设为 `0` 表示禁用。 | `60` | `60` | | `RPKI_RTR_TCP_KEEPALIVE_SECS` | TCP keepalive 时间,单位秒;设为 `0` 表示禁用。 | `60` | `60` |
@ -91,6 +95,8 @@ RTR Server 运行时从 `CCR` 目录中扫描最新的 `.ccr` 文件作为输入
- TLS 模式要求客户端证书认证。 - TLS 模式要求客户端证书认证。
- 当前输入源是 `CCR` 目录,不再是单独的文本 VRP / ASPA / Router Key 文件。 - 当前输入源是 `CCR` 目录,不再是单独的文本 VRP / ASPA / Router Key 文件。
- 刷新时会重新扫描 `RPKI_RTR_CCR_DIR`,并选取文件名排序最新的 `.ccr` 文件。 - 刷新时会重新扫描 `RPKI_RTR_CCR_DIR`,并选取文件名排序最新的 `.ccr` 文件。
- `RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS`(旧名 `RPKI_RTR_REFRESH_INTERVAL_SECS`)控制的是“服务端多长时间扫描并更新数据源”,不是 RTR EndOfData 的 timing。
- RTR 客户端在 EndOfData 中看到的 `refresh/retry/expire``RPKI_RTR_TIMING_REFRESH_SECS``RPKI_RTR_TIMING_RETRY_SECS``RPKI_RTR_TIMING_EXPIRE_SECS` 控制。
- `RPKI_RTR_STRICT_CCR_VALIDATION=false`CCR 中的非法 VRP / VAP 会被跳过并输出 warning`true` 时整份 CCR 更新失败。 - `RPKI_RTR_STRICT_CCR_VALIDATION=false`CCR 中的非法 VRP / VAP 会被跳过并输出 warning`true` 时整份 CCR 更新失败。
- `RPKI_RTR_TCP_KEEPALIVE_SECS=0` 表示关闭 keepalive非零值表示在整个连接生命周期内启用 keepalive。 - `RPKI_RTR_TCP_KEEPALIVE_SECS=0` 表示关闭 keepalive非零值表示在整个连接生命周期内启用 keepalive。
- `RPKI_RTR_PRUNE_DELTA_BY_SNAPSHOT_SIZE=true` 时,除了 `RPKI_RTR_MAX_DELTA` 的固定条数裁剪外,还会在累计 delta 估算 wire size 不小于 snapshot 时继续删除最老 delta。 - `RPKI_RTR_PRUNE_DELTA_BY_SNAPSHOT_SIZE=true` 时,除了 `RPKI_RTR_MAX_DELTA` 的固定条数裁剪外,还会在累计 delta 估算 wire size 不小于 snapshot 时继续删除最老 delta。

View File

@ -19,7 +19,7 @@ services:
RPKI_RTR_CCR_DIR: "/app/data" RPKI_RTR_CCR_DIR: "/app/data"
RPKI_RTR_SLURM_DIR: "/app/slurm" RPKI_RTR_SLURM_DIR: "/app/slurm"
RPKI_RTR_STRICT_CCR_VALIDATION: "false" RPKI_RTR_STRICT_CCR_VALIDATION: "false"
RPKI_RTR_REFRESH_INTERVAL_SECS: "300" RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS: "300"
volumes: volumes:
- ../../data:/app/data:ro - ../../data:/app/data:ro
- ../../rtr-db:/app/rtr-db - ../../rtr-db:/app/rtr-db

View File

@ -13,12 +13,18 @@ export RPKI_RTR_CCR_DIR
: "${RPKI_RTR_MAX_DELTA:=100}" : "${RPKI_RTR_MAX_DELTA:=100}"
: "${RPKI_RTR_STRICT_CCR_VALIDATION:=false}" : "${RPKI_RTR_STRICT_CCR_VALIDATION:=false}"
: "${RPKI_RTR_REFRESH_INTERVAL_SECS:=300}" : "${RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS:=300}"
: "${RPKI_RTR_TIMING_REFRESH_SECS:=3600}"
: "${RPKI_RTR_TIMING_RETRY_SECS:=600}"
: "${RPKI_RTR_TIMING_EXPIRE_SECS:=7200}"
: "${RPKI_RTR_MAX_CONNECTIONS:=512}" : "${RPKI_RTR_MAX_CONNECTIONS:=512}"
: "${RPKI_RTR_NOTIFY_QUEUE_SIZE:=1024}" : "${RPKI_RTR_NOTIFY_QUEUE_SIZE:=1024}"
export RPKI_RTR_MAX_DELTA export RPKI_RTR_MAX_DELTA
export RPKI_RTR_STRICT_CCR_VALIDATION export RPKI_RTR_STRICT_CCR_VALIDATION
export RPKI_RTR_REFRESH_INTERVAL_SECS export RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS
export RPKI_RTR_TIMING_REFRESH_SECS
export RPKI_RTR_TIMING_RETRY_SECS
export RPKI_RTR_TIMING_EXPIRE_SECS
export RPKI_RTR_MAX_CONNECTIONS export RPKI_RTR_MAX_CONNECTIONS
export RPKI_RTR_NOTIFY_QUEUE_SIZE export RPKI_RTR_NOTIFY_QUEUE_SIZE

View File

@ -22,12 +22,18 @@ export RPKI_RTR_TLS_CLIENT_CA_PATH
: "${RPKI_RTR_MAX_DELTA:=100}" : "${RPKI_RTR_MAX_DELTA:=100}"
: "${RPKI_RTR_STRICT_CCR_VALIDATION:=false}" : "${RPKI_RTR_STRICT_CCR_VALIDATION:=false}"
: "${RPKI_RTR_REFRESH_INTERVAL_SECS:=300}" : "${RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS:=300}"
: "${RPKI_RTR_TIMING_REFRESH_SECS:=3600}"
: "${RPKI_RTR_TIMING_RETRY_SECS:=600}"
: "${RPKI_RTR_TIMING_EXPIRE_SECS:=7200}"
: "${RPKI_RTR_MAX_CONNECTIONS:=512}" : "${RPKI_RTR_MAX_CONNECTIONS:=512}"
: "${RPKI_RTR_NOTIFY_QUEUE_SIZE:=1024}" : "${RPKI_RTR_NOTIFY_QUEUE_SIZE:=1024}"
export RPKI_RTR_MAX_DELTA export RPKI_RTR_MAX_DELTA
export RPKI_RTR_STRICT_CCR_VALIDATION export RPKI_RTR_STRICT_CCR_VALIDATION
export RPKI_RTR_REFRESH_INTERVAL_SECS export RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS
export RPKI_RTR_TIMING_REFRESH_SECS
export RPKI_RTR_TIMING_RETRY_SECS
export RPKI_RTR_TIMING_EXPIRE_SECS
export RPKI_RTR_MAX_CONNECTIONS export RPKI_RTR_MAX_CONNECTIONS
export RPKI_RTR_NOTIFY_QUEUE_SIZE export RPKI_RTR_NOTIFY_QUEUE_SIZE

View File

@ -23,11 +23,17 @@ export RPKI_RTR_TLS_KEY_PATH
export RPKI_RTR_TLS_CLIENT_CA_PATH export RPKI_RTR_TLS_CLIENT_CA_PATH
: "${RPKI_RTR_MAX_DELTA:=100}" : "${RPKI_RTR_MAX_DELTA:=100}"
: "${RPKI_RTR_REFRESH_INTERVAL_SECS:=300}" : "${RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS:=300}"
: "${RPKI_RTR_TIMING_REFRESH_SECS:=3600}"
: "${RPKI_RTR_TIMING_RETRY_SECS:=600}"
: "${RPKI_RTR_TIMING_EXPIRE_SECS:=7200}"
: "${RPKI_RTR_MAX_CONNECTIONS:=512}" : "${RPKI_RTR_MAX_CONNECTIONS:=512}"
: "${RPKI_RTR_NOTIFY_QUEUE_SIZE:=1024}" : "${RPKI_RTR_NOTIFY_QUEUE_SIZE:=1024}"
export RPKI_RTR_MAX_DELTA export RPKI_RTR_MAX_DELTA
export RPKI_RTR_REFRESH_INTERVAL_SECS export RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS
export RPKI_RTR_TIMING_REFRESH_SECS
export RPKI_RTR_TIMING_RETRY_SECS
export RPKI_RTR_TIMING_EXPIRE_SECS
export RPKI_RTR_MAX_CONNECTIONS export RPKI_RTR_MAX_CONNECTIONS
export RPKI_RTR_NOTIFY_QUEUE_SIZE export RPKI_RTR_NOTIFY_QUEUE_SIZE

View File

@ -29,7 +29,8 @@ struct AppConfig {
max_delta: u8, max_delta: u8,
prune_delta_by_snapshot_size: bool, prune_delta_by_snapshot_size: bool,
strict_ccr_validation: bool, strict_ccr_validation: bool,
refresh_interval: Duration, source_refresh_interval: Duration,
timing: Timing,
service_config: RtrServiceConfig, service_config: RtrServiceConfig,
} }
@ -51,7 +52,8 @@ impl Default for AppConfig {
max_delta: 100, max_delta: 100,
prune_delta_by_snapshot_size: false, prune_delta_by_snapshot_size: false,
strict_ccr_validation: false, strict_ccr_validation: false,
refresh_interval: Duration::from_secs(300), source_refresh_interval: Duration::from_secs(300),
timing: Timing::default(),
service_config: RtrServiceConfig { service_config: RtrServiceConfig {
max_connections: 512, max_connections: 512,
@ -126,22 +128,51 @@ impl AppConfig {
if let Some(value) = env_var("RPKI_RTR_STRICT_CCR_VALIDATION")? { if let Some(value) = env_var("RPKI_RTR_STRICT_CCR_VALIDATION")? {
config.strict_ccr_validation = parse_bool(&value, "RPKI_RTR_STRICT_CCR_VALIDATION")?; config.strict_ccr_validation = parse_bool(&value, "RPKI_RTR_STRICT_CCR_VALIDATION")?;
} }
if let Some(value) = env_var("RPKI_RTR_REFRESH_INTERVAL_SECS")? { let source_refresh_interval_new = env_var("RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS")?;
let secs: u64 = value.parse().map_err(|err| { let source_refresh_interval_legacy = env_var("RPKI_RTR_REFRESH_INTERVAL_SECS")?;
anyhow!( match (
"invalid RPKI_RTR_REFRESH_INTERVAL_SECS '{}': {}", source_refresh_interval_new.as_deref(),
value, source_refresh_interval_legacy.as_deref(),
err ) {
) (Some(new_value), Some(_)) => {
})?; let secs = parse_positive_u64(
if secs == 0 { new_value,
return Err(anyhow!( "RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS",
"invalid RPKI_RTR_REFRESH_INTERVAL_SECS '{}': must be >= 1", )?;
value config.source_refresh_interval = Duration::from_secs(secs);
)); warn!(
"both RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS and legacy RPKI_RTR_REFRESH_INTERVAL_SECS are set; using RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS"
);
} }
config.refresh_interval = Duration::from_secs(secs); (Some(new_value), None) => {
let secs = parse_positive_u64(
new_value,
"RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS",
)?;
config.source_refresh_interval = Duration::from_secs(secs);
}
(None, Some(legacy_value)) => {
let secs = parse_positive_u64(legacy_value, "RPKI_RTR_REFRESH_INTERVAL_SECS")?;
config.source_refresh_interval = Duration::from_secs(secs);
warn!(
"RPKI_RTR_REFRESH_INTERVAL_SECS is deprecated; use RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS"
);
}
(None, None) => {}
} }
if let Some(value) = env_var("RPKI_RTR_TIMING_REFRESH_SECS")? {
config.timing.refresh = parse_positive_u32(&value, "RPKI_RTR_TIMING_REFRESH_SECS")?;
}
if let Some(value) = env_var("RPKI_RTR_TIMING_RETRY_SECS")? {
config.timing.retry = parse_positive_u32(&value, "RPKI_RTR_TIMING_RETRY_SECS")?;
}
if let Some(value) = env_var("RPKI_RTR_TIMING_EXPIRE_SECS")? {
config.timing.expire = parse_positive_u32(&value, "RPKI_RTR_TIMING_EXPIRE_SECS")?;
}
config
.timing
.validate()
.map_err(|err| anyhow!("invalid RTR timing configuration: {}", err))?;
if let Some(value) = env_var("RPKI_RTR_MAX_CONNECTIONS")? { if let Some(value) = env_var("RPKI_RTR_MAX_CONNECTIONS")? {
config.service_config.max_connections = value config.service_config.max_connections = value
.parse() .parse()
@ -218,7 +249,7 @@ fn init_shared_cache(config: &AppConfig, store: &RtrStore) -> Result<SharedRtrCa
store, store,
config.max_delta, config.max_delta,
config.prune_delta_by_snapshot_size, config.prune_delta_by_snapshot_size,
Timing::default(), config.timing,
|| load_payloads_from_latest_sources(&payload_load_config), || load_payloads_from_latest_sources(&payload_load_config),
)?; )?;
@ -261,7 +292,7 @@ fn spawn_refresh_task(
store: RtrStore, store: RtrStore,
notifier: RtrNotifier, notifier: RtrNotifier,
) -> JoinHandle<()> { ) -> JoinHandle<()> {
let refresh_interval = config.refresh_interval; let refresh_interval = config.source_refresh_interval;
let payload_load_config = PayloadLoadConfig { let payload_load_config = PayloadLoadConfig {
ccr_dir: config.ccr_dir.clone(), ccr_dir: config.ccr_dir.clone(),
slurm_dir: config.slurm_dir.clone(), slurm_dir: config.slurm_dir.clone(),
@ -358,9 +389,12 @@ fn log_startup_config(config: &AppConfig) {
info!("max_delta={}", config.max_delta); info!("max_delta={}", config.max_delta);
info!("strict_ccr_validation={}", config.strict_ccr_validation); info!("strict_ccr_validation={}", config.strict_ccr_validation);
info!( info!(
"refresh_interval_secs={}", "source_refresh_interval_secs={}",
config.refresh_interval.as_secs() config.source_refresh_interval.as_secs()
); );
info!("rtr_timing_refresh_secs={}", config.timing.refresh);
info!("rtr_timing_retry_secs={}", config.timing.retry);
info!("rtr_timing_expire_secs={}", config.timing.expire);
info!("max_connections={}", config.service_config.max_connections); info!("max_connections={}", config.service_config.max_connections);
info!( info!(
"notify_queue_size={}", "notify_queue_size={}",
@ -407,3 +441,23 @@ fn parse_bool(value: &str, name: &str) -> Result<bool> {
_ => Err(anyhow!("invalid {} '{}': expected boolean", name, value)), _ => Err(anyhow!("invalid {} '{}': expected boolean", name, value)),
} }
} }
fn parse_positive_u64(value: &str, name: &str) -> Result<u64> {
let parsed = value
.parse::<u64>()
.map_err(|err| anyhow!("invalid {} '{}': {}", name, value, err))?;
if parsed == 0 {
return Err(anyhow!("invalid {} '{}': must be >= 1", name, value));
}
Ok(parsed)
}
fn parse_positive_u32(value: &str, name: &str) -> Result<u32> {
let parsed = value
.parse::<u32>()
.map_err(|err| anyhow!("invalid {} '{}': {}", name, value, err))?;
if parsed == 0 {
return Err(anyhow!("invalid {} '{}': must be >= 1", name, value));
}
Ok(parsed)
}

View File

@ -292,7 +292,7 @@ impl Timing {
impl Default for Timing { impl Default for Timing {
fn default() -> Self { fn default() -> Self {
Self { Self {
refresh: 60, refresh: 3600,
retry: 600, retry: 600,
expire: 7200, expire: 7200,
} }