1604 words
8 minutes
master0worker资源隔离

Master-Worker 资源隔离分析#


一、当前架构的资源隔离现状#

┌─────────────────────────────────────────────────────────────────┐
│ Master (8082) │ │ ┌───────────────────────────────────────────────────────────┐ │
│ │ SchedulerService ───▶ StringRedisTemplate ───▶ Redis│ │
│ │ LogManager ───▶ WebSocket (SimpMessagingTemplate)│ │
│ │ MasterNettyServer ───▶ NioEventLoopGroup (Port 9000) │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │ │
│ 内存:JVM Heap (Spring Boot) │
│ CPU:独立线程池 (NioEventLoop) │
└─────────────────────────────────────────────────────────────────┘
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Worker-1 │ │ Worker-2 │ │ Worker-N │
│ Java Agent │ │ Java Agent │ │ Java Agent │
│ ──────── │ │ ──────── │ │ ──────── │
│ train.py │ │ train.py │ │ train.py │
│ GPU: 1 │ │ GPU: 1 │ │ GPU: 1 │
└────────────┘ └────────────┘ └────────────┘
│ │ │
└────────────────────┼────────────────────┘
┌────────────┐
│ Redis │
│ (共享数据) │
└────────────┘

二、已实现的隔离#

1. 进程级隔离 ✅#

WorkerAgent 是独立 JVM 进程 ├── 每个 Worker 有独立的 Java Heap ├── 每个 Worker 有独立的 Python 进程 └── Worker 之间完全进程隔离

优点:

  • 一个 Worker 崩溃不影响其他 Worker
  • 内存不共享,无法相互影响
  • 可部署在不同机器上实现物理隔离

2. 任务抢占原子性 ✅#

// SchedulerService.tryPreemptWorker() 使用 Lua 脚本保证原子性
String script =
"if redis.call('get', KEYS[1]) == 'alive' and redis.call('exists', KEYS[2]) == 0 then " +
" redis.call('set', KEYS[2], ARGV[1], 'EX', 120); " + // 2分钟过期
" return 1; " +
"else " +
" return 0; " +
"end";
// KEYS[1] = worker:{workerId}:hb (心跳存活检查)
// KEYS[2] = worker:{workerId}:task (任务锁)
// ARGV[1] = taskId

防止:

  • 同一 Worker 被多个任务同时抢占
  • 任务分发重复

3. 心跳租约隔离 ✅#

Worker ──▶ Redis Key ──▶ 独占
worker:1:hb ──▶ 仅 Worker-1 的心跳
worker:1:task ──▶ 仅 Worker-1 的任务
task:xxx:workerId ──▶ 任务所有权

Worker 间资源状态完全隔离


三、缺失的隔离(风险点)#

1. GPU 资源隔离 ❌#

# WorkerAgent.runPythonTask() 直接启动 train.py
# 无 GPU 隔离配置
ProcessBuilder pb = new ProcessBuilder();
pb.command("uv", "run", "python", "scripts/train.py", ...);
// 问题:如果同一 GPU 被多个任务占用,会 OOM
问题:
Worker-1: 运行 task-A (占用 GPU 0)
Worker-2: 运行 task-B (也尝试用 GPU 0)
GPU 内存竞争 → OOM

解决方案:

# train.py 应该用 CUDA_VISIBLE_DEVICES 限制 GPU
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0" # 指定 GPU
# 或者用 NVIDIA Container Toolkit
# 或者用 nvidia-docker GPU 隔离

2. 内存/CPU 限制 ❌#

// WorkerAgent 启动 Python 进程时无资源限制
ProcessBuilder pb = new ProcessBuilder();
pb.directory(new File(System.getProperty("user.dir")));
// 问题:Python 进程可能无限占用内存
应该使用:
// 方案1: ProcessBuilder 限制
ProcessBuilder pb = new ProcessBuilder();
pb.command("python", "train.py", ...);
// 设置资源限制 (Linux)
new ProcessBuilder("prlimit", "--mem=4096000", "--pid", pid); // 4GB 内存
// 方案2: Docker 容器隔离
// docker run --memory=4g --cpus=2 train.py
// 方案3: cgroups (Kubernetes)

