Files
getDomain/docs/16_domainCheck_多机检测与跨地域部署设计.md
Your Name ebf632e651 first
2026-04-16 21:35:47 +08:00

19 KiB
Raw Permalink Blame History

16 domainCheck 多机检测与跨地域部署设计

一、目标

本文档用于固化 domainCheck 的正式多机落地方案,满足下面这些约束:

  • Web 后台、管理 API 必须部署在国外机器
  • 检测执行、代理、Redis、运行态存储部署在大陆机器
  • 最终结果、配置、归档、备份以国外机器为主
  • 初期部署不复杂,支持从 国外 1 台 + 大陆 1 台 起步
  • 后期不够时,优先横向增加大陆 Worker不推翻整体架构

一句话原则:

国外负责“管、看、存、备份”,大陆负责“跑、调度、抢任务、贴近代理资源”。

二、当前落地状态

截至 2026-04-16,第一阶段多机运行骨架已经完成,当前代码已具备:

  • 控制面节点注册与心跳
  • 执行面节点注册与心跳
  • 运行库骨架表自动初始化
  • 集群节点快照接口
  • 国外/大陆两套部署脚手架

当前已落地的运行态表:

  • detect_worker_nodes
  • detect_jobs
  • detect_job_items
  • detect_run_events
  • detect_sync_records

当前可直接验证的接口:

  • GET /api/v1/runtime/status
  • GET /api/v1/runtime/readiness
  • GET /api/v1/runtime/cluster
  • GET /api/v1/detect/job/active
  • GET /api/v1/detect/jobs
  • GET /api/v1/detect/queue-summary

当前 runtime/cluster 还补充了 summary 摘要,至少会返回:

  • status_counts
  • role_counts
  • region_counts
  • online_worker_nodes
  • online_control_nodes
  • busy_nodes
  • stale_nodes
  • offline_nodes

当前还补充了同步观测骨架:

  • GET /api/v1/runtime/sync-summary
  • GET /api/v1/runtime/sync-records

可用于提前观察:

  • 当前节点是否启用同步推送
  • 源地域 / 目标地域配置是否正确
  • detect_sync_records 最近状态分布

当前代码还补了一层“运行态自动投影”:

  • 控制面在读取 runtime/status 时,会把当前运行摘要按去重策略写入 detect_sync_records
  • 当前记录类型为:
    • runtime_projection
  • 当前还新增了“结果摘要投影”:
    • detect_result_projection
  • 用于把当前活跃任务的摘要、最近阶段事件、任务收敛进度先沉淀到统一同步面板
  • 其作用不是替代后续真正的 sync-service
  • 而是先保证跨地域部署阶段已经有统一可观察的“同步记录面板”

当前还补上了正式同步最小闭环骨架:

  • 大陆执行面可通过 SYNC_TARGET_API_BASE_URL 指向国外控制面
  • SYNC_PUSH_ENABLED=true,应由大陆 domaincheck-sync-agent 按轮询间隔自动推送最新运行态投影
  • 国外控制面通过:
    • POST /api/v1/runtime/sync-ingest 接收投影
  • 若配置了 SYNC_SHARED_TOKEN,接收端会校验:
    • X-Domaincheck-Sync-Token

因此当前虽然还没有完整业务结果同步服务,但“同步协议、发送端、接收端、记录面板、独立同步代理”都已经有了第一版可运行骨架

当前同步骨架已经支持的记录类型包括:

  • runtime_projection
  • runtime_ingest
  • detect_result_projection
  • detect_result_ingest
  • runtime_push

当前这一轮还补上了“结果批次同步可观测”能力:

  • GET /api/v1/runtime/sync-summary 现在会额外返回:
    • detect_result_batches
  • 可直接按最近检测任务查看:
    • 是否已生成结果投影
    • 是否已推送
    • 是否已被目标地域接收
    • 最近一次失败原因
  • 当前同步策略也已细化为:
    • runtime_projection 只推最新一条,避免把历史运行态投影整批补传
    • detect_result_projection 按批次补推,确保检测结果积压可以自动追平
  • 大陆 controller 的环境模板也已固定为:
    • NODE_ROLE=control 避免把 controller 误注册成普通 Worker导致运行中心和 sync-agent 承载判断失真

