logo
0
0
WeChat Login
feat: impl basic version

LLM Scheduler

私有化部署场景下的 LLM 请求调度网关,支持多模型多节点的请求路由、优先级队列和负载均衡。

定位

在私有化环境中,存在多台不同配置的 GPU 服务器,每台服务器部署的模型可能不同(如节点 A 部署 Qwen3-235B,节点 B 部署 Qwen3-32B),并发上限也不同。

调用方不应关心请求被分发到哪台机器,只需指定模型名并提交请求。

核心功能

功能说明
节点注册与健康检查GPU 节点启动时注册自身信息,scheduler 定期心跳检测
模型路由 + 负载均衡根据请求的 model 字段匹配可用节点,按当前负载选择最优节点
请求排队与优先级所有匹配节点满载时,请求进入优先级队列等待
透明转发作为反向代理,将请求透传到目标节点的 OpenAI 兼容 API
并发控制按节点维度严格控制并发数,防止 GPU OOM
请求持久化SQLite 存储请求记录和指标,支持历史查询和统计分析
管理面板内置 Web UI,可视化监控节点状态、请求记录和统计数据

快速开始

环境要求

  • Go 1.21+
  • Node.js 18+(前端开发)
  • pnpm(前端包管理)

编译运行

# 编译(含前端) make build # 仅编译后端(跳过前端构建) make build-only # 直接运行 make run # 或运行编译后的二进制 ./build/llm-scheduler

Docker 部署

# 构建镜像 make docker # 运行容器 docker run -d \ -p 8080:8080 \ -v $(pwd)/config.yaml:/app/config.yaml \ -v $(pwd)/data:/app/data \ llm-scheduler:latest

配置说明

配置文件 config.yaml

server: port: 8080 # 服务端口 read_timeout: 30s # 读取超时 write_timeout: 60s # 写入超时 database: path: "./data/scheduler.db" # SQLite 数据库路径 cleanup_enabled: true # 是否启用自动清理 retention_days: 7 # 数据保留天数 cleanup_interval: 1h # 清理间隔 scheduler: max_queue_size: 10000 # 优先级队列容量 worker_count: 10 # 调度工作线程数 health_check_interval: 30s # 健康检查周期 health_check_timeout: 5s # 健康检查超时 request_timeout: 300s # 请求超时时间 logging: level: info # 日志级别: debug, info, warn, error format: json # 日志格式: json, console auth: api_keys: [] # /v1/* API 密钥列表,为空则不验证 admin_api_keys: [] # /admin/* API 密钥列表,为空则不验证

支持环境变量覆盖,格式为 LLM_SCHEDULER_<SECTION>_<KEY>,例如:

  • LLM_SCHEDULER_SERVER_PORT=9090
  • LLM_SCHEDULER_DATABASE_PATH=/data/scheduler.db

API 接口

代理接口

POST /v1/chat/completions

透传 LLM 请求到目标节点(OpenAI 兼容格式)。

请求头:

Header说明
AuthorizationBearer token 认证(可选)
X-Priority优先级:low / normal(默认) / high / critical

请求体:

{ "model": "qwen3-235b", "messages": [ {"role": "user", "content": "Hello"} ], "stream": true }

响应: 透传目标节点的响应(支持流式 SSE)

节点管理接口

POST /admin/nodes

注册 GPU 节点。

{ "id": "node-1", "address": "http://192.168.1.10:8000", "models": ["qwen3-235b", "qwen3-32b"], "max_concurrent": 4, "weight": 100 }

GET /admin/nodes

获取所有节点列表。

GET /admin/nodes/:id

获取单个节点详情。

DELETE /admin/nodes/:id

注销节点。

统计接口

GET /admin/stats

获取请求统计信息。

响应:

{ "total_requests": 1000, "pending_requests": 5, "processing_count": 10, "completed_count": 980, "failed_count": 5, "avg_latency_ms": 1234.5 }

GET /admin/stats/models

获取按模型分组的统计信息。

响应:

{ "models": [ { "model": "qwen3-235b", "request_count": 500, "avg_latency_ms": 2000.0 } ] }

