跳转到主要内容
未知字段会直接触发反序列化错误,因为全局启用了 #[serde(deny_unknown_fields)]。时间字段使用 humantime 格式,例如 "30s""500ms""2m"

顶层结构

io_uring:       # io_uring ring 尺寸与 SQPOLL(变更需重启)
node:           # 运行时容量参数
listeners:      # 监听地址与协议
upstreams:      # 命名上游组
routes:         # 请求路由规则
plugins:        # WASM 与 Rhai 插件注册
observability:  # 指标服务
logging:        # 访问日志输出、采样、脱敏
control_plane:  # 节点本地管理 API

node

用于控制 worker 数、连接上限和全局 I/O 超时。
字段类型默认值说明
idstring"arc-node"人类可读的节点标识
workersinteger0数据平面 worker 线程数,0 表示自动识别 CPU 数
max_connectionsinteger0接受 TCP 连接的硬上限,0 表示不限
read_timeoutduration30s下游读取超时
write_timeoutduration30s下游写入超时
idle_timeoutduration60skeep-alive 空闲超时
node:
  id: "arc-prod-1"
  workers: 0
  max_connections: 100000
  read_timeout: 30s
  write_timeout: 30s
  idle_timeout: 60s

io_uring

控制每个 worker 线程的 io_uring 参数。该段全部字段变更都需要重启进程。
字段类型默认值说明
uring_entriesinteger2048提交队列 ring 大小(2 的幂)。如果 arc_ring_sq_dropped_total 非 0,建议增大。
sqpollbooleanfalse开启 SQPOLL(内核轮询线程),减少提交 syscall。内核 < 5.11 时需要 CAP_SYS_ADMIN。裸机推荐开启。
sqpoll_idle_msinteger2000SQPOLL 线程空闲多久后进入休眠(毫秒)。
如果 arc_ring_sq_dropped_totalarc_ring_cq_overflow_total 非 0,通常说明 ring 太小,建议将 uring_entries 翻倍。
io_uring:
  uring_entries: 4096   # 高流量节点可设为 4096
  sqpoll: true          # 裸机推荐
  sqpoll_idle_ms: 2000

listeners

