第一章:GMP调度耗时超标预警的业务影响与根因定位全景图
GMP(Goroutine-Machine-Processor)调度器是Go运行时的核心组件,其调度延迟一旦持续超过2ms(默认runtime.GOMAXPROCS下可观测阈值),将直接引发HTTP请求P99延迟跳升、数据库连接池耗尽、消息消费滞后等连锁故障。典型业务影响包括:微服务间gRPC调用超时率上升30%以上;Kafka消费者组频繁Rebalance;Prometheus指标采集断点导致告警失灵。
调度耗时超标的典型业务表征
- Web API响应时间P99突增至800ms+(正常应
go_goroutines指标无明显增长,但go_sched_latencies_seconds_bucket中le="0.002"桶计数骤降- 应用日志高频出现
"scheduler: preempted G"或"sysmon: scavenged"警告
根因定位的三层穿透路径
应用层:检查是否存在长时间阻塞系统调用(如syscall.Read未设timeout)、滥用runtime.LockOSThread或unsafe.Pointer引发GC屏障失效。
运行时层:启用GODEBUG=schedtrace=1000实时观察调度器状态,重点关注SCHED行中idleprocs为0且runqueue长度>50的异常周期。
系统层:通过perf record -e 'sched:sched_migrate_task' -p $(pgrep myapp) -- sleep 5捕获线程迁移事件,结合/proc/<pid>/stack确认是否因CPU亲和性配置冲突导致M频繁切换。
快速验证与干预指令
# 1. 实时采集调度延迟直方图(需Go 1.21+)
go tool trace -http=localhost:8080 ./myapp.trace
# 2. 检查当前GMP关键指标(需开启expvar)
curl http://localhost:6060/debug/expvar | jq '.sched'
# 关注 "gcount", "nmspinning", "nmidle" 字段突变
# 3. 强制触发调度器诊断(生产环境慎用)
GODEBUG=scheddump=1 ./myapp 2>&1 | grep -A 10 "SCHED"
上述操作需在低峰期执行,scheddump会短暂暂停所有P,单次输出后自动恢复。定位到根因后,优先调整GOMAXPROCS至CPU物理核心数,禁用非必要CGO调用,并确保所有I/O操作绑定context超时控制。
第二章:Go 1.22新调度器核心机制深度解析
2.1 P本地队列与全局运行队列的负载再平衡策略演进
早期 Go 调度器采用静态窃取:每个 P 维护本地运行队列(LRQ),空闲 P 周期性扫描其他 P 的 LRQ 尾部窃取任务,但易引发缓存抖动与负载毛刺。
动态窃取阈值机制
引入 stealLoad 自适应阈值,仅当源 P 队列长度 ≥ 2×目标 P 长度时才触发窃取:
func (p *p) shouldStealFrom(src *p) bool {
return len(src.runq) >= 2*len(p.runq) && len(src.runq) > 32
}
逻辑分析:
2*len(p.runq)避免频繁微调;> 32过滤噪声窃取,参数 32 来自 L1 缓存行对齐实测最优值。
负载均衡策略对比
| 策略 | 触发条件 | 吞吐波动 | 缓存局部性 |
|---|---|---|---|
| 静态周期窃取 | 每 60μs 扫描 | ±18% | 差 |
| 动态阈值窃取 | 队列失衡≥2倍 | ±4.2% | 优 |
调度决策流
graph TD
A[空闲P检测] --> B{本地队列为空?}
B -->|是| C[计算stealLoad阈值]
C --> D[扫描随机P候选]
D --> E{满足len(src)≥2×len(self)?}
E -->|是| F[从src.runq尾部窃取1/4任务]
2.2 抢占式调度触发条件变更对goroutine耗时分布的影响实测
Go 1.14 引入基于系统调用与定时器的抢占点,替代原先仅依赖函数调用栈深度的协作式抢占。这一变更显著影响长循环 goroutine 的响应延迟。
实测环境配置
- Go 版本:1.13(旧) vs 1.14+(新)
- 测试负载:
for i := 0; i < 1e9; i++ { _ = i * i }(无函数调用的 CPU 密集型循环)
耗时分布对比(单位:ms,P95)
| 场景 | Go 1.13(协作抢占) | Go 1.14+(异步抢占) |
|---|---|---|
| 单 goroutine 阻塞 | 8600+ | 12.3 |
// 启用 runtime/trace 捕获调度事件
import _ "net/http/pprof"
func main() {
go func() {
trace.Start(os.Stderr) // 记录全量调度事件
defer trace.Stop()
for i := 0; i < 1e9; i++ {}
}()
}
该代码块启用 runtime/trace,捕获 Goroutine 进入/离开运行队列、被抢占等事件;trace.Start 参数为 io.Writer,此处输出至 stderr 便于离线分析;需配合 go tool trace 可视化。
关键机制演进
- 旧机制:仅在函数调用返回时检查
preemptible标志 - 新机制:
sysmon线程每 10ms 扫描并强制抢占运行超 10ms 的 M - 抢占信号通过
SIGURG(Linux)或SetThreadContext(Windows)注入
graph TD A[sysmon 启动] –> B[每 10ms 检查所有 M] B –> C{M 运行 > 10ms?} C –>|是| D[发送抢占信号] C –>|否| E[跳过] D –> F[目标 M 在安全点暂停并转入 _Gpreempted]
2.3 netpoller与sysmon协同调度延迟的量化分析与火焰图验证
延迟观测点布设
在 runtime/proc.go 中插入微秒级采样钩子:
// 在 sysmon 循环中注入调度延迟观测
if atomic.Load64(&sched.nmspinning) == 0 {
start := nanotime()
// 模拟 netpoller 扫描前等待
netpoll(0) // 非阻塞轮询
delay := nanotime() - start
if delay > 10000 { // >10μs 记录
traceSchedDelay(delay)
}
}
该钩子捕获 netpoll 调用开销, 表示非阻塞模式,避免干扰正常调度流;traceSchedDelay 将延迟写入 perf event ring buffer,供后续火焰图聚合。
协同延迟分布(单位:μs)
| 场景 | P50 | P90 | P99 |
|---|---|---|---|
| 空闲网络(无事件) | 0.8 | 2.1 | 5.3 |
| 高频连接建立 | 12.7 | 48.9 | 136.2 |
调度协作时序
graph TD
A[sysmon 检测 M 长时间空闲] --> B[唤醒 netpoller 扫描就绪 fd]
B --> C{是否有新就绪 G?}
C -->|是| D[将 G 推入全局队列]
C -->|否| E[继续休眠或触发 GC]
2.4 GC STW阶段与调度器交互路径的耗时新增瓶颈点定位
在 Go 1.22+ 中,STW(Stop-The-World)阶段需协同调度器完成 P 状态冻结、G 队列快照及 sysmon 协作暂停,其中新增的 runtime.suspendGoroutines() 调用成为关键延迟源。
数据同步机制
STW 前需原子同步所有 P 的本地运行队列至全局队列,触发高频 cache line 争用:
// src/runtime/proc.go
func suspendGoroutines() {
for _, p := range allp {
if p != nil && p.status == _Prunning {
p.runq.pushBackBatch(&p.runq, &globalRunq) // ← 新增批处理同步
}
}
}
pushBackBatch 引入自旋等待 globalRunq.lock,实测在 64 核机器上平均阻塞 83μs(P95 达 210μs)。
关键瓶颈分布(STW 内部耗时占比)
| 阶段 | 平均耗时 | 主要开销来源 |
|---|---|---|
| P 状态冻结 | 12μs | atomic.Storeuintptr 跨 NUMA 访存延迟 |
| G 队列快照 | 83μs | globalRunq.lock 争用(见上代码) |
| sysmon 暂停 | 5μs | atomic.Loaduintptr(&sysmonWait) 循环检测 |
调度器协作流程
graph TD
A[GC start] --> B[Pre-STW:唤醒 sysmon 协作]
B --> C[STW entry:调用 suspendGoroutines]
C --> D[各 P 批量推送 runq 到 globalRunq]
D --> E[锁竞争 → CPU 自旋 → TLB miss 加剧]
E --> F[全部 P 确认冻结 → STW 完成]
2.5 M绑定P策略收紧导致的阻塞型系统调用放大效应复现
当 Go 运行时将 M(OS 线程)严格绑定到 P(处理器)且禁止跨 P 抢占时,阻塞型系统调用(如 read()、accept())无法移交 P 给其他 M,导致 P 长期空转等待。
数据同步机制
func serveConn(c net.Conn) {
buf := make([]byte, 4096)
for {
n, err := c.Read(buf) // 阻塞调用,M&P 被锁死
if err != nil { break }
process(buf[:n])
}
}
此处
c.Read()触发epoll_wait阻塞;若 M 无法解绑 P,则该 P 无法调度其他 G,造成吞吐骤降。
关键参数对比
| 参数 | 宽松策略(GOEXPERIMENT=nonblocking) | 收紧策略(默认) |
|---|---|---|
| M 解绑延迟 | ≥ 10ms(需 GC 或 sysmon 唤醒) | |
| P 复用率 | 92% | 37% |
调度路径变化
graph TD
A[Go syscall] --> B{M 是否可解绑?}
B -->|是| C[移交 P 给空闲 M]
B -->|否| D[当前 M 挂起,P 闲置]
第三章:调度耗时超标诊断工具链构建与实战
3.1 runtime/trace + pprof scheddelay 分析模板与阈值基线设定
scheddelay 衡量 Goroutine 就绪后到实际被调度执行的时间差,是识别调度瓶颈的关键指标。
数据采集模板
# 启用 trace + scheddelay profile
go run -gcflags="-l" main.go &
PID=$!
sleep 5
go tool trace -pprof=scheddelay $PID
-pprof=scheddelay从 trace 文件中提取调度延迟直方图;需确保GODEBUG=schedtrace=1000或runtime/trace.Start()已启用。
阈值基线建议(单位:μs)
| 场景类型 | P95 延迟阈值 | 风险说明 |
|---|---|---|
| 轻负载服务 | ≤ 50 μs | 正常调度吞吐 |
| 高并发 HTTP | ≤ 200 μs | 需关注 M/P 竞争 |
| GC 频繁时段 | ≤ 500 μs | 超过则可能触发 STW 扩散 |
核心分析流程
graph TD
A[trace.Start] --> B[运行 5s+]
B --> C[go tool trace -pprof=scheddelay]
C --> D[定位 P95 > 200μs 的 Goroutine]
D --> E[结合 goroutine profile 定位阻塞点]
3.2 自研gops-sched-probe插件在高并发服务中的低开销采样实践
为应对百万级 QPS 下 Goroutine 调度行为观测的性能瓶颈,我们设计了基于 runtime.ReadMemStats 与 debug.ReadGCStats 轻量钩子的 gops-sched-probe 插件,避免全量 pprof 采集带来的毫秒级停顿。
核心采样策略
- 采用时间窗口滑动+事件触发双模采样:每 500ms 固定采集调度器统计,仅当 Goroutine 数突增 >20% 时激活栈快照;
- 所有采集在非 GC STW 阶段异步执行,内存分配压测显示 CPU 开销稳定 ≤0.17%。
关键代码片段
// sched_probe.go: 增量式调度器指标提取(无锁原子操作)
func (p *Probe) sampleSched() {
runtime.GC() // 触发 GC 统计刷新(轻量,非阻塞)
p.mstats.NumGoroutine = uint64(runtime.NumGoroutine())
p.mstats.GCSys = atomic.LoadUint64(&memstats.GCSys)
}
此函数规避
runtime.Stack()全栈遍历,仅读取已由 runtime 维护的原子变量;runtime.GC()在此处仅用于同步 GC 计数器,实际不触发 GC,耗时
性能对比(单实例,48核)
| 采样方式 | 平均延迟增量 | Goroutine 泄漏误报率 |
|---|---|---|
| pprof/goroutine | +3.2ms | 12.7% |
| gops-sched-probe | +0.04ms | 0.0% |
graph TD
A[HTTP 请求到达] --> B{采样决策器}
B -->|周期性| C[读取 NumGoroutine/GCSys]
B -->|突变触发| D[采样 runtime/pprof.Labels]
C & D --> E[聚合为 protobuf 消息]
E --> F[通过 ring-buffer 异步写入]
3.3 基于eBPF的goroutine生命周期追踪与调度延迟归因分析
Go运行时将goroutine调度细节(如newg创建、gopark阻塞、goready唤醒、schedule执行)通过trace事件暴露,但默认开销高且不可动态启停。eBPF提供零侵入、低开销的内核/用户态协同观测能力。
核心追踪点
runtime.newproc1→ goroutine创建起点runtime.gopark/runtime.goready→ 状态跃迁关键桩runtime.schedule→ 抢占与调度延迟入口
eBPF探针示例(简化)
// trace_gopark.c — 捕获阻塞原因与等待时长
SEC("tracepoint/sched/sched_blocked_reason")
int trace_blocked(struct trace_event_raw_sched_blocked_reason *ctx) {
u64 goid = get_goroutine_id(); // 自定义辅助函数,从栈帧提取G指针ID
u64 now = bpf_ktime_get_ns();
bpf_map_update_elem(&g_start_time, &goid, &now, BPF_ANY);
return 0;
}
逻辑说明:利用
sched_blocked_reasontracepoint捕获goroutine进入阻塞前的精确时间戳;get_goroutine_id()通过遍历当前task_struct的stack并解析Go ABI约定的g寄存器(如R14on amd64)实现无符号运行时依赖的goroutine ID提取;g_start_time为BPF_MAP_TYPE_HASH映射,键为goid,值为纳秒级起始时间。
调度延迟归因维度
| 维度 | 数据来源 | 典型延迟场景 |
|---|---|---|
| P空闲等待 | runtime.schedule中P无可用G |
GC STW后P重启调度延迟 |
| M阻塞再绑定 | entersyscall→exitsyscall跨度 |
syscall返回后M未及时绑定P |
| G就绪队列竞争 | runtime.runqput + runqget差值 |
高并发select导致runq溢出 |
graph TD A[goroutine创建] –>|tracepoint: runtime.newproc1| B[记录goid+start_ts] B –> C{是否park?} C –>|yes| D[tracepoint: sched_blocked_reason] C –>|no| E[直接进入M执行] D –> F[计算park_duration = now – start_ts] F –> G[按wait_reason聚合延迟分布]
第四章:面向生产环境的降级兼容方案与灰度验证
4.1 GOMAXPROCS动态调优与P数量弹性伸缩的SRE自动化脚本
Go 运行时通过 GOMAXPROCS 控制可并行执行用户 Goroutine 的 OS 线程(P)数量。静态设置易导致资源浪费或调度瓶颈,需基于实时 CPU 负载动态伸缩。
核心监控指标
- 每秒 Goroutine 创建/阻塞数(
runtime.NumGoroutine()+runtime.ReadMemStats()) - P 队列长度与 GC 周期间隔
- 系统级
cpu_usage_percent(/proc/stat解析)
自动化调优脚本(Bash + Go 混合)
#!/bin/bash
# 动态调整 GOMAXPROCS:基于 cgroup v2 CPU.max 与当前负载比
CPU_MAX=$(cat /sys/fs/cgroup/cpu.max | awk '{print $1}') # 如 50000 → 50% quota
CURRENT_LOAD=$(grep 'cpu ' /proc/stat | awk '{print $2+$3+$4}') # user+system+nice jiffies
GOMAXPROCS_TARGET=$(( CPU_MAX * CURRENT_LOAD / 100000 )) # 归一化后取整
GOMAXPROCS_TARGET=$(( GOMAXPROCS_TARGET < 2 ? 2 : GOMAXPROCS_TARGET ))
echo "Setting GOMAXPROCS=$GOMAXPROCS_TARGET"
go env -w GOMAXPROCS="$GOMAXPROCS_TARGET"
逻辑分析:脚本从 cgroup 获取容器 CPU 配额上限,结合
/proc/stat实时计算活跃 CPU 时间占比,避免硬编码阈值;GOMAXPROCS下限设为 2,防止单 P 成为调度热点;go env -w持久化影响后续子进程,适用于长期运行的 SRE 巡检任务。
推荐伸缩策略对照表
| 场景 | 初始 P 数 | 伸缩触发条件 | 最大 P 上限 |
|---|---|---|---|
| 批处理作业 | 4 | 平均队列深度 > 128 | min(32, CPU cores) |
| 实时 API 服务 | 8 | p99 延迟 > 200ms | CPU cores × 1.2 |
| 内存密集型 ETL | 2 | GC pause > 50ms | 16 |
graph TD
A[采集 CPU.load & runtime.NumGoroutine] --> B{P 队列深度 > 阈值?}
B -->|是| C[上调 GOMAXPROCS]
B -->|否| D[检查 GC pause 是否超标]
D -->|是| C
D -->|否| E[维持当前 P 数]
4.2 关键goroutine优先级标记与runtime.LockOSThread的精准隔离策略
在高实时性场景中,需确保关键goroutine独占OS线程以规避调度延迟。
核心隔离机制
runtime.LockOSThread()将当前 goroutine 与底层 M(OS线程)永久绑定- 配合
GOMAXPROCS(1)可实现单线程确定性执行(仅限该 goroutine 所在 P)
典型用法示例
func criticalLoop() {
runtime.LockOSThread()
defer runtime.UnlockOSThread() // 必须配对,防止资源泄漏
for {
processRealTimeSignal()
time.Sleep(10 * time.Microsecond) // 严格周期控制
}
}
逻辑分析:
LockOSThread禁止运行时将该 goroutine 迁移至其他 OS 线程;defer UnlockOSThread保证退出前解绑,避免 Goroutine 泄漏导致 M 永久锁定。参数无显式输入,但隐式依赖当前 goroutine 上下文。
优先级标记实践(伪代码示意)
| 标记方式 | 是否影响调度器 | 适用阶段 |
|---|---|---|
runtime.LockOSThread |
是(强制绑定) | 启动期 |
自定义 priority 字段 |
否(需配合 cgo) | 运行时动态调整 |
graph TD
A[启动关键goroutine] --> B{调用 LockOSThread}
B --> C[绑定至当前M]
C --> D[禁用抢占式调度]
D --> E[执行硬实时任务]
4.3 Go 1.22调度器回退兼容层(sched-shim)的设计与热加载验证
Go 1.22 引入 sched-shim 作为轻量级 ABI 适配层,运行于新调度器(M:N→P:M)与旧 goroutine 代码路径之间,实现零停机热切换。
核心职责
- 拦截
runtime.newproc、runtime.gopark等关键调用 - 动态路由至 legacy 或 new scheduler 实现
- 维护 goroutine 状态镜像(G.status ↔ shim.state)
热加载验证流程
// sched_shim.go(简化示意)
func shimNewProc(fn func(), arg unsafe.Pointer) {
if atomic.LoadUint32(&shimMode) == MODE_NEW {
runtime.newproc1(fn, arg) // 直通新调度器
} else {
legacy_newproc(fn, arg) // 降级到旧路径
}
}
shimMode为原子变量,由runtime.SetSchedulerMode("new"/"legacy")控制;newproc1是新调度器入口,避免直接暴露内部函数签名。
| 验证维度 | legacy 模式 | new 模式 | 切换耗时 |
|---|---|---|---|
| Goroutine 创建延迟 | 124ns | 89ns | |
| Park/Unpark 正确性 | ✅ | ✅ | 全路径状态同步校验通过 |
graph TD
A[goroutine 调用 newproc] --> B{shimMode == MODE_NEW?}
B -->|是| C[newproc1 → P:M 调度]
B -->|否| D[legacy_newproc → M:N 回退]
C & D --> E[状态镜像同步:G.schedlink, G.status]
4.4 混合版本集群下跨Go版本调度行为差异的熔断与降级决策树
当Kubernetes集群中混布 Go 1.19(runtime.Gosched 行为变更)与 Go 1.21(抢占式调度强化)节点时,kube-scheduler 的 Pod 调度延迟分布出现双峰现象。
触发条件识别
GODEBUG=schedulertrace=1日志中preemptionVictims耗时 >80ms- 节点
go version标签不一致且kubelet --version报告调度器心跳抖动
熔断判定逻辑
// 基于节点Go版本与调度延迟的联合熔断检查
func shouldCircuitBreak(node *v1.Node, latency time.Duration) bool {
goVer := node.Labels["beta.kubernetes.io/go-version"] // e.g., "go1.21.0"
majorMinor := strings.TrimPrefix(goVer, "go")[:3] // "1.21"
return latency > 100*time.Millisecond &&
(majorMinor == "1.19" || majorMinor == "1.20")
}
该函数在调度插件 Filter 阶段注入:若目标节点运行旧版 Go 且单次调度延迟超阈值,则跳过该节点,避免雪崩。
降级路径选择
| 场景 | 降级动作 | 生效范围 |
|---|---|---|
| Go ≤1.20 + 高负载 | 启用 LeastRequestedPriority 替代 NodeResourcesBalancedAllocation |
单次调度周期 |
| Go ≥1.21 + 内存压力 | 强制启用 PodTopologySpread 约束 |
全局调度器 |
graph TD
A[调度请求] --> B{节点Go版本?}
B -->|≤1.20| C[测度调度延迟]
B -->|≥1.21| D[检查内存pressure]
C -->|>100ms| E[熔断:跳过节点]
C -->|≤100ms| F[正常调度]
D -->|high| G[降级:启用拓扑打散]
第五章:从调度耗时治理到云原生可观测性体系的演进路径
在某头部电商中台团队的K8s集群治理实践中,调度耗时突增问题曾导致大促期间订单创建延迟超2.3秒,P99调度延迟从120ms飙升至1850ms。团队最初仅聚焦于kube-scheduler日志抽样分析,但发现单点日志无法还原跨组件链路——Pod Pending阶段涉及API Server鉴权、etcd写入、调度器Filter/Score、Node资源同步等多个环节。
调度链路深度埋点改造
团队在kube-scheduler中注入OpenTelemetry SDK,对每个Plugin执行周期打点(如QueueSort, PreFilter, Filter, PostFilter, Score),并透传traceID至etcd client与kubelet。关键改造包括:
- 在
Framework.RunFilterPlugins()前后记录纳秒级时间戳; - 将Node资源水位(allocatable CPU/memory)、Pod亲和性规则数量作为Span标签上报;
- 通过eBPF hook捕获etcd write阻塞时长(基于
kprobe:etcdserver_put)。
多源指标融合建模
构建调度健康度指标体系,将离散信号统一为可计算维度:
| 指标类型 | 数据来源 | 计算逻辑 | 告警阈值 |
|---|---|---|---|
| Filter耗时P95 | OTLP traces | sum(rate(scheduler_plugin_latency_seconds_bucket{plugin="Filter"}[5m])) |
>400ms |
| Node同步延迟 | kubelet metrics | kubelet_node_status_report_frequency_seconds |
>60s |
| etcd写入抖动 | etcd metrics + eBPF | histogram_quantile(0.99, rate(etcd_disk_wal_fsync_duration_seconds_bucket[1h])) |
>150ms |
可观测性平台能力升级
将原有ELK日志平台与Prometheus+Grafana栈重构为统一可观测性平台:
- 使用Tempo接入全量调度trace,支持按
node_name+pod_priority_class下钻分析; - 在Grafana中嵌入Mermaid流程图,动态渲染异常调度链路(示例):
flowchart LR
A[API Server] -->|Admission Webhook| B[etcd]
B -->|Watch Event| C[kube-scheduler]
C --> D{Filter Plugins}
D -->|Node-1 CPU=92%| E[Reject]
D -->|Node-2 Memory=45%| F[Pass]
F --> G[Bind to Node-2]
根因定位实战案例
2023年双十二前压测中,调度P99延迟达1120ms。通过Tempo按plugin=Filter筛选trace,发现73%的慢请求集中于NodeResourcesFit插件,进一步关联node_name标签,定位到3台节点CPU allocatable被静态Pod长期占满(kubectl describe node node-07 | grep -A5 Allocatable)。运维团队紧急驱逐低优先级静态Pod后,调度延迟回落至180ms。
云原生可观测性反哺架构决策
基于半年调度trace数据训练LSTM模型,预测节点资源瓶颈发生概率,驱动自动扩缩容策略优化:当predict(node_cpu_pressure_prob) > 0.85时,提前触发Cluster Autoscaler扩容,并将该预测结果注入调度器的Score阶段作为权重因子。该机制使大促期间因节点资源不足导致的调度失败率下降92.7%。
治理成效量化对比
改造前后核心指标变化如下表所示(连续30天观测均值):
| 指标 | 改造前 | 改造后 | 变化幅度 |
|---|---|---|---|
| Pod平均调度耗时 | 842ms | 156ms | ↓81.5% |
| 调度失败率 | 3.2% | 0.17% | ↓94.7% |
| P99 trace采集覆盖率 | 61% | 99.98% | ↑64.6% |
| 根因定位平均耗时 | 112min | 8.3min | ↓92.6% |
平台已接入27个微服务团队的K8s集群,日均处理调度trace 4.2亿条,支撑每秒峰值12万次Pod创建请求。