当前这一轮还额外补齐了“检测会话追踪”能力:

  • POST /api/v1/detect/start 会生成本轮 cycle_token
  • cycle_token 会进入 Worker 控制指令
  • Worker 心跳元数据会回写 cycle_token / job_id / job_code
  • domain_started / domain_completed / domain_failed 事件会附带 cycle_token
  • GET /api/v1/detect/job/active 已支持按当前 cycle_token 聚合“本轮事件”

当前运行态还补齐了“代理执行语义”:

  • 代理可用时显示 代理正常
  • 代理暂时不可用但允许直连时显示 降级直连
  • 代理暂时不可用且不允许直连时显示 等待代理
  • 当代理源全部 HTTP 200raw_items=0 时,会额外标记为“供应池为空”,避免误判成程序异常

当前阶段的准确表述应为:

多机运行骨架已经落地,分布式调度与跨地域结果同步进入下一阶段。

截至当前这一轮代码,最小任务闭环也已经接上:

  • POST /api/v1/detect/start 会先创建 detect_jobs
  • Worker 会优先从 detect_job_items 领取任务
  • 运行中心已能显示当前活跃任务摘要
  • 节点状态里已能反映 busy / current_load
  • Worker 已支持小批量领取、任务续租、过期租约回收
  • API 控制面节点已支持定时心跳,避免集群视图把控制面误判为离线
  • 活跃任务接口已支持节点分布、进度百分比和最近事件回看
  • Worker 进程重启后会主动回收当前节点遗留的 running / claimed 运行态,避免后台出现“进程已重启但旧任务仍显示运行中”的残影

这意味着后续新增第二台大陆 Worker 时,已经不再是“完全从零设计”的状态,而是可以在现有骨架上继续细化调度策略。

当前最小联调命令也已经固定为:

cd /opt/domaincheck/domain-api
bash deploy/multi-region/check_cluster.sh http://127.0.0.1:8100

这条命令会连续检查:

  • /health
  • /api/v1/runtime/cluster
  • /api/v1/detect/status
  • /api/v1/detect/job/active

如需单独检查“跨地域同步骨架是否已接上”,建议再补两条:

curl http://127.0.0.1:8100/api/v1/runtime/sync-summary
curl http://127.0.0.1:8100/api/v1/runtime/sync-records?limit=10

如需快速拿到“当前这套多机部署是否已进入可联调 / 待处理 / 阻断”结论,当前也已经固定了:

curl http://127.0.0.1:8100/api/v1/runtime/readiness

该接口会直接给出:

  • status
    • ready
    • attention
    • blocking
  • summary
  • blocking_issues
  • warnings
  • info

如果这两条接口已经能看到:

  • source_region / target_region
  • records_total > 0
  • 最近记录里出现 runtime_projection

则说明当前测试服已经具备:

  • 同步配置观测入口
  • 同步记录落库入口
  • 后续接入正式 sync-service 的最小运行骨架

如果要在大陆 controller 节点本机确认“这台机器本身是否配成了 controller而不是普通 Worker”当前也已经固定了一条本机检查命令

cd /opt/domaincheck/domain-api
bash deploy/multi-region/check_mainland_controller.sh

这条命令会直接校验:

  • /etc/default/domaincheck-worker
  • NODE_ROLE=control
  • SYNC_PUSH_ENABLED=true
  • SYNC_TARGET_API_BASE_URL 是否已填写
  • domaincheck-worker
  • domaincheck-sync-agent 是否已经启动

如果当前客观条件下还不能把代码真正部署到大陆机器,当前也支持先在国外测试机上做“模拟多节点联调”:

cd /opt/domaincheck/domain-api
bash deploy/multi-region/simulate_multi_region.sh http://127.0.0.1:8100

这条命令会临时模拟:

  • 一个大陆 controller
  • 一个大陆 worker

它的目的不是替代真实部署,而是先把下面这些提前跑通:

  • runtime/readiness
  • runtime/cluster
  • 运行中心的多机就绪度提示
  • 文档、脚本、状态面板三者是否一致

