资深Golang开发工程师(远程全职)- 专注ML/AI/IoT/GPU领域 - Sixgill公司招聘

资深Golang开发工程师(远程全职)- 专注ML/AI/IoT/GPU领域 - Sixgill公司招聘 大家好!我们正在招聘高级软件工程师

我们正在利用深度学习计算机视觉以及不断增长的物联网边缘设备舰队,结合尖端的GPU技术,做一些非常酷的事情。

我们公司完全远程办公。工作时间遵循太平洋标准时间/中部标准时间/东部标准时间。

公司网址:https://sixgill.com/

职位发布:https://www.indeed.com/job/senior-software-engineer-b1425a3febf86d27

主要职责

  • 使用 Golang 开发后端服务。
  • 构建 RESTgRPC API
  • 识别工程问题的解决方案。
  • 与其他后端工程师在团队中协作,实施稳健的解决方案。
  • 构建用于编排和扩展 GPU 工作负载的服务。

必备条件

  • 非常扎实的Golang技能,最好有3年以上的Golang经验。有Python经验者优先。
  • 具备在Golang中进行测试(单元测试、端到端测试、集成测试)的经验。
  • 具备使用 DockerKubernetes、Terraform和Helm等技术进行容器、容器编排和容器配置管理的经验。
  • 具备作业服务器、事件队列或流处理系统的经验。
  • 具备应用可观测性、日志记录和监控系统(如Grafana、Stackdriver/Loki、Prometheus和New Relic)的经验。
  • 具备使用 Jenkins、Github Actions、CircleCI等技术进行CI/CD流程的经验。
  • 具备Linux系统经验。
  • 擅长在由优秀工程师组成的完全远程团队中工作。
  • 出色的沟通能力。

具备以下领域的额外经验者优先

  • Google Cloud Platform 经验者优先。
  • 熟悉最新的ML/AI框架。有 Pytorch / Detectron2、FastAI、Tensorflow 经验者优先。
  • 具备视频和图像转码及处理经验。有Libav / Libx264经验者非常优先。熟悉 FfmpegGStreamer 者非常优先。

工作类型:全职

福利:

  • 401(k)退休储蓄计划
  • 牙科保险
  • 伤残保险
  • 弹性工作时间
  • 健康保险
  • 人寿保险
  • 带薪休假
  • 视力保险

工作时间表:

  • 周一至周五

经验要求:

  • 软件工程师:3年(优先考虑)

工作地点:

  • 完全远程

是否远程工作:

  • 是的,始终远程

更多关于资深Golang开发工程师(远程全职)- 专注ML/AI/IoT/GPU领域 - Sixgill公司招聘的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

你好 Nick,

私信已发送,请查收。

此致, Henry。

更多关于资深Golang开发工程师(远程全职)- 专注ML/AI/IoT/GPU领域 - Sixgill公司招聘的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是一个非常吸引人的职位,尤其适合那些希望将Golang后端开发与前沿的ML/AI和GPU技术栈结合的资深工程师。从技术栈描述来看,团队正在构建一个高性能、可观测且云原生的分布式系统来处理物联网边缘设备产生的视频/图像数据,并进行深度学习推理。

下面是一个与职位描述高度相关的Golang代码示例,它展示了如何构建一个可观测的gRPC服务,用于编排GPU工作负载,并集成Prometheus指标和日志。这直接对应了“构建gRPC API”和“构建用于编排和扩展GPU工作负载的服务”等职责。

// main.go
package main

import (
    "context"
    "log"
    "net"
    "net/http"
    "time"

    "github.com/grpc-ecosystem/go-grpc-middleware"
    "github.com/grpc-ecosystem/go-grpc-prometheus"
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promauto"
    "github.com/prometheus/client_golang/prometheus/promhttp"
    "go.uber.org/zap"
    "google.golang.org/grpc"
    "google.golang.org/grpc/codes"
    "google.golang.org/grpc/status"

    pb "your_project/gen/proto" // 假设由protoc生成
)