GET /admin/requests

列出请求记录。

查询参数:

参数说明
status按状态过滤:pending, processing, completed, failed
model按模型过滤
node_id按节点过滤
limit返回数量限制(默认 100)
offset分页偏移
start_time开始时间(RFC3339 格式)
end_time结束时间(RFC3339 格式)

GET /admin/requests/:id

获取单个请求详情。

管理接口

GET /admin/status

获取调度器状态(队列大小、节点数量等)。

GET /health

健康检查端点(无需认证)。

调用流程

docwise-agent llm-scheduler GPU 节点 | | | |-- POST /v1/chat/completions ------>| | | (model=qwen3-235b, X-Priority) | | | |-- 按 model 筛选节点 --------------->| | |-- 选择负载最低节点 (least-conn) --->| | | (无可用节点则入队等待) | | | | | |-- 透传原始请求体 ----------------->| | | POST {node}/v1/chat/completions | | | | |<-- 流式/非流式响应透传 ------------|<-- 响应 ----------------------------|- | | (释放槽位) |

优先级说明

通过 X-Priority 请求头指定优先级,影响队列内的排序,不会抢占已在处理中的请求:

优先级说明
low后台任务,排在队尾
normal默认优先级
high优先于 normal/low 被消费
critical排在队首,优先于所有等待中的请求(仍需等待空闲槽位)

项目结构

llm-scheduler/ ├── cmd/server/main.go # 程序入口 ├── internal/ │ ├── config/config.go # 配置加载 │ ├── handler/ │ │ ├── proxy.go # 代理接口处理 │ │ ├── node.go # 节点管理接口 │ │ └── admin.go # 管理接口 │ ├── middleware/ │ │ ├── auth.go # 认证中间件 │ │ ├── priority.go # 优先级提取 │ │ └── logging.go # 请求日志 │ ├── model/ │ │ ├── node.go # GPU 节点模型 │ │ ├── request.go # 调度请求模型 │ │ └── priority.go # 优先级定义 │ ├── scheduler/ │ │ ├── queue.go # 优先级队列 │ │ ├── dispatcher.go # 调度分发器 │ │ ├── balancer.go # 负载均衡器 │ │ └── pool.go # 节点池管理 │ ├── proxy/ │ │ ├── forwarder.go # HTTP 转发器 │ │ └── stream.go # SSE 流式处理 │ ├── store/sqlite.go # SQLite 请求存储 │ ├── worker/healthcheck.go # 健康检查 │ └── router/router.go # 路由配置 ├── web/ # 前端源码 (Vue 3 + Naive UI) │ ├── src/ │ │ ├── views/ # 页面组件 │ │ ├── api/ # API 调用 │ │ └── components/ # 通用组件 │ ├── package.json │ └── vite.config.js ├── config.yaml # 配置文件 ├── Dockerfile # Docker 构建 ├── Makefile # 构建脚本 └── go.mod # Go 模块

开发命令

# 完整构建(前端 + 后端) make build # 仅构建后端 make build-only # 运行后端 make run # 前端开发 make web-install # 安装前端依赖 make web-dev # 启动前端开发服务器 (localhost:5173) make web-build # 构建前端 # 其他 make test # 测试 make lint # 代码检查 make tidy # 整理依赖 make clean # 清理构建产物 make docker # 构建 Docker 镜像

管理面板

启动服务后访问 http://localhost:8080 即可打开管理面板。

功能页面:

页面功能
仪表盘实时监控队列、节点状态、请求统计(5 秒自动刷新)
节点管理查看/注册/删除 GPU 节点
请求记录请求历史列表,支持状态筛选、分页、详情查看
统计分析按模型分组的请求统计和延迟分析

前端开发:

# 终端 1:启动后端 make run # 终端 2:启动前端开发服务器(支持热更新) make web-dev

前端开发服务器会自动代理 /admin/health 请求到后端(localhost:8080)。

依赖

待完善

  • 单元测试覆盖
  • 管理面板

License

MIT