如果测试服之前已经跑过旧节点、旧 worker当前还残留陈旧心跳记录也可以先清一次 detect_worker_nodes 里的历史残影,再观察 readiness

cd /opt/domaincheck/domain-api
bash deploy/multi-region/prune_cluster_nodes.sh --minutes 30 --dry-run
bash deploy/multi-region/prune_cluster_nodes.sh --minutes 30

它的作用是:

  • 清掉很久没心跳的旧节点记录
  • 避免运行中心长期被历史离线节点污染成 attention
  • 让单机模拟多节点联调时,看到更接近真实接入后的状态

三点五、当前实测结论

截至 2026-04-16 18:56,测试服已经验证通过:

  • domaincheck-apidomaincheck-worker 可在 systemd 下稳定重启
  • worker_mode=linux-systemd
  • runtime/cluster 可同时看到:
    • overseas-control-01
    • mainland-worker-01
  • 大陆 Worker 节点元数据已显示:
    • phase
    • detail
    • job_id
    • job_code
    • cycle_token
  • detect/job/activecurrent_cycle_events 已只回看当前这一轮检测事件,不再混入旧轮次历史

当前测试服最新一轮实测 cycle_token 示例:

  • aec105737f

该轮已确认能看到:

  • job_dispatch_requested
  • job_dispatch_sent
  • domain_started
  • domain_completed

这说明“控制面发起一次检测”到“执行面逐域名回写事件”的会话闭环已经打通。 也说明当前后台已经不再只会显示“有告警”,而是能明确说明任务到底是在正常代理、降级直连,还是被代理卡住。

四、推荐架构

1. 国外控制面

国外机器负责:

  • domain-web
  • domain-api
  • 国外主 PostgreSQL
  • 配置中心
  • 导出、审核、运营后台
  • 最终结果归档
  • 国外备份与日志归档

国外控制面的职责:

  • 对外提供访问入口
  • 保存最终业务结果
  • 保存系统配置和审计记录
  • 接收大陆执行面的结果同步
  • 为后续灾备提供稳定的权威数据源

2. 大陆执行面

大陆机器负责:

  • detect-worker
  • 大陆 Redis
  • 大陆运行库 PostgreSQL
  • 代理池配置与网络环境
  • 本地运行日志
  • 调度和任务租约

大陆执行面的职责:

  • 抢任务
  • 续租
  • 运行检测链路
  • 写入本地运行态
  • 汇总并同步结果到国外

3. 初期物理部署

当前最优起步方案:

  • 国外 1 台:
    • domain-web
    • domain-api
    • postgresql_main
  • 大陆 1 台:
    • redis
    • postgresql_runtime
    • scheduler
    • detect-worker

说明:

  • 这个起步方案的优先目标是先把跨地域职责边界定清楚
  • 大陆机器当前可以先把 Redis、运行库、调度和 Worker 放在同一台
  • 但逻辑上必须按不同角色设计,避免后续扩容时重新返工
  • 各节点身份建议统一通过 /etc/default/domaincheck-api/etc/default/domaincheck-worker 管理,不直接修改 service 文件正文

4. 后续扩容

当大陆执行压力不够时,扩容顺序建议为:

  1. 新增大陆 Worker 机器
  2. 如果 Redis 压力增大,再拆 Redis
  3. 如果运行库写入压力增大,再拆运行库
  4. 国外主库继续作为最终结果主库,不参与高频任务调度

后续结构示意:

国外
├── web + api + postgresql_main
└── backup / archive

大陆
├── redis + postgresql_runtime + scheduler
├── worker-01
├── worker-02
├── worker-03
└── worker-N

五、数据分层

1. 结果态数据

这类数据保存在国外主库:

  • 域名主数据
  • 检测最终结果
  • 黑名单结论
  • 导出记录
  • 审核记录
  • 系统配置
  • 操作审计

特点:

  • 最终一致
  • 生命周期长
  • 提供给后台页面和运营使用

2. 运行态数据

这类数据优先保存在大陆执行面:

  • 任务领取状态
  • 任务租约
  • 节点心跳
  • 当前阶段
  • 实时日志事件
  • 重试信息
  • 本地暂存结果

特点:

  • 高频读写
  • 延迟敏感
  • 主要服务于 Worker 协作和调度

