无需端口转发的Scheduler-worker集群:GRPC架构可行性咨询
核心结论
直接让Scheduler主动调用NAT后的Worker gRPC API行不通——NAT设备会直接丢弃外部发起的未关联连接请求。但完全可以通过反向流式长连接的方式实现你要的效果,完美契合“Worker主动订阅Scheduler”的需求。
可行架构方案(基于gRPC双向流)
我建议采用「Worker主动发起与Scheduler的长连接,复用该连接实现双向通信」的模式,具体设计如下:
1. 核心gRPC服务定义
Scheduler端服务(Worker主动连接)
service SchedulerService { // Worker注册并建立双向流:Worker发状态/结果,Scheduler下任务/指令 rpc RegisterWorker(stream WorkerMessage) returns (stream SchedulerMessage); } message WorkerMessage { oneof payload { WorkerStatus status = 1; // 定期上报资源状态 TaskResult result = 2; // 任务结果流 FileDownloadAck download_ack = 3; // 文件下载完成确认 } } message SchedulerMessage { oneof payload { TaskAssignment task = 1; // 下发任务 CancelTask cancel = 2; // 取消任务 FileDownloadRequest download = 3; // 要求下载指定测试文件 } }
配套核心数据结构(简化版)
message WorkerStatus { string worker_id = 1; int32 running_tasks = 2; float cpu_usage = 3; float memory_usage = 4; repeated string cached_files = 5; // 已缓存的测试文件列表 repeated TaskType supported_types = 6; // 支持的任务类型 } message TaskAssignment { string task_id = 1; TaskType type = 2; string code_content = 3; string required_file = 4; // 关联的测试文件 } enum TaskType { INTERACTIVE = 0; PRESET_TEST = 1; }
2. 关键流程实现
- Worker注册与保活:Worker启动后主动连Scheduler,发起
RegisterWorker双向流,定期发WorkerStatus当心跳;Scheduler如果长时间没收到心跳,直接标记该Worker离线。 - 任务分发逻辑:Scheduler根据任务类型、Worker已缓存的文件、当前运行任务数(不超过16),通过已建立的流下发
TaskAssignment。 - 任务执行与结果返回:Worker拿到任务后执行,把实时状态、结果(包括交互式任务的控制台流)通过同一个流回传给Scheduler。
- 文件缓存控制:Scheduler下发任务前先检查Worker的
cached_files,如果没对应文件,先发FileDownloadRequest,Worker下载完成后回传FileDownloadAck,Scheduler再下发任务。
3. 适配你的特殊需求
- 多类型专用Worker:Worker在
WorkerStatus里上报supported_types,Scheduler按任务类型精准匹配分发。 - 大文件传输:要么用gRPC流式传输,要么让Scheduler在
FileDownloadRequest里给个临时可访问的下载地址(比如Scheduler本地启个简单HTTP服务),Worker直接走HTTP下载,不占gRPC连接带宽。 - 并发任务控制:Scheduler严格根据Worker上报的
running_tasks控制下发数量,确保不超过16个的上限。
替代方案(非必要不推荐)
如果非要模拟“Scheduler调用Worker API”的体验,可以试试gRPC反向代理或者穿透服务,但会增加系统复杂度:
- 让Worker启动时主动向Scheduler注册,同时把自身gRPC服务暴露到STUN/TURN穿透网关,但要额外维护网关服务。
- 在Scheduler侧做反向代理,通过Worker发起的长连接转发对Worker API的调用请求,本质还是复用反向连接。
Go语言实现注意事项
- 配置gRPC Keepalive:给Worker(客户端)设心跳间隔,Scheduler(服务端)设超时检测,确保长连接稳定。
- 重连逻辑:Worker侧加自动重连,重连时重新注册身份,避免连接断开后失联。
- 流消息有序性:gRPC流是有序的,不用额外处理消息顺序,直接按业务逻辑发送就行。
- 任务隔离:Worker侧每个任务用单独进程或轻量容器隔离,防止单个任务崩溃影响整个Worker。
内容的提问来源于stack exchange,提问作者Krišjānis Petručeņa
相关产品推荐
相关产品推荐

