proxy-pool/docs/configuration/reference.md

11 KiB
Raw Blame History

配置参考

1. 加载规则

主配置格式为 YAML根字段 version 当前固定为 1。加载器启用严格字段 检查,拼写错误或未来版本字段不会被静默忽略。推荐启动命令显式传入配置路径:

go run ./cmd/proxy-controller -config configs/proxy-pool.yaml

所有时间值使用 Go duration例如 500ms30s5m。示例中的 ${TOKEN}${PASSWORD}${POSTGRES_URL} 等由加载器从同名环境变量 展开;这些值不得写入日志、指标、配置转储或错误响应。生产配置优先使用 环境变量或 Secret 文件,不提交明文值。

加载与热更新必须遵循同一顺序:

读取文件 -> 严格解析 -> 字段校验 -> 引用/正则校验
        -> 构建不可变快照 -> 计算差异 -> 原子替换

新配置任何一步失败时保留旧快照。删除或禁用 Upstream 只停止新 Fetch 和新 分配,已有连接进入 Drain不强制中断。

2. 根结构

version: 1
defaults: {}
security: {}
gateway: {}
distribution: {}
admin: {}
metrics: {}
storage: {}
routing: []
upstreams: {}
  • defaultsFetch 与 Check 的公共建议值。生产配置仍建议在每个启用的 Upstream 显式写出关键限制,避免继承关系不清。
  • security:跨入口启动保护。
  • gatewayHTTP/HTTPS CONNECT 数据面入口。
  • distribution:一次性独占提取入口。
  • admin:运维管理入口,必须与 Distribution 分端口。
  • metricsPrometheus 入口。
  • storageController 使用的 PostgreSQL 与 Redis 地址。
  • routing:有序 Routing 列表,自上而下首条命中停止。
  • upstreams:全局共享的 Upstream 运行时定义。

3. 安全与监听器

security:
  requireProtectionOnPublicListen: true

启用严格保护时,只要 Gateway、Distribution 或 Admin 满足以下全部条件, 启动即失败:

  1. 入口已启用且监听地址不是回环地址。
  2. auth.mode: none
  3. access.allowCIDRs 为空。

监听器公共字段:

enabled: true
listen: 0.0.0.0:8081
access:
  allowCIDRs: [10.0.0.0/8]
  trustedProxies: [10.10.0.10/32]
auth:
  mode: apiKey
  header: X-API-Key
  token: "${DISTRIBUTION_API_KEY}"
limits:
  maxConcurrentConnections: 100000
  requestsPerMinute: 6000
  requestsPerMinutePerClient: 600

trustedProxies 只决定何时接受 ForwardedX-Forwarded-For,不能替代 allowCIDRs。来自非可信代理的转发头必须忽略。

3.1 认证模式

  • none:无身份认证,访问控制与限流仍生效。
  • usernamePassword:使用 usernamepassword
  • apiKey:使用 headertoken
  • bearer:使用 Authorization: Bearer TOKENGateway 对应 Proxy-Authorization: Bearer TOKEN
  • ipWhitelist:使用 cidrs
  • anymethods 中任一方法成功即可Bearer 方法的 Secret 使用 value/valueFile

Gateway、Distribution、Admin 与 Provider API 是独立认证边界。改变其中一套 不得连带改变其他入口。

4. Gateway

gateway:
  enabled: true
  listen: 127.0.0.1:8080
  auth: {mode: none}
  limits:
    maxConcurrentConnections: 50000
  retry:
    maxAttempts: 2
    retryMethods: [GET, HEAD]
  destinationPolicy:
    denyPrivateNetworks: true
    denyLoopback: true
    denyLinkLocal: true
    denyCIDRs: [169.254.169.254/32]
    allowedPorts: [80, 443]
  • retryMethods 默认只应包含幂等方法。POST、PUT、PATCH、DELETE 不自动重试。
  • CONNECT 向 Client 写出 200 Connection Established 后不透明重放。
  • 目的地址策略必须在 DNS 解析前后都执行,防止 DNS Rebinding。
  • 三个 deny* 字段省略时均按 true 处理;只有显式配置为 false 才放行 对应类别,部分配置不会改变其他类别的安全默认值。
  • allowedPorts 省略时安全默认值为 [80, 443];配置空列表不表示开放全部端口。
  • 保留地址、CGNAT 与云元数据端点始终拒绝,不能通过私网/链路本地开关放行。
  • maxConcurrentConnections 是入口准入上限,不是 Proxy 容量上限。