六、任务模型

当前项目还偏向单机 Worker 直接扫描 domains 表的模式。正式多机化后,建议改为显式任务模型。

1. 核心表建议

建议新增:

  • detect_jobs
  • detect_job_items
  • detect_worker_nodes
  • detect_run_events
  • detect_sync_records

2. detect_jobs

表示一轮检测任务。

建议字段:

  • id
  • job_code
  • source
  • plan_hash
  • status
  • created_at
  • started_at
  • finished_at
  • created_by
  • remark

说明:

  • plan_hash 用于标识本轮检测所使用的规则版本和参数快照
  • 一轮任务可以对应大量域名任务项

3. detect_job_items

表示单个域名的具体任务项。

建议字段:

  • id
  • job_id
  • domain_id
  • status
  • claimed_by
  • claim_token
  • lease_expires_at
  • attempt_count
  • last_error
  • started_at
  • finished_at
  • result_version
  • updated_at

建议唯一约束:

  • unique(job_id, domain_id)

说明:

  • 多台 Worker 只抢 status=pending 且未被占用或租约已过期的任务
  • claim_token 用于避免状态回写串单
  • lease_expires_at 用于机器故障后的任务回收

4. detect_worker_nodes

表示 Worker 节点。

建议字段:

  • node_code
  • region
  • role
  • hostname
  • ip
  • status
  • worker_version
  • last_heartbeat_at
  • current_load
  • remark

说明:

  • 后台后续可以直接展示“哪个节点在线、哪个节点在跑、当前负载多少”

5. detect_run_events

表示高价值阶段日志。

建议字段:

  • id
  • job_id
  • job_item_id
  • node_code
  • event_type
  • level
  • message
  • payload_json
  • created_at

说明:

  • 页面展示优先依赖事件流,不直接硬依赖某一台机器本地日志文件
  • 原始大日志仍保留在大陆 Worker 本地

七、多机抢任务与去重

1. 抢任务方式

推荐使用数据库租约模型:

  • Worker 从 detect_job_items 中领取一批待处理任务
  • 使用 FOR UPDATE SKIP LOCKED 或原子更新方式抢占
  • 领取后写入:
    • claimed_by
    • claim_token
    • lease_expires_at

2. 去重原则

多机环境下,去重不能依赖“约定不重复”,必须依赖数据库约束和租约。

至少保证:

  • 同一轮 job_id 下,同一域名只出现一条任务项
  • 同一任务项同一时刻只允许被一个 claim_token 持有
  • 回写结果时校验 claim_token

3. 续租机制

Worker 执行过程中应定期续租:

  • 30-60 秒续租一次
  • 续租时更新 lease_expires_at
  • 如果节点挂掉,租约到期后其他 Worker 可重新领取

当前代码已实现的原则是:

  • 任务被领取后进入 claimed / running
  • 检测步骤执行过程中会持续续租
  • 若任务长期未续租且租约过期,会自动回收到 pending

这样可以避免:

  • 长任务跑到一半租约失效
  • Worker 异常退出后任务永远卡死
  • 后续多机扩容时出现大量“假占用”

4. 失败重试

建议对失败进行分类:

  • 网络失败
  • 代理失败
  • 第三方目标站异常
  • 程序逻辑失败

可按类型控制重试次数,不要无限重试。

5. 当前代码与目标模型的关系

当前代码里,运行态表和节点心跳已经具备,但主检测流程仍以现有 domains / detect_status 链路为主。

这意味着:

  • 现在已经可以先把“多机可见性”和“节点骨架”跑起来
  • 下一步要把“检测入口”从直接扫 domains,逐步切到 detect_jobs + detect_job_items
  • 切换时必须保留旧链路回退能力,避免一次性重写导致现网不稳

八、同步策略

1. 国外到大陆

同步内容:

  • 系统配置
  • 检测规则
  • 敏感词版本
  • 任务创建命令

特点:

  • 低频
  • 要求可靠
  • 可版本化

2. 大陆到国外

同步内容:

  • 任务进度摘要
  • 关键阶段事件
  • 最终检测结果
  • 黑名单结论
  • 归档日志包索引