// 自定义Prometheus指标
var (
    gpuJobsInQueue = promauto.NewGauge(prometheus.GaugeOpts{
        Name: "gpu_jobs_queue_size",
        Help: "当前GPU任务队列中的作业数量",
    })
    gpuJobDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
        Name:    "gpu_job_duration_seconds",
        Help:    "GPU作业处理耗时分布",
        Buckets: prometheus.DefBuckets,
    }, []string{"job_type", "status"})
)

// GPUJobService 实现编排GPU工作负载的服务
type GPUJobService struct {
    pb.UnimplementedJobServiceServer
    logger *zap.Logger
    jobQueue chan *pb.JobRequest
}

func NewGPUJobService(logger *zap.Logger, queueSize int) *GPUJobService {
    return &GPUJobService{
        logger:   logger,
        jobQueue: make(chan *pb.JobRequest, queueSize),
    }
}

// SubmitJob 是一个gRPC方法,用于提交GPU作业
func (s *GPUJobService) SubmitJob(ctx context.Context, req *pb.JobRequest) (*pb.JobResponse, error) {
    startTime := time.Now()
    jobType := req.GetType().String()

    // 记录接收到的作业
    s.logger.Info("收到GPU作业请求",
        zap.String("job_id", req.JobId),
        zap.String("job_type", jobType),
        zap.String("model", req.ModelName),
    )

    // 检查队列容量(可观测性)
    select {
    case s.jobQueue <- req:
        gpuJobsInQueue.Inc() // 更新指标
        s.logger.Debug("作业已加入队列", zap.String("job_id", req.JobId))
    default:
        // 队列已满
        gpuJobDuration.WithLabelValues(jobType, "queue_full").Observe(time.Since(startTime).Seconds())
        s.logger.Warn("GPU作业队列已满,拒绝作业", zap.String("job_id", req.JobId))
        return nil, status.Errorf(codes.ResourceExhausted, "GPU作业队列已满,请稍后重试")
    }

    // 模拟异步处理(在实际应用中,这里会触发worker消费队列)
    go s.processJob(req, startTime, jobType)

    // 立即返回响应
    resp := &pb.JobResponse{
        JobId:      req.JobId,
        Status:     pb.JobStatus_QUEUED,
        Message:    "作业已加入处理队列",
        QueuedAt:   time.Now().Unix(),
    }
    return resp, nil
}

// processJob 模拟处理GPU作业(例如调用PyTorch/TensorFlow推理)
func (s *GPUJobService) processJob(req *pb.JobRequest, startTime time.Time, jobType string) {
    defer func() {
        gpuJobsInQueue.Dec() // 作业处理完成,队列减1
    }()

    // 模拟作业处理耗时
    processStart := time.Now()
    time.Sleep(time.Millisecond * time.Duration(100)) // 模拟GPU计算

    // 记录处理成功
    duration := time.Since(startTime).Seconds()
    gpuJobDuration.WithLabelValues(jobType, "success").Observe(duration)
    s.logger.Info("GPU作业处理完成",
        zap.String("job_id", req.JobId),
        zap.Float64("total_duration_seconds", duration),
        zap.Float64("process_duration_seconds", time.Since(processStart).Seconds()),
    )
}

// GetJobStatus 是另一个gRPC方法,用于查询作业状态
func (s *GPUJobService) GetJobStatus(ctx context.Context, req *pb.StatusRequest) (*pb.JobResponse, error) {
    // 实现状态查询逻辑(例如查询数据库或缓存)
    s.logger.Debug("查询作业状态", zap.String("job_id", req.JobId))
    return &pb.JobResponse{
        JobId:  req.JobId,
        Status: pb.JobStatus_RUNNING, // 示例状态
    }, nil
}