5. Distribution

distribution:
  enabled: true
  listen: 127.0.0.1:8081
  auth: {mode: none}
  clientIdentification: {mode: sourceIP}
  limits:
    requestsPerMinute: 60
    requestsPerMinutePerClient: 30
  extraction:
    fulfillment: partial
    maxCountPerRequest: 20
    minRemainingTTL: 30s
    maxHealthCheckAge: 15s
    reserveForGateway: 5

Extraction 是固定的一次性独占行为,没有 modeleaseDurationreleaserenew 配置。事务提交后执行 AVAILABLE -> EXTRACTED,该 Proxy 不再由 Gateway 或 Distribution 分配。

  • fulfillmentpartialallOrNothing,默认语义为 partial
  • maxCountPerRequest:单次请求硬上限。
  • minRemainingTTL:剩余寿命低于此值时不参与提取。
  • maxHealthCheckAge:最近检查早于此窗口时不参与提取。
  • reserveForGateway:提取后必须留给 Gateway 的最低符合条件库存数量。

partial 会提交实际可得数量;allOrNothing 数量不足时事务回滚,一个也不 提取。认证关闭时仍应使用 sourceIP 识别匿名 Client 并执行全局/来源限流。

clientIdentification.mode 支持:

  • sourceIP:使用可信代理链解析后的来源地址;省略配置时采用此模式。
  • authenticatedClient:使用 Basic 用户名或 Token 的稳定不可逆摘要;要求 启用认证。
  • authenticatedClientOrSourceIP:优先认证主体,无主体时回退来源地址。

6. Routing

routing:
  - name: api-post
    enabled: true
    purpose: gateway
    match:
      hostRegex: '^api\\.example\\.com$'
      methods: [POST]
      pathRegex: '^/v1/'
      headers: {X-Tenant: premium}
    upstreams: [provider-a, provider-b]
    strategy:
      type: sequential
      switchAfterEmptyFetch: 5
      endBehavior: stayLast
    onUnavailable:
      action: reject
      waitTimeout: 0s
  • Routing 列表有序,首条匹配后停止。
  • purposegatewayextract
  • strategy.type 支持 sequentialrandomroundRobinweightedleastConnections
  • weighted 使用 weights 映射,键必须引用本 Routing 的 Upstream。
  • sequential 必须设置大于零的 switchAfterEmptyFetch
  • onUnavailable.actionrejectwaitdirect;默认建议 reject

Sequential 的空计数属于 Upstream当前索引属于 Routing。只有 Provider 响应 成功、模板成功且合法候选为零时才增加空计数。错误不改变空计数;重复候选 会重置空计数但增加独立 duplicate 指标。

7. Upstream