特点:

  • 高频部分只传摘要和关键事件
  • 最终结果必须幂等

3. 幂等要求

结果同步到国外时,必须支持幂等:

  • 同一 job_item_id 重复上报不应产生重复结果
  • 同一域名同一轮任务只保留最终有效状态

4. 推荐同步落地方式

第一阶段不建议直接做数据库双向复制,更推荐独立同步服务:

  • 大陆执行面负责写本地运行态
  • sync-service 负责批量汇总结果与事件
  • 国外控制面负责接收、落库、归档

推荐第一阶段同步内容:

  • 最终检测结果
  • 关键阶段事件
  • 失败摘要
  • 节点健康摘要
  • 配置快照版本

不建议第一阶段同步:

  • 全量原始日志
  • 高频心跳明细
  • 临时抓取中间产物

原因:

  • 成本高
  • 跨地域网络抖动会放大耦合
  • 对运营后台价值不成比例

九、部署建议

1. 国外机器

目录建议:

/opt/domaincheck
├── domain-api
├── domain-web
└── shared

部署角色:

  • web
  • api
  • postgresql_main

2. 大陆调度中心

目录建议:

/opt/domaincheck
├── domainCheck
├── runtime-db
├── redis
└── shared

部署角色:

  • scheduler
  • redis
  • postgresql_runtime
  • worker

3. 大陆纯 Worker 节点

目录建议:

/opt/domaincheck
├── domainCheck
└── shared

部署角色:

  • worker

4. 一键化原则

部署脚本必须满足:

  • 新机器只需要少量环境变量
  • 不要求现场手工改很多路径
  • 国外机和大陆机各自有独立入口脚本
  • 后续新增大陆 Worker 节点继续复用同一脚本

5. 当前建议的最小部署

当前最适合正式起步的形态:

  • 国外 1 台:
    • domain-web
    • domain-api
    • 国外主 PostgreSQL
  • 大陆 1 台:
    • redis
    • 大陆运行库 PostgreSQL
    • detect-worker
    • 后续可补 sync-service

扩容时优先:

  1. 新增大陆 Worker
  2. 再视压力拆分大陆运行库与 Redis
  3. 国外控制面保持稳定,不跟着高频扩缩

十、阶段性落地建议

第一阶段

先完成:

  • 国外控制面部署
  • 大陆单机执行面部署
  • 节点注册与心跳
  • 当前后台继续可用

第二阶段

再完成:

  • 任务项模型
  • 多 Worker 抢任务
  • 事件日志流
  • 结果异步同步回国外

第三阶段

最后完成:

  • 大陆多 Worker 横向扩容
  • 运行库与调度中心独立拆分
  • 国外归档和监控补齐

十一、运行与观测建议

多机之后,不能再只靠“登录某台机器 tail 日志”来判断系统状态。

建议分层:

  • 大陆 Worker 本地保留完整原始日志
  • detect_run_events 保存关键阶段事件
  • 国外后台优先展示事件流、节点负载和同步状态
  • 真排障时再下钻到具体节点原始日志

后台建议优先展示:

  • 当前在线节点数
  • 每节点最近心跳
  • 每节点当前负载
  • 当前活跃任务数
  • 队列积压与最老待领年龄
  • 租约是否过期、是否即将到期
  • 近 15 分钟每节点吞吐
  • 最近失败摘要
  • 最近同步结果
  • 最近结果摘要投影

十二、下一阶段开发清单

接下来建议按下面顺序继续落地:

  1. 后台创建 detect_jobs / detect_job_items
  2. Worker 实现批量 claim / renew / finish / fail
  3. 增加租约超时回收
  4. 将检测阶段事件写入 detect_run_events
  5. 增加 sync-service
  6. 完成第二台大陆 Worker 接入演练

十三、最终建议

对当前项目来说,最优解不是“全部放国外”,也不是“全部放大陆”,而是:

  • 国外做控制面和主结果库
  • 大陆做执行面和运行态调度
  • 先从 国外 1 台 + 大陆 1 台 起步
  • 后续优先横向增加大陆 Worker

一句话总结:

先把职责边界设计对,再让部署简单;后续扩容时只加 Worker不再重构核心架构。