没有端口转发的计划程序工作群集



你好,Satckoverflow!

TLDR我想重新创建https://github.com/KorayGocmen/scheduler-worker-grpc而无需在工作者上进行端口转发。

我正试图为我的学校建立一个有竞争力的编程评委服务器,作为一个项目来评估提交的内容,我在那里教孩子们编程。

因为计算量很大,所以我希望有多个工作节点。调度器将接收提交并将它们分发给工作节点。为了便于工作者部署(因为它经常会发生变化(,我希望工作者能够订阅调度器,从而成为工作者并接收作业。

工作程序可能与调度器不在同一网络上+工作程序驻留在VM中(可能稍后会移植到docker,但目前存在问题(。

调度器应该能够知道工作者的资源使用情况,向工作者发送不同类型的作业,并接收结果流。

我目前正在考虑使用grpc来满足我对工人和调度器之间通信的要求。

我可以创建多种调度器服务方法,如:

  1. 注册工人,接收一系列作业
  2. 流式处理作业结果,一无所获
  3. 定期流式处理工作状态,不接收任何内容

然而,我更喜欢以下内容,但idk是否可能:

  • 调度程序GRPC api:
    • 注册一个worker(使worker GRPC api可用于调度器(
  • 工人GRPC api:
    • 启动作业(返回作业状态流(
    • 取消工作
    • 获取资源使用情况

如果连接丢失,工作程序应自动注销。

所以我的问题是……如果工作程序在NAT后面而没有端口转发,是否可以创建一个grpc工作程序api,该api可以注册到调度器中供以后使用?

其他可能不必要的信息:

更糟糕的是,我有多种完全不同类型的工作(流式传输交互式控制台,针对准备好的测试用例执行代码(。我可能只是为不同的工作创造不同的工人。

有时,作业涉及在本地文件系统上有大文件(高达500 MB(,这些文件通常保存在调度器附近,因此我想将作业发送给已经从调度器下载了特定文件的工作者。否则,请下载其中一个工作者的大型文件。在工作程序上同时拥有所有文件需要超过20 GB,因此我想避免它

一个工人可以同时运行多个作业(最多16个(。

我正在用go编写系统。

只要只有工作人员启动连接,就不必担心NAT。gRPC支持双向(或双向(流式传输。这意味着您的所有需求都可以使用调度器上的一台服务器来实现;调度器不需要连接回工作者。

根据您的描述,您的服务可能如下所示:

syntax = "proto3";
import "google/protobuf/empty.proto";
service Scheduler {
rpc GetJobs(GetJobsRequest) returns (stream GetJobsResponse) {}
rpc ReportWorkerStatus(stream ReportWorkerStatusRequest) returns (google.protobuf.Empty) {}
rpc ReportJobStatus(stream JobStatus) returns (stream JobAction) {}
}
enum JobType {
JOB_TYPE_UNSPECIFIED = 0;
JOB_TYPE_CONSOLE = 1;
JOB_TYPE_EXEC = 2;
}
message GetJobsRequest {
// List of job types this worker is willing to accept.
repeated JobType types = 1;
}
message GetJobsResponse {
string jobId = 0;
JobType type = 1;
string fileName = 2;
bytes fileContent = 3;
// etc.
}
message ReportWorkerStatusRequest {
float cpuLoad = 0;
uint64 availableDiskSpace = 1;
uint64 availableMemory = 2;
// etc.
// List of filenames or file hashes, or whatever else you need to precisely
// report the presence of files.
repeated string haveFiles = 2;
}

这在很大程度上是一个偏好问题(例如,您可以使用oneof而不是枚举(,但希望很明显,从客户端到服务器的单个连接就足以满足您的需求。

维护一组可用的工作人员非常简单:

func (s *Server) GetJobs(req *pb.GetJobRequest, stream pb.Scheduler_GetJobsServer) error {
ctx := stream.Context()
s.scheduler.AddWorker(req)
defer s.scheduler.RemoveWorker(req)
for {
job, err := s.scheduler.GetJob(ctx, req)
switch {
case ctx.Err() != nil: // client disconnected
return nil
case err != nil:
return err
}
if err := stream.Send(job); err != nil {
return err
}
}
}

基础教程包括所有类型流的示例,包括Go中的服务器和客户端实现。

至于注册,这通常只意味着创建某种凭证,工作人员在与服务器通信时将使用这种凭证。这可能是一个随机生成的令牌(服务器可以使用它来加载相关联的元数据(,或者用户名/密码组合,或者TLS客户端证书,或者类似的东西。在设置工作人员时,详细信息将取决于您的基础结构和所需的工作流程。

相关内容

最新更新