性能、稳定性与测试
前面几天你已经能写出功能完整的插件;今天补上"上生产"的最后一环——性能与稳定性。插件跑在网关关键路径上,一点抖动都会放大。今天看 wasm-go 应对 Wasm 特有问题的三个机制(rebuild 重建、IO 限流、streaming inject),以及怎么给插件写单元测试。明天(Day 20)就编译部署收官。
Wasm 的内存难题
rebuild 重建
CommonVmCtx 有三个 rebuild 相关字段(plugin_wrapper.go:91-93):rebuildAfterRequests(处理多少请求后重建)、requestCount(当前计数)、rebuildMaxMem(内存达多少字节重建)。
通过选项开启(Day 05):WithRebuildAfterRequests(1000) / WithRebuildMaxMemBytes(100*1024*1024)。
requestCount、检查 VM 内存,达到阈值就设"重建标志",让网关在合适时机换一个新 VM。这是"主动预防内存问题"而非"等出事再处理"。两个触发条件
- 按请求数(
WithRebuildAfterRequests):处理满 N 个请求就重建——适合"内存随请求数线性增长"的场景。 - 按内存(
WithRebuildMaxMemBytes):VM 内存达到阈值就重建——更精准,直接盯内存。
WithRebuildAfterRequests(1000) + WithRebuildMaxMemBytes(100MB)。场景 A(内存涨得慢):处理到第 1000 个请求时内存才 40MB → 按请求数先触发重建。
场景 B(有个大 body 请求):才处理 300 个请求,内存已冲到 100MB → 按内存先触发重建。
两条防线像"每 1 万公里 或 每半年保养",哪个先到走哪个。
rebuild 例子
examples/rebuild-example/main.go:
wrapper.SetCtx("rebuild-example",
wrapper.ParseConfig(parseConfig),
wrapper.ProcessRequestHeaders(onHttpRequestHeaders),
wrapper.WithRebuildAfterRequests[RebuildConfig](1000), // 1000 请求后重建
wrapper.WithRebuildMaxMemBytes[RebuildConfig](100*1024*1024), // 或内存达 100MB
)
// 钩子里能读 VM 内存监控:
data, _ := proxywasm.GetProperty([]string{"plugin_vm_memory"})
memorySize := binary.LittleEndian.Uint64([]byte(data)) // 当前 VM 内存字节数
plugin_vm_memory 是 Higress 版 Envoy 暴露的属性(回想 Day 03 的 CallForeignFunction——Higress 定制),能读到当前 VM 内存用量。你可以监控它、打日志观察增长趋势,据此调 rebuild 阈值。IO 并发限制(回收 Day 10 伏笔)
WithMaxRequestsPerIoCycle(plugin_wrapper.go:490,Day 10 在 OnPluginStart 里见它被设置)。注释(:466-489)详解了它的必要性:
streaming inject
Day 12 提过的 NeedPauseStreamingResponse + PushBuffer/PopBuffer + InjectEncodedDataToFilterChain(配套 proto 在 pkg/protos/inject_encoded_data.pb.go):用于"流式响应期间调外部服务再改写内容"。
NeedPauseStreamingResponse)→ 缓冲当前数据到内部队列(PushBuffer)→ 异步调外部服务 → 拿到结果后 InjectEncodedDataToFilterChain 把改写后的数据注入回流。这是 wasm-go 里最复杂的能力,只有内容改写类插件才用得上,一般插件无需碰。pkg/test 单元测试
pkg/test/ 提供测试辅助:test.go(测试框架)、host.go(模拟宿主环境)、redis.go(模拟 Redis)、utils.go。配合 rule_matcher_test.go、cluster_wrapper_test.go 等测试文件。
pkg/test 提供一个"模拟宿主",让你在普通 Go 测试里模拟"请求头到达""发起 HTTP 调用"等,验证插件行为。这样能像测普通 Go 代码一样 go test 插件逻辑,不用起真网关。写插件时配上单测,能在部署前抓住大部分 bug——这是工程化的重要一环。看 rule_matcher_test.go 学怎么测规则匹配。今日小结 + 动手
🧠 今天你应该能回答
- 为什么 Wasm 里 Go 插件会内存膨胀?rebuild 怎么解决?
- rebuild 两个触发条件?取值怎么权衡?
- IO 并发限制解决什么隐患?为什么全局取最小值?
- streaming inject 适合什么场景?怎么给插件写单测?
✋ 动手
cd /Users/bitmart/work/codes/github/higress-group/wasm-go
cat examples/rebuild-example/main.go
sed -n '435,505p' pkg/wrapper/plugin_wrapper.go
ls pkg/test/
go test ./pkg/matcher/ 2>&1 | tail -20