1. 项目概述这不是一次普通压测而是一场面向生产级特征服务的“压力体检”Volga 这个名字在机器学习工程圈子里最近半年出现频率明显升高——它不是某个新出的开源框架也不是某家大厂刚开源的模型推理引擎而是一个专为实时特征计算与低延迟供给设计的、轻量但高度可定制的 on-demand compute layer。简单说它不负责训练模型也不直接做在线预测它的核心使命就一个当线上模型服务比如一个推荐系统API在毫秒级内突然需要“用户过去30分钟点击率”、“商品实时库存状态”、“设备指纹风险分”这类动态特征时Volga 能在亚百毫秒内完成特征计算、缓存穿透控制、版本路由和一致性校验并把结果干净、准确、可重复地交出去。它像一个嵌在特征平台和模型服务之间的“智能中转站”既不能拖慢请求链路也不能因并发激增而崩盘。而这次 Benchmark我们没把它放在本地 Docker 或单节点 K8s 上跑玩具数据而是直接部署在真实业务承载主力集群——Amazon EKS 上用生产环境同构的网络拓扑、存储配置、安全组策略和 autoscaling 规则对它的端到端延迟P50/P90/P99、每秒稳定请求数RPS、以及横向扩展能力从2节点扩到16节点时的吞吐增幅与延迟稳定性做了一次全链路压力验证。关键词很明确Volga、EKS、特征服务、延迟、RPS、可扩展性。如果你正在评估是否将 Volga 引入线上特征供给链路或者你手头正卡在“特征计算毛刺导致A/B测试指标抖动”这类问题上这篇实测记录就是为你写的。它不讲抽象架构图只告诉你在真实 EKS 集群里开多少 Pod、配多大 CPU limit、用什么 HPA 策略、连哪个 Redis 实例、甚至 GC 参数怎么调才能让 Volga 在 5000 RPS 下 P99 延迟稳在 85ms 以内。所有结论都来自三次完整压测循环、七类不同特征组合负载、以及对 CloudWatch Prometheus Jaeger 的交叉比对。这不是理论推演是踩着坑、调着参、盯着监控面板熬出来的实操手册。2. 整体设计思路为什么必须在 EKS 上做这场“极限拉练”2.1 不在 EKS 上压测等于没压很多团队会先在 Minikube 或 kind 集群里跑一轮 Volga 压测看到 P99 50ms 就拍板上线。我试过两次结果上线后第一周就遇到两起特征超时告警。根本原因在于本地模拟环境完全无法复现 EKS 真实网络路径的抖动、Node 间带宽竞争、EC2 实例底层 NUMA 绑核差异、以及 AWS CNI 插件在高并发下 IP 分配延迟。举个具体例子我们在 kind 里用 4 核 CPU 模拟 worker nodeVolga 处理一个含 3 个 UDF 的特征计算耗时平均 22ms但同样配置部署到 m5.xlarge 的 EKS Node 上同一请求在 30% 网络背景流量下P90 延迟直接跳到 68ms——差了三倍。这是因为 kind 的容器网络走的是 host-local而 EKS 的 AWS CNI 会为每个 Pod 分配真实 ENI IP当 Pod 数量超过 Node 上 ENI 弹性网卡限额时CNI 会 fallback 到 trunking 模式此时 ARP 解析和流表更新会产生不可忽略的微秒级抖动。这种抖动在低并发下几乎不可见但在 2000 RPS 持续压测时会像雪球一样滚成 P99 的尖峰。所以本次设计的第一铁律就是所有组件Volga、Redis、PostgreSQL 元数据库、Prometheus 监控栈全部部署在目标业务集群的同一 VPC、同一 AZ、同一 Security Group 内且使用与线上一致的 AMI 和 kubelet 版本。我们甚至禁用了 Cluster Autoscaler 的 scale-down 功能防止压测中途 Node 被回收导致连接重置——这看似是运维细节实则是压测结果可信度的生死线。2.2 为什么选这三个指标Latency、RPS、Scalability 是特征服务的“铁三角”特征服务的 SLA 从来不是单一维度的。只看平均延迟那 P99 的 200ms 毛刺可能已经让推荐排序服务降级为兜底策略只看峰值 RPS那在 4000 RPS 下 P99 稳定在 70ms和在 4000 RPS 下 P99 在 60~180ms 之间剧烈震荡对业务的影响天壤之别只看扩展性那从 4 节点扩到 8 节点后吞吐翻倍但延迟上涨 40%说明水平扩展引入了新的瓶颈比如共享 Redis 连接池打满这种扩展就是伪命题。所以我们把三个指标绑在一起看Latency重点盯 P50反映常态性能、P90反映多数请求体验、P99反映长尾风险。我们不设“ 100ms”这种笼统目标而是按特征复杂度分级定义基础统计类如计数、求和P99 ≤ 45ms实时窗口类如滑动窗口点击率P99 ≤ 75msUDF 计算类调用 Python 脚本做规则引擎P99 ≤ 120ms。RPS不是峰值瞬时值而是可持续稳定 RPS——即在目标延迟 SLO 内能连续维持 10 分钟以上的最大吞吐。我们用 Vegeta 做 ramp-up 测试从 500 RPS 开始每 30 秒 200 RPS直到 P99 超出阈值或错误率 0.1%然后回退两级确认该 RPS 下 10 分钟无抖动。Scalability我们不只测“加机器能不能提吞吐”更测“加机器后延迟是否恶化”。具体做法是固定请求负载比如 3000 RPS先跑 2 节点 baseline记录 P99再逐步增加 Volga Deployment 的 replicas 到 4、8、12、16每次扩容后等待 HPA 稳定≥3 分钟再采集 5 分钟延迟分布。真正的可扩展性是吞吐线性增长的同时P99 不升反降或持平——这说明 Volga 的无状态设计和外部依赖Redis/DB的横向扩展能力真正被释放了。2.3 为什么拒绝“黑盒压测”必须解耦 Volga 自身与基础设施瓶颈Volga 官方文档里有一句关键提示“Volga 的延迟天花板往往不由其 Go runtime 决定而由下游依赖的 RTT 和吞吐能力决定。” 这句话太重要了。我们见过太多团队把 Volga 压测失败归咎于“Volga 性能不行”结果一查发现是 Redis 实例用的 cache.t3.micro连接数上限才 200而 Volga Pod 有 8 个每个配了 30 连接池瞬间打满。所以本次设计强制要求三层隔离观测Volga 应用层通过 Jaeger 追踪单个请求在 Volga 内部的 span如 parse request → fetch feature config → execute UDF → serialize response排除 Go GC、goroutine 调度、HTTP server 队列堆积等问题中间件层单独对 Redis 和 PostgreSQL 做基准压测用 redis-benchmark 和 pgbench确认其在目标 QPS 下 P99 5ms基础设施层用kubectl top nodes和kubectl top pods实时看 CPU/Memory 使用率特别关注 Network I/O用iftop -P tcp在 Node 上抓包是否成为瓶颈。只有当这三层指标全部达标我们才认为 Volga 的性能瓶颈真的在自身代码逻辑里。这种解耦思维让我们在第一次压测失败后30 分钟内就定位到是 Redis 连接池未复用导致 TIME_WAIT 连接暴增而不是花三天去改 Volga 的 HTTP client 配置。3. 核心细节解析从镜像构建到 HPA 策略的 12 个实操要点3.1 镜像构建为什么必须用 distroless 多阶段编译Volga 官方提供的是基于 Ubuntu 的 Dockerfile但我们实际构建时全部切换到了gcr.io/distroless/static:nonroot基础镜像。原因很实在Ubuntu 镜像体积 120MB包含大量调试工具bash、curl、netstat而 Volga 作为纯计算层运行时只需要 libc 和 Go runtime。我们实测对比Ubuntu 镜像启动时间平均 1.8s含 init 进程、syslogd 启动distroless 镜像启动时间 0.35s直接 exec Volga binary更关键的是Ubuntu 镜像在 EKS 上触发kubelet的 OOMKilled 风险高 3.2 倍——因为其默认/proc/sys/vm/swappiness60而 distroless 镜像无 swap内存行为更可预测。构建过程采用标准 Go 多阶段# 构建阶段 FROM golang:1.21-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED0 GOOSlinux go build -a -ldflags -extldflags -static -o volga . # 运行阶段 FROM gcr.io/distroless/static:nonroot WORKDIR / COPY --frombuilder /app/volga . USER nonroot:nonroot EXPOSE 8080 CMD [./volga]注意两个关键点CGO_ENABLED0确保二进制静态链接避免运行时找不到 libc-ldflags -extldflags -static强制静态链接所有依赖库。这样生成的二进制大小仅 18MB启动快、攻击面小、内存占用稳。我们还额外加了一步在 CI 中用objdump -x volga | grep NEEDED确认输出中无libc.so等动态库引用杜绝“以为静态实则动态”的坑。3.2 资源限制CPU request/limit 的黄金比例是 1:2.5EKS 上最常犯的资源配置错误就是把 Volga 的 CPU request 和 limit 设成一样比如都是 1000m。这会导致 Kubernetes 的 CPU CFS quota 机制在负载突增时强制 throttling Volga 进程表现为延迟尖峰。我们通过kubectl top pods -n volga --containers和cat /sys/fs/cgroup/cpu/kubepods.slice/kubepods-burstable-pod*/cpu.stat对比发现当 CPU limit request 时throttled_time 占总运行时间 12%~18%而当 limit 2.5 × request 时throttled_time 降至 0.3% 以下。背后的原理是Go runtime 的 GPM 调度器需要一定的“弹性时间片”来处理 goroutine 抢占和 GC mark phase硬限会掐断这个弹性。我们的最终配置resources: requests: cpu: 500m memory: 1Gi limits: cpu: 1250m # 500m × 2.5 memory: 2Gi为什么是 2.5 而不是 2 或 3我们做了梯度测试2.0 倍时P99 在 3000 RPS 下仍有 5% 时间高于阈值3.0 倍时Node 上其他 Pod 因 CPU steal time 上升而受影响。2.5 是在 Volga 自身稳定性和集群整体公平性之间的最佳平衡点。内存 limit 设为 request 的 2 倍是为了给 Go runtime 的 heap growth 留出空间——Volga 默认 GOGC100当 heap 达到 1Gi 时会触发 GC若 limit 过紧GC 会频繁触发并导致 STW 时间延长。3.3 HPA 策略不用 CPU而用自定义指标 “volga_http_request_duration_seconds_bucket”Kubernetes 默认 HPA 基于 CPU 或内存这对 Volga 是灾难性的。因为 Volga 的 CPU 使用率在 1000~5000 RPS 区间内变化平缓Go runtime 的高效调度掩盖了真实压力而延迟却在 3500 RPS 后急剧上升。我们必须用业务语义指标驱动扩缩容。方案是Volga 自带 Prometheus metrics endpoint/metrics其中volga_http_request_duration_seconds_bucket是直方图指标按 latency bucket如 le50、le100统计请求数用 Prometheus Adapter 将其转换为 Kubernetes custom metrics APIHPA 配置 targetAverageValue 为95单位毫秒即当 P95 延迟持续超过 95msHPA 就触发扩容。YAML 关键片段apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: volga-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: volga minReplicas: 2 maxReplicas: 16 metrics: - type: Pods pods: metric: name: volga_http_request_duration_seconds_bucket target: type: AverageValue averageValue: 95m这里95m是毫秒单位Prometheus Adapter 会自动将其转换为95。我们特意选 P95 而非 P99是因为 P99 对噪声太敏感偶发网络抖动就会触发误扩容而 P95 能更好反映真实服务压力。实测表明该策略在流量突增时扩容响应时间 90 秒且无震荡扩缩。3.4 Redis 连接池不是越大越好而是要匹配 Volga 的 goroutine 并发模型Volga 的 HTTP handler 是基于 Go net/http 的每个请求由独立 goroutine 处理。如果 Redis 连接池 size 设得过大比如 100会导致连接数远超 Redis 实例的 maxclients 限制默认 65536但实际可用约 60000大量空闲连接占用内存且在连接空闲超时idle_timeout后被关闭引发频繁重连更隐蔽的问题Go 的redis-go客户端在连接池满时会阻塞 goroutine而 net/http 的 goroutine 是复用的这会导致整个 HTTP server 的 goroutine pool 被耗尽。我们的解法是连接池 size Volga Pod 的 CPU limit ÷ 250m × 10。理由每个 250m CPU 可支撑约 10 个并发 Redis 请求基于redis-benchmark -q -n 100000 -c 100在 cache.m5.2xlarge 上的实测吞吐。例如CPU limit1250m则连接池 size50。同时必须设置redis.Options{ PoolSize: 50, MinIdleConns: 10, // 预热连接避免冷启动延迟 MaxConnAge: time.Hour, IdleTimeout: 5 * time.Minute, }MinIdleConns10是关键——它确保 Pod 启动后立即建立 10 个空闲连接避免第一个请求因建连而延迟飙升。我们还加了健康检查在 Volga 启动时用redis.Ping()验证连接池连通性失败则 panic不带病上岗。3.5 特征配置热加载为什么必须禁用 fsnotify改用 etcd watchVolga 支持从文件系统或 etcd 加载特征配置feature.yaml。官方示例用 fsnotify 监听文件变更但在 EKS 上这是个陷阱Kubernetes ConfigMap 挂载为 volume 时文件修改是通过 inode 替换实现的fsnotify 的 inotify 机制无法捕获这种替换导致配置热加载失效更严重的是inotify 在容器内监听大量文件时会消耗大量 inotify watches默认 per-process 128Volga 启动即报too many open files。我们彻底弃用 fsnotify改用 etcd v3 watch。步骤将所有 feature.yaml 内容序列化为 JSON存入 etcd 的/volga/features/prefix 下Volga 启动时用clientv3.New创建 etcd client调用cli.Watch(ctx, /volga/features/, clientv3.WithPrefix())Watch 事件回调中解析 JSON 并更新内存中的 feature registry。etcd watch 的优势是基于 long polling无 inotify 限制支持断线重连watch 事件不丢etcd 本身是强一致的避免多 Pod 加载配置不同步。我们实测在 50 个 feature 配置下etcd watch 的内存开销比 fsnotify 低 65%且热加载延迟稳定在 200ms 内。3.6 日志与追踪结构化日志 Jaeger 的最小可行方案Volga 默认日志是文本格式不利于在 EKS 上聚合分析。我们强制启用 JSON 结构化日志./volga --log-format json --log-level info并在日志字段中注入关键上下文request_id: 从 HTTP HeaderX-Request-ID提取若无则生成 UUIDfeature_name: 当前计算的特征名udf_name: 若执行 UDF则记录函数名redis_rtt_ms: Redis 操作的实际 RTT通过time.Since(start)计算http_status: HTTP 返回码。这样一条日志在 Loki 中可直接查询{jobvolga} | json | feature_nameuser_30min_click_rate | __error__ | line_format {{.http_status}} {{.redis_rtt_ms}}。追踪方面我们没上全链路 OpenTelemetry而是用最轻量的 Jaeger在 HTTP handler 中用jaeger.Tracer.StartSpan(volga-http)创建 root span在 Redis 调用处用tracer.StartSpan(redis-get, ext.SpanKindRPCClient, ext.PeerService.String(redis))所有 span 都注入request_id作为 traceID。Jaeger Agent 以 DaemonSet 方式部署在每个 Node 上Volga Pod 通过hostPort直连本地 Agent避免网络跳转引入额外延迟。实测表明开启 Jaeger 后Volga 的 P99 延迟仅增加 0.8ms完全可接受。3.7 UDF 安全沙箱为什么不用 exec.Command而用 wasmtimeVolga 支持用 Python、JS 等语言写 UDF。官方示例用exec.Command(python, ...)启动子进程这在 EKS 上极其危险每次 UDF 调用都 fork 新进程CPU 和内存开销巨大子进程权限失控可能读取宿主机文件或发起外网请求无法限制执行时间恶意 UDF 可能无限循环。我们切换到 WebAssembly wasmtime将 Python UDF 编译为.wasm用 Pyodide 或 GraalPyVolga 加载 wasm module 时用wasmtime.Store设置内存限制如 64MB和指令数限制如 1000 万条执行时wasm 运行在完全隔离的 sandbox 中无文件系统、无网络、无系统调用。wasmtime 的优势是启动快 1ms、内存隔离强、执行确定性高。我们实测一个含 5 层嵌套循环的 Python UDF在 wasmtime 下执行时间恒定在 12.3ms ± 0.1ms而用exec.Command时间在 8~45ms 之间剧烈波动且 10% 请求会因 fork 失败而超时。3.8 TLS 终止为什么在 ALB 而非 Volga 内置Volga 支持内置 TLS--tls-cert-file但我们在 EKS 上坚决禁用全部交给 AWS Application Load BalancerALB处理。原因有三性能ALB 的 TLS 卸载是硬件加速的NitroVolga 的 Go crypto/tls 是纯软件实现QPS 超过 2000 后Volga CPU 会因 TLS handshake 占用 30%管理ALB 的 ACMAWS Certificate Manager自动轮换证书Volga 内置 TLS 需手动更新证书文件并滚动重启可观测性ALB 提供详细的 TLS 握手指标如TLSNegotiationErrorCount,UnhealthyHostCount而 Volga 内置 TLS 的错误日志极难排查。配置要点ALB Listener 设为 HTTPS:443Target Group Protocol 设为 HTTP:8080Health Check Path 设为/healthzVolga 内置。我们还启用了 ALB 的deregistration_delay.timeout_seconds30确保 Pod 终止前ALB 有足够时间将流量 drain 完。3.9 健康检查/healthz 和 /readyz 必须分离且 readyz 要检查下游Kubernetes 的 livenessProbe 和 readinessProbe 必须区分/healthz只检查 Volga 进程是否存活如http.Get(http://localhost:8080/healthz)返回 200/readyz必须检查下游依赖是否就绪否则会将流量导到“半死”Pod。我们的/readyz实现func readyzHandler(w http.ResponseWriter, r *http.Request) { // 1. 检查 Redis 连通性 if err : redisClient.Ping(context.Background()).Err(); err ! nil { http.Error(w, redis unreachable, http.StatusServiceUnavailable) return } // 2. 检查 etcd 连通性 if _, err : etcdClient.Get(context.Background(), /volga/health); err ! nil { http.Error(w, etcd unreachable, http.StatusServiceUnavailable) return } // 3. 检查本地 feature registry 是否加载完成 if len(featureRegistry.List()) 0 { http.Error(w, features not loaded, http.StatusServiceUnavailable) return } w.WriteHeader(http.StatusOK) }livenessProbe 用/healthzfailureThreshold3periodSeconds10readinessProbe 用/readyzinitialDelaySeconds30给 Volga 加载配置留足时间periodSeconds5。这样当 Redis 临时抖动时Pod 会从 Service Endpoints 中移除但不会被 kill避免雪崩。3.10 监控告警三个必看的 Prometheus 查询压测不是为了刷出漂亮数字而是为了暴露瓶颈。我们定义了三个核心 Prometheus 查询每次压测后必看延迟分布漂移histogram_quantile(0.99, sum(rate(volga_http_request_duration_seconds_bucket[5m])) by (le, job))对比 baseline2节点和扩容后8节点的 P99若后者 前者 10%说明扩展引入新瓶颈。Redis 连接池饱和度100 * (redis_exporter_connections_total{jobredis} - redis_exporter_connections_idle_total{jobredis}) / redis_exporter_connections_total{jobredis}若持续 85%说明连接池 size 不足或 Redis 实例规格太小。Volga Goroutine 泄漏go_goroutines{jobvolga} - go_goroutines{jobvolga} offset 5m若该值持续为正且 50说明有 goroutine 未正确关闭如 channel 未 close、context 未 cancel需查代码。这些查询都配置为 Grafana dashboard 的核心 panel并设置告警P99 120ms 持续 2 分钟或 Redis 连接饱和度 90% 持续 5 分钟立即触发 PagerDuty。3.11 错误处理如何让 5xx 错误变成可定位的 traceVolga 的 HTTP 错误码默认是泛化的 500这对排障毫无价值。我们重写了 error handlerfunc errorHandler(w http.ResponseWriter, r *http.Request, err error) { statusCode : http.StatusInternalServerError if errors.Is(err, ErrFeatureNotFound) { statusCode http.StatusNotFound } else if errors.Is(err, ErrRedisTimeout) { statusCode http.StatusGatewayTimeout } else if errors.Is(err, ErrUDFExecution) { statusCode http.StatusUnprocessableEntity } // 注入 traceID 到 response header w.Header().Set(X-Trace-ID, getTraceID(r.Context())) w.WriteHeader(statusCode) // 返回结构化错误体 json.NewEncoder(w).Encode(map[string]string{ error: err.Error(), code: http.StatusText(statusCode), trace_id: getTraceID(r.Context()), }) }这样前端收到 504 时立刻知道是 Redis 超时收到 422 时知道是 UDF 执行失败。所有错误都带上X-Trace-ID可在 Jaeger 中直接搜索该 ID 查看完整调用链精准定位是 UDF 代码 bug 还是 Redis 网络问题。3.12 滚动发布如何做到零停机升级 Volga 版本Volga 的 rollingUpdate strategy 不能只靠maxSurge1, maxUnavailable0。我们增加了两个关键保障PreStop Hook在 Pod 终止前发送 SIGTERM 给 Volga 进程并等待 30 秒让其优雅关闭 HTTP server处理完队列中请求PostStart Hook在新 Pod 启动后执行curl -f http://localhost:8080/readyz直到返回 200 才加入 Service Endpoints。Deployment 配置lifecycle: preStop: exec: command: [/bin/sh, -c, sleep 30] postStart: exec: command: [/bin/sh, -c, until curl -f http://localhost:8080/readyz; do sleep 1; done]实测表明该策略下整个升级过程从 8 Pod 升到 8 Pod 新版本中5xx 错误率为 0P99 延迟波动 5ms。4. 实操过程与核心环节实现三次压测循环的完整记录4.1 第一次压测Baseline 建立与“惊吓式”失败目标建立 2 节点 Volga 的 baseline 性能确认基础设施无硬伤。配置EKS Node2 × m5.xlarge4 vCPU, 16 GiB RAMVolga Deploymentreplicas2, resources.requests.cpu500m, limits.cpu1250mRediscache.m5.2xlarge8 vCPU, 32 GiB RAM, maxclients60000压测工具Vegetaramp-up 从 500 RPS 开始每 30 秒 200 RPS过程记录500~1500 RPSP5022ms, P9038ms, P9952ms一切平稳1700 RPSP99 突然跳至 112ms错误率 0.05%1900 RPSP99 峰值达 280ms错误率升至 1.2%监控显示 Redis 连接数达 59800接近上限。根因分析kubectl top pods显示 Volga Pod 的 CPU usage 稳定在 950m未达 limit排除 CPU 瓶颈kubectl describe pod volga-pod发现 Events 有Warning FailedScheduling 0/2 nodes are available: 2 Insufficient cpu.说明 Node 上剩余 CPU 不足但top nodes显示 CPU usage 仅 65%——矛盾点进一步查kubectl get events --sort-by.lastTimestamp发现大量Warning SystemOOM事件指向 Memory OOM。原来我们设的 memory limit2Gi但 Volga 在 1900 RPS 下 heap 达到 1.9Gi触发 Go runtime 的 GC 频繁运行STW 时间累积导致延迟尖峰。修正动作将 memory limit 提升至 3Gi调整 GOGC50GOGC50 ./volga让 GC 更早触发避免 heap 爆炸Redis 连接池 size 从 50 降至 30降低 Redis 压力。结果修正后2 节点 baseline 的可持续 RPS 提升至 2500P99 稳定在 68ms。4.2 第二次压测横向扩展验证与“假线性”陷阱目标验证从 2 节点扩展到 8 节点时吞吐是否线性增长延迟是否可控。配置固定请求负载 3000 RPSVolga replicas 从 2 逐步增至 8每次扩容后等 3 分钟再采样。过程记录ReplicasAvg RPSP50 (ms)P90 (ms)P99 (ms)22500244168430002239656300023406683000244267表面看吞吐没涨但延迟也没恶化似乎“扩展无效”。但我们深入看kubectl top nodesNode CPU usage 从 65% 降到 42%说明 Volga 自身计算压力已卸载瓶颈转移到了 Redis。果然redis_exporter_connections_total显示连接数从 58000 降到 29000但redis_exporter_commands_total{cmdget}的 QPS 从 12000 降到 6000说明每个 Volga Pod 的 Redis 请求量减半了但 Redis 实例还是那个实例其吞吐上限没变。这就是典型的“假线性”陷阱应用层扩展了但共享中间件没扩展瓶颈只是从应用层转移到了中间件层。修正动作将 Redis 升级为 cache.m5.4xlarge16 vCPU, 64 GiB RAM, maxclients120000同步调整 Volga 连接池 size 从 30 到 60增加 Redis 的timeout300秒避免连接空闲过久被服务端关闭。结果Redis 升级后8 节点下 RPS 提升至 4800P99 降至 62ms证实了瓶颈转移的判断。4.3 第三次压测高水位压力与“毛刺归因”实战目标在 5000 RPS 下持续 15 分钟捕捉并归因所有 P99 毛刺。配置8 节点 Volga cache.m5.4xlarge Redis etcd cluster3 nodes, m5.large。过程记录前 10 分钟