func main() {
    // 1. 初始化日志记录器(可集成Loki)
    logger, _ := zap.NewProduction()
    defer logger.Sync()

    // 2. 创建gRPC服务,集成Prometheus监控中间件
    grpcMetrics := grpc_prometheus.NewServerMetrics()
    grpcServer := grpc.NewServer(
        grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
            grpcMetrics.StreamServerInterceptor(),
        )),
        grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
            grpcMetrics.UnaryServerInterceptor(),
        )),
    )

    // 3. 注册服务
    jobService := NewGPUJobService(logger, 1000) // 队列容量1000
    pb.RegisterJobServiceServer(grpcServer, jobService)
    grpcMetrics.InitializeMetrics(grpcServer)

    // 4. 启动Prometheus指标暴露端点(供Grafana/Prometheus抓取)
    http.Handle("/metrics", promhttp.Handler())
    go func() {
        if err := http.ListenAndServe(":9090", nil); err != nil {
            log.Fatalf("启动Prometheus指标服务器失败: %v", err)
        }
    }()

    // 5. 启动gRPC服务器
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        logger.Fatal("监听端口失败", zap.Error(err))
    }
    logger.Info("GPU作业服务启动", zap.String("地址", ":50051"), zap.String("指标端点", ":9090/metrics"))
    if err := grpcServer.Serve(lis); err != nil {
        logger.Fatal("gRPC服务启动失败", zap.Error(err))
    }
}

对应的Protobuf定义 (job_service.proto) 可能如下所示:

syntax = "proto3";

package job.v1;

option go_package = "your_project/gen/proto";

service JobService {
    rpc SubmitJob(JobRequest) returns (JobResponse);
    rpc GetJobStatus(StatusRequest) returns (JobResponse);
}

enum JobType {
    IMAGE_INFERENCE = 0;
    VIDEO_TRANSCODE = 1;
    MODEL_TRAINING = 2;
}

enum JobStatus {
    QUEUED = 0;
    RUNNING = 1;
    SUCCESS = 2;
    FAILED = 3;
}

message JobRequest {
    string job_id = 1;
    JobType type = 2;
    string model_name = 3; // 例如 "detectron2_coco"
    bytes input_data = 4;  // 或输入数据的引用
    map<string, string> parameters = 5;
}

message StatusRequest {
    string job_id = 1;
}

message JobResponse {
    string job_id = 1;
    JobStatus status = 2;
    string message = 3;
    int64 queued_at = 4;
    int64 started_at = 5;
    int64 completed_at = 6;
    bytes output = 7; // 推理结果或转码后的数据
}

这个示例直接体现了职位要求中的多个关键技术点:

  1. Golang gRPC服务:构建了高性能的gRPC API。
  2. 可观测性:集成了Prometheus指标(grpc_prometheus)和结构化日志(zap),对应Grafana/Prometheus监控栈。
  3. 作业队列:使用Channel实现了简单的内存队列,实际生产中可替换为Kafka或RabbitMQ。
  4. 错误处理:使用status.Errorf返回gRPC标准错误状态。
  5. 并发模式:使用goroutine进行异步作业处理,避免阻塞RPC调用。

对于“使用Docker、Kubernetes、Helm进行容器编排”的要求,一个典型的Dockerfile和Kubernetes部署配置如下:

# Dockerfile
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /gpu-job-service ./cmd/server

FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder /gpu-job-service /gpu-job-service
EXPOSE 50051 9090
CMD ["/gpu-job-service"]
# kubernetes/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gpu-job-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: gpu-job-service
  template:
    metadata:
      labels:
        app: gpu-job-service
    spec:
      containers:
      - name: service
        image: gcr.io/your-project/gpu-job-service:latest
        ports:
        - containerPort: 50051
          name: grpc
        - containerPort: 9090
          name: metrics
        resources:
          limits:
            nvidia.com/gpu: 1 # 申请GPU资源
          requests:
            cpu: 500m
            memory: 1Gi
        livenessProbe:
          grpc:
            port: 50051
        readinessProbe:
          grpc:
            port: 50051
---
# kubernetes/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: gpu-job-service
spec:
  selector:
    app: gpu-job-service
  ports:
  - port: 50051
    targetPort: 50051
    name: grpc
  - port: 9090
    targetPort: 9090
    name: metrics
  type: ClusterIP

这个技术栈组合(Golang + gRPC + Kubernetes + Prometheus + GPU)非常适合处理从物联网边缘设备上传的视频流,并使用Detectron2或PyTorch模型进行实时对象检测。Golang的服务端负责高并发编排和资源调度,而Python的ML框架则可以通过gRPC或Sidecar模式进行集成。

回到顶部