监听器是一个数组,每个元素绑定一个地址。
字段类型必填说明
namestring监听器标识,ACME 配置会引用
kindstring协议类型(见下表)
bindstring监听地址,例如 "0.0.0.0:443"
socketobject操作系统 socket 调优
tlsobjecthttps / h3 场景必需
kind 可选值:
说明
http明文 HTTP/1.1 + H2C
httpsTLS 上的 HTTP(ALPN:HTTP/1.1 + HTTP/2),需要 tls
h3QUIC 上的 HTTP/3,需要 tls
tcp原始 TCP 四层代理
udp原始 UDP 四层代理
socket 可选项:
字段类型默认值说明
so_reuseportbooleanfalse开启 SO_REUSEPORT
tcp_fastopen_backlogintegernull开启 TCP Fast Open
dscpintegernullQoS 的 DSCP/TOS 值
keepaliveobjectnullTCP keepalive 探测(idleintervalcount
listeners:
  - name: http
    kind: http
    bind: "0.0.0.0:8080"
    socket:
      so_reuseport: true

  - name: https
    kind: https
    bind: "0.0.0.0:8443"
    tls:
      certificates:
        - sni: "example.com"
          cert_pem: "./certs/example.com.crt"
          key_pem: "./certs/example.com.key"

tls

仅在监听器 kindhttpsh3 时生效。
字段类型默认值说明
acmeobjectnullACME 自动证书管理
certificatesarray[]启动时加载的静态证书
min_versionstringnulltls12tls13
max_versionstringnullTLS 最高版本
cipher_suitesstring[][]密码套件优先级(空表示 Rustls 默认)
session_resumptionbooleantrue是否启用会话恢复
certificates 元素字段:
字段说明
sni主机名,支持精确匹配或通配符("*.example.com"
cert_pemPEM 证书链路径
key_pemPEM 私钥路径
数组第一张证书会作为未命中 SNI 的兜底证书。

tls.acme

用于从 ACME CA 自动签发并续期证书。
字段类型默认值说明
emailstringnullACME 账号联系邮箱
directory_urlstringLet’s EncryptACME 目录地址
account_keyobjectrequired账号密钥配置
domainsstring[]required要签发证书的域名列表
challengeobjectrequired挑战类型
renew_beforeduration720h提前续期时间窗口
account_key 字段:
字段说明
algorithmed25519rsa2048
encrypted_key_path加密密钥文件路径
passphrase{ type: env, name: VAR }{ type: file, path: /path }
challenge 类型:
type额外字段说明
http_01listener通过指定监听器做 HTTP-01(必须绑定 80)
tls_alpn_01listener通过 TLS 监听器做 TLS-ALPN-01
dns_01providerDNS-01,可接 Cloudflare、Route53、RFC2136、webhook、hook
完整 ACME 示例:
tls:
  acme:
    email: you@example.com
    domains: [example.com, www.example.com]
    account_key:
      algorithm: ed25519
      encrypted_key_path: /etc/arc/acme-key.enc
      passphrase:
        type: env
        name: ACME_KEY_PASSPHRASE
    challenge:
      type: tls_alpn_01
      listener: https
    renew_before: 720h

upstreams

这是命名上游组数组,路由通过 name 引用上游。
字段类型默认值说明
namestringrequired路由动作中引用的上游名
discoveryobjectrequired上游地址发现方式
lbobjectpeak_ewma负载均衡算法
healthobject(empty)主动与被动健康检查
poolobject见下文连接池参数
timeoutsobject见下文上游超时覆盖参数

discovery

静态地址:
discovery:
  type: static
  endpoints:
    - address: "10.0.0.1:3000"
      weight: 1
    - address: "10.0.0.2:3000"
      weight: 2
DNS 发现:
discovery:
  type: dns
  hostname: api.internal
  port: 3000
  respect_ttl: true
  fallback_poll: 10s

lb(负载均衡)

algorithm额外字段说明
round_robin均匀轮询
weighted_round_robinendpoint.weight 加权轮询
least_requests选择在途请求最少的节点
consistent_hashkey, virtual_nodesKetama 一致性哈希
peak_ewmadecay(duration)基于延迟的 Peak EWMA 选择
一致性哈希 key 来源可以是 client_ipheader(需 name)或 cookie(需 name)。

health

主动健康检查:
health:
  active:
    interval: 10s
    path: /health
    fail_after: 3
    pass_after: 2
被动健康检查:
health:
  passive:
    error_rate_threshold: 0.2
    window: 30s
    ejection_time: 60s

pool(连接池)

字段默认值说明
max_idle1024每个上游最大空闲连接数
idle_ttl30s超过该时长的空闲连接会被回收
max_lifetime300s单连接最大生命周期

timeouts(上游超时)

字段默认值说明
connect2s上游 TCP 建连超时
write30s写请求到上游超时
ttfb5s发出请求后等待首字节超时
read30s读取完整响应超时

tls(上游 TLS)

可选。配置后 Arc 会与上游建立 TLS 连接。
字段默认值说明
ca_pemnull用于校验上游证书的 CA 文件路径
client_cert_pemnull客户端证书路径(双向 TLS)
client_key_pemnull客户端私钥路径(双向 TLS)
insecurefalse跳过上游证书校验,仅建议开发环境使用
完整上游 TLS 示例见 TLS 与证书

routes

路由规则为数组。匹配优先级遵循“更具体优先”:精确路径优先于通配路径,长路径优先于短路径。
字段类型默认值说明
namestringrequired路由名(用于日志与插件)
matchobjectrequired匹配条件
actionobjectrequired命中后的动作
rate_limitobjectnull路由级限流
mirrorobjectnull流量镜像
splitobjectnull加权分流
pluginsarray[]该路由绑定的插件

match

字段默认值说明
host[]主机名列表,空表示不限
methods[]HTTP 方法列表,空表示不限
pathrequired路径模式
headers[]Header 谓词(全部满足)
cookies[]Cookie 谓词
query[]Query 参数谓词
exprnull组合命名匹配器的布尔表达式(AND/OR/NOT)
路径模式:
模式示例行为
精确匹配/api/v1/users仅命中完全相同路径
段捕获/users/{id}捕获单个路径段
尾部捕获/{*rest}捕获后续全部路径
通配段/static/*匹配单段通配
Header 谓词 op 可选:existscontainsregexequals。全部操作都需要 name;值比较类操作还需要 valuepattern

action

字段默认值说明
upstreamrequired上游组名称
rewritenullURL 重写(pattern + replace
headers[]转发前 Header 变更
redirectnull直接重定向(status + location
retry见下文重试策略
Header 变更操作 opaddsetremove retry 字段:
字段默认值说明
max_retries1最大重试次数
backoff50ms重试固定退避时间
idempotent_onlytrue仅重试 GET/HEAD/OPTIONS 等幂等请求

rate_limit

字段默认值说明
qpsrequired令牌补充速率
burstrequired桶容量(最大突发)
keyclient_ip限流 key 生成策略
status429超限响应状态码
key 策略可选:client_ipheader(需 name)或 route(全路由共享桶)。

mirror

# 简写
mirror: api-shadow

# 完整写法
mirror:
  - upstream: api-v2-shadow
    sample: 0.5
    timeout: 3s
    transform:
      headers:
        set: { X-Shadow: "true" }
        remove: [X-Real-User]
      path: "/v2$path"
    compare:
      enabled: true
      ignore_headers: [Date]
      ignore_body_fields: ["$.timestamp"]
      on_diff: log

split(流量分流)

split:
  choices:
    - upstream: app-v1
      weight: 90
    - upstream: app-v2
      weight: 10
  key:
    source: client_ip

plugins

全局插件注册区。路由通过名字引用插件。
plugins:
  wasm:
    - name: my-filter
      file: ./plugins/my-filter.wasm
      budget: 2ms

  rhai:
    - name: add-header
      inline: |
        request.set_header("X-Via", "arc");
        0
      max_ops: 50000

WASM 插件字段

字段默认值说明
namerequired插件标识
filerequired.wasm 文件路径
budget2ms单次调用 CPU 预算

Rhai 脚本字段

字段默认值说明
namerequired脚本标识
inlinerequired内联 Rhai 代码
max_ops50000单次调用操作上限

把插件绑定到路由

routes:
  - name: api
    match:
      path: /api/{*rest}
    action:
      upstream: app
    plugins:
      - name: my-filter
        stage: request_headers
stage 可选值:
说明
l4L4/TCP 层,HTTP 解析前
request_headers收到请求头后
request_body请求体缓冲完成后
response_headers上游响应头到达后
response_body响应体接收完成后
log写访问日志时

observability

控制指标与管理端点。访问日志配置在下文 logging
字段默认值说明
metrics_bind"127.0.0.1:9090"Prometheus /metrics 绑定地址
metrics_enabledtrue是否开启指标端点
tracingnullOTLP 追踪导出(endpointinsecure
observability:
  metrics_bind: "0.0.0.0:9090"   # 暴露到所有网卡(建议配防火墙)
  metrics_enabled: true
  tracing:
    endpoint: "http://otel-collector:4317"
    insecure: true

logging

控制结构化 NDJSON 访问日志。logging 是顶层字段,和 observability 分离。 logging.output
字段默认值说明
logging.output.file/var/log/arc/access.log日志输出文件
logging.output.stdoutfalse是否同时输出到 stdout
logging.output.rotation.max_size500mb文件达到该体积后轮转
logging.output.rotation.max_files30保留轮转文件数量
logging.output.rotation.compresstrue是否 gzip 压缩轮转文件
logging.access
字段默认值说明
logging.access.sample0.01请求采样比例(0.0–1.0),主采样开关
logging.access.force_on_status[401,403,429,500,502,503,504]无论采样比例,命中这些状态码都强制记录
logging.access.force_on_slow500无论采样比例,耗时超过该毫秒值都强制记录
observability.access_log.sample(默认 1.0)和 logging.access.sample(默认 0.01)是两个独立字段。前者是旧参数,后者会覆盖前者。新配置建议统一使用 logging.access.sample
logging.redact
字段默认值说明
logging.redact.headers["Authorization","Cookie",…]命中后替换为 [REDACTED]
logging.redact.query_params["token","secret",…]命中后替换为 [REDACTED]
logging.writer
字段默认值说明
logging.writer.ring_capacity8192每 worker 的 SPSC ring 大小(条目数)
logging.writer.batch_bytes262144批次达到该大小时触发刷盘(字节)
logging.writer.flush_interval50定时刷盘间隔(毫秒)
logging:
  output:
    file: /var/log/arc/access.log
    stdout: false
    rotation:
      max_size: 500mb
      max_files: 30
      compress: true
  access:
    sample: 0.01
    force_on_status: [401, 403, 429, 500, 502, 503, 504]
    force_on_slow: 500
  redact:
    headers: [Authorization, Cookie, X-Api-Key]
    query_params: [token, secret, password]

control_plane

字段默认值说明
enabledfalse总开关。不开启则控制面服务不会启动
bind"127.0.0.1:22100"控制面 HTTP 服务监听地址
rolestandalonestandaloneleaderfollower
node_idhostname集群 gossip 的唯一节点名
peers[]leader 发起 HTTP 推送时的 peer URL 列表
quorum0提交前最少成功节点数,0 表示多数派
auth_tokennullBearer token;null 表示仅回环可访问
pull_fromnullfollower 拉取配置的 leader URL
longpoll_timeout_ms30000长轮询服务端挂起时长
peer_timeout_ms5000节点间 validate/commit 请求超时
peer_concurrency16集群下发时并行 peer 请求上限
runtime_threads2control plane runtime 的 Tokio 线程数
compile_threads2JSON 编译 spawn_blocking 线程上限
max_body_bytes16 MiB配置端点请求体大小上限
control_plane 下所有字段变更都需要重启进程。 接口说明见 网关控制面 API 参考

完整示例

node:
  id: "prod-1"
  workers: 0
  max_connections: 100000
  read_timeout: 30s
  write_timeout: 30s
  idle_timeout: 60s

listeners:
  - name: http
    kind: http
    bind: "0.0.0.0:8080"
  - name: https
    kind: https
    bind: "0.0.0.0:8443"
    tls:
      certificates:
        - sni: "*.example.com"
          cert_pem: /etc/arc/certs/wildcard.crt
          key_pem: /etc/arc/certs/wildcard.key

upstreams:
  - name: api
    discovery:
      type: static
      endpoints:
        - address: "10.0.1.1:3000"
        - address: "10.0.1.2:3000"
    lb:
      algorithm: peak_ewma
      decay: 10s
    health:
      active:
        interval: 10s
        path: /health
    pool:
      max_idle: 512
      idle_ttl: 30s
    timeouts:
      connect: 2s
      ttfb: 5s

routes:
  - name: api
    match:
      path: /api/{*rest}
      methods: [GET, POST, PUT, DELETE]
    action:
      upstream: api
      retry:
        max_retries: 2
        backoff: 100ms
        idempotent_only: true
    rate_limit:
      qps: 1000
      burst: 2000
      key:
        by: client_ip

  - name: root
    match:
      path: /{*rest}
    action:
      upstream: api

observability:
  metrics_bind: "127.0.0.1:9090"

control_plane:
  enabled: true
  bind: "127.0.0.1:22100"
  auth_token: "your-secret-token"