upstreams:
  provider-a:
    enabled: true
    exposure: [gateway, extract]
    provider:
      billingMode: fetch
      protocols: [http, https]
    api:
      url: https://provider-a.example/proxies
      method: GET
      auth:
        type: apiKey
        location: header
        name: X-Provider-Key
        value: "${PROVIDER_API_KEY}"
      headers: {}
      query: {count: '100'}
      body: {type: json, value: {}}
      template: '{{.}}'
    proxyAuth: {type: response}
    pool: {maxSize: 1000, shrinkDelay: 30s}
    capacity: {maxConcurrencyPerProxy: 10}
    lifecycle: {ttl: 2m, allocationSafetyMargin: 15s}
    fetch:
      requestInterval: 1s
      timeout: 3s
      maxAttempts: 3
      maxInFlight: 1
      maxTotal: 100000
      maxResponseBytes: 1048576
      templateTimeout: 100ms
      retry: {initial: 500ms, max: 30s, jitter: 20}
    check:
      interval: 30s
      jitter: 20
      maxInFlight: 100
      timeout: 2s
      maxAttempts: 2
      maxConsecutiveFailures: 3
      urls: [http://connect.rom.miui.com/generate_204]

7.1 Provider 与代理认证

  • api.auth 用于系统访问 Provider API。
  • proxyAuth 用于最终连接被获取的 Proxy。
  • Provider api.auth.type 支持 nonebasicbearerapiKey
  • apiKey 使用 location: header|querynamevalue,程序负责 Header 设置或 Query URL 编码。
  • basic 使用 usernamepasswordbearer 使用 token
  • proxyAuth.type: response 表示凭据来自 Provider 响应。
  • proxyAuth.type: static 使用配置中的 usernamepassword
  • proxyAuth.type: ipWhitelist 表示 Provider 按出口 IP 放行,不配置账号密码。

Provider API 认证不使用入口的 auth.mode,代理连接认证也不使用 mode。三者的字段和凭据不可互相回退:

# 对外 Distribution/Gateway/Admin
auth:
  mode: apiKey
  header: X-API-Key
  token: "${CLIENT_API_KEY}"

# 请求 Provider API
auth:
  type: bearer
  token: "${PROVIDER_API_TOKEN}"

# 连接 Provider 返回的 Proxy
proxyAuth:
  type: static
  username: "${PROVIDER_PROXY_USER}"
  password: "${PROVIDER_PROXY_PASSWORD}"

7.2 Pool 与累计额度

  • pool.maxSize:当前系统维护且尚未 EXTRACTED 的 Proxy 硬上限,包括 FETCHED、CHECKING、AVAILABLE、SUSPECT、DRAINING 和 pending expected。
  • fetch.maxTotal:当前运行或计费周期内,从 Provider 成功获取的累计上限; 0 表示不设置累计上限。

fetch.maxTotal 不得小于 pool.maxSize。提取一个 Proxy 会释放当前库存位置, 但不会恢复累计获取额度。

7.3 Fetch 限制

  • requestInterval:同一 Provider 请求间隔。
  • timeout:单次调用超时。
  • maxAttempts:单次补池动作最大尝试次数。
  • maxInFlight:同一 Provider 同时在途请求数。
  • maxResponseBytes:读取响应的硬上限。
  • templateTimeout:模板解析执行上限。
  • retry错误退避HTTP 429 还必须尊重 Retry-After

大量缺池信号必须合并成 singleflight 或容量为 1 的通知,不能按 Gateway 请求 数量线性触发 Provider API。

7.4 生命周期与健康

  • 明确绝对过期时间优先于响应 TTL响应 TTL 优先于配置 lifecycle.ttl
  • 距离过期不足 allocationSafetyMargin 时停止新分配。
  • check.jitter 为调度抖动百分比,避免所有 Proxy 同时探测。
  • 第一次有意义失败进入 SUSPECT达到 maxConsecutiveFailures 后才进入 UNHEALTHY。

8. 存储、Admin 与 Metrics

admin:
  enabled: true
  listen: 127.0.0.1:8082
  auth: {mode: none}
metrics:
  enabled: true
  listen: 127.0.0.1:9090
storage:
  postgresURL: "${POSTGRES_URL}"
  redisURL: "${REDIS_URL}"

PostgreSQL 是 Proxy 生命周期、Routing 选择、Worker 所有权和 Extraction Record 的权威存储。Redis 只承载可重建的短期协调状态,不能成为独占提取的唯一事实 来源。Metrics 标签禁止 Proxy IP、Client ID、Session、完整 URL 和 Request ID。

9. 启动前校验清单

  1. version 必须为 1,未知字段拒绝。
  2. 所有启用监听器具有合法 host:port
  3. 非回环监听器满足认证或来源 CIDR 保护。
  4. Routing 名称唯一,正则可编译,引用的 Upstream 存在。
  5. Sequential 阈值大于零,onUnavailable.action 明确。
  6. 启用的 Upstream 有正数 pool.maxSize、并发和 Fetch 限制。
  7. allocationSafetyMargin < ttl
  8. fetch.maxTotal == 0fetch.maxTotal >= pool.maxSize
  9. Distribution 的 fulfillment 合法,单次数量大于零。
  10. Secret 未写入日志可见配置转储。