3. 任务并发数限制 ❌#

// 当前:Worker 同时只能运行 1 个任务
// 但没有机制强制这个限制
// MasterHandler 接收 EXECUTE_TASK 后直接启动线程
new Thread(() -> runPythonTask(ctx, req), "Task-Executor-" + taskId).start();
改进方案:
// Worker 端信号量控制并发
private static final Semaphore TASK_SEMAPHORE = new Semaphore(1);
private void handleExecuteTask(ChannelHandlerContext ctx, ExecuteTaskRequest req) {
if (!TASK_SEMAPHORE.tryAcquire()) {
// 拒绝任务,让 Master 重新调度
sendRejection(ctx, req.getTaskId(), "Worker busy");
return;
}
try {
// 执行任务
} finally {
TASK_SEMAPHORE.release();
}
}

4. 任务间文件系统隔离 ❌#

// 所有任务共享同一个工作目录
File workerLogDir = new File("server_log");
File workerLogFile = new File(workerLogDir, taskId + ".log");
// 问题:如果任务同名文件会冲突

改进:

// 每个任务独立的目录
File taskDir = new File("server_log/" + taskId);
taskDir.mkdirs();
File workerLogFile = new File(taskDir, "output.log");

四、完整资源隔离矩阵

┌────────────┬──────────────┬─────────────────────────┬──────────┐
│ 资源类型 │ 隔离方式 │ 当前状态 │ 风险等级 │
├────────────┼──────────────┼─────────────────────────┼──────────┤
│ 进程内存 │ JVM 进程隔离 │ ✅ Worker 进程级隔离 │ 低 │
├────────────┼──────────────┼─────────────────────────┼──────────┤
│ GPU 显存 │ 无 │ ❌ 多任务可能 GPU 冲突 │ 高 │
├────────────┼──────────────┼─────────────────────────┼──────────┤
│ CPU 时间 │ 无 │ ❌ 任务可能 CPU 垄断 │ 中 │
├────────────┼──────────────┼─────────────────────────┼──────────┤
│ 磁盘空间 │ 无 │ ❌ 日志可能撑爆磁盘 │ 中 │
├────────────┼──────────────┼─────────────────────────┼──────────┤
│ 网络带宽 │ 无 │ ❌ 任务日志可能打爆网络 │ 中 │
├────────────┼──────────────┼─────────────────────────┼──────────┤
│ 任务并发 │ 无 │ ❌ Worker 可接受多任务 │ 中 │
├────────────┼──────────────┼─────────────────────────┼──────────┤
│ 文件路径 │ 无 │ ❌ 同名文件可能冲突 │ 低 │
├────────────┼──────────────┼─────────────────────────┼──────────┤
│ Redis 连接 │ 独立连接 │ ✅ 每 Worker 独立连接 │ 低 │
└────────────┴──────────────┴─────────────────────────┴──────────┘

五、生产级隔离架构

┌─────────────────────────────────────────────────────────────────────┐
│ 推荐的 Worker 资源隔离 │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ Worker Agent (JVM) │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ TaskSlot-1 │ │ TaskSlot-2 │ │ TaskSlot-N │ ← Semaphore│ │
│ │ │ ┌───────┐ │ ┌───────┐ │ │ ┌───────┐ │ │ │
│ │ │ │Python │ │ │Python │ │ │ │Python │ │ │ │
│ │ │ │Process│ │ │Process│ │ │ │Process│ │ │ │
│ │ │ │cgroup │ │ │cgroup │ │ │ │cgroup │ │ │ │
│ │ │ │memory │ │ │memory │ │ │ │memory │ │ │ │
│ │ │ │ cpu │ │ │ cpu │ │ │ │ cpu │ │ │ │
│ │ │ │ gpu │ │ │ gpu │ │ │ │ gpu │ │ │ │
│ │ │ └───────┘ │ └───────┘ │ │ └───────┘ │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘

资源隔离技术栈:

┌─────────────────────────────────────────────────────────────────────┐
│ 隔离层 │
├─────────────────────────────────────────────────────────────────────┤
│ GPU隔离 │ NVIDIA Device Plugin (K8s) / CUDA_VISIBLE_DEVICES │
├─────────────────────────────────────────────────────────────────────┤
│ 内存隔离 │ cgroups memory.limit / Docker --memory │
├─────────────────────────────────────────────────────────────────────┤
│ CPU隔离 │ cgroups cpu.shares / Docker --cpus │
├─────────────────────────────────────────────────────────────────────┤
│ IO隔离 │ cgroups blkio.throttle / Docker --device-read-bps │
├─────────────────────────────────────────────────────────────────────┤
│ 进程隔离 │ Linux Namespace / Docker container │
└─────────────────────────────────────────────────────────────────────┘

六、快速改进建议#

1. 最小改进:GPU 绑定#

WorkerAgent.java
// 根据 workerId 绑定不同 GPU
private String getGpuForWorker(String workerId) {
// 简单哈希:确保同一 Worker 永远用同一 GPU
int gpuIndex = Math.abs(workerId.hashCode() % availableGpuCount);
return String.valueOf(gpuIndex);
}
// 启动 Python 时设置环境变量
ProcessBuilder pb = new ProcessBuilder();
pb.environment().put("CUDA_VISIBLE_DEVICES", getGpuForWorker(workerId));

2. 中等改进:cgroups 资源限制#

Terminal window
# 启动 Worker 前创建 cgroup
sudo cgcreate -g memory,cpu:/worker-1
sudo cgset -r memory.limit_in_bytes=4G /worker-1
sudo cgset -r cpu.shares=1024 /worker-1
# 在 cgroup 中启动进程
sudo cgexec -g memory,cpu:/worker-1 java -jar worker.jar

3. 最佳改进:Kubernetes + Docker#

worker-deployment.yaml
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: worker
resources:
limits:
nvidia.com/gpu: 1
memory: "4Gi"
cpu: "2"
requests:
memory: "2Gi"
cpu: "1"
env:
- name: CUDA_VISIBLE_DEVICES
value: "0"

七、总结#

┌────────────┬─────────────────┬───────────────────────────┐
│ 方面 │ 当前实现 │ 建议 │
├────────────┼─────────────────┼───────────────────────────┤
│ 进程隔离 │ ✅ JVM 进程独立 │ 保持 │
├────────────┼─────────────────┼───────────────────────────┤
│ 任务原子性 │ ✅ Lua 脚本保证 │ 保持 │
├────────────┼─────────────────┼───────────────────────────┤
│ GPU 隔离 │ ❌ 完全缺失 │ 添加 CUDA_VISIBLE_DEVICES │
├────────────┼─────────────────┼───────────────────────────┤
│ 内存限制 │ ❌ 无限制 │ 添加 cgroups/docker limit │
├────────────┼─────────────────┼───────────────────────────┤
│ 并发控制 │ ❌ 无限制 │ 添加 Semaphore │
├────────────┼─────────────────┼───────────────────────────┤
│ 文件隔离 │ ❌ 共享目录 │ 改为任务独立目录 │
├────────────┼─────────────────┼───────────────────────────┤
│ 网络 QoS │ ❌ 无 │ 限流 + 异步日志 │
└────────────┴─────────────────┴───────────────────────────┘

当前系统适合:

  • 单机单 GPU 少量任务
  • 任务负载可控的环境

不适合:

  • 多租户环境
  • 大规模多任务并行
  • 关键业务(无资源保障)
master0worker资源隔离
https://sgjki547.top/posts/master-worker-isolation/
Author
SGJki
Published at
2026-04-06
License
CC BY-NC-SA 4.0